Feature Extraction
Transformers
Safetensors
English
hyperstyler
style-transfer
authorship
custom_code
Instructions to use JKSHINPG/HyperStyler with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use JKSHINPG/HyperStyler with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="JKSHINPG/HyperStyler", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("JKSHINPG/HyperStyler", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Download hyperstyler.py from JKSHINPG/HyperStyler: direct link, hf CLI and curl.
- Browser
- Download file 34.4 kB
-
https://huggingface.co/JKSHINPG/HyperStyler/resolve/main/hyperstyler.py
- Command line
-
hf download hf://JKSHINPG/HyperStyler/hyperstyler.py
-
curl -L -o hyperstyler.py https://huggingface.co/JKSHINPG/HyperStyler/resolve/main/hyperstyler.py
34.4 kB
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| from .modeling_t5_hyperstyler import T5ForConditionalGeneration_HyperStyler | |
| class HyperStyler(nn.Module): | |
| def __init__(self, base_model, config = None, use_style=False, t5_config=None): | |
| super().__init__() | |
| if t5_config is not None: | |
| # Build the architecture only; weights come from the HyperStyler checkpoint. | |
| self.model = T5ForConditionalGeneration_HyperStyler(t5_config) | |
| else: | |
| self.model = T5ForConditionalGeneration_HyperStyler.from_pretrained(base_model) | |
| self.use_style = use_style | |
| if self.use_style: | |
| self.base_config = { | |
| "d_model" : self.model.config.d_model, #1024 | |
| "num_encoder_layers" : self.model.config.num_layers, | |
| "num_decoder_layers" : self.model.config.num_decoder_layers, | |
| } | |
| self.config = config | |
| self.use_hypernet = config['use_hypernet'] | |
| self.use_stylonavigator = config['use_stylonavigator'] | |
| self.ctrl_dim = config['ctrl_dim'] | |
| if self.use_stylonavigator: | |
| sn_config = config['stylo_navigator_config'] | |
| self.style_navigator = StyleNavigator(self.base_config['d_model'], config['ctrl_dim'], | |
| dropout=sn_config['dropout'] , | |
| temperature= sn_config['temperature']) | |
| if self.use_hypernet: | |
| hn_config = config['hypernet_config'] | |
| self.hypernet = HyperNetwork(model_config=self.base_config, | |
| hypernet_config=hn_config, | |
| ctrl_dim = self.ctrl_dim) | |
| else: | |
| hn_config = config['hypernet_config'] | |
| self.internal_controller = InternalControl(model_config=self.base_config, | |
| hypernet_config=hn_config, | |
| ctrl_dim = self.ctrl_dim) | |
| def freeze_stylonavigator(self): | |
| for name, param in self.style_navigator.named_parameters(): | |
| param.requires_grad = False | |
| def base_model_freeze(self): | |
| for name, param in self.model.named_parameters(): | |
| param.requires_grad = False | |
| def freeze_encoder_only(self): | |
| for name, param in self.model.named_parameters(): | |
| # encoder freeze | |
| if name.startswith("encoder."): | |
| param.requires_grad = False | |
| # shared embedding freeze | |
| elif name.startswith("shared."): | |
| param.requires_grad = False | |
| else: | |
| param.requires_grad = True | |
| def forward(self, input_ids, attention_mask, labels=None, style_embs=None, style_masks=None, idx_labels=None,target_style_embs=None,): | |
| if self.use_style: | |
| stylonavigator = None | |
| hypernet = None | |
| internal_controller = None | |
| if self.use_stylonavigator: | |
| stylonavigator = self.style_navigator | |
| if self.use_hypernet: | |
| hypernet = self.hypernet | |
| else: | |
| internal_controller = self.internal_controller | |
| return self.model( | |
| input_ids=input_ids, attention_mask=attention_mask, | |
| labels=labels, | |
| style_embs = style_embs, style_masks = style_masks, | |
| style_navigator = stylonavigator, | |
| hypernetwork = hypernet, | |
| idx_labels=idx_labels, | |
| internal_controller= internal_controller, | |
| target_style_embs=target_style_embs, | |
| ) | |
| else: | |
| return self.model( | |
| input_ids=input_ids, attention_mask=attention_mask, labels=labels | |
| ) | |
| def generate(self, input_ids, attention_mask, style_embs=None, style_masks=None, **kwargs): | |
| if self.use_style: | |
| stylonavigator = None | |
| hypernet = None | |
| internal_controller = None | |
| if self.use_stylonavigator: | |
| stylonavigator = self.style_navigator | |
| if self.use_hypernet: | |
| hypernet = self.hypernet | |
| else: | |
| internal_controller = self.internal_controller | |
| return self.model.generate( | |
| input_ids=input_ids, attention_mask=attention_mask , | |
| style_embs = style_embs, style_masks = style_masks, | |
| style_navigator = stylonavigator, | |
| hypernetwork = hypernet, | |
| internal_controller= internal_controller, **kwargs | |
| ) | |
| else: | |
| return self.model.generate( | |
| input_ids=input_ids, attention_mask=attention_mask, **kwargs | |
| ) | |
| class StyleNavigator(nn.Module): | |
| """ | |
| Aggregates multiple author style embeddings (few-shot samples) | |
| into a single style summary embedding. | |
| Cosine-space normalization + learnable scaling for stability. | |
| """ | |
| def __init__(self, d_model, style_dim, dropout=0.1 , temperature= 1.0): | |
| super().__init__() | |
| self.d_model = d_model | |
| self.style_dim = style_dim | |
| # --- Text Multi-Head Self-Attention --- | |
| self.cross_attn = MultiHeadAttention(d_model, style_dim, style_dim, style_dim, 16) | |
| self.style_attn = MultiHeadAttention(style_dim, style_dim, style_dim, style_dim, 16) | |
| self.style_layer_norm = nn.LayerNorm(style_dim) | |
| self.text_layer_norm = nn.LayerNorm(d_model) | |
| self.q_layer_norm = nn.LayerNorm(style_dim) | |
| self.k_layer_norm = nn.LayerNorm(style_dim) | |
| self.dropout = nn.Dropout(dropout) | |
| self.temperature = temperature | |
| self._init_weights() | |
| def _init_weights(self): | |
| for m in self.modules(): | |
| if isinstance(m, nn.Linear): | |
| nn.init.xavier_uniform_(m.weight) | |
| nn.init.zeros_(m.bias) | |
| def forward(self, text_embs, style_embs, text_mask=None, style_mask=None, idx_labels= None): | |
| #B, N, D = text_embs.shape | |
| norm_style_embs = self.style_layer_norm(style_embs) | |
| norm_text_embs = self.text_layer_norm(text_embs) | |
| query = self.cross_attn(norm_text_embs, norm_style_embs, norm_style_embs, text_mask, style_mask) | |
| query = self.mask_mean_pooling(query, text_mask).unsqueeze(1) | |
| key = self.style_attn(norm_style_embs, q_mask= style_mask, k_mask=style_mask) | |
| query = self.q_layer_norm(query) | |
| key = self.k_layer_norm(key) | |
| attn_logits = (query @ key.transpose(-2, -1)) / (key.size(-1) ** 0.5) | |
| if style_mask is not None: | |
| style_mask = style_mask.unsqueeze(1) | |
| attn_logits = attn_logits.masked_fill(style_mask == 0, -1e9) | |
| accuracy = None | |
| loss = None | |
| if idx_labels is not None: | |
| attn_probs = F.softmax(attn_logits, dim=-1) | |
| log_probs = F.log_softmax(attn_logits.squeeze(1), dim=-1) | |
| loss = nn.NLLLoss()(log_probs, idx_labels) | |
| pred_idx = torch.argmax(attn_probs.squeeze(1), dim=-1) | |
| accuracy = (pred_idx == idx_labels).float().mean() | |
| # for teacher forcing to later network | |
| selected_embs = style_embs.gather(1, idx_labels.view(-1, 1, 1).expand(-1, 1, style_embs.size(-1))).squeeze(1) | |
| else: | |
| attn_probs = F.softmax(attn_logits / self.temperature, dim=-1) | |
| #print("attn_probs : ", attn_probs.shape) | |
| #print("style_embs : ",style_embs.shape) | |
| selected_embs = (attn_probs @ style_embs).squeeze(1) | |
| #pred_idx = torch.argmax(attn_probs.squeeze(1), dim=-1) | |
| #selected_embs = style_embs.gather(1, pred_idx.view(-1, 1, 1).expand(-1, 1, style_embs.size(-1))).squeeze(1) | |
| return selected_embs, loss, accuracy, attn_probs | |
| def mask_mean_pooling(self, x, mask): | |
| if mask is not None: | |
| mask = mask.float().unsqueeze(-1) # [B, Nq, 1] | |
| out = (x * mask).sum(dim=1) / (mask.sum(dim=1).clamp_min(1e-6)) | |
| else: | |
| out = x.mean(dim=1) | |
| return out | |
| class BaseMLP(nn.Module): | |
| def __init__(self, input_dim, intermediate_dim, output_dim, bias=False, out_layer_norm = False, dropout=0.1): | |
| super().__init__() | |
| self.input_dim = input_dim | |
| self.intermediate_dim = intermediate_dim | |
| self.output_dim = output_dim | |
| self.final_out_dim = self.output_dim[0] * self.output_dim[1] | |
| self.out_layer_norm = out_layer_norm | |
| if out_layer_norm: | |
| self.layer_norm = nn.LayerNorm(self.output_dim[1]) | |
| self.fc = nn.Sequential( | |
| nn.Linear(input_dim, intermediate_dim), | |
| nn.SiLU(), | |
| nn.Dropout(dropout), | |
| nn.Linear(intermediate_dim, intermediate_dim), | |
| nn.SiLU(), | |
| nn.Dropout(dropout), | |
| ) | |
| # projection layer for weight / bias | |
| self.fc_weight = nn.Linear(intermediate_dim, self.final_out_dim) | |
| if bias: | |
| self.fc_bias = nn.Linear(intermediate_dim, self.final_out_dim) | |
| self._init_hyper_heads_bias() | |
| self._init_fc() | |
| self._init_hyper_heads() # bias_hyperinit | |
| def _init_fc(self): | |
| for m in self.fc: | |
| if isinstance(m, nn.Linear): | |
| nn.init.xavier_uniform_(m.weight) | |
| nn.init.zeros_(m.bias) | |
| def _init_hyper_heads(self): | |
| #nn.init.constant_(self.fc_weight.weight, 0.0) | |
| #nn.init.xavier_uniform_(self.fc_weight.weight) | |
| nn.init.xavier_uniform_(self.fc_weight.weight, gain=0.5) | |
| nn.init.zeros_(self.fc_weight.bias) | |
| def _init_hyper_heads_bias(self): | |
| nn.init.xavier_uniform_(self.fc_bias.weight) | |
| nn.init.zeros_(self.fc_bias.bias) | |
| def forward(self, x): | |
| """ | |
| x: [batch, num_layers, ctrl_dim] | |
| output: [batch, num_layers, *output_dim] | |
| """ | |
| bsz, n_layer, d = x.shape | |
| h = self.fc(x.view(bsz * n_layer, d)) # [batch*num_layers, hidden_dim] | |
| w = self.fc_weight(h) # [batch*num_layers, final_out_dim] | |
| #b = self.fc_bias(h) # [batch*num_layers, final_out_dim] | |
| w = w.view(bsz, n_layer, *self.output_dim) # [batch, num_layers, *output_dim] | |
| #b = b.view(bsz, n_layer, *self.output_dim) # [batch, num_layers, *output_dim] | |
| if self.out_layer_norm: | |
| w = self.layer_norm(w) | |
| return w #, b | |
| class InternalControl(nn.Module): | |
| def __init__(self, model_config, hypernet_config, ctrl_dim): | |
| super().__init__() | |
| self.layer_embeddings = HyperEmbeddingforInternalControl(ctrl_dim, model_config, hypernet_config, block_name="decoder") | |
| d_model = model_config['d_model'] | |
| self.mlp = BaseMLP(ctrl_dim, d_model, (1, d_model), dropout=hypernet_config['dropout']) | |
| self.model_config = model_config | |
| self.hypernet_config = hypernet_config | |
| self.q = nn.Linear(ctrl_dim, ctrl_dim, bias=False) | |
| if self.hypernet_config['search_config'] == "MHA": | |
| self.k = nn.Linear(ctrl_dim, ctrl_dim, bias=False) | |
| self.layers_layer_norm = nn.LayerNorm(ctrl_dim) | |
| self.style_layer_norm = nn.LayerNorm(ctrl_dim) | |
| self.v = nn.Linear(ctrl_dim, ctrl_dim, bias=False) | |
| self.o = nn.Linear(ctrl_dim, ctrl_dim, bias=False) | |
| self.out_layer_norm = nn.LayerNorm(ctrl_dim) | |
| self._init_weights() | |
| def _init_weights(self): | |
| # q, k, v, o projection | |
| target_layers = [self.q, self.v, self.o] | |
| if self.hypernet_config['search_config'] == "MHA": | |
| target_layers.append(self.k) | |
| for m in target_layers: # , | |
| if isinstance(m, nn.Linear): | |
| nn.init.xavier_uniform_(m.weight, gain=0.5) | |
| if m.bias is not None: | |
| nn.init.zeros_(m.bias) | |
| def forward(self, author_embs): | |
| generated_prefix = {} | |
| layer_embs = self.layer_embeddings.embedding.weight | |
| B = author_embs.size(0) | |
| L, D = layer_embs.shape | |
| H = 16 | |
| d_h = D // H | |
| #Q = layer_embs.view(L, H, d_h).transpose(0, 1) | |
| #### | |
| norm_layer_embs = self.layers_layer_norm(layer_embs)#, layer_embs.shape[-1:]) | |
| norm_style_embs = self.style_layer_norm(author_embs)#, style_embs.shape[-1:]) | |
| Q = self.q(norm_layer_embs).view(L, H, d_h).transpose(0, 1) | |
| #### | |
| K = self.k(norm_style_embs).unsqueeze(1).view(B, 1, H, d_h).transpose(1, 2) | |
| V = self.v(norm_style_embs).unsqueeze(1).view(B, 1, H, d_h).transpose(1, 2) | |
| attn = torch.einsum("hld,bhnd->bhln", Q, K) #/ (d_h ** 0.5) | |
| out = torch.einsum("bhln,bhnd->bhld", attn, V) | |
| out = out.transpose(1, 2).contiguous().view(B, L, D) | |
| out = self.o(out) | |
| out = self.out_layer_norm(out) | |
| # out : [batch, n_layers, dim] | |
| attn_layer_embs = layer_embs.unsqueeze(0) + out | |
| gen_query = self.mlp(attn_layer_embs).squeeze(-2) # B, N, D | |
| for i, layer_name in enumerate(self.layer_embeddings.q_name_list): | |
| generated_prefix[layer_name] = gen_query[:,i,:] # B, 1, D | |
| return generated_prefix | |
| class HyperNetwork(nn.Module): | |
| def __init__(self, model_config, hypernet_config, ctrl_dim): | |
| super().__init__() | |
| self.prefix_embeddings = None | |
| self.adapter_embeddings = None | |
| d_model = model_config['d_model'] | |
| self.model_config = model_config | |
| self.hypernet_config = hypernet_config | |
| if 'selfattn' in hypernet_config['target_layers']: | |
| self.decoder_self_prefix_embeddings = HyperEmbeddingforPrefix(ctrl_dim, model_config, hypernet_config, block_name="decoder", layer_name="self") | |
| self.decoder_self_prefix_key = BaseMLP(ctrl_dim, d_model, (1, d_model), dropout=hypernet_config['dropout'] , out_layer_norm = True) | |
| self.decoder_self_prefix_value = BaseMLP(ctrl_dim, d_model, (1, d_model), dropout=hypernet_config['dropout'] , out_layer_norm = True) | |
| if 'crossattn' in hypernet_config['target_layers']: | |
| self.decoder_cross_prefix_embeddings = HyperEmbeddingforPrefix(ctrl_dim, model_config, hypernet_config, block_name="decoder", layer_name="cross") | |
| self.decoder_cross_prefix_key = BaseMLP(ctrl_dim, d_model, (1, d_model), dropout=hypernet_config['dropout'] , out_layer_norm = True) | |
| self.decoder_cross_prefix_value = BaseMLP(ctrl_dim, d_model, (1, d_model), dropout=hypernet_config['dropout'] , out_layer_norm = True) | |
| if 'ffn' in hypernet_config['target_layers']: | |
| self.decoder_adapter_embeddings = HyperEmbeddingforAdaptor(ctrl_dim, model_config, hypernet_config, block_name="decoder") | |
| if self.hypernet_config['parameter_efficiency_mode']: | |
| self.decoder_adaptor_Wu = BaseMLP(ctrl_dim, d_model, (1, d_model), dropout=hypernet_config['dropout']) | |
| self.decoder_adaptor_Wd = BaseMLP(ctrl_dim, d_model, (1, d_model), dropout=hypernet_config['dropout']) | |
| else: | |
| self.decoder_adaptor_Wu = BaseMLP(ctrl_dim, d_model, (hypernet_config["rank"], d_model), dropout=hypernet_config['dropout']) | |
| self.decoder_adaptor_Wd = BaseMLP(ctrl_dim, d_model, (d_model, hypernet_config["rank"]), dropout=hypernet_config['dropout']) | |
| self.q = nn.Linear(ctrl_dim, ctrl_dim, bias=False) | |
| if self.hypernet_config['search_config'] == "MHA" or self.hypernet_config['search_config'] == "MHA_all_style_embeddings": | |
| self.k = nn.Linear(ctrl_dim, ctrl_dim, bias=False) | |
| self.layers_layer_norm = nn.LayerNorm(ctrl_dim) | |
| self.style_layer_norm = nn.LayerNorm(ctrl_dim) | |
| self.v = nn.Linear(ctrl_dim, ctrl_dim, bias=False) | |
| self.o = nn.Linear(ctrl_dim, ctrl_dim, bias=False) | |
| self.out_layer_norm = nn.LayerNorm(ctrl_dim) | |
| self._init_weights() | |
| def _init_weights(self): | |
| # q, k, v, o projection | |
| target_layers = [self.q, self.v, self.o] | |
| if self.hypernet_config['search_config'] == "MHA" or self.hypernet_config['search_config'] == "MHA_all_style_embeddings": | |
| target_layers.append(self.k) | |
| for m in target_layers: # , | |
| if isinstance(m, nn.Linear): | |
| nn.init.xavier_uniform_(m.weight, gain=0.5) | |
| if m.bias is not None: | |
| nn.init.zeros_(m.bias) | |
| def get_inputs_multiheadattn_for_ablation(self, embedding_module, style_embs, style_masks): | |
| layer_embs = embedding_module.embedding.weight # [L_q, D] | |
| B, L_k, D = style_embs.shape | |
| L_q = layer_embs.size(0) | |
| H = 16 | |
| d_h = D // H | |
| norm_layer_embs = self.layers_layer_norm(layer_embs) | |
| norm_style_embs = self.style_layer_norm(style_embs) | |
| # Q: [B, H, L_q, d_h] | |
| Q = self.q(norm_layer_embs) \ | |
| .view(L_q, H, d_h).transpose(0, 1) \ | |
| .unsqueeze(0).expand(B, -1, -1, -1) | |
| # K, V: [B, H, L_k, d_h] | |
| K = self.k(norm_style_embs) \ | |
| .view(B, L_k, H, d_h).transpose(1, 2) | |
| V = self.v(norm_style_embs) \ | |
| .view(B, L_k, H, d_h).transpose(1, 2) | |
| attn_logits = torch.einsum("bhld,bhnd->bhln", Q, K) | |
| attn_logits = attn_logits / (d_h ** 0.5) | |
| style_masks = style_masks.unsqueeze(1).unsqueeze(2) # [B,1,1,L_k] | |
| attn_logits = attn_logits.masked_fill(style_masks == 0, float("-inf")) | |
| attn = torch.softmax(attn_logits, dim=-1) | |
| out = torch.einsum("bhln,bhnd->bhld", attn, V) | |
| out = out.transpose(1, 2).contiguous().view(B, L_q, D) | |
| out = self.o(out) | |
| out = self.out_layer_norm(out) | |
| return layer_embs.unsqueeze(0) + out | |
| def get_inputs_multihead(self, embedding_module, style_embs): | |
| layer_embs = embedding_module.embedding.weight | |
| B = style_embs.size(0) | |
| L, D = layer_embs.shape | |
| H = 16 | |
| d_h = D // H | |
| #Q = layer_embs.view(L, H, d_h).transpose(0, 1) | |
| #### | |
| norm_layer_embs = self.layers_layer_norm(layer_embs)#, layer_embs.shape[-1:]) | |
| norm_style_embs = self.style_layer_norm(style_embs)#, style_embs.shape[-1:]) | |
| Q = self.q(norm_layer_embs).view(L, H, d_h).transpose(0, 1) | |
| #### | |
| K = self.k(norm_style_embs).unsqueeze(1).view(B, 1, H, d_h).transpose(1, 2) | |
| V = self.v(norm_style_embs).unsqueeze(1).view(B, 1, H, d_h).transpose(1, 2) | |
| attn = torch.einsum("hld,bhnd->bhln", Q, K) #/ (d_h ** 0.5) | |
| out = torch.einsum("bhln,bhnd->bhld", attn, V) | |
| out = out.transpose(1, 2).contiguous().view(B, L, D) | |
| out = self.o(out) | |
| out = self.out_layer_norm(out) | |
| # out : [batch, n_layers, dim] | |
| return layer_embs.unsqueeze(0) + out | |
| def get_inputs(self, embedding_module, style_embs, style_masks=None): | |
| if self.hypernet_config['search_config'] == "MHA": | |
| return self.get_inputs_multihead(embedding_module, style_embs) | |
| elif self.hypernet_config['search_config'] == "MHA_all_style_embeddings": | |
| return self.get_inputs_multiheadattn_for_ablation(embedding_module, style_embs, style_masks) | |
| elif self.hypernet_config['search_config'] == "none": | |
| return embedding_module + style_embs | |
| else: | |
| # [L, D] | |
| layer_embs = embedding_module.embedding.weight | |
| Q = self.q(layer_embs) # [L, D] | |
| Q = F.normalize(Q, dim=-1) # remaining direction | |
| # K, V: style direction | |
| norm_style_embs = F.normalize(style_embs, dim=-1) | |
| K = norm_style_embs.unsqueeze(1) # [B, 1, D] | |
| V = self.v(norm_style_embs).unsqueeze(1) # [B, 1, D] | |
| # Attention: layer–style alignment | |
| # Q: [L, D], K: [B, 1, D] → attn: [B, L, 1] | |
| attn = torch.einsum("ld,bnd->bln", Q, K) | |
| # Modulation | |
| # attn: [B, L, 1], V: [B, 1, D] → out: [B, L, D] | |
| out = torch.einsum("bln,bnd->bld", attn, V) | |
| out = self.o(out) | |
| out = self.out_layer_norm(out) | |
| # Residual connection | |
| return layer_embs.unsqueeze(0) + out | |
| def forward(self, author_embs, style_masks=None): #style_embs, style_masks): | |
| # style_embs: [batch, num_style_embs, d] | |
| generated_parameters = {} | |
| for layer in self.hypernet_config['target_layers']: | |
| if layer == "selfattn": | |
| generated_parameters['is_selfattn'] = True | |
| if layer == "crossattn": | |
| generated_parameters['is_crossattn'] = True | |
| if layer == "ffn": | |
| generated_parameters['is_ffn'] = True | |
| #author_embs = self.author_encoder(style_embs, style_masks) | |
| if 'selfattn' in self.hypernet_config['target_layers']: | |
| dec_self_embs = self.get_inputs(self.decoder_self_prefix_embeddings, author_embs, style_masks) | |
| dec_self_prefix = self.generate_prefix_params( | |
| dec_self_embs, | |
| self.decoder_self_prefix_key, self.decoder_self_prefix_value, | |
| self.decoder_self_prefix_embeddings.key_name_list, self.decoder_self_prefix_embeddings.value_name_list, | |
| self.decoder_self_prefix_embeddings.key_idx_list, self.decoder_self_prefix_embeddings.value_idx_list, | |
| ) | |
| generated_parameters.update(dec_self_prefix) | |
| if 'crossattn' in self.hypernet_config['target_layers']: | |
| dec_cross_embs = self.get_inputs(self.decoder_cross_prefix_embeddings, author_embs, style_masks) | |
| dec_cross_prefix = self.generate_prefix_params( | |
| dec_cross_embs, | |
| self.decoder_cross_prefix_key, self.decoder_cross_prefix_value, | |
| self.decoder_cross_prefix_embeddings.key_name_list, self.decoder_cross_prefix_embeddings.value_name_list, | |
| self.decoder_cross_prefix_embeddings.key_idx_list, self.decoder_cross_prefix_embeddings.value_idx_list, | |
| ) | |
| generated_parameters.update(dec_cross_prefix) | |
| if 'ffn' in self.hypernet_config['target_layers']: | |
| dec_adapt_embs = self.get_inputs(self.decoder_adapter_embeddings, author_embs, style_masks) | |
| dec_adaptor_params = self.generate_adaptor_params( | |
| dec_adapt_embs, | |
| self.decoder_adaptor_Wu, self.decoder_adaptor_Wd, | |
| self.decoder_adapter_embeddings.Wu_name_list, self.decoder_adapter_embeddings.Wd_name_list, | |
| self.decoder_adapter_embeddings.Wu_idx_list, self.decoder_adapter_embeddings.Wd_idx_list, | |
| ) | |
| generated_parameters.update(dec_adaptor_params) | |
| return generated_parameters | |
| def generate_adaptor_params(self, layer_embs, Wu_mlp, Wd_mlp, | |
| Wu_name_list, Wd_name_list, Wu_idx_list, Wd_idx_list): | |
| """ | |
| layer_embs: [B, num_layers, D] | |
| Wu_mlp, Wd_mlp: BaseMLP for up/down projection | |
| embedding_obj: HyperEmbeddingforAdaptor instance | |
| returns: dict(name -> tensor) | |
| """ | |
| generated_parameters = {} | |
| gen_Wu = Wu_mlp(layer_embs[:, Wu_idx_list ,:]) | |
| gen_Wd = Wd_mlp(layer_embs[:, Wd_idx_list,:]) | |
| #print("gen_Wd : ", gen_Wd.shape) # [B, layer, 1, d_embs] | |
| if self.hypernet_config['parameter_efficiency_mode']: | |
| layer_names = [] | |
| layer_to_indices = {} | |
| for i, name in enumerate(Wu_name_list): | |
| # e.g. "decoder_ffn_3_Wu_2" → "decoder_ffn_3" | |
| layer_name = "_".join(name.split("_")[:3]) | |
| if layer_name not in layer_to_indices: | |
| layer_to_indices[layer_name] = [] | |
| layer_names.append(layer_name) | |
| layer_to_indices[layer_name].append(i) | |
| for layer_name in layer_names: | |
| idxs = torch.tensor(layer_to_indices[layer_name], device=gen_Wu.device, dtype=torch.long) | |
| Wu_tensor = gen_Wu.index_select(1, idxs) # [B, rank, d_embs] | |
| Wd_tensor = gen_Wd.index_select(1, idxs) # [B, rank, d_embs] | |
| generated_parameters[f"{layer_name}_Wu"] = Wu_tensor.squeeze(2) | |
| generated_parameters[f"{layer_name}_Wd"] = Wd_tensor.squeeze(2).transpose(1, 2) | |
| #print("Wu_tensor :", Wu_tensor.shape) | |
| #print("Wd_tensor :", Wd_tensor.shape) | |
| else: | |
| for i, name in enumerate(Wu_name_list): | |
| generated_parameters[name] = gen_Wu[:, i, :, :] # [B, rank, d_embs] | |
| for i, name in enumerate(Wd_name_list): | |
| generated_parameters[name] = gen_Wd[:, i, :, :] # [B, d_embs, rank] | |
| return generated_parameters | |
| def generate_prefix_params(self, layer_embs, prefix_key_mlp, prefix_value_mlp, | |
| key_name_list, value_name_list, key_idx_list, value_idx_list): | |
| """ | |
| layer_embs: [B, L, D] | |
| prefix_key_mlp/value_mlp: BaseMLP modules | |
| name_list: list of prefix token names | |
| idx_list: list of embedding index | |
| returns: dict(layer_name -> {"key": tensor, "value": tensor}) | |
| """ | |
| generated_parameters = {} | |
| # key prefix | |
| gen_key = prefix_key_mlp(layer_embs[:,key_idx_list,:]).squeeze(-2) | |
| gen_val = prefix_value_mlp(layer_embs[:,value_idx_list,:]).squeeze(-2) | |
| layer_names = [] | |
| layer2idx = {} | |
| for i, name in enumerate(key_name_list): | |
| layer_name = "_".join(name.split("_")[:3]) + "_prefix" | |
| if layer_name not in layer2idx: | |
| layer2idx[layer_name] = [] | |
| layer_names.append(layer_name) | |
| layer2idx[layer_name].append(i) | |
| for layer_name in layer_names: | |
| idxs = torch.tensor(layer2idx[layer_name], device=gen_key.device, dtype=torch.long) | |
| key_tensor = gen_key.index_select(1, idxs) | |
| val_tensor = gen_val.index_select(1, idxs) | |
| generated_parameters[f"{layer_name}_key"] = key_tensor | |
| generated_parameters[f"{layer_name}_value"] = val_tensor | |
| return generated_parameters | |
| class HyperEmbedding(nn.Module): | |
| def __init__(self, model_config, hypernet_config): | |
| super().__init__() | |
| self.model_config = model_config | |
| self.hypernet_config = hypernet_config | |
| self.name_to_idx = None | |
| self.embedding = None | |
| def get_embeddings(self, namelist): | |
| idxs = [self.name_to_idx[n] for n in namelist] | |
| return self.embedding.weight[idxs] | |
| class HyperEmbeddingforPrefix(HyperEmbedding): | |
| def __init__(self, ctrl_dim, model_config, hypernet_config, block_name=None, layer_name=None): | |
| super().__init__(model_config, hypernet_config) | |
| self.block_name = block_name | |
| self.layer_name = layer_name | |
| self.name_to_idx = self.create_dictionary_name_to_idx() | |
| self.key_dict = {key: value for key, value in self.name_to_idx.items() if "key" in key} | |
| self.value_dict = {key: value for key, value in self.name_to_idx.items() if "value" in key} | |
| self.key_name_list = list(self.key_dict.keys()) | |
| self.value_name_list = list(self.value_dict.keys()) | |
| self.key_idx_list = list(self.key_dict.values()) | |
| self.value_idx_list = list(self.value_dict.values()) | |
| self.name_list = list(self.name_to_idx.keys()) | |
| self.embedding = nn.Embedding(len(self.name_to_idx), | |
| embedding_dim=ctrl_dim) | |
| def create_dictionary_name_to_idx(self): | |
| dictionary = {} | |
| idx = 0 | |
| if self.block_name == "decoder": | |
| for i in range(self.model_config[f'num_{self.block_name}_layers']): | |
| for j in range(self.hypernet_config['num_prefix']): | |
| dictionary[f'{self.block_name}_{self.layer_name}_{i}_key_prefix_{j}'] = idx; idx += 1 | |
| dictionary[f'{self.block_name}_{self.layer_name}_{i}_value_prefix_{j}'] = idx; idx += 1 | |
| # elif self.block_name == "encoder": | |
| # num_layers = self.model_config[f'num_{self.block_name}_layers'] | |
| # for i in range(num_layers//2, num_layers,1): | |
| # for j in range(self.hypernet_config['num_prefix']): | |
| # dictionary[f'{self.block_name}_{self.layer_name}_{i}_key_prefix_{j}'] = idx; idx += 1 | |
| # dictionary[f'{self.block_name}_{self.layer_name}_{i}_value_prefix_{j}'] = idx; idx += 1 | |
| else: | |
| raise ValueError(f"wrong block name. input block.name : {self.block_name}") | |
| return dictionary | |
| class HyperEmbeddingforAdaptor(HyperEmbedding): | |
| def __init__(self, ctrl_dim, model_config, hypernet_config, block_name=None, weight_type=None): | |
| super().__init__(model_config, hypernet_config) | |
| self.block_name = block_name | |
| self.weight_type = weight_type | |
| self.name_to_idx = self.create_dictionary_name_to_idx() | |
| self.Wu_dict = {key: value for key, value in self.name_to_idx.items() if "Wu" in key} | |
| self.Wd_dict = {key: value for key, value in self.name_to_idx.items() if "Wd" in key} | |
| self.Wu_name_list = list(self.Wu_dict.keys()) | |
| self.Wd_name_list = list(self.Wd_dict.keys()) | |
| self.Wu_idx_list = list(self.Wu_dict.values()) | |
| self.Wd_idx_list = list(self.Wd_dict.values()) | |
| self.embedding = nn.Embedding(len(self.name_to_idx), | |
| embedding_dim=ctrl_dim) | |
| def create_dictionary_name_to_idx(self): | |
| dictionary = {} | |
| idx = 0 | |
| if self.block_name == "decoder": | |
| for i in range(self.model_config[f'num_{self.block_name}_layers']): | |
| if self.hypernet_config['parameter_efficiency_mode']: | |
| for j in range(self.hypernet_config['rank']): | |
| dictionary[f'{self.block_name}_ffn_{i}_Wu_{j}'] = idx; idx += 1 | |
| dictionary[f'{self.block_name}_ffn_{i}_Wd_{j}'] = idx; idx += 1 | |
| else: | |
| dictionary[f'{self.block_name}_ffn_{i}_Wu'] = idx; idx += 1 | |
| dictionary[f'{self.block_name}_ffn_{i}_Wd'] = idx; idx += 1 | |
| # elif self.block_name == "encoder": | |
| # num_layers = self.model_config[f'num_{self.block_name}_layers'] | |
| # for i in range(num_layers//2, num_layers,1): | |
| # if self.hypernet_config['parameter_efficiency_mode']: | |
| # for j in range(self.hypernet_config['rank']): | |
| # dictionary[f'{self.block_name}_ffn_{i}_Wu_{j}'] = idx; idx += 1 | |
| # dictionary[f'{self.block_name}_ffn_{i}_Wd_{j}'] = idx; idx += 1 | |
| # else: | |
| # dictionary[f'{self.block_name}_ffn_{i}_Wu'] = idx; idx += 1 | |
| # dictionary[f'{self.block_name}_ffn_{i}_Wd'] = idx; idx += 1 | |
| else: | |
| raise ValueError(f"wrong block name. input block.name : {self.block_name}") | |
| return dictionary | |
| class HyperEmbeddingforInternalControl(HyperEmbedding): | |
| def __init__(self, ctrl_dim, model_config, hypernet_config, block_name=None, weight_type=None): | |
| super().__init__(model_config, hypernet_config) | |
| self.block_name = block_name | |
| self.weight_type = weight_type | |
| self.name_to_idx = self.create_dictionary_name_to_idx() | |
| self.q_dict = {key: value for key, value in self.name_to_idx.items() if "control_token" in key} | |
| self.q_name_list = list(self.q_dict.keys()) | |
| self.q_idx_list = list(self.q_dict.values()) | |
| self.embedding = nn.Embedding(len(self.name_to_idx), | |
| embedding_dim=ctrl_dim) | |
| def create_dictionary_name_to_idx(self): | |
| dictionary = {} | |
| idx = 0 | |
| for i in range(self.model_config[f'num_{self.block_name}_layers']): | |
| dictionary[f'{self.block_name}_control_token_layer_{i}'] = idx; idx += 1 | |
| return dictionary | |
| class MultiHeadAttention(nn.Module): | |
| def __init__(self, in_q_dim, in_kv_dim, inter_dim, out_dim, num_heads=16, dropout=0.1): | |
| super().__init__() | |
| self.num_heads = num_heads | |
| self.in_q_dim = in_q_dim | |
| self.in_kv_dim = in_kv_dim | |
| self.inter_dim = inter_dim | |
| self.out_dim = out_dim | |
| self.q_proj = nn.Linear(in_q_dim, inter_dim) | |
| self.k_proj = nn.Linear(in_kv_dim, inter_dim) | |
| self.v_proj = nn.Linear(in_kv_dim, inter_dim) | |
| self.o_proj = nn.Linear(inter_dim, out_dim) | |
| self.dropout = nn.Dropout(dropout) | |
| def forward(self, query, key=None, value=None, q_mask=None, k_mask=None): | |
| """ | |
| query : [B, Nq, Dq] | |
| key : [B, Nk, Dk] | |
| value : [B, Nk, Dk] | |
| q_mask: [B, Nq] | |
| k_mask: [B, Nk] | |
| """ | |
| if key is None: | |
| key = query | |
| if value is None: | |
| value = key | |
| B, Nq, Dq = query.shape | |
| _, Nk, Dk = key.shape | |
| H = self.num_heads | |
| head_dim = self.inter_dim // H | |
| Q = self.q_proj(query).view(B, Nq, H, head_dim).transpose(1, 2) | |
| K = self.k_proj(key).view(B, Nk, H, head_dim).transpose(1, 2) | |
| V = self.v_proj(value).view(B, Nk, H, head_dim).transpose(1, 2) | |
| # --- scaled dot-product --- | |
| attn_scores = (Q @ K.transpose(-2, -1)) / (head_dim ** 0.5) | |
| # --- key mask (block attention to invalid keys) | |
| if k_mask is not None: | |
| k_mask = k_mask.unsqueeze(1).unsqueeze(2) # [B, 1, 1, Nk] | |
| attn_scores = attn_scores.masked_fill(k_mask == 0, -1e9) | |
| attn = F.softmax(attn_scores, dim=-1) | |
| attn = self.dropout(attn) | |
| out = attn @ V # [B, H, Nq, d_h] | |
| out = out.transpose(1, 2).contiguous().view(B, Nq, self.inter_dim) | |
| out = self.o_proj(out) | |
| # --- query mask (zero out invalid queries after attention) | |
| if q_mask is not None: | |
| q_mask = q_mask.unsqueeze(-1) # [B, Nq, 1] | |
| out = out * q_mask | |
| return out | |