Sutskever 30 #14:不挑了,每一对都算一遍

#13 Memory Networks 里 attention 干的是挑:拿问题去跟每条事实比一比,挑出该读的那条,多跳就是顺着挑好几次。从 #09 Bahdanau 起,这一整条线都在把「挑」做得更软、更可微。 Santoro 那帮人 2017 年的 A simple neural network module for relational reasoning(模型常被叫 Relation Network,下面简称 RN)问了句反过来的话:能不能不挑?它的答案是不挑。把每一对对象 (o_i, o_j) 都丢进同一个小网络 g,全部加起来,再用 f 从这个和里读出答案: $$RN(O) = f_\phi\Big(\sum_{i,j} g_\theta(o_i, o_j, q)\Big)$$没有 attention 权重,没有路由,没有谁比谁重要。所有对一视同仁,各算一遍,求和。听着挺笨,但这一笨恰好是后来 self-attention 的骨架——self-attention 不过是把这个等权的和换成了 softmax 加权的和。 为什么求和就够 三件事撑着这个模块。一个 relation 本来就是「两个对象的函数」,同一个 g 用在每一对上,参数省,还逼着模型把关系当成通用的东西,而不是给每对配一套。一堆对象本来没有先后,先求和再读出,意味着打乱顺序结果一个字都不变——置换不变是白送的。问题 q 拼进每一对里,g 看到的是 (o_i, o_j, q),于是「关心哪种关系」由问题说了算。 读出那一步就是过个 f 再 softmax, $$\hat a = \mathrm{softmax}\big(f_\phi(r)\big), \qquad r = \sum_{i,j} g_\theta(o_i, o_j, q)$$跟 #12 NTM 那套 location addressing、erase/add 比,这里干净得不像话:两个 MLP,一次求和。论文标题里的 simple 不是谦虚。 ...

June 5, 2026

Sutskever 30 #13:只读,但读好几遍

从 #12 的"写"接过来 #12 Neural Turing Machine 让 attention 既能读也能写一块外部 memory。代价是那套寻址机器很重:内容寻址之外还要 interpolation、convolutional shift、sharpening 一条流水线,写的时候又要 erase 再 add。东西能跑,但训练很 brittle,换个任务就得重调。 Sukhbaatar、Szlam、Weston、Fergus 2015 End-To-End Memory Networks(这一篇下面简称 MemN2N)问了个反方向的问题:这些机器是不是大部分都可以不要? 它的答案是:把写砍掉,把 location addressing 砍掉,只留 NTM 里最朴素的那一半——content-based 的读。memory 不再是一块要反复擦改的矩阵,就是输入本身,写一次,之后只读。 只读会不会太弱?MemN2N 的补法是:读好几遍。一遍不够就拿这一遍的结果当新问题再读一遍。下面把这事拆开看。 记忆就是输入本身 NTM 要专门维护一块 N×M 的矩阵,每步擦改。MemN2N 干脆不写:一段话里的每个事实,就是 memory 里的一行。 把每个事实 x_i(一句话的 bag-of-words)用一个嵌入矩阵投成向量 m_i = A x_i,问题 q 投成 u = B q。读一遍就是一次 content addressing——跟 #11 Luong 的点积、#12 的内容寻址是同一个动作: $$p_i = \mathrm{softmax}(u^\top m_i), \qquad o = \sum_i p_i\, c_i$$p 是 attention 权重,o 是读出来的内容。注意读出用的是另一套嵌入 c_i = C x_i——一套嵌入管"拿什么去匹配",一套管"匹配上了读回什么"。后来 Transformer 里 key 和 value 分开,是同一个分工。 ...

June 4, 2026

Sutskever 30 #12:让 attention 能写

