基于深度学习的自然语言处理——神经网络训练
基于深度学习的自然语言处理——神经网络训练
神经网络训练
神经网络也是可微分的参数化函数,常用的训练方法就是基于梯度的优化方法。
计算图
计算图的概念
- 计算图是任意数学表达式的一种图表达结构
- 计算图是一个有向无环图,其中结点对应数学变量或运算,边对应节点间的计算流。
- 示例:(a∗b+1)∗(a∗b+2)\left( {a * b + 1} \right) * \left( {a * b + 2} \right)(a∗b+1)∗(a∗b+2)
- 神经网络也可以表示为计算图的形式
前向计算
前向计算就是计算图中每个节点的输出,
假设fif_ifi为结点iii的计算函数,π(i)\pi\left(i\right)π(i)为结点iii的父节点,π−1(i)\pi^{-1}\left(i\right)π−1(i)为结点iii的子节点,vi(i)v_i\left(i\right)vi(i)为结点iii的输出,则前向计算可以表示为:
for i=1i=1i=1 to NNN do
令a1,...,am=π−1(i)a_1,...,a_m=\pi^{-1}\left(i\right)a1,...,am=π−1(i)
v(i)←fi(v(a1),⋯ ,v(am))v\left( i \right) \leftarrow {f_i}\left( {v\left( {{a_1}} \right), \cdots ,v\left( {{a_m}} \right)} \right)v(i)←fi(v(a1),⋯,v(am))
反向计算
反向传播过程开始于损失结点NNN,向前传播,指定d(i)d\left(i\right)d(i)为∂N∂i\frac{{\partial N}}{{\partial i}}∂i∂N,可以表示为:
d(N)←1d\left( N \right) \leftarrow 1d(N)←1 (∂N∂N=1)(\frac{{\partial N}}{{\partial N}} = 1)(∂N∂N=1)
for i=N−1i=N-1i=N−1 to 111 do
d(i)←∑j∈π(i)d(j)⋅∂fj∂id\left( i \right) \leftarrow \sum\nolimits_{j \in \pi \left( i \right)} {d\left( j \right) \cdot \frac{{\partial {f_j}}}{{\partial i}}}d(i)←∑j∈π(i)d(j)⋅∂i∂fj (∂N∂i=∑j∈π(i)∂N∂j∂j∂i)( {\frac{{\partial N}}{{\partial i}} = \sum\limits_{j \in \pi \left( i \right)} {\frac{{\partial N}}{{\partial j}}\frac{{\partial j}}{{\partial i}}} })(∂i∂N=j∈π(i)∑∂j∂N∂i∂j)
软件实现
- 在Python中使用DyNet架构创建图
import dynet as dy #模型初始化 model=dy.Model() mW1=model.add_parameters((20,150)) #向模型添加权重参数 mb1=model.add_parameters(20) mW2=model.add_parameters((17,20)) mb2=model.add_parameters(17) lookup=model.add_lookup_parameters((100,50)) #向模型添加查找参数 trainer=dy.SimpleSGDTrainer(model) #定义训练器 def get_index(x): pass #将词映射为索引值 #构建图结构并执行 #更新模型参数 #只显示一个数据点,实践中应该运行一个数据填充循环 #建立计算图 dy.renew_cg() #创建一个新图 #将模型参数创建 W1=dy.parameter(mW1) b1=dy.parameter(mb1) W2=dy.parameter(mW2) b2=dy.parameter(mb2) #生成embeddings层 vthe=dy.lookup[get_index("the")] vblack=dy.lookup[get_index("black")] vdog=dy.lookup[get_index("dog")] #将叶子结点连接成完整的图 x=dy.concatenate([vthe,vblack,vdog]) output=dy.softmax(W2*(dy.tanh(W1*x+b1))+b2) loss=-dy.log(dy.pick(output,5)) loss_value=loss.forward() loss.backward() #计算参数并存储 trainer.update() #通过梯度进行参数更新
- 在Python中通过Tensorflow实现
#TensorFlow import tensorflow as tf W1=tf.get_variable("W1",[20,150]) b1=tf.get_variable("b1",[20]) W2=tf.get_variable("W2",[17,20]) b2=tf.get_variable("b2",[17]) def get_index(x): pass p1=tf.placeholder(tf.int32,[]) p2=tf.placeholder(tf.int32,[]) p3=tf.placeholder(tf.int32,[]) target=tf.placeholder(tf.int32,[]) v_w1=tf.nn.embedding_lookup(lookup,p1) v_w2=tf.nn.embedding_lookup(lookup,p2) v_w3=tf.nn.embedding_lookup(lookup,p3) x=tf.concat([v_w1,v_w2.v_w3],0) output=tf.nn.softmax(tf.einsum("ij,j->i",W2,tf.tanh(tf.einsum("ij,j->i",W1,x)+b1))+b2) loss=-tf.log(output[target]) trainer=tf.train.GradientDescentOptimizer(0.1).minimize(losss) #完成图的初始化工作,编译并赋予具体数据 #只显示一个数据点,实践中我们将使用一个数据输入环 with tf.Session() as sess: sess.run(tf.global_variables_initializer()) feed_dict={ p1:get_index("the"), p2:get_index("black"), p3:get_index("dog"), target:5 } loss_value=sess.run(loss,feed_dict) sess.run(trainer,feed_dict)
- 两者的区别 DyNet使用动态图结构,为每个训练样本创建不同的计算图进行前传和反传
- TensorFlow使用静态图结构,每一个训练样本都输入到同一张图中。
实现流程
具有计算图概念的神经网络训练
for iteration=1 to T do for 数据集中训练样本(x_i,y_i) do loss_node<-build_computation_graph(x_i,y_i,parameters) #用户自定义函数,给定输入、输出和网络结构可自动生成计算图 loss_node.forward() gradients<-loss_node().backward() parameters<-update_parameters(parameters,gradients) #优化器特定更新规则 return parameters
网络构成
实践经验
优化算法选择
虽然SGD算法效果很好,但是收敛速度慢,在训练大型网络时Adam算法非常有效。
初始化
- xavier初始化(针对tanhtanhtanh函数)
建议权重矩阵WWW以如下公式初始化:
W∼U[−6din+dout,+6din+dout]W \sim U\left[ { - \frac{{\sqrt 6 }}{{\sqrt {{d_{in}} + {d_{out}}} }}, + \frac{{\sqrt 6 }}{{\sqrt {{d_{in}} + {d_{out}}} }}} \right]W∼U[−din+dout6,+din+dout6]
其中U[a,b]U\left[ {a,b} \right]U[a,b]是范围[a,b]\left[ {a,b} \right][a,b]的一个均值采样。 - 针对ReLUReLUReLU函数
从均值为000,方差为2din\sqrt {\frac{2}{{{d_{in}}}}}din2的高斯分布采样进行权重初始化。
重启与集成
- 随即重启:多次进行训练过程,每次都进行随机初始化,并选择最好的一个。
- 模式集成:一旦有了多个模型,可以根据模型的集成进行预测。
梯度消失与梯度爆炸
- 梯度消失(非常接近0) 网络变浅
- 逐步训练
- batch-normalization方法
- 使用特定结构帮助梯度流动
-
如果范数大于阈值,就剪掉
g^\hat gg^表示网络中所有参数的梯度,∥g^∥\left\| {\hat g} \right\|∥g^∥为其L2L_2L2范数,如果∥g^∥>threshold\left\| {\hat g} \right\|>threshold∥g^∥>threshold,则令g^\hat gg^为threshold∥g^∥\frac{{threshold}}{{\left\| {\hat g} \right\|}}∥g^∥threshold。
饱和神经元与死亡神经元
- 饱和神经元 特点 造成该层的输出都接近于111
- 带有tanhtanhtanh和sigmoidsigmoidsigmoid激活函数的网络层往往容易饱和
- 饱和神经元具有很小的梯度
-
由值太大的输入层造成
-
更改初始化
-
特点
大部分甚至所有的值都为负值
-
由进入网络的负值引起
-
减少学习速率
随机打乱
网络读入训练样本的顺序是很重要的。
学习率
实验应该从[0,1]\left[ {0,1} \right][0,1]内尝试初始学习率,观察网络losslossloss值,一旦losslossloss值停止改进则降低学习率。
建议使用ηt=η0(1+η0λt)−1{\eta _t} = {\eta _0}{\left( {1 + {\eta _0}\lambda t} \right)^{ - 1}}ηt=η0(1+η0λt)−1作为学习率的表达式,η0\eta_0η0为初始学习率,ηt\eta_tηt为第ttt个训练样例的学习率,λ\lambdaλ为超参。
minibatch
在每训练111个训练样例(minibatch=1minibatch=1minibatch=1)或kkk个训练样例(minibatch=kminibatch=kminibatch=k)后更新参数。
大的minibatchminibatchminibatch对训练是有益的。
《基于深度学习的自然语言处理》
- 用CNTK搞深度学习 (二) 训练基于RNN的自然语言模型 ( language model )
- 《神经网络和深度学习》系列文章十:[热身]一个基于矩阵的快速计算神经网络输出的方法
- 基于深度学习的自然语言处理——文本特征构造
- 基于深度学习的自然语言处理——NLP特征的案例分析
- 笔记-cs224n(基于深度学习的自然语言处理)
- 基于深度学习的病毒检测技术无需沙箱环境,直接将样本文件转换为二维图片,进而应用改造后的卷积神经网络 Inception V4 进行训练和检测
- 基于深度学习Keras框架的训练数据增强方法(转)
- 基于随机采样获取训练、测试数据示例(Python)
- 基于随机采样获取训练、测试数据示例(Python)
- 基于深度学习的目标检测的研究进展2
- 一个基于特征向量的近似网页去重算法——term用SVM人工提取训练,基于term的特征向量,倒排索引查询相似文档,同时利用cos计算相似度
- 基于bp神经网络的mnist 数据集的深度学习
- 基于Keras的深度学习的相关基础概念的讲解
- 基于opencv2.0的haar算法以人脸识别为例的训练分类器xml的方法
- 基于深度学习的OCR-from 美團技術團隊
- 基于keras的深度学习基本概念讲解——深度学习之从小白到入门
- 基于深度学习的图像语义分割技术概述之4常用方法
- 深度学习(十八)基于R-CNN的物体检测
- 《神经网络和深度学习》系列文章八:迈向深度学习
- [置顶] 基于深度学习的雷达目标检测识别——写在毕业前