162 lines
5.2 KiB
Python
162 lines
5.2 KiB
Python
import torch
|
|
import torch.nn as nn
|
|
|
|
from .base import LycorisBaseModule
|
|
from ..logging import warning_once
|
|
|
|
|
|
class NormModule(LycorisBaseModule):
|
|
name = "norm"
|
|
support_module = {
|
|
"layernorm",
|
|
"groupnorm",
|
|
}
|
|
weight_list = ["w_norm", "b_norm"]
|
|
weight_list_det = ["w_norm"]
|
|
|
|
def __init__(
|
|
self,
|
|
lora_name,
|
|
org_module: nn.Module,
|
|
multiplier=1.0,
|
|
rank_dropout=0.0,
|
|
module_dropout=0.0,
|
|
rank_dropout_scale=False,
|
|
**kwargs,
|
|
):
|
|
"""if alpha == 0 or None, alpha is rank (no scaling)."""
|
|
super().__init__(
|
|
lora_name=lora_name,
|
|
org_module=org_module,
|
|
multiplier=multiplier,
|
|
rank_dropout=rank_dropout,
|
|
module_dropout=module_dropout,
|
|
rank_dropout_scale=rank_dropout_scale,
|
|
**kwargs,
|
|
)
|
|
if self.module_type == "unknown":
|
|
if not hasattr(org_module, "weight") or not hasattr(org_module, "_norm"):
|
|
warning_once(f"{type(org_module)} is not supported in Norm algo.")
|
|
self.not_supported = True
|
|
return
|
|
else:
|
|
self.dim = org_module.weight.numel()
|
|
self.not_supported = False
|
|
elif self.module_type not in self.support_module:
|
|
warning_once(f"{self.module_type} is not supported in Norm algo.")
|
|
self.not_supported = True
|
|
return
|
|
|
|
self.w_norm = nn.Parameter(torch.zeros(self.dim))
|
|
if hasattr(org_module, "bias"):
|
|
self.b_norm = nn.Parameter(torch.zeros(self.dim))
|
|
if hasattr(org_module, "_norm"):
|
|
self.org_norm = org_module._norm
|
|
else:
|
|
self.org_norm = None
|
|
|
|
@classmethod
|
|
def make_module_from_state_dict(cls, lora_name, orig_module, w_norm, b_norm):
|
|
module = cls(
|
|
lora_name,
|
|
orig_module,
|
|
1,
|
|
)
|
|
module.w_norm.copy_(w_norm)
|
|
if b_norm is not None:
|
|
module.b_norm.copy_(b_norm)
|
|
return module
|
|
|
|
def make_weight(self, scale=1, device=None):
|
|
org_weight = self.org_module[0].weight.to(device, dtype=self.w_norm.dtype)
|
|
if hasattr(self.org_module[0], "bias"):
|
|
org_bias = self.org_module[0].bias.to(device, dtype=self.b_norm.dtype)
|
|
else:
|
|
org_bias = None
|
|
if self.rank_dropout and self.training:
|
|
drop = (torch.rand(self.dim, device=device) < self.rank_dropout).to(
|
|
self.w_norm.device
|
|
)
|
|
if self.rank_dropout_scale:
|
|
drop /= drop.mean()
|
|
else:
|
|
drop = 1
|
|
drop = (
|
|
torch.rand(self.dim, device=device) < self.rank_dropout
|
|
if self.rank_dropout and self.training
|
|
else 1
|
|
)
|
|
weight = self.w_norm.to(device) * drop * scale
|
|
if org_bias is not None:
|
|
bias = self.b_norm.to(device) * drop * scale
|
|
return org_weight + weight, org_bias + bias if org_bias is not None else None
|
|
|
|
def get_diff_weight(self, multiplier=1, shape=None, device=None):
|
|
if self.not_supported:
|
|
return 0, 0
|
|
w = self.w_norm * multiplier
|
|
if device is not None:
|
|
w = w.to(device)
|
|
if shape is not None:
|
|
w = w.view(shape)
|
|
if self.b_norm is not None:
|
|
b = self.b_norm * multiplier
|
|
if device is not None:
|
|
b = b.to(device)
|
|
if shape is not None:
|
|
b = b.view(shape)
|
|
else:
|
|
b = None
|
|
return w, b
|
|
|
|
def get_merged_weight(self, multiplier=1, shape=None, device=None):
|
|
if self.not_supported:
|
|
return None, None
|
|
diff_w, diff_b = self.get_diff_weight(multiplier, shape, device)
|
|
org_w = self.org_module[0].weight.to(device, dtype=self.w_norm.dtype)
|
|
weight = org_w + diff_w
|
|
if diff_b is not None:
|
|
org_b = self.org_module[0].bias.to(device, dtype=self.b_norm.dtype)
|
|
bias = org_b + diff_b
|
|
else:
|
|
bias = None
|
|
return weight, bias
|
|
|
|
def forward(self, x):
|
|
if self.not_supported or (
|
|
self.module_dropout
|
|
and self.training
|
|
and torch.rand(1) < self.module_dropout
|
|
):
|
|
return self.org_forward(x)
|
|
scale = self.multiplier
|
|
|
|
w, b = self.make_weight(scale, x.device)
|
|
if self.org_norm is not None:
|
|
normed = self.org_norm(x)
|
|
scaled = normed * w
|
|
if b is not None:
|
|
scaled += b
|
|
return scaled
|
|
|
|
kw_dict = self.kw_dict | {"weight": w, "bias": b}
|
|
return self.op(x, **kw_dict)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
base = nn.LayerNorm(128).cuda()
|
|
norm = NormModule("test", base, 1).cuda()
|
|
print(norm)
|
|
test_input = torch.randn(1, 128).cuda()
|
|
test_output = norm(test_input)
|
|
torch.sum(test_output).backward()
|
|
print(test_output.shape)
|
|
|
|
base = nn.GroupNorm(4, 128).cuda()
|
|
norm = NormModule("test", base, 1).cuda()
|
|
print(norm)
|
|
test_input = torch.randn(1, 128, 3, 3).cuda()
|
|
test_output = norm(test_input)
|
|
torch.sum(test_output).backward()
|
|
print(test_output.shape)
|