- 人工智能
- 深度学习
- NLP
- 计算机视觉
- 强化学习
【免费下载链接】google-research
Google Research
本技术指南围绕 task_set/tasks/losg_problems/README.md 展开,系统讲解 google-research 仓库中losg_problems模块的来龙去脉:它源自经典论文《Learned Optimizers that Scale and Generalize》(LOSG)的问题集,经 TensorFlow 版本适配后成为 TaskSet 元学习优化器基准的核心组成部分。读完本文,你将掌握该问题集的完整目录结构、Problem基类与Spec数据结构的设计、六类玩具优化问题与随机数据集的生成原理、以及如何通过ModelAdapter把任意 TensorFlow 模型改造成可元训练的问题对象,并能在本地运行对应测试与训练脚本。
问题集的来源与定位
task_set/tasks/losg_problems/README.md 全文只有一句话说明:
These problems are a copy (and slight modification for tensorflow updates and formatting) to those found in: https://github.com/tensorflow/models/tree/master/research/learned_optimizer/problems
翻译过来即:本目录下的问题是 LOSG(Learned Optimizers that Scale and Generalize)问题集的副本,仅针对 TensorFlow 版本更新与代码格式做了轻微修改。这与 task_set/tasks/losg_tasks.py 头部注释相互印证——该文件明确指出其构建的任务"与 LOSG 论文所用任务相似,但包含了与原问题集不同的设置",并给出论文 arXiv 编号 1703.04813。
在 google-research 的 TaskSet 项目中(论文《Using a thousand optimization tasks to learn hyperparameter search strategies》,arXiv:2002.11887),这些 LOSG 问题被重新组织为两类用途:
- 优化器元训练(meta-training):作为随机采样任务族的组成部分,参与训练学习型优化器;
- 优化器评测(evaluation):固定参数的 2D 测试问题,用于验证优化器性能。
从代码引用关系可以清晰看到它的核心地位:task_set/tasks/losg_tasks.py 同时导入了losg_problems下的datasets、problem_generator、problem_spec三个模块,task_set/tasks/fixed/fixed_2d.py 也依赖该问题集构建固定评测任务。
目录结构与各文件职责
losg_problems目录共包含 7 个文件,职责划分非常清晰:
| 文件 | 职责 |
|---|---|
| README.md | 来源说明(LOSG 问题集副本) |
| problem_spec.py | 定义Spec数据结构,统一封装"问题类 + 参数" |
| problem_generator.py | 核心模块:Problem基类与全部玩具优化问题实现 |
| datasets.py | 监督学习数据集的生成与批量切分工具 |
| model_adapter.py | 把任意 TensorFlow 图适配为Problem接口 |
| problem_generator_test.py | 问题基类与稀疏梯度的单元测试 |
| datasets_test.py | 数据集生成与 batch 切分的单元测试 |
| model_adapter_test.py | ModelAdapter变量替换机制的单元测试 |
核心数据结构:Spec——问题定义的"延迟构造器"
problem_spec.py 是整个问题集复用的关键数据结构。它基于collections.namedtuple定义,字段为callable、args、kwargs,本质上是"函数/类 + 参数"的语法糖:
class Spec(collections.namedtuple("Spec", "callable args kwargs")): """Syntactic sugar for keeping track of a function/class + args.""" __slots__ = () def build(self): """Returns the output of the callable.""" return self.callable(*self.args, **self.kwargs)使用方式在 losg_tasks.py 中有大量实例,例如构造一个随机二次型问题:
problem_spec.Spec(pg.Quadratic, (cfg["dim"],), {"noise_stdev": cfg["noise_stdev"]})build()调用时才真正实例化问题对象。这种设计让问题定义可以脱离构建过程被序列化、随机采样和延迟构建,是 TaskSet 大规模随机生成任务族(sampler/getter 机制)的基础。
Problem 基类:统一的优化问题接口
problem_generator.py 定义了Problem基类,为所有优化问题提供统一接口。子类必须重写objective方法并声明参数形状param_shapes。
初始化与随机种子管理
def __init__(self, param_shapes, random_seed, noise_stdev, init_fn=None):关键逻辑(problem_generator.py):
random_seed必须是整数或None,否则抛出ValueError;- 若传入
None,则从MAX_SEED = 4294967295范围内随机抽取种子; - 设置
np.random.seed(self.random_seed)保证问题内部的随机数据可复现; noise_stdev记录梯度噪声强度,init_fn用于自定义变量初始化(默认为空操作)。
参数初始化
基类提供两套初始化入口(problem_generator.py):
init_tensors(seed):返回形状与param_shapes一一对应的tf.random_normal张量;init_variables(seed):在名为"parameters"的变量作用域下把这些张量包装成tf.Variable。
值得注意的是,SoftmaxClassifier与ConvNet会重写init_tensors以使用不同的初始化分布(见下文各问题类介绍)。
objective 与 gradients
objective(parameters, data=None, labels=None)是子类必须实现的抽象方法(基类直接raise NotImplementedError)。gradients则在 problem_generator.py 中统一实现:通过tf.gradients计算梯度后叠加noise_stdev强度的高斯噪声,并特殊处理了tf.IndexedSlices类型的稀疏梯度(对values加噪声、保留indices)。
数据集生成器:datasets.py
监督学习类问题需要数据,datasets.py 提供了统一的数据容器与五类随机生成器。
Dataset 容器
Dataset是(data, labels)二元命名元组(datasets.py):data为 float32 数组(形状(N, D_i)),labels为 int32/int64 数组。它提供:
size属性:样本数;batch_indices(num_batches, batch_size)方法:生成打乱后的 minibatch 索引列表,逻辑参考mnist.py——一个 epoch 结束后自动重新洗牌,覆盖整个数据集;若 data 与 labels 长度不一致则抛出ValueError(datasets.py)。
五类随机数据集
| 函数 | 生成方式 | 典型用途 |
|---|---|---|
noisy_parity_class | 标签为若干个上下文类别之和的奇偶类,noise_prob=0.25概率翻转标签 | 稀疏 softmax 回归的稀疏输入 |
random | 基于 sklearn 的make_classification,sep控制类别分离度 | 稠密分类问题 |
random_binary | 均匀随机 0/1 特征 | 二值输入分类 |
random_symmetric | 先采样一半高斯样本,再取相反数拼接 | 要求数据集大小能被 2 整除 |
random_mlp | 随机权重 MLP 的输出二值化 | 依赖链、外向蛇形等结构问题 |
random_mlp的实现细节在 datasets.py:输入x为标准高斯样本,逐层乘以按sqrt(2)/sqrt(n_features)缩放的高斯随机权重并做 ReLU 裁剪,默认 6 层、宽度 20,最终把输出的第一维按正负二值化为标签。noisy_parity_class则在 datasets.py 中实现:y = (sum(x) + noise) % n_classes,天然构造了稀疏到稀疏的学习任务。
玩具优化问题家族全景
problem_generator.py 共实现 20 余个问题类,可按性质分为五组。这些问题都提供surface(xlim, ylim, n)方法(2D 问题)以支持目标函数曲面可视化。
1. 二次型问题族
Quadratic(ndim):f(x) = 0.5 * ||Wx - y||^2,其中W为随机高斯矩阵、y为随机高斯向量(problem_generator.py);IsotropicQuadratic:各向同性二次型,目标为各参数平方和(problem_generator.py);SumOfQuadratics(ndim):sum((params - data)^2) - sum(data^2) + epsilon,通过减去原点损失使全局最小值为epsilon,需配合random_symmetric数据集使用(problem_generator.py);ProjectionQuadratic(ndim):sum((params * data)^2),数据集提供不同探测方向,全局最小值在原点(problem_generator.py);Bowl(condition_number, angle):二维二次碗,通过condition_number和旋转角构造 Hessian 矩阵,matrix = sqrt(Hessian).dot(rotation_matrix),目标0.5 * ||Ax||^2(problem_generator.py)。
2. 经典二维测试函数族
这些函数参考了 SFU 优化测试函数集合,全部继承自Problem2D(参数形状为(2,)):
| 问题类 | 数学特征 | 初始化范围 | 源码位置 |
|---|---|---|---|
Rosenbrock | 单一全局最小值[1, 1],目标值为 0 | [-5, 10) | problem_generator.py |
Saddle | 鞍点x^2 - y^2 | 默认 | problem_generator.py |
LogSumExp | 对数求和指数,含多个指数项 | 默认 | problem_generator.py |
Ackley | 大量局部最小值 | [-32.768, 32.768) | problem_generator.py |
Beale | 多峰、尖峰 | [-4.5, 4.5) | problem_generator.py |
Booth | 沿一个维度有长谷 | [-10, 10) | problem_generator.py |
StyblinskiTang | 凹凸起伏的二维函数 | [-5, 5) | problem_generator.py |
Matyas | 谷地中的单一全局最小值 | [-10, 10) | problem_generator.py |
Branin | 三个全局最小值 | x1 ∈ [-5,10), x2 ∈ [0,15) | problem_generator.py |
Michalewicz | 陡峭山脊与山谷,m=5控制陡峭度 | [0, π) | problem_generator.py |
其中Rosenbrock目标为(1-x)^2 + 100*(y-x^2)^2;Ackley结合指数衰减与余弦振荡,是典型的强多峰测试函数。Problem2D.surface方法(problem_generator.py)会新建临时 TensorFlow 图和会话,通过 placeholder 与feed_dict在网格上批量计算目标值,可直接用于绘制损失曲面。
3. 分类模型问题族(SoftmaxClassifier 体系)
SoftmaxClassifier是监督分类问题的公共父类(problem_generator.py),提供了统一的inference、objective、argmax、accuracy四件套:
- objective:softmax 交叉熵 + L2 正则,正则系数由
FLAGS.l2_reg_scale控制(默认1e-3,通过--l2_reg_scale命令行 flag 配置)。受限于 TensorFlow 历史 bug(b/31402852),当前仅支持 2 类问题,超过 2 类会抛出ValueError; - accuracy:通过
tf.contrib.metrics.accuracy计算分类正确率。
其子类包括:
| 问题类 | 网络结构 | 参数形状 |
|---|---|---|
SoftmaxRegression | 线性层Wx + b | (n_features, n_classes)+(n_classes,) |
SparseSoftmaxRegression | embedding 查找 + 求和 + 线性层 | (n_classes, n_features)+(n_features, n_classes)+(n_classes,) |
OneHotSparseSoftmaxRegression | 与上面相同但不用 embedding op,改用 one-hot 矩阵乘法 | 同上 |
FullyConnected | 多层感知机,默认hidden_sizes=(32, 64)、sigmoid 激活 | 每层一组(prev, sz)权重 +(sz,)偏置 |
ConvNet | N 层卷积 + 全连接输出层 | 每个卷积核(h, w, in, out)+ 仿射层权重/偏置 |
SoftmaxClassifier.init_tensors采用tf.random_normal(shape) * 1.2 / sqrt(shape[0])缩放初始化(problem_generator.py),而ConvNet则使用stddev=0.01的高斯初始化(problem_generator.py)。FullyConnected.inference将特征展平后逐层做activation(matmul + bias)前向传播(problem_generator.py)。
4. 结构化优化难题
LOSG 问题集特意包含一批考验优化器"长期规划能力"的结构化问题:
DependencyChain(ndim):参数必须按序收敛,每个参数在前一个参数归零前无法归零,目标为x0^2 + sum(xi^2 / (x_{i-1}^2 + EPSILON))(problem_generator.py);MinMaxWell(ndim):仅当参数绝对值的全局最小值和最大值都等于 1 时取全局最小,其余参数梯度为零,max_sqr + 1/min_sqr - 2 + epsilon(problem_generator.py);OutwardSnake(ndim):向无穷外盘旋的路径,理想步长沿全程恒定,依赖数据指定半径与正弦距离权重(problem_generator.py)。
5. 问题变换包装器
这些类不定义新目标函数,而是包装既有问题以改变其数值特性:
| 包装器 | 作用 | 关键参数 |
|---|---|---|
Rescale | 将问题参数整体放大/缩小scale倍 | scale(默认 10.0) |
SumTask | 把多个问题的目标函数相加,参数拼接 | problem_specs列表 |
Norm | 计算残差的 N-范数:(sum(|diff|+ε)^p)^(1/p) | norm_power |
LogObjective | 对目标取对数log(obj + ε) - log(ε) | 无 |
SparseProblem | 以概率zero_probability将梯度置零 | zero_probability(默认 0.99) |
其中SparseProblem.gradients的实现(problem_generator.py)用tf.where(mask, zero_grad, noisy_grad)按均匀随机数与zero_prob的比较结果掩码梯度,模拟深度神经网络中常见的零梯度现象。
ModelAdapter:把真实模型接入 Problem 接口
model_adapter.py 的ModelAdapter是连接"任意 TensorFlow 模型"与"元训练问题"的桥梁。它继承pg.Problem,构造时接收一个make_loss_and_init_fn回调(model_adapter.py),该回调返回两个函数:
make_loss:构建模型图并返回损失,图中必须包含模型全部变量但不含队列;make_init_fn:给定参数列表,返回一个接收tf.Session的初始化函数。
变量捕获机制
_get_variables(model_adapter.py)通过mock.patch.object(RefVariable, "__init__", custom_init)在构建图时拦截变量创建:所有变量被强制设为trainable=False并放入LOCAL_VARIABLES集合(避免进入优化器 checkpoint),同时按原始trainable属性区分"参数"与"常量"。该过程被包在名为unused_graph的 name scope 中,便于 TensorBoard 识别。
变量替换机制
objective的核心是_make_with_custom_variables(model_adapter.py):通过 mockRefVariable.value方法,把模型中每个变量名映射到外部传入的参数张量,实现"用优化器的当前参数值替换模型内部变量"的语义。这正是元学习优化器训练所必需的——损失必须能被外部参数控制。
model_adapter_test.py 给出了完整验证用例:构造x + c(一个可训练参数、一个常量)的问题,用ModelAdapter包装后验证:参数替换为tf.constant(0.0)时目标值从 4.0 变为 2.0,证明变量替换机制生效。
在 TaskSet 中的集成:从问题类到注册任务
LOSGProblemTask:问题定义的 Task 化包装
losg_tasks.py 中的LOSGProblemTask(losg_tasks.py)继承base.BaseTask,把(problem_spec.Spec, dataset, batch_size)三元组包装成可训练的 Task:
- 有数据集时用
tf.data.Dataset.from_tensor_slices构造无限重复、打乱、按 batch 切分的迭代器; - 通过
tf.custom_gradient定义fake_gradient,将问题自身的objective与gradients无缝接入自动微分; call_split中强制np.random.seed(self._problem.random_seed),保证每次前向计算的问题内部随机状态一致;current_params/initial_params分别返回当前变量值与初始值,供优化器训练使用。
随机任务族与固定任务
losg_tasks.py 的_problem_sample_get字典注册了 14 类可采样问题(quadratic、bowl、sparse_softmax_regression、optimization_test_problems、fully_connected、norm、dependency_chain、outward_snake、min_max_well、sum_of_quadratics、projection_quadratic、sparse_problems、rescale_problems、log_objective),每个类别都有配套的_sample_*配置采样器。例如:
- quadratic 的维度
dim在[10, 1000]对数均匀采样,噪声强度以 0.5 概率在[0.01, 10.0]采样(losg_tasks.py); - sparse_problems 的
zero_probability在[0.9, 0.99]均匀采样(losg_tasks.py); - rescale_problems 的
scale在[0.001, 1000.0]对数采样(losg_tasks.py)。
这些采样器通过@registry.task_registry.register_sampler("losg_tasks_family")注册为任务族,并由get_losg_tasks_family负责实例化(losg_tasks.py)。
而 fixed_2d.py 则以register_fixed注册了固定种子(random_seed=1/2、task seed=123)的TwoD_Bowl1/10/100/1000、TwoD_Rosenbrock、TwoD_Ackley、TwoD_Beale、TwoD_StyblinskiTang等固定评测任务,用于优化器的确定性对比。
验证与运行
单元测试
三个测试文件覆盖了问题集的全部关键行为,可通过 TensorFlow 1.x 测试框架直接运行:
python3 -m task_set.tasks.losg_problems.problem_generator_test python3 -m task_set.tasks.losg_problems.datasets_test python3 -m task_set.tasks.losg_problems.model_adapter_test各测试要点:
- problem_generator_test.py:验证
init_tensors/init_variables的形状与类型正确性、梯度数量与顺序; - problem_generator_test.py:验证
SparseProblem在zero_prob=0.0(梯度永不置零)、1.0(全部置零)、0.5(部分置零)三种情况下的梯度行为; - datasets_test.py:验证
batch_indices的批量大小、打乱性与数据标签长度不一致时的ValueError; - datasets_test.py:验证各数据集生成器的样本数、特征维度、标签范围与二值性、对称性;
- model_adapter_test.py:验证
ModelAdapter的参数计数与变量替换语义。
端到端训练
按照 task_set/README.md 的说明,可以直接用train_inner.py训练某个任务:
python3 -m task_set.train_inner --optimizer_name="adam4p_wide_grid_seed107" --task_name="mlp_family_seed117" --output_directory="/tmp/root_data_dir"注意环境前提:TaskSet 目前仅支持 TensorFlow 1.x(如 tensorflow-1.15)与对应版本的 Sonnet,完整依赖清单见 task_set/requirements.txt。
扩展自定义问题
若要在该问题集基础上添加新问题,按以下步骤即可:
- 继承
Problem:在 problem_generator.py 中定义子类,声明param_shapes,实现objective(parameters, data, labels),需要时重写init_tensors(自定义初始化范围)与gradients(自定义梯度变换); - 用
Spec封装:通过problem_spec.Spec(MyProblem, args, kwargs)描述问题,便于延迟构建与序列化; - 需要监督数据时:在 datasets.py 中新增生成函数,返回
Dataset命名元组; - 接入任务族:在 losg_tasks.py 的
_problem_sample_get中注册(采样器, 构造器)对,或通过register_fixed注册固定任务; - 补充测试:参照现有三个测试文件,覆盖新问题的初始化形状、梯度与数据合法性。
小结
losg_problems虽源自 LOSG 论文的问题集副本,但在 google-research 的 TaskSet 项目中扮演着"优化器元训练与评测问题库"的基础角色:Spec提供统一的延迟构造语法,Problem基类定义了 objective/gradients/初始化三件套接口,datasets.py供给监督数据,ModelAdapter打通任意 TensorFlow 模型,losg_tasks.py与fixed_2d.py则将其组装为可随机采样、可固定评测的完整任务体系。无论是复现 LOSG 实验、训练学习型优化器,还是构建自定义优化基准,这个目录都是最直接的起点。
- 人工智能
- 深度学习
- NLP
- 计算机视觉
- 强化学习
【免费下载链接】google-research
Google Research
相关推荐
TaskSet 使用指南:用上千个优化任务评估与元训练学习型优化器(google-research)
TaskSet 使用指南:用上千个优化任务评估与元训练学习型优化器(google research) TaskSet 是 google research 仓库中
人工智能深度学习NLP计算机视觉强化学习Shampoo 优化器 PyTorch 实现深度解析:google-research 可扩展二阶预条件优化器指南
Shampoo 优化器 PyTorch 实现深度解析:google research 可扩展二阶预条件优化器指南 本文以 scalable_shampoo/py
人工智能深度学习NLP计算机视觉强化学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考