2024-05-28 01:37:40 -04:00
import logging
2024-05-26 13:44:17 -04:00
from spandrel import ModelLoader , ImageModelDescriptor
2023-04-15 18:55:17 -04:00
from comfy import model_management
2023-03-11 13:09:28 -05:00
import torch
2023-03-11 14:04:13 -05:00
import comfy . utils
2023-03-17 17:57:57 -04:00
import folder_paths
2025-10-10 02:08:40 +03:00
from typing_extensions import override
from comfy_api . latest import ComfyExtension , io
2026-04-10 18:48:26 -07:00
import comfy . model_management
2026-07-25 06:34:40 +10:00
import comfy . model_patcher
2023-03-11 13:09:28 -05:00
2024-05-28 01:37:40 -04:00
try :
from spandrel_extra_arches import EXTRA_REGISTRY
from spandrel import MAIN_REGISTRY
MAIN_REGISTRY . add ( * EXTRA_REGISTRY )
logging . info ( " Successfully imported spandrel_extra_arches: support for non commercial upscale models. " )
except :
pass
2025-10-10 02:08:40 +03:00
class UpscaleModelLoader ( io . ComfyNode ) :
2023-03-11 13:09:28 -05:00
@classmethod
2025-10-10 02:08:40 +03:00
def define_schema ( cls ) :
return io . Schema (
node_id = " UpscaleModelLoader " ,
display_name = " Load Upscale Model " ,
2026-05-27 17:43:33 -07:00
category = " model/loaders " ,
2025-10-10 02:08:40 +03:00
inputs = [
io . Combo . Input ( " model_name " , options = folder_paths . get_filename_list ( " upscale_models " ) ) ,
] ,
outputs = [
io . UpscaleModel . Output ( ) ,
] ,
)
2023-03-11 13:09:28 -05:00
2025-10-10 02:08:40 +03:00
@classmethod
def execute ( cls , model_name ) - > io . NodeOutput :
2024-09-17 16:57:17 +09:00
model_path = folder_paths . get_full_path_or_raise ( " upscale_models " , model_name )
2023-05-14 15:10:40 -04:00
sd = comfy . utils . load_torch_file ( model_path , safe_load = True )
2023-09-07 03:31:43 -04:00
if " module.layers.0.residual_group.blocks.0.norm1.weight " in sd :
sd = comfy . utils . state_dict_prefix_replace ( sd , { " module. " : " " } )
2024-05-26 13:44:17 -04:00
out = ModelLoader ( ) . load_from_state_dict ( sd ) . eval ( )
if not isinstance ( out , ImageModelDescriptor ) :
raise Exception ( " Upscale model must be a single-image model. " )
2026-07-25 06:34:40 +10:00
out . patcher = comfy . model_patcher . CoreModelPatcher ( out . model , load_device = model_management . get_torch_device ( ) , offload_device = model_management . unet_offload_device ( ) )
2025-10-10 02:08:40 +03:00
return io . NodeOutput ( out )
2023-03-11 13:09:28 -05:00
2025-10-10 02:08:40 +03:00
load_model = execute # TODO: remove
2023-03-11 13:09:28 -05:00
2025-10-10 02:08:40 +03:00
class ImageUpscaleWithModel ( io . ComfyNode ) :
@classmethod
def define_schema ( cls ) :
return io . Schema (
node_id = " ImageUpscaleWithModel " ,
display_name = " Upscale Image (using Model) " ,
category = " image/upscaling " ,
2026-01-21 15:36:02 -08:00
search_aliases = [ " upscale " , " upscaler " , " upsc " , " enlarge image " , " super resolution " , " hires " , " superres " , " increase resolution " ] ,
2025-10-10 02:08:40 +03:00
inputs = [
io . UpscaleModel . Input ( " upscale_model " ) ,
io . Image . Input ( " image " ) ,
] ,
outputs = [
io . Image . Output ( ) ,
] ,
)
2023-03-11 13:09:28 -05:00
2025-10-10 02:08:40 +03:00
@classmethod
def execute ( cls , upscale_model , image ) - > io . NodeOutput :
2026-07-25 06:34:40 +10:00
device = upscale_model . patcher . load_device
2024-04-22 18:42:41 -04:00
2026-07-25 06:34:40 +10:00
memory_required = ( 512 * 512 * 3 ) * image . element_size ( ) * max ( upscale_model . scale , 1.0 ) * 384.0 #The 384.0 is an estimate of how much some of these models take, TODO: make it more accurate
2024-04-22 18:42:41 -04:00
memory_required + = image . nelement ( ) * image . element_size ( )
2026-07-25 06:34:40 +10:00
model_management . load_models_gpu ( [ upscale_model . patcher ] , memory_required = memory_required )
2024-04-22 18:42:41 -04:00
2023-03-11 13:09:28 -05:00
in_img = image . movedim ( - 1 , - 3 ) . to ( device )
2023-07-24 19:47:32 -04:00
tile = 512
overlap = 32
2026-04-10 18:48:26 -07:00
output_device = comfy . model_management . intermediate_device ( )
2023-07-24 19:47:32 -04:00
oom = True
2026-07-25 06:34:40 +10:00
while oom :
try :
steps = in_img . shape [ 0 ] * comfy . utils . get_tiled_scale_steps ( in_img . shape [ 3 ] , in_img . shape [ 2 ] , tile_x = tile , tile_y = tile , overlap = overlap )
pbar = comfy . utils . ProgressBar ( steps )
s = comfy . utils . tiled_scale ( in_img , lambda a : upscale_model ( a . float ( ) ) , tile_x = tile , tile_y = tile , overlap = overlap , upscale_amount = upscale_model . scale , pbar = pbar , output_device = output_device )
oom = False
except Exception as e :
model_management . raise_non_oom ( e )
tile / / = 2
if tile < 128 :
raise e
2026-01-04 16:13:50 -08:00
2026-04-10 18:48:26 -07:00
s = torch . clamp ( s . movedim ( - 3 , - 1 ) , min = 0 , max = 1.0 ) . to ( comfy . model_management . intermediate_dtype ( ) )
2025-10-10 02:08:40 +03:00
return io . NodeOutput ( s )
upscale = execute # TODO: remove
class UpscaleModelExtension ( ComfyExtension ) :
@override
async def get_node_list ( self ) - > list [ type [ io . ComfyNode ] ] :
return [
UpscaleModelLoader ,
ImageUpscaleWithModel ,
]
2023-03-11 13:09:28 -05:00
2025-10-10 02:08:40 +03:00
async def comfy_entrypoint ( ) - > UpscaleModelExtension :
return UpscaleModelExtension ( )