☰
google-research TaskSet 中的 losg_problems 优化问题集:从 LOSG 到可扩展的元学习优化器基准
2026/10/11 14:13:16 网站建设 项目流程
  • 人工智能
  • 深度学习
  • NLP
  • 计算机视觉
  • 强化学习

【免费下载链接】google-research

Google Research

项目地址:https://gitcode.com/gh_mirrors/go/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.pyModelAdapter变量替换机制的单元测试

核心数据结构: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,)
SparseSoftmaxRegressionembedding 查找 + 求和 + 线性层(n_classes, n_features)+(n_features, n_classes)+(n_classes,)
OneHotSparseSoftmaxRegression与上面相同但不用 embedding op,改用 one-hot 矩阵乘法同上
FullyConnected多层感知机,默认hidden_sizes=(32, 64)、sigmoid 激活每层一组(prev, sz)权重 +(sz,)偏置
ConvNetN 层卷积 + 全连接输出层每个卷积核(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。

扩展自定义问题

若要在该问题集基础上添加新问题,按以下步骤即可:

  1. 继承Problem:在 problem_generator.py 中定义子类,声明param_shapes,实现objective(parameters, data, labels),需要时重写init_tensors(自定义初始化范围)与gradients(自定义梯度变换);
  2. 用Spec封装:通过problem_spec.Spec(MyProblem, args, kwargs)描述问题,便于延迟构建与序列化;
  3. 需要监督数据时:在 datasets.py 中新增生成函数,返回Dataset命名元组;
  4. 接入任务族:在 losg_tasks.py 的_problem_sample_get中注册(采样器, 构造器)对,或通过register_fixed注册固定任务;
  5. 补充测试:参照现有三个测试文件,覆盖新问题的初始化形状、梯度与数据合法性。

小结

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

项目地址:https://gitcode.com/gh_mirrors/go/google-research
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询