Daily Tech Briefing
AI 科技速览

每天 5 分钟内学习 AI。获取最新的人工智能新闻,理解其重要性,并学习如何将其应用于您的工作。

AI 快讯
AI前线 · 2026/7/30 17:12:29
从GPT-2到Kimi K3:七年规模扩大2.26万倍,大模型架构主线是在建立一套“记忆操作系统”

从GPT-2到Kimi K3:七年规模扩大2.26万倍,大模型架构主线是在建立一套“记忆操作系统”

AI 中文解读
从GPT-2到Kimi K3,七年时间模型规模膨胀了2.26万倍,但真正值得关注的不是数字,而是AI的“大脑”正在从什么都记的“硬盘”进化成会主动管理信息的“操作系统”。早期模型像是一个只会把所有信息堆在一起的仓库,每次生成内容都要翻遍整个仓库,效率极低;而Kimi K3学会了像人类一样区分哪些信息需要记住、哪些可以遗忘、哪些必须及时更新。这种“选择性记忆”让AI既能处理海量数据,又不会因为信息过载而卡顿。对普通人来说,这意味着未来用AI写文章、做翻译、回答复杂问题时,速度和准确度将大幅提升,再也不用忍受AI“答非所问”或“重复啰嗦”的尴尬。更重要的是,这种架构突破让AI能真正理解长期对话的上下文,比如陪你聊天一整年还能记得你上个月提过的爱好,或者帮你整理三年前的项目文档。技术门槛的降低也会让更多智能助手、教育工具、办公软件变得更好用,AI将不再是“人工智障”,而是真正可信赖的“大脑外挂”。
摘要:从 GPT-2 到 Kimi K3,大模型技术演进路线展示了 AI 架构如何从“记住一切”,走向“选择性记忆”。KV Cache 解决生成效率问题,Linear Attention 探索更高效的长期记忆,DeltaNet 和 Kimi Linear 则进一步让模型学会更新、遗忘和管理信息。这篇文章将沿着七年的架构演进,解析大模型规模增长背后的技术变化,以及 Kimi K3 如何通过新的记忆机制突破传统 Transformer 的限制。22580 个,这是 Kimi K3(2026)模型相当于多少个 GPT-2(2019)模型。七年间,我们将模型规模扩大了 22,580 倍。但这仅仅是……规模扩大吗?在这篇工作日志中,我将回顾我们是如何走到今天这一步的,以及自那时以来,究竟发生了多少变化(或者说,变化有多小)。我们将追溯促成 Kimi K3 诞生的主要架构发展历程。GPT-2GPT-2 采用仅解码器(decoder-only)架构:tok_emb = self.transformer.wte(idx) # 形状为 (b, t, n_embd) 的词元嵌入pos_emb = self.transformer.wpe(pos) # 形状为 (t, n_embd) 的位置嵌入x = self.transformer.drop(tok_emb + pos_emb)for block in self.transformer.h:x = block(x)x = self.transformer.ln_f(x)logits = self.lm_head(x)return logits复制代码输入会获得词元嵌入和位置嵌入:GPT-2 输入嵌入(Token Embedding + Position Embedding)结构图放大来看,每个 Transformer 块的结构如下:class Block(nn.Module): def __init__(self, config): super().__init__() self.ln_1 = LayerNorm(config.n_embd, bias=config.bias) self.attn = CausalSelfAttention(config) self.ln_2 = LayerNorm(config.n_embd, bias=config.bias) self.mlp = MLP(config) def forward(self, x): x = x + self.attn(self.ln_1(x)) x = x + self.mlp(self.ln_2(x)) return x复制代码GPT-2 Block 结构示意图(包含 Attention 与 MLP 的残差连接)注意力计算过程如下:B, T, C = x.size() # 批次大小、序列长度、嵌入维度(n_embd)# 为批次中的所有注意力头计算 query、key 和 value,并将注意力头维度移到前面q, k, v = self.c_attn(x).split(self.n_embd, dim=2)k = k.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)q = q.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)v = v.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)# 手动实现注意力计算att = (q @ k.transpose(-2, -1)) * (1.0 / math.sqrt(k.size(-1)))att = att.masked_fill(self.bias[:, :, :T, :T] == 0, float('-inf'))att = F.softmax(att, dim=-1)att = self.attn_dropout(att)y = att @ v # (B, nh, T, T) x (B, nh, T, hs) -> (B, nh, T, hs)y = y.transpose(1, 2).contiguous().view(B, T, C) # 将所有注意力头的输出重新拼接起来# 输出投影y = self.resid_dropout(self.c_proj(y))return y复制代码最终的隐藏状态矩阵生成后,语言模型头(LM Head)会将其映射为词表上的 logits。在自回归解码过程中,只需要最后一个位置的 logits 来选择下一个词元。这是仅解码器生成方式中的一个低效点:模型会计算每个输入位置的表示,但每个解码步骤只使用最后一个位置的 logits。如果没有缓存,其中许多计算都会在生成下一个词元时重复进行。自回归解码过程及最后一个位置 logits 的提取示意图KV 缓存(KV Cache)源于一个直观的观察:将新生成的词元追加到输入后,模型原本需要重新计算此前所有词元的投影。存储这些词元的键(Key)和值(Value)向量,可以避免这种重复计算。这个存储空间就是 KV 缓存。它保存了此前 N−1 个词元的向量,并且可能变得非常庞大,甚至造成内存带宽瓶颈。总体而言,在词表包含约 5 万个词元、网络包含 12 个 Block 和 12 个注意力头、嵌入维度为 768 的情况下,我们的基准模型大约拥有 1.24 亿个参数。vocab_size: int = 50304 # GPT-2 的词表大小为 50257,为提升效率而填充至最接近的 64 的倍数n_layer: int = 12n_head: int = 12n_embd: int = 768复制代码Kimi K3 拥有 2.8 万亿(2.8T)个参数。就参数量而言,一个 Kimi K3 模型大约相当于 22,580 个 GPT-2 模型。线性注意力(Linear Attention)Softmax 注意力机制会在 q·k 点积之后应用非线性变换,使每个 Query 与每个 Key 相互关联。而线性注意力则分别对 q 和 k 应用特征映射(例如 ELU + 1)。这使得矩阵乘法具备重新结合的特性,从而可以将不断增长的 K 和 V 向量集合压缩为一个固定大小的 D×D 状态矩阵。论文中关于 O(N²) 的描述曾让我感到困惑:“Transformer 每个时间步的计算成本与当前序列长度的平方成正比。”这种说法并不完全准确。这其实是 Flash Attention 所解决的问题……后来我发现,Flash Attention 是在 2020 年发布的。在当时,训练过程中通常会显式构造完整的 N×N 注意力矩阵。Flash Attention 尚未出现,而参考实现中的自回归生成通常会在没有 KV 缓存的情况下重新计算历史 Token。def forward(self, x, mask=None, past_kv=None): # x 形状为 b,t,d b,t,d=x.shape d_head=d//self.num_heads h=self.num_heads qkv=self.qkv_proj(x) q=qkv[:, :, :d].view(b,t,h,d_head).transpose(1,2) k=qkv[:, :, d:2*d].view(b,t,h,d_head).transpose(1,2) v=qkv[:, :, 2*d:].view(b,t,h,d_head).transpose(1,2) # 在 prefill 阶段,q,k,v 的形状为 b,h,t,d # 在 decode 阶段,形状为 b,h,1,d # 因此需要在时间维度(dim=2)上进行拼接 if past_kv is not None: k_past=past_kv[0] v_past=past_kv[1] k=torch.cat((k_past,k),dim=2) v=torch.cat((v_past,v),dim=2) scores=(q@k.transpose(-1,-2))/math.sqrt(d_head) if past_kv is None: # 当前处于 prefill 阶段,需要进行掩码 causal_mask=torch.ones(t,t,dtype=bool, device=q.device) causal_mask=torch.triu(causal_mask, diagonal=1) scores=scores.masked_fill(causal_mask, float('-inf')) if mask is not None: scores=scores.masked_fill(~mask, float('-inf')) attn=scores.softmax(-1) o=attn@v o=o.trans
分享
阅读原文