minimind/learning/day01/02_deep_dive.md

2.5 KiB
Raw Blame History

Day 1 Deep Dive: MiniMind 模型结构拆解

深挖问题 1:MiniMind 的最小 forward 路径是什么?

打开 model/model_minimind.py:

  1. MiniMindForCausalLM.forward
  2. MiniMindModel.forward
  3. MiniMindBlock.forward
  4. Attention.forward
  5. FeedForward.forward

你要能追踪:

input_ids
-> embed_tokens
-> dropout
-> N x MiniMindBlock
-> RMSNorm
-> lm_head
-> logits
-> cross_entropy loss

重点观察:

  • input_ids.shape == [batch, seq_len]
  • hidden_states.shape == [batch, seq_len, hidden_size]
  • logits.shape == [batch, seq_len, vocab_size]

深挖问题 2:为什么 forward 里是这样算 loss?

代码位置:MiniMindForCausalLM.forward

核心逻辑:

x = logits[..., :-1, :]
y = labels[..., 1:]
loss = F.cross_entropy(x.view(-1, x.size(-1)), y.view(-1), ignore_index=-100)

理解方式:

  • 位置 0 的 logits 预测 token 1。
  • 位置 1 的 logits 预测 token 2。
  • 最后一个位置没有下一个 token,所以丢掉。
  • label 的第一个 token 没有被任何上文预测,所以丢掉。

ignore_index=-100 是训练中最重要的 mask 约定之一。pretrain 用它忽略 padding;SFT 用它忽略 user/system/prompt 部分。

深挖问题 3:Attention 里 GQA 是怎么实现的?

看 Attention.__init__:

  • num_attention_heads
  • num_key_value_heads
  • n_rep = q_heads // kv_heads

看 repeat_kv:

  • K/V heads 先少算。
  • attention 前把 K/V 复制到和 Q heads 对齐。

工业理解:

  • 训练时省一部分参数和计算。
  • 推理时 KV cache 更小。
  • 对小模型通常是合理取舍。

深挖问题 4:MoE 为什么有 aux loss?

看 MOEFeedForward.forward:

  • gate 给每个 token 分配 expert。
  • topk_idx 决定 token 去哪个 expert。
  • aux_loss 鼓励 expert 负载更均衡。

工业风险:

  • 没有负载均衡,部分 expert 可能被过度使用。
  • 原生 PyTorch MoE 训练不一定快,因为 expert 分派有额外调度开销。

今日小实验

写一个临时 Python 片段,不修改项目文件:

python - <<'PY'
import torch
from model.model_minimind import MiniMindConfig, MiniMindForCausalLM

config = MiniMindConfig(hidden_size=128, num_hidden_layers=2)
model = MiniMindForCausalLM(config)
input_ids = torch.randint(0, config.vocab_size, (2, 16))
labels = input_ids.clone()
out = model(input_ids, labels=labels)
print(out.logits.shape)
print(out.loss.item())
PY

你要解释:

  • 为什么随机模型也有 loss?
  • loss 大概应接近 log(vocab_size),为什么?