小白的深度学习NLP调参经验总结

以下只是我从博客里整理出来的,有很多都没自己试过,也许并不准确。

所有网络都涉及到的参数:

learning rate: 1e-2到1e-5之间。一般设1e-3就可以。

batch size: 16, 32, 64, 128, 256。一般设2^N,具体N取多少可以根据自己的计算资源来决定。

optimizer:Adam,SGD,Adadelta。一般用Adam就可以。

dropout:0.3, 0.5, 0.7, 数据量多的时候也可以不加。一般设0.5。

activation function:常用的就是relu, tanh, 和relu的几个变体(leaky-relu, gelu)。一般用relu, 但RNN优先用tanh。

hidden size:64, 128, 256, 512。之所以设2^N是为了方便一些分头、分片之类的操作。

weight initializer:常用的是random_normal和random_uniform。网上说可以无脑使用Xavier nitializer,但是我又查了查,在激活函数为relu的情况之下,其实应该使用He initializer。

打算采取的策略是embedding用random_uniform,其他地方无脑使用xavier_initializer。

Xavier initializer和He initializer在tensorflow1.12中的实现如下:

# Xavier initializer:
tf.contrib.layers.xavier_initializer(
    uniform=True,
    seed=None,
    dtype=tf.float32
)
# He initializer(也叫MSRA initializer):
tf.contrib.layers.variance_scaling_initializer(
    factor=2.0,
    mode='FAN_IN',
    uniform=False,
    seed=None,
    dtype=tf.float32
)

用于正则化和标准化的参数:

上面这些都是每一个网络都一定包含的参数。下面还有一些参数,可以选择性地加入你的网络当中:

learning rate decay:一般常用exponential_decay就可以。

公式如下:

decayed\_learning\_rate = learning\_rate \times decay\_rate^{\frac{global\_step}{decay\_steps}}

tensorflow中该函数实现如下:

tf.train.exponential_decay(
    learning_rate,
    global_step,
    decay_steps,
    decay_rate,
    staircase=False,
    name=None
)
# 参数说明:
# learning_rate: 初始化学习率,我看还有设成0.5的,感觉好高呀
# global_step: 当前的步数。所以网络中需要有这样一个计数器来记录当前步数
# decay_steps: 衰减步数。一般设置成10?

个人感觉,learning_rate_decay和Adam等优化器中的学习率衰减难道不是做了重复的操作?我觉得learning_rate_decay也许不一定有必要。

normalization: Transformer中自带layer normalization,这个不必说。CNN后面一般都会接Batch Normalization,但是RNN后面似乎一般不接Normalization。

regulization:首先明确一件事情,l1 regularization用于实现权值稀疏,l2 regularization用于防止过拟合。在标准的SGD算法中,l2 regularization和权值衰减(weight decay)是等价的,而在Adam等较复杂的优化器中,l2 regularization和权值衰减并不完全等价。

按照《深度学习与神经网络》一书的说法,l1和l2正则化在深度学习中效果不如在传统机器学习中明显。一般见到的是在损失函数中添加一个l2正则项,大小在1e-4到1e-3之间。tensorflow的实现如下:

l2_losses = tf.add_n([tf.nn.l2_loss(v) for v in tf.trainable_variables() if 'bias' not in v.name])

label smoothing:注意label smoothing是一种正则化技术,而不是为了解决数据不均衡问题而提出的。在分类任务中,one hot的标签会导致模型过于相信预测的类别,所以添加一个正则项来减少其置信度。一般设0.1。

gradient clip: 这个函数感觉加上了不会对训练有害,只会对训练有益(反正只截断异常的梯度,不会影响到正常的梯度。tensorflow中的实现如下:

tf.clip_by_norm(
    t,
    clip_norm,
    axes=None,
    name=None
)
# clip norm设置为5即可

如果换成了tf.clip_by_global_norm,clip_norm也可以设置为5。

CNN的参数:

用于NLP的CNN与在图像或者语音上不同,一般一到两层就足够了,而且pooling方式一般采用的是1-max pooling,也就是说,会把每一个隐藏向量池化为一个数值。这种池化方式决定了不可能每一层conv后面都接pooling。

kernel size: [N, hidden_size], 其中N可以选择2,4,6,8。可以设多个以学到不同的N-gram特征。

padding: 一般设'SAME',这样的话可以多层CNN直接拼接,不需要变换维度。

filter num: 128,256,512。不过也有人说设16,32,64之类的数就足够了。我觉得可能和任务以及数据有关。

有的人习惯在relu之前接一层batch_normalization,有的人说不接也行。个人感觉,接不接BN和数据有关。

RNN的参数:

这里以LSTM为例,也是一般一到两层就足够了。激活函数选用tanh。

习惯上会接一个dropoutWrapper,其在tensorflow中的实现如下:

tf.nn.rnn_cell.DropoutWrapper(
    cell,
    input_keep_prob=1.0,
    output_keep_prob=1.0,
    state_keep_prob=1.0,
    variational_recurrent=False,
    input_size=None,
    dtype=None,
    seed=None,
    dropout_state_filter_visitor=None
)
# 一般设置output_keep_prob与你的dropout rate相对应即可。

猜你喜欢

转载自blog.csdn.net/bonjourdeutsch/article/details/102778038