正则化(regularization)是machine learning种非常常见的减少过拟合、降低泛化误差的方法。对deep learning模型,过多的参数增加了过拟合的风险,常见的降低过拟合风险的方法包括数据扩增、dropout以及添加正则约束,本文主要对tensorflow中的变量正则化进行介绍。
正则化介绍:
-
L1正则
对模型添加L1范数约束,即:
对于变量集合W=[w1, w2, ..., wn],L1正则作用结果为:
当L1正则在变量参数w较小的情况下,能够直接缩减至0,这个性质常被用于降低数据维度(特征筛选),就是我们常说的LASSO方法。
-
L2正则
变量参数添加L2正则,在tensorflow超参数设置中就是常见的Weight Decay参数所对应的方法,另外也有岭回归、Tikhonov regularization等名称。
对于变量集合W=[w1, w2, ..., wn],L2正则作用结果为:
变量的L2正则loss即为Weight Decay * Lw(计算结果添加到总体loss,那么训练过程对该节点参数自然会增加约束)
-
L0正则
L0正则方法表示的是计算变量集合中非零元素的个数,这种方法在稀疏表示算法中比较常用。
Tensorlow相关
tensorflow中对参数使用正则项分为两步:
- 创建正则化方法;
- 将正则化方法应用到参数上。
在tensorflow中实现上述两步,可以自己手动定义(麻烦 ╯□╰ ...)或者直接使用tensorflow内带的实现方法.
-
tf.contrib.layers.l2_regularizer(lambda)(w)
这个函数直接为w变量计算L2正则项,可以在创建变量时使用。
def create_variable(name, shape, weight_decay):
initializer = tf.contrib.layers.xavier_initializer()
regularizer = tf.contrib.layers.l2_regularizer(scale=weight_decay)
new_variables = tf.get_variable(name, shape=shape, initializer=initializer,
regularizer=regularizer)
return new_variables
之后所有的变量创建直接使用上述接口函数就可以。
看到这里,其实想重新审视一下tf.get_variables()和tf.Variables()这两个函数,在传入参数里面又很多细节需要注意的地方,这里把源码里面相关的参数贴出来看一下:
get_variable(
name,
shape=None,
dtype=None,
initializer=None,
regularizer=None,
trainable=True,
collections=None,
caching_device=None,
partitioner=None,
validate_shape=True,
use_resource=None,
custom_getter=None,
constraint=None
)
Args:
- name:新变量或现有变量的名称。
- shape:新变量或现有变量的形状。
- dtype:新变量或现有变量的类型(默认为DT_FLOAT)。
- ininializer:如果创建了则用它来初始化变量。
- regularizer:A(Tensor - > Tensor或None)函数;将它应用于新创建的变量的结果将添加到集合tf.GraphKeys.REGULARIZATION_LOSSES中,并可用于正则化。
- trainable:如果为True,还将变量添加到图形集合GraphKeys.TRAINABLE_VARIABLES(参见tf.Variable)。
- collections:要将变量添加到的图表集合列表。默认为[GraphKeys.GLOBAL_VARIABLES](参见tf.Variable)。
- caching_device:可选的设备字符串或函数,描述变量应被缓存以供读取的位置。默认为Variable的设备。如果不是None,则在另一台设备上缓存。典型用法是在使用变量驻留的Ops的设备上进行缓存,以通过Switch和其他条件语句进行重复数据删除。
- partitioner:可选callable,接受完全定义的TensorShape和要创建的Variable的dtype,并返回每个轴的分区列表(当前只能对一个轴进行分区)。
- validate_shape:如果为False,则允许使用未知形状的值初始化变量。如果为True,则默认为initial_value的形状必须已知。
- use_resource:如果为False,则创建常规变量。如果为true,则使用定义良好的语义创建实验性ResourceVariable。默认为False(稍后将更改为True)。在Eager模式下,此参数始终强制为True。
- custom_getter:Callable,它将第一个参数作为true getter,并允许覆盖内部get_variable方法。 custom_getter的签名应与此方法的签名相匹配,但最适合未来的版本将允许更改:def custom_getter(getter,* args,** kwargs)。也允许直接访问所有get_variable参数:def custom_getter(getter,name,* args,** kwargs)。一个简单的身份自定义getter只需创建具有修改名称的变量是:python def custom_getter(getter,name,* args,** kwargs):return getter(name +'_suffix',* args,** kwargs)
标红加粗的几个参数是个人认为比较重要和常用的,这一块涉及到tensorflow管理图的方法,详细的介绍打算之后再写文介绍,下面需要用到的会涉及tenorflow的collection概念,大概就是tensorflow在管理图的时候定义的一些集合空间,tensorflow在创建图的过程中,会自动用一些collection来对图节点(op)进行分类,方便之后的调用,类似name_scope,这部分collection被称为tf.GraphKeys,常见的GraphKeys有:
- GLOBAL_VARIABLES: 该collection默认加入所有的Variable对象,并且在分布式环境中共享。一般来说,包含在MODEL_VARIABLES中,MODEL_VARIABLES包含在GLOBAL_VARIABLES中。
- LOCAL_VARIABLES: 与GLOBAL_VARIABLES不同的是,它只包含本机器上的Variable,即不能在分布式环境中共享。
- MODEL_VARIABLES: 顾名思义,模型中的变量,在构建模型中,所有用于正向传递的Variable都将添加到这里。
- TRAINALBEL_VARIABLES: 所有用于反向传递的Variable,即可训练(可以被optimizer优化,进行参数更新)的变量。
- SUMMARIES: 跟Tensorboard相关,这里的Variable都由tf.summary建立并将用于可视化。
- QUEUE_RUNNERS: the QueueRunner objects that are used to produce input for a computation.
- MOVING_AVERAGE_VARIABLES: the subset of Variableobjects that will also keep moving averages.
- REGULARIZATION_LOSSES: regularization losses collected during graph construction.
我们为变量创建的正则项都是被collect或者说需要被collect在regularization_losses中,因此自己写正则项定义好了之后利用tf.add_to_collection就可以。
-
tf.add_to_collection和tf.get_collection
tf.add_to_collection和tf.get_collection是将变量加入Graph集合和根据key从集合中取出内容的操作,tf.get_collection返回一个列表,内容是这个集合的所有元素。
自定义好变量正则项之后再把正则项添加进loss集合就行。
def get_weight(shape, lambda):
var = tf.Variable(tf.random_normal(shape),dtype=tf.float32)
tf.add_to_collection("losses",tf.contrib.layers.l2_regularizer(lambda)(var)) #losses是
#损失函数集合
return var
损失函数的定义实际上我觉得也是一种正则项(例如一些任务使用L2距离作为损失函数),也就是作用在所有变量空间的一种约束条件。
以上是自己的一些学习记录,如果由不正确的地方还请见谅~~