Skip to content

Confusion about the weight gi #6

Description

@TreasureHunter

Hi, excited to see your new work, but I have some questions.

From your code

query_states = self.q_proj(hidden_states)
key_states = self.k_proj(hidden_states)
value_states = self.v_proj(hidden_states)
gate = query_states.view(-1, self.num_heads, self.head_dim)
logits = torch.stack([torch.norm(gate[:,i,:], p=2, dim=1) for i in range(self.shared_head, self.num_heads)], dim=1)
logits_std = logits.std(dim=1, keepdim=True)
logits_norm = logits / (logits_std / 1)
gates = F.softmax(logits_norm, dim=1)
num_tokens, num_experts = gates.shape
_, indices = torch.topk(gates, k=self.routed_head, dim=1)
mask = F.one_hot(indices, num_classes=num_experts).sum(dim=1)
mask = mask.reshape(bsz, q_len, -1)
mask = torch.cat([torch.ones_like(mask).to(query_states.dtype), mask], dim=-1).to(query_states.dtype)
query_states = query_states.view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
key_states = key_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
value_states = value_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
kv_seq_len = key_states.shape[-2]
if past_key_value is not None:
kv_seq_len += past_key_value.get_usable_length(kv_seq_len, self.layer_idx)
cos, sin = self.rotary_emb(value_states, seq_len=kv_seq_len)
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids)
if past_key_value is not None:
cache_kwargs = {"sin": sin, "cos": cos} # Specific to RoPE models
key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)
key_states = repeat_kv(key_states, self.num_key_value_groups)
value_states = repeat_kv(value_states, self.num_key_value_groups)
if attention_mask is not None:
if attention_mask.size() != (bsz, 1, q_len, kv_seq_len):
raise ValueError(
f"Attention mask should be of size {(bsz, 1, q_len, kv_seq_len)}, but is {attention_mask.size()}"
)
# SDPA with memory-efficient backend is currently (torch==2.1.2) bugged with non-contiguous inputs with custom attn_mask,
# Reference: https://github.com/pytorch/pytorch/issues/112577.
if query_states.device.type == "cuda" and attention_mask is not None:
query_states = query_states.contiguous()
key_states = key_states.contiguous()
value_states = value_states.contiguous()
attn_output = torch.nn.functional.scaled_dot_product_attention(
query_states,
key_states,
value_states,
attn_mask=attention_mask,
dropout_p=self.attention_dropout if self.training else 0.0,
# The q_len > 1 is necessary to match with AttentionMaskConverter.to_causal_4d that does not create a causal mask in case q_len == 1.
is_causal=self.is_causal and attention_mask is None and q_len > 1,
)
attn_output = attn_output.transpose(1, 2).contiguous()
attn_output = attn_output.reshape(bsz, q_len, self.num_heads, self.head_dim)
attn_output = torch.einsum("bne,bned->bned", mask, attn_output)

In Section 3.2 of your paper, you mention that each attention head is associated with a weight gi calculated through Equation 5. However, in the provided code implementation, it appears that 50% of the heads are designated as shared heads and 25% as routed heads, with the corresponding gi values for these 75% of heads seemingly fixed at 1.

This implementation detail appears inconsistent with the theoretical framework described by the formula. Specifically, I could not locate code segments that align with the mathematical derivation presented in the paper. Could you clarify this discrepancy between the theoretical formulation and its practical implementation?

Looking forward to your reply!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions