功放parameter是什么意思 parameter是什么意思( 五 )


事实上 , ENAS 要学习和挑选的就是 Node 之间的连线关系 , 通过不同的连线就会产生大量的神经网络模型结构 , 从中选择最优的连线相当于“设计”了新的神经网络模型。如果大家理解了可能觉得这种生成神经网路的结构有点 low , 因为生成的网络结构样式比较相似 , 而且节点数必须是固定的 , 甚至很难在其中创造出 1x1 polling 这样的新型结构 。是的 , 这些吐槽都是对的 , 目前 ENAS 可以做的就是帮你把连线改一下然后生成一个新的模型 , 但这个就是 ENAS 共享权重的基础 , 而且可以以极低的代码量帮你调整模型结构生成一个更好的模型 , 接下来就是本文最核心的 ENAS 的 E(Efficient)的实现原理介绍了 。
我们知道 , TensorFlow 表示了 Tensor 数据的流向 , 而流向的蓝图就是用户用 Python 代码定义的计算图(Graph) , 如果我们要实现上图中所有 Layer 连成一条直线的模型 , 我们就需要在代码中指定多个 Layer , 然后以此把输入和输出连接起来 , 这样就可以训练一个模型的权重了 。当我们把上图中所有 Layer 连成一条直线的模型改成右边交叉连线的模型 , 显然两者是不同的 Graph , 而前一个导出模型权重的 checkpoint 是无法导入到后一个模型中的 。但直观上看这几个节点位置本没有变 , 如果输入和输出的 Tensor 的 shape 不变 , 这些节点的权重个数是一样的 , 也就是说左边 Node0、Node1、Node2、Node3 的权重是可以完全复制到右边对应的节点的 。
这也就是 ENAS 实现权重共享的原理 , 首先会定义数量固定的 Node , 然后通过一组参数去控制每个节点连接的前置节点索引 , 这组参数就是我们最终要挑选出来的 , 因为有了它就可以表示一个固定神经网络结构 , 只要用前面提到的优化算法如贝叶斯优化、DQN 来调优选择最好的这组参数就可以了 。
那评估模型也是先生成多组参数 , 然后用新的网络结构来训练模型得到 AUC 等指标吗?答案是否定的 , 如果是这样那就和普通的 NAS 算法没什么区别了 。因为训练模型后评估就是非常不 Efficient 的操作 , 这里评估模型是指各组模型用相同的一组权重 , 各自在未被训练的验证集中做一次 Inference , 最终选择 AUC 或者正确率最好的模型结构 , 其实也就是选择节点的连线方式或者是表示连线方式的一组参数 。
稍微总结一下 , 因为 ENAS 生成的所有模型节点数是一样的 , 而且节点的输入和输出都是一样的 , 因此所有模型的所有节点的所有权重都是可以加载来使用的 , 因此我们只需要训练一次模型得到权重后 , 让各个模型都去验证集做一个预估  , 只要效果好的说明发现了更好的模型了 。实际上这个过程会进行很多次 , 而这组共享的权重也会在一段时间后更新 , 例如我找到一个更好的模型结构了 , 就可以用这个接口来训练更新权重 , 然后看有没有其他模型结构在使用这组权重后能在验证机有更好的表现 。
回到前面 TensorFlow 实现 ENAS 的问题 , 我们知道 TensorFlow 要求开发者先定义 Graph , 然后再加载权重来运行 , 但定义 Graph 的过程与模型训练过程是分开的 , 而 ENAS 要求我们在模型训练过程中不断调整 Graph 的结构来尝试更好的 Graph 模型结构 。这在声明式(Declarative)编程接口的 TensorFlow 上其实不好实现 , 而命令式(Imperative)编程接口的 PyTorch 上反而更好实现 。当然这里可以为 TensorFlow 正名 , 因为 ENAS 的作者就提供了基于 TensorFlow 的 ENAS 源码实现 , 开源地址 https://github.com/melodyguan/enas。我们也深入看了下代码 , 作者用了大量 tf.case、tf.while 这样的接口 , 其实是在 TensorFlow 的 Graph 中根据参数来生成最终训练的 child 模型的 Graph  , 因此没有用 Python 代码定义所有 child 模型的 Graph 的集合 , 也不需要每次都重新构建 Graph 来影响模型训练的性能 。

推荐阅读