CoolFace
Apppublic

fred-dev/comfy_ui_ali

sourceHugging Facemitupdated 1y agoView on Hugging Face
0likes
ops.py376 linesDownload Raw Back to comfy
1"""2    This file is part of ComfyUI.3    Copyright (C) 2024 Stability AI4 5    This program is free software: you can redistribute it and/or modify6    it under the terms of the GNU General Public License as published by7    the Free Software Foundation, either version 3 of the License, or8    (at your option) any later version.9 10    This program is distributed in the hope that it will be useful,11    but WITHOUT ANY WARRANTY; without even the implied warranty of12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the13    GNU General Public License for more details.14 15    You should have received a copy of the GNU General Public License16    along with this program.  If not, see <https://www.gnu.org/licenses/>.17"""18 19import torch20import logging21import comfy.model_management22from comfy.cli_args import args, PerformanceFeature23import comfy.float24 25cast_to = comfy.model_management.cast_to #TODO: remove once no more references26 27def cast_to_input(weight, input, non_blocking=False, copy=True):28    return comfy.model_management.cast_to(weight, input.dtype, input.device, non_blocking=non_blocking, copy=copy)29 30def cast_bias_weight(s, input=None, dtype=None, device=None, bias_dtype=None):31    if input is not None:32        if dtype is None:33            dtype = input.dtype34        if bias_dtype is None:35            bias_dtype = dtype36        if device is None:37            device = input.device38 39    bias = None40    non_blocking = comfy.model_management.device_supports_non_blocking(device)41    if s.bias is not None:42        has_function = len(s.bias_function) > 043        bias = comfy.model_management.cast_to(s.bias, bias_dtype, device, non_blocking=non_blocking, copy=has_function)44        if has_function:45            for f in s.bias_function:46                bias = f(bias)47 48    has_function = len(s.weight_function) > 049    weight = comfy.model_management.cast_to(s.weight, dtype, device, non_blocking=non_blocking, copy=has_function)50    if has_function:51        for f in s.weight_function:52            weight = f(weight)53    return weight, bias54 55class CastWeightBiasOp:56    comfy_cast_weights = False57    weight_function = []58    bias_function = []59 60class disable_weight_init:61    class Linear(torch.nn.Linear, CastWeightBiasOp):62        def reset_parameters(self):63            return None64 65        def forward_comfy_cast_weights(self, input):66            weight, bias = cast_bias_weight(self, input)67            return torch.nn.functional.linear(input, weight, bias)68 69        def forward(self, *args, **kwargs):70            if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:71                return self.forward_comfy_cast_weights(*args, **kwargs)72            else:73                return super().forward(*args, **kwargs)74 75    class Conv1d(torch.nn.Conv1d, CastWeightBiasOp):76        def reset_parameters(self):77            return None78 79        def forward_comfy_cast_weights(self, input):80            weight, bias = cast_bias_weight(self, input)81            return self._conv_forward(input, weight, bias)82 83        def forward(self, *args, **kwargs):84            if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:85                return self.forward_comfy_cast_weights(*args, **kwargs)86            else:87                return super().forward(*args, **kwargs)88 89    class Conv2d(torch.nn.Conv2d, CastWeightBiasOp):90        def reset_parameters(self):91            return None92 93        def forward_comfy_cast_weights(self, input):94            weight, bias = cast_bias_weight(self, input)95            return self._conv_forward(input, weight, bias)96 97        def forward(self, *args, **kwargs):98            if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:99                return self.forward_comfy_cast_weights(*args, **kwargs)100            else:101                return super().forward(*args, **kwargs)102 103    class Conv3d(torch.nn.Conv3d, CastWeightBiasOp):104        def reset_parameters(self):105            return None106 107        def forward_comfy_cast_weights(self, input):108            weight, bias = cast_bias_weight(self, input)109            return self._conv_forward(input, weight, bias)110 111        def forward(self, *args, **kwargs):112            if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:113                return self.forward_comfy_cast_weights(*args, **kwargs)114            else:115                return super().forward(*args, **kwargs)116 117    class GroupNorm(torch.nn.GroupNorm, CastWeightBiasOp):118        def reset_parameters(self):119            return None120 121        def forward_comfy_cast_weights(self, input):122            weight, bias = cast_bias_weight(self, input)123            return torch.nn.functional.group_norm(input, self.num_groups, weight, bias, self.eps)124 125        def forward(self, *args, **kwargs):126            if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:127                return self.forward_comfy_cast_weights(*args, **kwargs)128            else:129                return super().forward(*args, **kwargs)130 131    class LayerNorm(torch.nn.LayerNorm, CastWeightBiasOp):132        def reset_parameters(self):133            return None134 135        def forward_comfy_cast_weights(self, input):136            if self.weight is not None:137                weight, bias = cast_bias_weight(self, input)138            else:139                weight = None140                bias = None141            return torch.nn.functional.layer_norm(input, self.normalized_shape, weight, bias, self.eps)142 143        def forward(self, *args, **kwargs):144            if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:145                return self.forward_comfy_cast_weights(*args, **kwargs)146            else:147                return super().forward(*args, **kwargs)148 149    class ConvTranspose2d(torch.nn.ConvTranspose2d, CastWeightBiasOp):150        def reset_parameters(self):151            return None152 153        def forward_comfy_cast_weights(self, input, output_size=None):154            num_spatial_dims = 2155            output_padding = self._output_padding(156                input, output_size, self.stride, self.padding, self.kernel_size,157                num_spatial_dims, self.dilation)158 159            weight, bias = cast_bias_weight(self, input)160            return torch.nn.functional.conv_transpose2d(161                input, weight, bias, self.stride, self.padding,162                output_padding, self.groups, self.dilation)163 164        def forward(self, *args, **kwargs):165            if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:166                return self.forward_comfy_cast_weights(*args, **kwargs)167            else:168                return super().forward(*args, **kwargs)169 170    class ConvTranspose1d(torch.nn.ConvTranspose1d, CastWeightBiasOp):171        def reset_parameters(self):172            return None173 174        def forward_comfy_cast_weights(self, input, output_size=None):175            num_spatial_dims = 1176            output_padding = self._output_padding(177                input, output_size, self.stride, self.padding, self.kernel_size,178                num_spatial_dims, self.dilation)179 180            weight, bias = cast_bias_weight(self, input)181            return torch.nn.functional.conv_transpose1d(182                input, weight, bias, self.stride, self.padding,183                output_padding, self.groups, self.dilation)184 185        def forward(self, *args, **kwargs):186            if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:187                return self.forward_comfy_cast_weights(*args, **kwargs)188            else:189                return super().forward(*args, **kwargs)190 191    class Embedding(torch.nn.Embedding, CastWeightBiasOp):192        def reset_parameters(self):193            self.bias = None194            return None195 196        def forward_comfy_cast_weights(self, input, out_dtype=None):197            output_dtype = out_dtype198            if self.weight.dtype == torch.float16 or self.weight.dtype == torch.bfloat16:199                out_dtype = None200            weight, bias = cast_bias_weight(self, device=input.device, dtype=out_dtype)201            return torch.nn.functional.embedding(input, weight, self.padding_idx, self.max_norm, self.norm_type, self.scale_grad_by_freq, self.sparse).to(dtype=output_dtype)202 203        def forward(self, *args, **kwargs):204            if self.comfy_cast_weights or len(self.weight_function) > 0 or len(self.bias_function) > 0:205                return self.forward_comfy_cast_weights(*args, **kwargs)206            else:207                if "out_dtype" in kwargs:208                    kwargs.pop("out_dtype")209                return super().forward(*args, **kwargs)210 211    @classmethod212    def conv_nd(s, dims, *args, **kwargs):213        if dims == 2:214            return s.Conv2d(*args, **kwargs)215        elif dims == 3:216            return s.Conv3d(*args, **kwargs)217        else:218            raise ValueError(f"unsupported dimensions: {dims}")219 220 221class manual_cast(disable_weight_init):222    class Linear(disable_weight_init.Linear):223        comfy_cast_weights = True224 225    class Conv1d(disable_weight_init.Conv1d):226        comfy_cast_weights = True227 228    class Conv2d(disable_weight_init.Conv2d):229        comfy_cast_weights = True230 231    class Conv3d(disable_weight_init.Conv3d):232        comfy_cast_weights = True233 234    class GroupNorm(disable_weight_init.GroupNorm):235        comfy_cast_weights = True236 237    class LayerNorm(disable_weight_init.LayerNorm):238        comfy_cast_weights = True239 240    class ConvTranspose2d(disable_weight_init.ConvTranspose2d):241        comfy_cast_weights = True242 243    class ConvTranspose1d(disable_weight_init.ConvTranspose1d):244        comfy_cast_weights = True245 246    class Embedding(disable_weight_init.Embedding):247        comfy_cast_weights = True248 249 250def fp8_linear(self, input):251    dtype = self.weight.dtype252    if dtype not in [torch.float8_e4m3fn]:253        return None254 255    tensor_2d = False256    if len(input.shape) == 2:257        tensor_2d = True258        input = input.unsqueeze(1)259 260    input_shape = input.shape261    input_dtype = input.dtype262    if len(input.shape) == 3:263        w, bias = cast_bias_weight(self, input, dtype=dtype, bias_dtype=input_dtype)264        w = w.t()265 266        scale_weight = self.scale_weight267        scale_input = self.scale_input268        if scale_weight is None:269            scale_weight = torch.ones((), device=input.device, dtype=torch.float32)270        else:271            scale_weight = scale_weight.to(input.device)272 273        if scale_input is None:274            scale_input = torch.ones((), device=input.device, dtype=torch.float32)275            input = torch.clamp(input, min=-448, max=448, out=input)276            input = input.reshape(-1, input_shape[2]).to(dtype)277        else:278            scale_input = scale_input.to(input.device)279            input = (input * (1.0 / scale_input).to(input_dtype)).reshape(-1, input_shape[2]).to(dtype)280 281        if bias is not None:282            o = torch._scaled_mm(input, w, out_dtype=input_dtype, bias=bias, scale_a=scale_input, scale_b=scale_weight)283        else:284            o = torch._scaled_mm(input, w, out_dtype=input_dtype, scale_a=scale_input, scale_b=scale_weight)285 286        if isinstance(o, tuple):287            o = o[0]288 289        if tensor_2d:290            return o.reshape(input_shape[0], -1)291 292        return o.reshape((-1, input_shape[1], self.weight.shape[0]))293 294    return None295 296class fp8_ops(manual_cast):297    class Linear(manual_cast.Linear):298        def reset_parameters(self):299            self.scale_weight = None300            self.scale_input = None301            return None302 303        def forward_comfy_cast_weights(self, input):304            out = fp8_linear(self, input)305            if out is not None:306                return out307 308            weight, bias = cast_bias_weight(self, input)309            return torch.nn.functional.linear(input, weight, bias)310 311def scaled_fp8_ops(fp8_matrix_mult=False, scale_input=False, override_dtype=None):312    logging.info("Using scaled fp8: fp8 matrix mult: {}, scale input: {}".format(fp8_matrix_mult, scale_input))313    class scaled_fp8_op(manual_cast):314        class Linear(manual_cast.Linear):315            def __init__(self, *args, **kwargs):316                if override_dtype is not None:317                    kwargs['dtype'] = override_dtype318                super().__init__(*args, **kwargs)319 320            def reset_parameters(self):321                if not hasattr(self, 'scale_weight'):322                    self.scale_weight = torch.nn.parameter.Parameter(data=torch.ones((), device=self.weight.device, dtype=torch.float32), requires_grad=False)323 324                if not scale_input:325                    self.scale_input = None326 327                if not hasattr(self, 'scale_input'):328                    self.scale_input = torch.nn.parameter.Parameter(data=torch.ones((), device=self.weight.device, dtype=torch.float32), requires_grad=False)329                return None330 331            def forward_comfy_cast_weights(self, input):332                if fp8_matrix_mult:333                    out = fp8_linear(self, input)334                    if out is not None:335                        return out336 337                weight, bias = cast_bias_weight(self, input)338 339                if weight.numel() < input.numel(): #TODO: optimize340                    return torch.nn.functional.linear(input, weight * self.scale_weight.to(device=weight.device, dtype=weight.dtype), bias)341                else:342                    return torch.nn.functional.linear(input * self.scale_weight.to(device=weight.device, dtype=weight.dtype), weight, bias)343 344            def convert_weight(self, weight, inplace=False, **kwargs):345                if inplace:346                    weight *= self.scale_weight.to(device=weight.device, dtype=weight.dtype)347                    return weight348                else:349                    return weight * self.scale_weight.to(device=weight.device, dtype=weight.dtype)350 351            def set_weight(self, weight, inplace_update=False, seed=None, **kwargs):352                weight = comfy.float.stochastic_rounding(weight / self.scale_weight.to(device=weight.device, dtype=weight.dtype), self.weight.dtype, seed=seed)353                if inplace_update:354                    self.weight.data.copy_(weight)355                else:356                    self.weight = torch.nn.Parameter(weight, requires_grad=False)357 358    return scaled_fp8_op359 360def pick_operations(weight_dtype, compute_dtype, load_device=None, disable_fast_fp8=False, fp8_optimizations=False, scaled_fp8=None):361    fp8_compute = comfy.model_management.supports_fp8_compute(load_device)362    if scaled_fp8 is not None:363        return scaled_fp8_ops(fp8_matrix_mult=fp8_compute and fp8_optimizations, scale_input=fp8_optimizations, override_dtype=scaled_fp8)364 365    if (366        fp8_compute and367        (fp8_optimizations or PerformanceFeature.Fp8MatrixMultiplication in args.fast) and368        not disable_fast_fp8369    ):370        return fp8_ops371 372    if compute_dtype is None or weight_dtype == compute_dtype:373        return disable_weight_init374 375    return manual_cast376