- 人工智能
- 深度学习
- NLP
- 计算机视觉
- 强化学习
【免费下载链接】google-research
Google Research
本指南以google-research仓库中 incontext/README.md 所指向的预印本研究《What Learning Algorithm is In-context Learning? Investigations with Linear Models》为骨架,系统拆解 incontext/ 代码库的全部实现:数据生成、Transformer 训练、对比算法、探针模型与可视化工具。读者读完本文后,将掌握这套实验框架的完整调用链、全部命令行参数含义,并能复现"上下文内学习(In-context Learning,ICL)究竟等价于哪种经典学习算法"这一核心实验。
一、研究背景与代码库定位
大语言模型能够在提示中通过少量示例(few-shot exemplars)完成新任务而不更新权重,这一现象被称为 In-context Learning。一个核心科学问题是:Transformer 在上下文内执行的"隐式学习算法"到底是什么?
incontext/README.md 明确指出,本仓库对应预印本论文:
What Learning Algorithm is In-context Learning? Investigations with Linear ModelsEkin Akyürek, Jacob Andreas, Dale Schuurmans, Tengyu Ma, Denny Zhou
该研究采用"用线性模型做实验"的策略:把 ICL 问题简化为线性回归的上下文内学习——即给定若干(x, y)示例后,让 Transformer 预测新输入x对应的y。由于线性回归存在解析解(最小二乘、岭回归等),研究者可以把 Transformer 在上下文内隐式学习的"行为权重"(behavioral weight)与经典算法逐一对照,从而判定其内部实现的算法类型。
代码库本身是一个可运行的实验框架,由以下模块构成(目录结构见 incontext/):
| 文件 | 职责 |
|---|---|
| incontext/incontext/sampler_lib.py | 线性回归数据的随机采样与分布字符串解析 |
| incontext/incontext/transformer_lib_flax.py | Flax Transformer 主干与学习率调度器 |
| incontext/incontext/predictor_flax.py | 因果语言模型(CausalLM)预测头与损失计算 |
| incontext/incontext/model_trainer.py | 主模型训练、评估与可视化入口 |
| incontext/incontext/main.py | 实验入口:参数解析、训练调度、探针可选训练 |
| incontext/incontext/algos.py | 经典回归算法集合与在线回归评测 |
| incontext/incontext/probe_flax.py / probe_trainer.py | 从隐状态解码权重的探针模型 |
| incontext/incontext/plotting.py | 经验分布、隐式权重路径等可视化 |
| incontext/incontext/linear_model.py / train_linear_lib.py | 单层线性模型的 SGD/GD 基准训练 |
| incontext/incontext/utils.py | 随机种子、Flag 转配置等公共工具 |
| incontext/run.sh / requirements.txt / setup.py | 环境搭建与打包 |
依赖以 JAX 生态为主:requirements.txt 声明了flax、jax、matplotlib、tensorflow(用于gfile文件读写)、numpy、absl-py、optax;此外 algos.py 还直接使用了sklearn的linear_model、neighbors、metrics模块。
二、数据生成:Sampler 与分布字符串语法
2.1 分布字符串的解析规则
训练与评估的数据分布完全由字符串控制,解析逻辑在 sampler_lib.py 的str_to_distribution_fn中:
- 单分布格式为
类型*alpha+beta:类型仅支持uniform(np.random.rand)与normal(np.random.randn),采样结果乘以alpha并加上beta。例如默认值"normal*1.0+0.0"即标准正态分布,"normal*2.5+0"表示标准差放大到 2.5,"normal*1+2.5"表示均值偏移到 2.5。 - 混合分布用逗号连接多个单分布,例如
"normal*1+0,uniform*1+0"。此时每个子分布各采样一份 batch,再按 batch 维度随机挑选合并,等效于均匀混合采样。 - 未知类型会抛出
ValueError("Unknown distribution type.")。
2.2 Sampler 的序列构造
Sampler类(sampler_lib.py)负责生成一条完整的上下文序列,核心参数包括:
length:示例(exemplar)个数;dim:x向量的维度;hidden_size:序列向量的维度(填充后的宽度);x_distribution_fn/w_distribution_fn:x与回归系数w的采样函数;noise_std:大于 0 时给y添加高斯噪声,默认 0.0。
sample()方法(sampler_lib.py)的核心逻辑是:为每个示例依次采样x与系数w,通过np.einsum("bi,bi->b", coefficients, x)计算y,然后将x_vec([0, x]前置零位)与y_vec([y, 0...0]后置dim个零填充)交替拼接成一条长度为length * 2的序列,返回(out, coefficients, xs, ys)四元组。这种"x 与 y 交替、零填充对齐维度"的编码方式,与后续CausalLM中按偶数位抽取y的损失设计一一对应(详见第三节)。
2.3 对训练与评估的影响
noise_std直接控制任务难度:在 model_trainer.py 中,主训练用的Sampler以x_distribution_str、w_distribution_str、noise_std构造;而在评估阶段 model_trainer.py 会额外以eval_noise_std = x_dim / 20生成带噪声的测试分布,用于考察模型对标签噪声的鲁棒性。此外 test_empirical_statistics 中采样num_exemplars - 1个示例并注释说明"否则用于最后一个示例的位置编码将是未训练参数"——这是序列长度与位置编码最大长度(max_len=(num_exemplars+1)*2)之间必须留出余量的直接证据。
三、Transformer 实现:CausalLM 与自注意力补丁
3.1 CausalLM:按偶数位取 y 的自回归损失
incontext/incontext/predictor_flax.py 定义了CausalLM模块。前向流程为:
- 取
seq_from = inputs[:, :-1, :](预测下一位置); - 用
nn.attention.make_causal_mask构造因果掩码; - 送入 transformer_lib_flax.py 的
Transformer,可返回各层注意力权重; - 经
nn.Dense投影(默认输出维度 1,即只预测 y;开启loss_on_x_steps时预测完整向量); extract_y(predictor_flax.py)按jnp.arange(offset, seq.shape[1], 2)取出偶数位置,即只保留 y 步的预测;- 损失为预测 y 与目标 y 的平方误差和(
(y_pred - y_target)**2).sum(axis=-1)),可选的return_attention=True会把各层注意力权重一并返回,供可视化使用。
loss_on_x_steps标志定义在 predictor_flax.py,默认False,表示只对 y 步计算损失。
3.2 Transformer 主干与可配置项
transformer_lib_flax.py 的TransformerConfig定义了全部结构超参数,而对应的命令行 Flag 定义在文件开头(L45-L73):
| Flag | 默认值 | 含义 |
|---|---|---|
n_layers | 12 | 编码器层数 |
n_heads | 8 | 注意力头数(要求hidden_size % n_heads == 0) |
hidden_size | 512 | 模型宽度 |
norm_first | True | Pre-LN:先 LayerNorm 再注意力/MLP |
final_layer_norm | False | 是否在输出前追加最后一层 LayerNorm |
disable_layer_norms | False | 完全禁用 LayerNorm(消融用) |
inner_dim | None | MLP 中间维度,None 时取hidden_size * 4 |
kernel_init/bias_init | uniform_scaling | 注意力/MLP 参数初始化器 |
linear_w_init/linear_bias_init | uniform_scaling | 投影层初始化器 |
posemb_init | uniform_scaling | 位置嵌入初始化器 |
activation_fn | gelu | 激活函数(可选 gelu/relu/tanh/softplus/sofu) |
Transformer的组成(L355-L408):先经nn.Dense投影到hidden_size,再加可学习位置嵌入(PositionEmbeddings,L189-L221,按max_len截取),然后堆叠num_layers个Encoder1DBlock(L267-L352),每个块为"自注意力 + 残差 + MLP + 残差"结构。初始化器支持字符串解析(nn_init_parser,L127-L140):uniform_scaling、ones、zeros、normal(std)。
3.3 自注意力补丁:返回注意力权重
incontext/flax/self_attention_patch.py 是从flax.linen.attention复制并改造的版本:在 dot_product_attention 与MultiHeadDotProductAttention中增加了return_attention分支,使注意力权重可以被返回并序列化。Encoder1DBlock调用的是补丁版SelfAttention(transformer_lib_flax.py),其qkv_features=hidden_size // num_heads。这一改动直接服务于 model_trainer.py 中导出attention_stats.pkl的分析需求——研究者借此观察注意力在示例之间如何分配权重。
四、训练管线与命令行参数全解
4.1 实验入口 main.py
incontext/incontext/main.py 是标准实验入口,流程为:解析 flags →utils.flags_to_args()生成ConfigDict→ 创建实验目录并写config.json→utils.set_seed→ 初始化模型 → 训练主模型 → 保存metrics.pickle与 checkpoint → 可选训练探针。其自有 Flag:
| Flag | 默认值 | 含义 |
|---|---|---|
seed | 0 | 随机种子(同时作用于 Python、numpy 与 JAX) |
batch_size | 64 | 每步采样的序列条数 |
x_dim | 20 | 输入维度(也是系数维度) |
num_exemplars | 40 | 每条序列的示例个数 |
exp_folder | exp | 实验输出目录 |
debug | False | 调试预测与后验分布 |
train_probe | False | 主模型训练完成后是否追加训练探针 |
主模型训练与评估 Flag 定义在 model_trainer.py:
| Flag | 默认值 | 含义 |
|---|---|---|
n_epochs | 5001 | 训练轮数 |
n_iter_per_epoch | 100 | 每轮迭代次数 |
learning_rate | 1e-4 | 基础学习率 |
weight_decay | 0 | AdamW 权重衰减 |
lr_scheduler_type | cosine | cosine / warmup / 常数 |
adam_b1 | 0.9 | Adam 一阶动量 |
adam_b2 | 0.98 | Adam 二阶动量 |
adam_eps | 1e-9 | Adam 数值稳定项 |
x_distribution_str | normal*1.0+0.0 | 训练时 x 的分布 |
w_distribution_str | normal*1.0+0.0 | 训练时 w 的分布 |
noise_std | 0.0 | 训练标签噪声标准差 |
4.2 训练步骤与多设备并行
train_step(model_trainer.py)实现单步更新:jax.value_and_grad求梯度,jax.lax.pmean(grads, "batch")做跨设备梯度平均,state.apply_gradients更新参数,损失经pmean汇总、y_errors经psum求和。模型通过jax.pmap并行化(L317-L320),数据用common_utils.shard分片到各设备,dropout 随机数按设备拆分(L418-L420)。
优化器为optax.adamw(L301-L307),学习率调度有三种选择,由lr_scheduler_type控制(L284-L299):
cosine:create_learning_rate_scheduler(transformer_lib_flax.py),warmup 步数为(n_epochs // 5) * n_iter_per_epoch,随后按半余弦周期衰减;warmup:create_learning_rate_scheduler_v2(L448-L516),因子串"constant * linear_warmup";- 其他:恒为
learning_rate的常数调度。
train主循环(model_trainer.py)每eval_every_n_epochs(默认 1000)触发一次eval_model,并把每轮指标堆叠保存;checkpoint 经flax.training.checkpoints.save_checkpoint写入exp_folder/ckpt/(L226-L248)。
4.3 跨分布评估
eval_model(model_trainer.py)在固定测试分布集合上分别扰动w 分布与x 分布进行评估。默认测试集为("normal*1+0", "normal*2.5+0", "normal*1+2.5");当训练分布本身是混合分布(x_distribution_str含逗号)时,还会追加"normal*1+-2.5"与"normal*1+5.0"(L431-L444)。每轮评估输出到exp_folder/plots/distribution/w_{str}/与x_{str}/子目录,其中*被替换为x以兼容文件系统;x 扰动下还会生成noise_{x_dim/20}/子目录对应带噪测试。
五、对比算法集合:ICL 的"候选学习算法"
5.1 统一接口与评分
incontext/incontext/algos.py 定义了RegressionAlgorithm抽象基类(L50-L120),统一接口为fit(x, y)、predict(x)、get_parameters()、iterate(x, y)、is_iterative()、reset(),并提供scores()计算 R2 与 MSE。实现包括:
- LeastSquareAlgorithm(L123-L148):
sklearn.linear_model.LinearRegression,即标准最小二乘; - FakeLeastSquareAlgorithm(L151-L180):直接使用先验精度矩阵计算
weight = (precision @ x.T @ y) / n的"伪最小二乘"(对应文中Lstsq-Constant-Sigma); - RidgeRegressionAlgorithm(L183-L214):
sklearn.linear_model.Ridge,alpha默认 0.01; - KNNAlgorithm(L217-L243):
sklearn.neighbors.KNeighborsRegressor,支持 uniform / distance 加权; - SGD(L246-L306):自实现随机梯度下降,
window=1表示在线(只看当前样本),window=-1表示全量梯度,梯度裁剪到[-20, 20],支持weight_decay。
5.2 在线回归评测
核心评测函数online_regression(algos.py)模拟"上下文内学习"过程:对每条序列,遍历第 1 到最后一个示例,迭代式算法(is_iterative())用当前样本iterate,非迭代算法用fit(x[:i])重拟合,随后预测下一个x_i并记录预测与参数。online_regression_with_batch(L332-L349)批量执行并返回逐示例的 MSE 曲线。
值得一提的细节:algos.py的if __name__ == "__main__"分支(L352-L503)是一个可直接运行的算法对比实验——在x_dim=10, hidden_size=128, num_exemplars=64下对 16 种算法变体(不同学习率、窗口、权重衰减、Ridge alpha、KNN 加权)在三种 w/x 分布下绘制 MSE 曲线,保存为algos_w_*.jpeg/algos_x_*.jpeg。这是"先有候选算法、再与 Transformer 行为对齐"方法论的直接体现。
六、探针模型:从隐状态解码真实权重
除了行为层面的对比,代码库还提供了权重层面的探针:直接训练一个线性解码器,从 Transformer 各层最后一个 token 的隐状态恢复回归系数。
incontext/incontext/probe_flax.py 的ProbeModel对每一层独立使用一个nn.Dense(config.x_dim),输入该层最后一个位置的 hidden state,输出与真实系数coefficients对比求平方误差,最终返回形状为 batch 的逐层误差堆叠。ProbeConfig(L42-L51)包含hidden_size、num_layers、x_dim、max_len等字段。
incontext/incontext/probe_trainer.py 负责探针训练:
- 用冻结的主模型(
state.params)前向得到seq_hiddens(L115-L117),转置为(layer, batch, len, hidden)后分片; - 训练循环与主模型一致,采用
optax.adamw与 cosine 调度(L189-L212); - 新增 Flag:
probe_learning_rate(默认 0.001)、probe_epochs(默认 20)、probe_iters(默认 100)、probe_lr_scheduler_type(默认 cosine)。
探针的意义在于:如果某层隐状态能被线性映射出精确的回归系数,就说明该层内部"编码"了最小二乘等算法对应的解,为"Transformer 隐式执行了某类学习算法"提供内部证据。
七、可视化与实证分析工具
incontext/incontext/plotting.py 提供三类核心可视化,全部由 model_trainer.py 的test_empirical_statistics触发,输出在exp_folder/plots/下:
行为权重的经验拟合:
plot_empirical_distribution(L75-L322)用模型对一组随机x的预测y_pred反拟合一个带截距的最小二乘模型(algo_fn(fit_intercept=True)),得到"行为权重"w_empirical与 R2;随后绘制:- 3D 经验平面(红色)与真实平面(蓝色)对比(
plot_planes_3d,L62-L72); - 逐示例的预测误差曲线(
_errors.jpeg)、与最小二乘/岭回归/SGD 等算法的误差对比(plot_an_algorithm调用online_regression_with_batch); - 各算法与 Transformer 预测的发散度曲线(
_divergence.jpeg); - 可选的预测序列保存(
_predictions.pkl)。
- 3D 经验平面(红色)与真实平面(蓝色)对比(
隐式权重路径:
plot_implicit_w(L325-L382)在每个示例前缀长度上重复"预测→反拟合"过程,绘制w_empirical在权重空间中的轨迹(_w.jpeg)、各前缀 R2(_r2.jpeg),以及与真实最小二乘权重差异||Wlsq2-Wimp||^2随示例数变化的曲线(_wdiff.jpeg)——这是判定"ICL 是否收敛到最小二乘"最直观的证据图。基向量可视化:
plot_basis_image(L385-L428)逐个维度构造只有该维度非零的x,比较模型预测(红点)与真实y(蓝点)的散点图,检查模型是否在每个坐标方向上对齐。
此外,average_stats.jpeg、average_stats.pkl与attention_stats.pkl汇总了平均预测误差与各层注意力权重,供后续离线分析。
八、线性基准:单层模型的 SGD/GD 对照
为回答"ICL 等价于什么算法",incontext/incontext/linear_model.py 与 incontext/incontext/train_linear_lib.py 还提供了一个显式线性层 + SGD/GD的对照组:LinearModel(linear_model.py)只是一个无偏置的nn.Dense(1),LinearConfig.alpha控制 L2 正则强度。
train_linear_lib.py 的run_exp(L98-L163)在每条序列上运行optax.sgd,其中gd=True时用全量历史样本计算梯度(梯度下降),gd=False时只用当前样本(真正的 SGD),并逐示例记录下一示例的预测损失。main(L166-L202)默认在x_dim=10、num_exemplars=32、w 分布normal*1+5.0下采样并平均多条序列的损失,输出losses.png。该实验用于刻画"显式 SGD 在同样任务上的学习曲线",作为与 Transformer 隐式行为对照的基准。
九、环境搭建与运行指南
9.1 依赖安装
仓库提供两种方式:
- 一键脚本:run.sh 执行
virtualenv -p python3 .创建本地虚拟环境、source ./bin/activate激活、pip install -r requirements.txt安装依赖,随后运行python -m incontext.utils验证模块可导入。注意该脚本基于 Bash 与virtualenv,需要预先安装对应工具。 - 手动安装:直接
pip install -r requirements.txt,或执行pip install .(setup.py 以setuptools将包注册为incontext)。
值得提醒:requirements.txt未显式列出scikit-learn,但 algos.py 与 least_square.py 均直接import sklearn,因此运行对比算法实验前需自行补装scikit-learn。模型训练需要 JAX 可用的后端(CPU/GPU/TPU 均可,多设备时自动启用pmap并行)。
9.2 复现 Transformer 主实验
以 main.py 的默认参数(x_dim=20、num_exemplars=40、batch_size=64、n_epochs=5001、hidden_size=512、n_layers=12、n_heads=8)为例:
# 训练 + 评估(含绘图与 checkpoint) python -m incontext.main \ --seed=0 \ --x_dim=20 \ --num_exemplars=40 \ --batch_size=64 \ --n_epochs=5001 \ --exp_folder=exp # 附加探针训练 python -m incontext.main --train_probe=True --exp_folder=exp # 修改训练分布(如增大 w 方差) python -m incontext.main --w_distribution_str="normal*2.5+0" --exp_folder=exp_w2p5运行产物集中在exp_folder:config.json(参数快照)、metrics.pickle(逐步指标)、ckpt/(可恢复的 checkpoint)、plots/distribution/(全部可视化与统计数据)。
9.3 运行算法对比与线性基准
# 经典算法集合的 MSE 曲线(直接执行 algos.py 的 main 分支) python -m incontext.algos # 单层线性模型 SGD/GD 基准 python -m incontext.train_linear_lib --seed=0 --x_dim=10 --num_exemplars=32 --batch_size=32 # 最小二乘变体对比示例(least_square.py 的 main 分支,含伪最小二乘) python -m incontext.least_square十、总结:这套框架回答了什么问题
纵观全库,incontext/ 的贡献是一套**"算法归因"实验方法论**:在可控的线性回归 ICL 任务上,同时实现(a)数据分布参数化采样(第二节)、(b)可配置的因果 Transformer 训练与跨分布评估(第三、四节)、(c)一组候选经典算法与在线回归评测(第五节)、(d)权重层面的探针解码(第六节)、以及(e)行为权重路径与误差发散可视化(第七节)。通过对比 Transformer 的行为权重、隐式权重轨迹与最小二乘/SGD 等算法的对应关系,即可实证检验论文提出的核心主张——ICL 内部执行的隐式学习算法究竟与哪一类经典算法一致。
需要说明的是:本仓库提供的是实验代码与工具链,论文的完整实验结论与数据需以预印本正文为准;本文所有实现细节均来自 incontext/README.md 及上述源码文件,可直接对照查阅。
- 人工智能
- 深度学习
- NLP
- 计算机视觉
- 强化学习
【免费下载链接】google-research
Google Research
相关推荐
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考