从 #10 留下的问题接过来 #10 Pointer Networks 让 attention 第一次直接当输出——softmax 不再对着固定词表挑词,而是对着输入位置挑一个。decoder 每一步指向输入里的某个地方。 不过那还是 read-only 的指针。模型只能指过去读,不能在那个位置上留下新内容。 Graves、Wayne、Danihelka 2014 Neural Turing Machines 把指针往前推了一步:attention 不只能读,还能写。模型旁边放一块外部 memory,就是一张可读可写的矩阵。每一步 controller 算出两类指针:一组用来读,一组用来擦+加。 这就是 NTM 的主问题:如果 attention 已经能指向输入里的位置,下一步自然就是:它能不能指向一块可读可写的记忆? 一块 N×M 的矩阵 把 memory 想成一个矩阵 M,N 行(slot 数),每行 M 维(slot 大小)。这就是 NTM 的"外部 memory"。 读操作很直接。给一个 attention 权重 w(一个长度为 N 的概率分布),读出来的就是按 w 对所有行的加权求和: $$r_t = \sum_i w_t(i) \cdot M_t(i)$$跟 Bahdanau attention 算 context vector 是一样的——只是这里的"key/value"不是 encoder 的 annotations,而是 memory 矩阵本身。 写操作多一步:先按 w 擦掉旧内容,再按 w 加上新内容。controller 输出两个 M 维向量:一个 erase vector e,一个 add vector a: ...

April 27, 2026

Sutskever 30 #11:让 attention 算得快一点

从 #10 留下的尾巴说起 #10 Pointer Networks 结尾留了一句:2015 年 attention 沿两条线继续长——一条是 Pointer Networks,让 attention 直接当输出;另一条是 Luong,让 attention 算得更便宜。 这一篇走第二条。 Bahdanau 2014 把 attention 接进了 NMT,效果好。但 attention 这一步本身是有成本的。每生成一个目标词,decoder 都要对 encoder 的所有位置打一遍分。源句 50 个词,decoder 生成 50 个词,光是算 score 就要 2500 次。 每一次 score 怎么算,决定了这件事到底贵不贵。 Bahdanau 的算分方式 Bahdanau 用的是加性形式: $$e_{ij} = v^\top \tanh(W s_{i-1} + U h_j)$$s 是 decoder 的上一步状态,h 是 encoder 第 j 个位置的 annotation。 这里面有三组参数:W(把 s 投到打分空间)、U(把 h 投到打分空间)、v(把打分空间压成一个标量)。算一次 score 要做两次矩阵乘、一个 tanh、一个内积。 ...

April 25, 2026

Sutskever 30 #10:答案就在输入里

从上一篇留下的问题说起 #09 Bahdanau attention 里 attention 是 decoder 的一件工具:每生成一个词,先对 encoder 的所有位置打分,按权重加权求和,得到一个 context 向量喂给 decoder。最终输出还是走 softmax,对着一张固定词表挑一个词。 翻译任务这么做没问题。词表就那几万个词,目标语言里可能出现的词都在表里。 一旦任务变了,问题就出来了。 有些任务的答案不在固定词表里 给 7 个二维点,让模型按凸包顺序把其中几个点排出来——输出不是词,是"第 2 号点、第 5 号点、第 6 号点…“这种索引。 所谓凸包顺序,就是沿着最外圈走一圈时,外圈那些点出现的次序。内部的点不参与。 每一步的输出都是"看这 7 个输入点中的哪一个”。固定词表在这里就不够用了。 做法 1:把点的坐标离散化成 tokens,放进词表。坐标是连续的,词表会很大,而且每换一批点就得重训。 做法 2:让词表大小等于输入长度,每次动态调整。7 个点词表就是 7;10 个点词表就是 10。这已经碰到 Pointer Networks 的方向了,但标准 seq2seq 里 decoder 输出层的维度是固定的,换个输入长度还得改网络结构。 真正的问题是这一句:有些任务的答案不在固定词表里,答案就在输入本身。 这类任务不少:凸包(输出是输入点的子集,按某种顺序);排序(输出是输入的重排);TSP(输出是城市的访问顺序)。共同点是输出的每一步都是在说"回去看输入里的哪一个位置"。 机制:让 softmax 指回输入 Pointer Networks 做了一件很朴素的事。 Bahdanau attention 里,每一步算出的 attention 分布只是中间产物——过 softmax 得到权重,再乘 annotations 加权求和,得到 context 向量。分布本身被丢掉了。 Pointer Networks 让 softmax 后的 attention 分布直接当输出分布用:原来 softmax 对着固定词表挑词;现在 softmax 对着输入位置挑一个。 ...

