大模型入门教程2 - 撕掉“语义理解”的滤镜:用 GPT-2 架构直接算钢琴曲

#撕掉“语义理解”的滤镜:用 GPT-2 架构直接算钢琴曲

系列导读:上一篇(从 Bigram 到 GPT-2) 我们推导了从 Bigram 到 GPT-2 的架构演进。很多人看到 Self-Attention(自注意力)、Token Embedding(词向量)这些术语,容易产生一种科幻滤镜:仿佛神经网络真的“读懂”了人类语言的语义。其实不然,本质上全是张量计算与条件概率拟合。今天我们不改一行模型架构代码,直接把训练数据从莎士比亚文本换成 MIDI 钢琴曲,在免费 Colab T4 GPU 上算 10 分钟,看看同一个 Decoder-Only Transformer 能算出什么结果。


#1. 核心祛魅:Transformer 根本不知道输入的是文字还是琴键

回顾上一篇实现的 SimpleLLM(6 层、6 头、隐藏层维度 384、上下文窗口 256 的 GPT-2 架构):

  1. 输入端:只接收形状为 (B, T) 的一维整数序列。
  2. 输出端:只负责预测下一个整数编号的概率分布 (B, T, vocab_size)。

对 Transformer 而言,整数 39 代表英文字母、汉字“我”,还是钢琴上的中央 C(C4),在数学上没有任何区别。它既不懂语法,也不懂乐理。只要任意模态的信息能被编码成一维离散整数流(Token Sequence),同一套自回归矩阵乘法就能从中暴力拟合出长程共现概率。


#2. 怎么把钢琴曲变成 Token 序列?

文本天然是一维线性的,而钢琴曲是复调的:左手和弦与右手旋律可能同时按下,每个音符还有不同的持续时长与按键力度。

为了直接喂给同一个 GPT-2 模型,我们把 MIDI 音乐拆解为 308 个离散事件(vocab_size = 308),将整首钢琴曲拍平为一维整数流:

  • 0 .. 87(按下琴键 NOTE_ON,88 个 Token):对应钢琴 88 个键(MIDI 音高 21 到 108)。
  • 88 .. 175(松开琴键 NOTE_OFF,88 个 Token):释放对应的琴键。只要连续输出多个 NOTE_ON 而不推进时间,解码出来就是同时弹响的和弦。
  • 176 .. 275(时间推进 TIME_SHIFT,100 个 Token):将时间轴向前推进 1 到 100 步(每步 10 毫秒,单次最多推进 1 秒)。
  • 276 .. 307(按键力度 VELOCITY,32 个 Token):将 0 到 127 的力度量化为 32 个档位,记录触键的轻重。

经过这层编码转换后,一段优美的钢琴独奏在模型眼里就变成了一串纯粹的整数序列:[298, 20, 275, 51, 44, 39, ...](设定力度 $\to$ 按下低音根音 $\to$ 延时 1 秒 $\to$ 连续按下三和弦)。


#3. 实验对比:免费 T4 GPU 训练 10 分钟,两种反差曲风

为了直观检验这套“纯概率计算”能学到什么程度,我们挑选了两种风格极度反差的钢琴曲集,在完全相同的 SimpleLLM 架构(约 1,080 万参数)上各自训练 1,000 步(耗时约 8 到 10 分钟),并在推理时给定完全相同的起始音符(单个中央 C,编号 39),让模型连续自回归生成 1,000 个事件 Token:

#0. 对照基线:未经训练的随机权重

在参数处于随机初始化状态时,模型对 NOTE_ON、NOTE_OFF 和时间步长的配对毫无概念,在 88 个琴键上胡乱跨越八度砸键,听起来就像一只猫在琴键上乱踩:

#1. Slow 风格:萨蒂(Erik Satie)忧郁慢板

训练集为 6 首萨蒂慢板作品(如 Gymnopédies、Gnossiennes,共 8,211 个 Token)。训练 1,000 步后(loss 降至 0.0337),模型算出了大步长 TIME_SHIFT 的高频分布,自动拉开了呼吸感与留白,左手低音单音与右手三和弦缓慢交替:

#2. Bright 风格:乔普林(Scott Joplin)欢快拉格泰姆

训练集为 6 首乔普林 Ragtime 作品(如 The Entertainer、Maple Leaf Rag,共 41,524 个 Token)。同样训练 1,000 步后(loss 降至 0.0537),生成的序列中密集穿插着 10 到 20 毫秒的短促时间步与高频音符切换,直接复刻出了欢快跳跃的切分律动:


#4. 小结:哪有什么“懂音乐”,全是统计规律

对比上面三段音频,结论非常直白:

  1. 没有语义,只有分布:从头到尾,模型里没有任何一行关于“五线谱”、“和声学”或“节拍器”的规则。所谓的“慢板忧郁感”与“欢快切分感”,在底层不过是 176..275 号时间 Token 与 0..175 号音高 Token 的条件概率分布差异。
  2. Attention 的本质:当生成下一个音符时,QKV 自注意力机制只是在前 256 个历史整数里做向量内积检索,比如发现前文出现了按下中央 C 的 NOTE_ON(Token 39)且尚未出现对应的松键 NOTE_OFF(Token 127),于是拉高后续输出 TIME_SHIFT 和 NOTE_OFF(Token 127)的概率 logits。
  3. 小数据下的记忆拼接:由于训练集只有几万个 Token,而模型拥有上千万参数(训练 Loss 被压到了 0.03 ~ 0.05),模型实际上背下了大量原曲的局部动机片段并进行重组。要从“死记硬背局部套路”走向真正的长程泛化,就必须扩大数据规模与模型容量,而这正是接下来我们要拆解的现代大模型架构演进。