Module neuralops.trainer.methods
Training method plugins: LoRA, DoRA, DisLoRA, Fisher, GeLoRA, LLRD, Mixout, R‑Drop, R3F. All methods are registered via the METHOD_REGISTRY and can be applied by name.
Sub-modules
neuralops.trainer.methods.fisher-
Fisher information based importance scoring for adaptive rank allocation.
neuralops.trainer.methods.gelora-
GeLoRA: Intrinsic dimension estimation for adaptive rank selection.
neuralops.trainer.methods.llrd-
LLRD: Layer‑wise Learning Rate Decay.
neuralops.trainer.methods.lora-
LoRA, DoRA, DisLoRA implementations.
neuralops.trainer.methods.mixout-
Mixout: Regularisation by mixing weights with a frozen copy.
neuralops.trainer.methods.rdrop_r3f-
R‑Drop and R3F (regularised dropout / robust representation learning).
neuralops.trainer.methods.registry
Functions
def apply_dislora(model, config) ‑> None-
Expand source code
@register_method("dislora") def apply_dislora(model, config) -> None: """Apply dislora.""" _apply_adapters( model, config.lora_r, config.lora_alpha, config.lora_dropout, "dislora", dislora_beta=config.dislora_beta, dislora_capacity_factor=config.dislora_capacity_factor, )Apply dislora.
def apply_dora(model, config) ‑> None-
Expand source code
@register_method("dora") def apply_dora(model, config) -> None: """Apply dora.""" _apply_adapters(model, config.lora_r, config.lora_alpha, config.lora_dropout, "dora")Apply dora.
def apply_fisher_gelora(model, config) ‑> None-
Expand source code
@register_method("fisher_gelora") def apply_fisher_gelora(model, config) -> None: """Apply fisher gelora.""" logger.info("Fisher‑GeLoRA registered. Use compute_gelora_base_ranks in training script.")Apply fisher gelora.
def apply_fisher_lora(model, config) ‑> None-
Expand source code
@register_method("fisher_lora") def apply_fisher_lora(model, config) -> None: """Apply fisher lora.""" logger.info( "Fisher‑LoRA method called – but requires dataset, tokenizer, task_keys. " "Use a wrapper in training script to call compute_fisher_importance with actual data." )Apply fisher lora.
def apply_llrd(model, config) ‑> None-
Expand source code
@register_method("llrd") def apply_llrd(model, config) -> None: """Apply llrd.""" logger.info("LLRD registered. Use --method llrd to enable layer‑wise learning rates.")Apply llrd.
def apply_lora(model, config) ‑> None-
Expand source code
@register_method("lora") def apply_lora(model, config) -> None: """Apply lora.""" _apply_adapters(model, config.lora_r, config.lora_alpha, config.lora_dropout, "lora")Apply lora.
def apply_mixout(model, config) ‑> None-
Expand source code
@register_method("mixout") def apply_mixout(model, config) -> None: """Apply mixout.""" replace_linears_with_mixout(model, config.mixout_p) logger.info("Mixout applied.")Apply mixout.
def apply_r3f(model, config) ‑> None-
Expand source code
@register_method("r3f") def apply_r3f(model, config) -> None: """Apply r3f.""" passApply r3f.
def apply_rdrop(model, config) ‑> None-
Expand source code
@register_method("rdrop") def apply_rdrop(model, config) -> None: """Apply rdrop.""" passApply rdrop.
def available_methods() ‑> Any-
Expand source code
def available_methods() -> Any: """Return list of all registered method names.""" return list(METHOD_REGISTRY.keys())Return list of all registered method names.
-
Expand source code
def collect_hidden_states(model, dataloader, num_batches=10, max_samples=800) -> Any: """Collect hidden states.""" layers = get_encoder_layers(model) num_layers = len(layers) hidden_states_per_layer = {i: [] for i in range(num_layers)} hooks = [] def hook_fn(layer_idx) -> Any: """Hook fn.""" def hook(module, input, output) -> None: """Hook.""" hs = output[0].detach() if isinstance(output, tuple) else output.detach() hidden_states_per_layer[layer_idx].append(hs) return hook for i, layer in enumerate(layers): hook = layer.register_forward_hook(hook_fn(i)) hooks.append(hook) model.eval() total = 0 with torch.no_grad(): for i, batch in enumerate(dataloader): if i >= num_batches or total >= max_samples: break batch = {k: v.to(model.device) for k, v in batch.items() if isinstance(v, torch.Tensor)} model(**batch) total += batch["input_ids"].size(0) for hook in hooks: hook.remove() for i in range(num_layers): if hidden_states_per_layer[i]: hidden_states_per_layer[i] = torch.cat(hidden_states_per_layer[i], dim=0) else: hidden_states_per_layer[i] = torch.empty(0) return hidden_states_per_layerCollect hidden states.
def compute_fisher_importance(model, dataset, tokenizer, task_keys, config, target_substrings=None) ‑> Any-
Expand source code
def compute_fisher_importance( model, dataset, tokenizer, task_keys, config, target_substrings=None ) -> Any: """Compute and return fisher importance.""" if target_substrings is None: target_substrings = ["query", "key", "value", "dense"] sent1_key, sent2_key = task_keys device = next(model.parameters()).device sample_size = min(config.fisher_sample_size, len(dataset)) indices = np.random.choice(len(dataset), sample_size, replace=False) sampled = dataset.select(indices) def collate_fn(batch) -> Any: """Collate fn.""" if sent2_key is None: texts = [ex[sent1_key] for ex in batch] enc = tokenizer( texts, truncation=True, max_length=config.max_seq_length, padding=True, return_tensors="pt", ) else: texts1 = [ex[sent1_key] for ex in batch] texts2 = [ex[sent2_key] for ex in batch] enc = tokenizer( texts1, texts2, truncation=True, max_length=config.max_seq_length, padding=True, return_tensors="pt", ) labels = [ex["label"] for ex in batch] is_reg = task_keys.get("is_regression", False) enc["labels"] = torch.tensor(labels, dtype=torch.float if is_reg else torch.long) return enc loader = DataLoader( sampled, batch_size=config.per_device_train_batch_size, collate_fn=collate_fn ) fisher = {} model.eval() for param in model.parameters(): param.requires_grad = True for i, batch in enumerate(loader): if i >= config.fisher_num_batches: break batch = {k: v.to(device) for k, v in batch.items()} outputs = model(**batch) loss = outputs.loss loss.backward() for name, param in model.named_parameters(): if param.grad is None: continue if not any(ts in name for ts in target_substrings): continue score = (param.grad**2).mean().item() module_name = name.replace(".weight", "").replace(".bias", "") fisher[module_name] = fisher.get(module_name, 0.0) + score model.zero_grad() if not fisher: return None for k in fisher: fisher[k] /= config.fisher_num_batches scores = np.array(list(fisher.values())) scores = scores - np.max(scores) exp_scores = np.exp(scores) norm_scores = exp_scores / (np.sum(exp_scores) + 1e-8) fisher = {k: norm_scores[i] for i, k in enumerate(fisher.keys())} return fisherCompute and return fisher importance.
def compute_gelora_base_ranks(model, dataloader, config) ‑> Any-
Expand source code
def compute_gelora_base_ranks(model, dataloader, config) -> Any: """Compute and return gelora base ranks.""" layer_hidden = collect_hidden_states(model, dataloader, num_batches=8, max_samples=800) layer_id = {} for idx, hs in layer_hidden.items(): if hs.shape[0] < 10: id_val = 1.0 else: id_val = estimate_intrinsic_dimension_pytorch(hs, k=min(5, hs.shape[0] - 1)) base_rank = max( config.gelora_min_rank, min(config.gelora_max_rank, int(id_val + config.gelora_margin)), ) layer_id[idx] = base_rank logger.info(f"Layer {idx} intrinsic dim ≈ {id_val:.2f} → base rank {base_rank}") target_substrings = ["query", "key", "value", "dense"] rank_dict = {} for name, _ in model.named_modules(): if ( any(ts in name for ts in target_substrings) and "classifier" not in name and "pooler" not in name ): parts = name.split(".") layer_idx = None for i, part in enumerate(parts): if part == "layer" and i + 1 < len(parts): try: layer_idx = int(parts[i + 1]) break except (ValueError, TypeError): pass rank_dict[name] = layer_id.get(layer_idx, config.lora_r) return rank_dictCompute and return gelora base ranks.
def estimate_intrinsic_dimension_pytorch(hidden_states, k=5) ‑> Any-
Expand source code
def estimate_intrinsic_dimension_pytorch(hidden_states, k=5) -> Any: """Estimate intrinsic dimension pytorch.""" if hidden_states.dim() == 3: hidden_states = hidden_states.mean(dim=1) elif hidden_states.dim() != 2: raise ValueError(f"Expected 2D or 3D tensor, got {hidden_states.dim()}D") N = hidden_states.shape[0] if k + 1 > N: return 1.0 if N > 1000: idx = torch.randperm(N)[:1000] hidden_states = hidden_states[idx] dist = torch.cdist(hidden_states, hidden_states) dist.fill_diagonal_(float("inf")) topk_dist, _ = torch.topk(dist, k, dim=1, largest=False) d_k = topk_dist[:, -1:] log_ratios = torch.log(topk_dist / (d_k + 1e-8)) id_per_point = -1.0 / torch.mean(log_ratios, dim=1) id_global = torch.mean(id_per_point).item() return max(1.0, id_global)Estimate intrinsic dimension pytorch.
def get_llrd_param_groups(model, base_lr, weight_decay, decay) ‑> Any-
Expand source code
def get_llrd_param_groups(model, base_lr, weight_decay, decay) -> Any: """Return the llrd param groups.""" no_decay = ["bias", "LayerNorm.weight", "layer_norm.weight", "layernorm.weight"] max_layer = -1 for name, _ in model.named_parameters(): if "encoder.layer." in name: layer = int(name.split("encoder.layer.")[1].split(".")[0]) max_layer = max(max_layer, layer) num_layers = max_layer + 1 emb_decay, emb_nodecay = [], [] layer_decay = {i: [] for i in range(num_layers)} layer_nodecay = {i: [] for i in range(num_layers)} head_decay, head_nodecay = [], [] for name, param in model.named_parameters(): if "embeddings" in name: if any(nd in name for nd in no_decay): emb_nodecay.append(param) else: emb_decay.append(param) elif "encoder.layer." in name: layer = int(name.split("encoder.layer.")[1].split(".")[0]) if any(nd in name for nd in no_decay): layer_nodecay[layer].append(param) else: layer_decay[layer].append(param) elif "classifier" in name or "pooler" in name: if any(nd in name for nd in no_decay): head_nodecay.append(param) else: head_decay.append(param) groups = [] emb_lr = base_lr * (decay ** (num_layers + 1)) if emb_decay: groups.append({"params": emb_decay, "lr": emb_lr, "weight_decay": weight_decay}) if emb_nodecay: groups.append({"params": emb_nodecay, "lr": emb_lr, "weight_decay": 0.0}) for layer in range(num_layers): lr_layer = base_lr * (decay ** (num_layers - layer)) if layer_decay[layer]: groups.append( { "params": layer_decay[layer], "lr": lr_layer, "weight_decay": weight_decay, } ) if layer_nodecay[layer]: groups.append({"params": layer_nodecay[layer], "lr": lr_layer, "weight_decay": 0.0}) if head_decay: groups.append({"params": head_decay, "lr": base_lr, "weight_decay": weight_decay}) if head_nodecay: groups.append({"params": head_nodecay, "lr": base_lr, "weight_decay": 0.0}) return groupsReturn the llrd param groups.
def get_method(name: str) ‑> Any-
Expand source code
def get_method(name: str) -> Any: """Return the method function by name, or None if not found.""" return METHOD_REGISTRY.get(name)Return the method function by name, or None if not found.
def r3f_forward(model, input_ids, attention_mask, token_type_ids, labels, epsilon, is_regression) ‑> Any-
Expand source code
def r3f_forward( model, input_ids, attention_mask, token_type_ids, labels, epsilon, is_regression ) -> Any: """R3f forward.""" base_kwargs = { "input_ids": input_ids, "attention_mask": attention_mask, "labels": labels, } if token_type_ids is not None: base_kwargs["token_type_ids"] = token_type_ids out_clean = model(**base_kwargs) logits_clean = out_clean.logits embed = model.get_input_embeddings() inputs_embeds = embed(input_ids) noise = torch.randn_like(inputs_embeds) * epsilon noise_kwargs = { "inputs_embeds": inputs_embeds + noise, "attention_mask": attention_mask, "labels": labels, } if token_type_ids is not None: noise_kwargs["token_type_ids"] = token_type_ids out_noisy = model(**noise_kwargs) logits_noisy = out_noisy.logits if is_regression: mse = nn.MSELoss() loss_clean = mse(logits_clean.view(-1), labels.view(-1)) loss_noisy = mse(logits_noisy.view(-1), labels.view(-1)) p = torch.distributions.Normal(logits_clean, torch.ones_like(logits_clean)) q = torch.distributions.Normal(logits_noisy, torch.ones_like(logits_noisy)) kl = torch.distributions.kl_divergence(p, q).mean() loss = (loss_clean + loss_noisy) / 2.0 + kl else: ce = nn.CrossEntropyLoss() loss_clean = ce(logits_clean.view(-1, logits_clean.size(-1)), labels.view(-1)) loss_noisy = ce(logits_noisy.view(-1, logits_noisy.size(-1)), labels.view(-1)) logp_clean = F.log_softmax(logits_clean, dim=-1) logp_noisy = F.log_softmax(logits_noisy, dim=-1) p = torch.softmax(logits_clean, dim=-1) q = torch.softmax(logits_noisy, dim=-1) kl1 = F.kl_div(logp_clean, q, reduction="batchmean") kl2 = F.kl_div(logp_noisy, p, reduction="batchmean") loss = (loss_clean + loss_noisy) / 2.0 + (kl1 + kl2) / 2.0 return loss, logits_cleanR3f forward.
def rdrop_loss(logits1, logits2, labels, is_regression, alpha) ‑> Any-
Expand source code
def rdrop_loss(logits1, logits2, labels, is_regression, alpha) -> Any: """Rdrop loss.""" if is_regression: loss_fn = nn.MSELoss() loss1 = loss_fn(logits1.view(-1), labels.view(-1)) loss2 = loss_fn(logits2.view(-1), labels.view(-1)) p = torch.distributions.Normal(logits1, torch.ones_like(logits1)) q = torch.distributions.Normal(logits2, torch.ones_like(logits2)) kl = ( torch.distributions.kl_divergence(p, q).mean() + torch.distributions.kl_divergence(q, p).mean() ) / 2.0 loss = (loss1 + loss2) / 2.0 + alpha * kl else: ce = nn.CrossEntropyLoss() loss1 = ce(logits1.view(-1, logits1.size(-1)), labels.view(-1)) loss2 = ce(logits2.view(-1, logits2.size(-1)), labels.view(-1)) logp1 = F.log_softmax(logits1, dim=-1) logp2 = F.log_softmax(logits2, dim=-1) p1 = torch.softmax(logits1, dim=-1) p2 = torch.softmax(logits2, dim=-1) kl1 = F.kl_div(logp1, p2, reduction="batchmean") kl2 = F.kl_div(logp2, p1, reduction="batchmean") kl = (kl1 + kl2) / 2.0 loss = (loss1 + loss2) / 2.0 + alpha * kl return lossRdrop loss.
def register_method(name: str) ‑> Any-
Expand source code
def register_method(name: str) -> Any: """Decorator to register a method callable.""" def decorator(fn) -> Any: """Decorator.""" METHOD_REGISTRY[name] = fn return fn return decoratorDecorator to register a method callable.
Classes
class DisLoRALinear (linear: torch.nn.modules.linear.Linear,
r: int,
alpha: float,
dropout: float,
beta: float = 0.5,
capacity_factor: float = 1.0)-
Expand source code
class DisLoRALinear(nn.Module): def __init__( self, linear: nn.Linear, r: int, alpha: float, dropout: float, beta: float = 0.5, capacity_factor: float = 1.0, ) -> None: super().__init__() self.linear = linear self.linear.weight.requires_grad = False if linear.bias is not None: linear.bias.requires_grad = False self.r = r self.beta = beta self.capacity_factor = capacity_factor if r > 0: self.lora_A = nn.Linear(linear.in_features, r, bias=False) self.lora_B = nn.Linear(r, linear.out_features, bias=False) kaiming_uniform_(self.lora_A.weight, a=math.sqrt(5)) zeros_(self.lora_B.weight) self.scaling = alpha / r self.dropout = nn.Dropout(dropout) self.register_buffer("_eye", torch.eye(r)) else: self.lora_A = self.lora_B = None self.scaling = 1.0 self.dropout = nn.Identity() def forward(self, x) -> Any: """Forward pass — compute module output from inputs.""" base = self.linear(x) if self.r > 0: lora = self.lora_B(self.lora_A(self.dropout(x))) * self.scaling return base + lora return base def ortho_loss(self) -> Any: """Ortho loss.""" if self.lora_A is None: return 0.0 A = self.lora_A.weight B = self.lora_B.weight reg = (A @ A.T - self._eye).pow(2).sum() + (B.T @ B - self._eye).pow(2).sum() return self.beta * regBase class for all neural network modules.
Your models should also subclass this class.
Modules can also contain other Modules, allowing them to be nested in a tree structure. You can assign the submodules as regular attributes::
import torch.nn as nn import torch.nn.functional as F class Model(nn.Module): def __init__(self) -> None: super().__init__() self.conv1 = nn.Conv2d(1, 20, 5) self.conv2 = nn.Conv2d(20, 20, 5) def forward(self, x): x = F.relu(self.conv1(x)) return F.relu(self.conv2(x))Submodules assigned in this way will be registered, and will also have their parameters converted when you call :meth:
to, etc.Note
As per the example above, an
__init__()call to the parent class must be made before assignment on the child.:ivar training: Boolean represents whether this module is in training or evaluation mode. :vartype training: bool
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def forward(self, x) ‑> Any-
Expand source code
def forward(self, x) -> Any: """Forward pass — compute module output from inputs.""" base = self.linear(x) if self.r > 0: lora = self.lora_B(self.lora_A(self.dropout(x))) * self.scaling return base + lora return baseForward pass — compute module output from inputs.
def ortho_loss(self) ‑> Any-
Expand source code
def ortho_loss(self) -> Any: """Ortho loss.""" if self.lora_A is None: return 0.0 A = self.lora_A.weight B = self.lora_B.weight reg = (A @ A.T - self._eye).pow(2).sum() + (B.T @ B - self._eye).pow(2).sum() return self.beta * regOrtho loss.
class DoRALinear (linear: torch.nn.modules.linear.Linear, r: int, alpha: float, dropout: float)-
Expand source code
class DoRALinear(nn.Module): def __init__(self, linear: nn.Linear, r: int, alpha: float, dropout: float) -> None: """Execute __init__ operation.""" super().__init__() self.linear = linear self.linear.weight.requires_grad = False if linear.bias is not None: linear.bias.requires_grad = False self.r = r if r > 0: self.m = nn.Parameter(torch.ones(linear.out_features)) self.lora_A = nn.Linear(linear.in_features, r, bias=False) self.lora_B = nn.Linear(r, linear.out_features, bias=False) kaiming_uniform_(self.lora_A.weight, a=math.sqrt(5)) zeros_(self.lora_B.weight) self.scaling = alpha / r self.dropout = nn.Dropout(dropout) else: self.m = nn.Parameter(torch.ones(linear.out_features)) self.lora_A = self.lora_B = None self.scaling = 1.0 self.dropout = nn.Identity() def forward(self, x) -> Any: """Forward pass — compute module output from inputs.""" base_out = self.linear(x) if self.r > 0: lora = self.lora_B(self.lora_A(self.dropout(x))) * self.scaling weight_norm = self.linear.weight.norm(p=2, dim=1, keepdim=True) direction = self.linear.weight / (weight_norm + 1e-8) delta = self.m.unsqueeze(1) * direction + lora return F.linear(x, delta, self.linear.bias) return base_outBase class for all neural network modules.
Your models should also subclass this class.
Modules can also contain other Modules, allowing them to be nested in a tree structure. You can assign the submodules as regular attributes::
import torch.nn as nn import torch.nn.functional as F class Model(nn.Module): def __init__(self) -> None: super().__init__() self.conv1 = nn.Conv2d(1, 20, 5) self.conv2 = nn.Conv2d(20, 20, 5) def forward(self, x): x = F.relu(self.conv1(x)) return F.relu(self.conv2(x))Submodules assigned in this way will be registered, and will also have their parameters converted when you call :meth:
to, etc.Note
As per the example above, an
__init__()call to the parent class must be made before assignment on the child.:ivar training: Boolean represents whether this module is in training or evaluation mode. :vartype training: bool
Execute init operation.
Ancestors
- torch.nn.modules.module.Module
Methods
def forward(self, x) ‑> Any-
Expand source code
def forward(self, x) -> Any: """Forward pass — compute module output from inputs.""" base_out = self.linear(x) if self.r > 0: lora = self.lora_B(self.lora_A(self.dropout(x))) * self.scaling weight_norm = self.linear.weight.norm(p=2, dim=1, keepdim=True) direction = self.linear.weight / (weight_norm + 1e-8) delta = self.m.unsqueeze(1) * direction + lora return F.linear(x, delta, self.linear.bias) return base_outForward pass — compute module output from inputs.
class LoRALinear (linear: nn.Module, r: int = 16, alpha: float = 32.0, dropout: float = 0.05)-
Expand source code
class LoRALinear(nn.Module): """Linear layer wrapped with Low-Rank Adaptation (LoRA) adapters.""" def __init__( self, linear: nn.Module, r: int = 16, alpha: float = 32.0, dropout: float = 0.05, ) -> None: super().__init__() if hasattr(linear, "in_features"): self.in_features = linear.in_features self.out_features = linear.out_features elif hasattr(linear, "weight"): # HuggingFace Conv1D (used in GPT-2) has weight shape [in_features, out_features] self.in_features = linear.weight.shape[0] self.out_features = linear.weight.shape[1] else: raise ValueError(f"Unsupported linear module: {type(linear)}") self.r = int(r) self.alpha = float(alpha) self.scaling = float(alpha) / max(1, self.r) if self.r > 0 else 1.0 self.merged = False # Base linear layer (frozen) self.base_layer = linear self.base_layer.weight.requires_grad = False if self.base_layer.bias is not None: self.base_layer.bias.requires_grad = False device = linear.weight.device # Trainable LoRA parameters are kept in FP32 for numerical stability # and compatibility with torch.amp.GradScaler in mixed precision. dtype = torch.float32 # LoRA trainable low-rank matrices if self.r > 0: self.lora_A = nn.Linear( self.in_features, self.r, bias=False, device=device, dtype=dtype ) self.lora_B = nn.Linear( self.r, self.out_features, bias=False, device=device, dtype=dtype ) self.lora_dropout = nn.Dropout(dropout) if dropout > 0.0 else nn.Identity() self.reset_parameters() else: self.lora_A = None self.lora_B = None self.lora_dropout = nn.Identity() def reset_parameters(self) -> None: """Initialize lora_A with Kaiming uniform and lora_B with zeros.""" if self.r > 0 and self.lora_A is not None and self.lora_B is not None: kaiming_uniform_(self.lora_A.weight, a=math.sqrt(5)) zeros_(self.lora_B.weight) @property def weight(self) -> torch.Tensor: """Expose base layer weight for compatibility with hooks and inspectors.""" return self.base_layer.weight @property def bias(self) -> torch.Tensor | None: """Expose base layer bias for compatibility with hooks and inspectors.""" return self.base_layer.bias def merge(self) -> None: """In-place merge LoRA delta weight into the base linear layer.""" if self.r > 0 and not self.merged and self.lora_A is not None and self.lora_B is not None: delta_w = (self.lora_B.weight @ self.lora_A.weight) * self.scaling is_conv1d = "conv1d" in self.base_layer.__class__.__name__.lower() or ( not isinstance(self.base_layer, nn.Linear) and self.base_layer.weight.shape == (self.in_features, self.out_features) ) if is_conv1d: delta_w = delta_w.t() self.base_layer.weight.data.add_(delta_w.to(self.base_layer.weight.dtype)) self.merged = True def unmerge(self) -> None: """Subtract LoRA delta weight to revert the base linear layer to unmerged state.""" if self.r > 0 and self.merged and self.lora_A is not None and self.lora_B is not None: delta_w = (self.lora_B.weight @ self.lora_A.weight) * self.scaling is_conv1d = "conv1d" in self.base_layer.__class__.__name__.lower() or ( not isinstance(self.base_layer, nn.Linear) and self.base_layer.weight.shape == (self.in_features, self.out_features) ) if is_conv1d: delta_w = delta_w.t() self.base_layer.weight.data.sub_(delta_w.to(self.base_layer.weight.dtype)) self.merged = False def forward(self, x: torch.Tensor) -> torch.Tensor: """Forward pass combining base projection with low-rank adapter delta.""" base_out = self.base_layer(x) if self.r > 0 and not self.merged and self.lora_A is not None and self.lora_B is not None: lora_in = self.lora_dropout(x).to(dtype=self.lora_A.weight.dtype) lora_out = self.lora_B(self.lora_A(lora_in)) * self.scaling return base_out + lora_out.to(dtype=base_out.dtype) return base_out def __repr__(self) -> str: return ( f"LoRALinear(in_features={self.in_features}, out_features={self.out_features}, " f"r={self.r}, alpha={self.alpha}, scaling={self.scaling:.4f})" )Linear layer wrapped with Low-Rank Adaptation (LoRA) adapters.
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Instance variables
prop bias : torch.Tensor | None-
Expand source code
@property def bias(self) -> torch.Tensor | None: """Expose base layer bias for compatibility with hooks and inspectors.""" return self.base_layer.biasExpose base layer bias for compatibility with hooks and inspectors.
prop weight : torch.Tensor-
Expand source code
@property def weight(self) -> torch.Tensor: """Expose base layer weight for compatibility with hooks and inspectors.""" return self.base_layer.weightExpose base layer weight for compatibility with hooks and inspectors.
Methods
def forward(self, x: torch.Tensor) ‑> torch.Tensor-
Expand source code
def forward(self, x: torch.Tensor) -> torch.Tensor: """Forward pass combining base projection with low-rank adapter delta.""" base_out = self.base_layer(x) if self.r > 0 and not self.merged and self.lora_A is not None and self.lora_B is not None: lora_in = self.lora_dropout(x).to(dtype=self.lora_A.weight.dtype) lora_out = self.lora_B(self.lora_A(lora_in)) * self.scaling return base_out + lora_out.to(dtype=base_out.dtype) return base_outForward pass combining base projection with low-rank adapter delta.
def merge(self) ‑> None-
Expand source code
def merge(self) -> None: """In-place merge LoRA delta weight into the base linear layer.""" if self.r > 0 and not self.merged and self.lora_A is not None and self.lora_B is not None: delta_w = (self.lora_B.weight @ self.lora_A.weight) * self.scaling is_conv1d = "conv1d" in self.base_layer.__class__.__name__.lower() or ( not isinstance(self.base_layer, nn.Linear) and self.base_layer.weight.shape == (self.in_features, self.out_features) ) if is_conv1d: delta_w = delta_w.t() self.base_layer.weight.data.add_(delta_w.to(self.base_layer.weight.dtype)) self.merged = TrueIn-place merge LoRA delta weight into the base linear layer.
def reset_parameters(self) ‑> None-
Expand source code
def reset_parameters(self) -> None: """Initialize lora_A with Kaiming uniform and lora_B with zeros.""" if self.r > 0 and self.lora_A is not None and self.lora_B is not None: kaiming_uniform_(self.lora_A.weight, a=math.sqrt(5)) zeros_(self.lora_B.weight)Initialize lora_A with Kaiming uniform and lora_B with zeros.
def unmerge(self) ‑> None-
Expand source code
def unmerge(self) -> None: """Subtract LoRA delta weight to revert the base linear layer to unmerged state.""" if self.r > 0 and self.merged and self.lora_A is not None and self.lora_B is not None: delta_w = (self.lora_B.weight @ self.lora_A.weight) * self.scaling is_conv1d = "conv1d" in self.base_layer.__class__.__name__.lower() or ( not isinstance(self.base_layer, nn.Linear) and self.base_layer.weight.shape == (self.in_features, self.out_features) ) if is_conv1d: delta_w = delta_w.t() self.base_layer.weight.data.sub_(delta_w.to(self.base_layer.weight.dtype)) self.merged = FalseSubtract LoRA delta weight to revert the base linear layer to unmerged state.
class MethodTrainer (method, rdrop_alpha, r3f_epsilon, is_regression, *args, **kwargs)-
Expand source code
class MethodTrainer(Trainer): def __init__(self, method, rdrop_alpha, r3f_epsilon, is_regression, *args, **kwargs) -> None: """Execute __init__ operation.""" super().__init__(*args, **kwargs) self.method = method self.rdrop_alpha = rdrop_alpha self.r3f_epsilon = r3f_epsilon self.is_regression = is_regression def compute_loss(self, model, inputs, return_outputs=False, **kwargs) -> Any: """Compute and return loss.""" if "rdrop" in self.method.lower(): outputs1 = model(**inputs) outputs2 = model(**inputs) loss = rdrop_loss( outputs1.logits, outputs2.logits, inputs["labels"], self.is_regression, self.rdrop_alpha, ) return (loss, outputs1) if return_outputs else loss elif "r3f" in self.method.lower(): loss, logits = r3f_forward( model, input_ids=inputs["input_ids"], attention_mask=inputs.get("attention_mask"), token_type_ids=inputs.get("token_type_ids"), labels=inputs["labels"], epsilon=self.r3f_epsilon, is_regression=self.is_regression, ) return (loss, logits) if return_outputs else loss return super().compute_loss(model, inputs, return_outputs, **kwargs)Trainer is a simple but feature-complete training and eval loop for PyTorch, optimized for 🤗 Transformers.
Args -----= model ([
PreTrainedModel] ortorch.nn.Module, optional): The model to train, evaluate or use for predictions. If not provided, amodel_initmust be passed.<Tip> [`Trainer`] is optimized to work with the [`PreTrainedModel`] provided by the library. You can still use your own models defined as <code>torch.nn.Module</code> as long as they work the same way as the 🤗 Transformers models. </Tip>args ([
TrainingArguments], optional): The arguments to tweak for training. Will default to a basic instance of [TrainingArguments] with theoutput_dirset to a directory named tmp_trainer in the current directory if not provided. data_collator (DataCollator, optional): The function to use to form a batch from a list of elements oftrain_datasetoreval_dataset. Will default to [default_data_collator] if noprocessing_classis provided, an instance of [DataCollatorWithPadding] otherwise if the processing_class is a feature extractor or tokenizer. train_dataset (torch.utils.data.Dataset|torch.utils.data.IterableDataset|datasets.Dataset, optional): The dataset to use for training. If it is a [~datasets.Dataset], columns not accepted by themodel.forward()method are automatically removed.Note that if it's a <code>torch.utils.data.IterableDataset</code> with some randomization and you are training in a distributed fashion, your iterable dataset should either use a internal attribute <code>generator</code> that is a <code>torch.Generator</code> for the randomization that must be identical on all processes (and the Trainer will manually set the seed of this <code>generator</code> at each epoch) or have a <code>set\_epoch()</code> method that internally sets the seed of the RNGs used.eval_dataset (
torch.utils.data.Dataset| dict[str,torch.utils.data.Dataset] |datasets.Dataset, optional): The dataset to use for evaluation. If it is a [~datasets.Dataset], columns not accepted by themodel.forward()method are automatically removed. If it is a dictionary, it will evaluate on each dataset prepending the dictionary key to the metric name. processing_class (PreTrainedTokenizerBaseorBaseImageProcessororFeatureExtractionMixinorProcessorMixin, optional): Processing class used to process the data. If provided, will be used to automatically process the inputs for the model, and it will be saved along the model to make it easier to rerun an interrupted training or reuse the fine-tuned model. model_init (Callable[[], PreTrainedModel], optional): A function that instantiates the model to be used. If provided, each call to [~Trainer.train] will start from a new instance of the model as given by this function.The function may have zero argument, or a single one containing the optuna/Ray Tune trial object, to be able to choose different architectures according to hyperparameters (such as layer count, sizes of inner layers, dropout probabilities etc).compute_loss_func (
Callable, optional): A function that accepts the raw model outputs, labels, and the number of items in the entire accumulated batch (batch_size * gradient_accumulation_steps) and returns the loss. For example, see the default loss function used by [Trainer]. compute_metrics (Callable[[EvalPrediction], Dict], optional): The function that will be used to compute metrics at evaluation. Must take a [EvalPrediction] and return a dictionary string to metric values. Note When passing TrainingArgs withbatch_eval_metricsset toTrue, your compute_metrics function must take a booleancompute_resultargument. This will be triggered after the last eval batch to signal that the function needs to calculate and return the global summary statistics rather than accumulating the batch-level statistics callbacks (List of [TrainerCallback], optional): A list of callbacks to customize the training loop. Will add those to the list of default callbacks detailed in here.If you want to remove one of the default callbacks used, use the [`Trainer.remove_callback`] method.optimizers (
tuple[torch.optim.Optimizer, torch.optim.lr_scheduler.LambdaLR], optional, defaults to(None, None)): A tuple containing the optimizer and the scheduler to use. Will default to an instance of [AdamW] on your model and a scheduler given by [get_linear_schedule_with_warmup] controlled byargs. optimizer_cls_and_kwargs (tuple[Type[torch.optim.Optimizer], dict[str, Any]], optional): A tuple containing the optimizer class and keyword arguments to use. Overridesoptimandoptim_argsinargs. Incompatible with theoptimizersargument.Unlike <code>optimizers</code>, this argument avoids the need to place model parameters on the correct devices before initializing the Trainer.preprocess_logits_for_metrics (
Callable[[torch.Tensor, torch.Tensor], torch.Tensor], optional): A function that preprocess the logits right before caching them at each evaluation step. Must take two tensors, the logits and the labels, and return the logits once processed as desired. The modifications made by this function will be reflected in the predictions received bycompute_metrics.Note that the labels (second parameter) will be <code>None</code> if the dataset does not have them.Important attributes:
- **model** -- Always points to the core model. If using a transformers model, it will be a [`PreTrainedModel`] subclass. - **model_wrapped** -- Always points to the most external model in case one or more other modules wrap the original model. This is the model that should be used for the forward pass. For example, under <code>DeepSpeed</code>, the inner model is wrapped in <code>DeepSpeed</code> and then again in <code>torch.nn.DistributedDataParallel</code>. If the inner model hasn't been wrapped, then <code>self.model\_wrapped</code> is the same as <code>self.model</code>. - **is_model_parallel** -- Whether or not a model has been switched to a model parallel mode (different from data parallelism, this means some of the model layers are split on different GPUs). - **place_model_on_device** -- Whether or not to automatically place the model on the device. Defaults to <code>True</code> unless model parallel, DeepSpeed, FSDP, full fp16/bf16 eval, or SageMaker MP is active. Can be overridden by subclassing <code>TrainingArguments</code> and overriding the <code>place\_model\_on\_device</code> property. - **is_in_train** -- Whether or not a model is currently running <code>train</code> (e.g. when <code>evaluate</code> is called while in <code>train</code>)Execute init operation.
Ancestors
- transformers.trainer.Trainer
Methods
def compute_loss(self, model, inputs, return_outputs=False, **kwargs) ‑> Any-
Expand source code
def compute_loss(self, model, inputs, return_outputs=False, **kwargs) -> Any: """Compute and return loss.""" if "rdrop" in self.method.lower(): outputs1 = model(**inputs) outputs2 = model(**inputs) loss = rdrop_loss( outputs1.logits, outputs2.logits, inputs["labels"], self.is_regression, self.rdrop_alpha, ) return (loss, outputs1) if return_outputs else loss elif "r3f" in self.method.lower(): loss, logits = r3f_forward( model, input_ids=inputs["input_ids"], attention_mask=inputs.get("attention_mask"), token_type_ids=inputs.get("token_type_ids"), labels=inputs["labels"], epsilon=self.r3f_epsilon, is_regression=self.is_regression, ) return (loss, logits) if return_outputs else loss return super().compute_loss(model, inputs, return_outputs, **kwargs)Compute and return loss.
class MixoutLinear (linear: torch.nn.modules.linear.Linear, p: float)-
Expand source code
class MixoutLinear(nn.Module): def __init__(self, linear: nn.Linear, p: float) -> None: super().__init__() self.in_features = linear.in_features self.out_features = linear.out_features self.weight = linear.weight self.bias = linear.bias self.p = p self.register_buffer("target_weight", self.weight.data.clone()) if self.bias is not None: self.register_buffer("target_bias", self.bias.data.clone()) def forward(self, x) -> Any: """Forward pass — compute module output from inputs.""" if self.training and self.p > 0: mask = torch.bernoulli(torch.full_like(self.weight, 1 - self.p)) mixed_weight = self.weight * mask + self.target_weight * (1 - mask) if self.bias is not None: mask_bias = torch.bernoulli(torch.full_like(self.bias, 1 - self.p)) mixed_bias = self.bias * mask_bias + self.target_bias * (1 - mask_bias) else: mixed_bias = None return F.linear(x, mixed_weight, mixed_bias) return F.linear(x, self.weight, self.bias)Base class for all neural network modules.
Your models should also subclass this class.
Modules can also contain other Modules, allowing them to be nested in a tree structure. You can assign the submodules as regular attributes::
import torch.nn as nn import torch.nn.functional as F class Model(nn.Module): def __init__(self) -> None: super().__init__() self.conv1 = nn.Conv2d(1, 20, 5) self.conv2 = nn.Conv2d(20, 20, 5) def forward(self, x): x = F.relu(self.conv1(x)) return F.relu(self.conv2(x))Submodules assigned in this way will be registered, and will also have their parameters converted when you call :meth:
to, etc.Note
As per the example above, an
__init__()call to the parent class must be made before assignment on the child.:ivar training: Boolean represents whether this module is in training or evaluation mode. :vartype training: bool
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def forward(self, x) ‑> Any-
Expand source code
def forward(self, x) -> Any: """Forward pass — compute module output from inputs.""" if self.training and self.p > 0: mask = torch.bernoulli(torch.full_like(self.weight, 1 - self.p)) mixed_weight = self.weight * mask + self.target_weight * (1 - mask) if self.bias is not None: mask_bias = torch.bernoulli(torch.full_like(self.bias, 1 - self.p)) mixed_bias = self.bias * mask_bias + self.target_bias * (1 - mask_bias) else: mixed_bias = None return F.linear(x, mixed_weight, mixed_bias) return F.linear(x, self.weight, self.bias)Forward pass — compute module output from inputs.