April 24, 2026

Sutskever 30 #09:不再只靠最后一个向量

同一年,两组人 2014 年 9 月,两篇论文几乎同时挂上 arXiv。 一篇是 Sutskever、Vinyals、Le 的 Sequence to Sequence Learning with Neural Networks。Google Brain 出品,用两个 LSTM——一个读输入、一个生成输出——直接刷新了英法翻译的纪录。这是 #04 讲过的故事。 另一篇是 Bahdanau、Cho、Bengio 的 Neural Machine Translation by Jointly Learning to Align and Translate。蒙特利尔大学加雅各布大学,用 GRU + 双向 encoder,每生成一个目标词都回头看一遍源句。 两组人没合作,也没引用对方的当年版本,但他们面对的是同一个问题:任意长度的输入最后都要变成一个固定长度的向量,句子一长,信息就会丢。 两篇论文的处理办法不一样。Sutskever 还在固定向量里想办法,倒着读输入,让最先要翻译的信息离 decoder 更近。Bahdanau 把 encoder 的每一步都留下来,decoder 每一步根据当前状态选择要参考哪些 encoder state。 卡在哪里 #04 里有一张图:序列越长,第一个词的信息能存活到最后一个 hidden state 的比例越低。50 个词的句子,开头那个词存活率不到 2%。 LSTM 已经缓解了长距离记忆问题。这里卡住的是另一件事:decoder 只拿到 encoder 最后一步的状态。这个状态是一个固定大小的向量,不管输入是 5 个词还是 50 个词,维度都不变。容量有上限,信息没上限。 Sutskever 论文里有一个做法暴露了这件事:把输入序列倒过来读,BLEU 涨好几个点。“Je suis étudiant” 改成 “étudiant suis Je” 喂进去。倒读没有改变模型容量,只是让 encoder 最后一步离 decoder 最先要生成的词更近。这种局部修补能挤出几个点,但也说明结构本身还没换过。 ...

April 23, 2026

Sutskever 30 #04:记住了,然后呢?

上一篇留下的问题 上一篇里,LSTM 解决了 vanilla RNN 记不远的问题——加法通道让梯度不再衰减,记忆可以跨越几十步传下去。 但我们一直在做同一件事:给定一个序列,预测下一个 token。输入和输出共享同一个时间线——第 1 步输入产生第 1 步输出,第 2 步输入产生第 2 步输出。 现实世界的很多任务不是这样的。翻译:一句中文进去,一句英文出来,长度不同,语序不同。摘要:一段话进去,一句话出来。对话:一个问题进去,一个回答出来。 输入是一个序列,输出是另一个序列。长度可以不同,结构可以不同。怎么办? 两个 LSTM,一根管子 2014 年,Sutskever、Vinyals 和 Le 提出了一个极简的方案:用两个 LSTM,中间接一根管子。 Encoder:一个 LSTM,把输入序列从头读到尾。读完之后,最后一步的 hidden state 就是整个输入的"总结"——一个固定长度的向量。 Decoder:另一个 LSTM,拿到这个向量作为初始状态,一个 token 一个 token 地生成输出。 就这么简单。输入和输出可以不同长度,因为 encoder 把任意长度的输入压缩成一个固定长度的向量,decoder 从这个向量展开成任意长度的输出。 代码的核心就几行(这里用简化的 RNN 展示结构,实际论文用的是 LSTM——gate 的细节上一篇讲过了): # Encoder:读完整个输入,拿到最后的 hidden state h = np.zeros((hidden_size, 1)) for x in input_sequence: concat = np.vstack([x, h]) h = np.tanh(np.dot(W_enc, concat) + b_enc) context = h # 这就是"总结"——整个输入压缩成一个向量 # Decoder:从 context 开始,逐步生成输出 h = context for t in range(max_output_length): concat = np.vstack([prev_output, h]) h = np.tanh(np.dot(W_dec, concat) + b_dec) output = np.dot(W_out, h) + b_out prev_output = output 这个架构有个名字——encoder-decoder,也叫 seq2seq(sequence to sequence)。它是 Sutskever 自己的工作,发表时直接打破了法语-英语翻译的最佳纪录。 ...

April 17, 2026