NLP系列——(6)神经网络+FastText

    xiaoxiao2022-07-07  207

    神经网络+FastText

    一、神经网络基础1.1 前馈神经网络1.1.1 神经元模型1.1.2 前馈神经网络1.1.3 网络层数1.1.4 输入层1.1.5 输出层1.1.6 隐藏层1.1.7 隐藏单元1.1.8 激活函数1.1.9 前馈神经网络与反向传播算法(推导过程) 1.2 感知机1.2.1 感知机的原理1.2.2 点到线的距离1.2.3 样本到超平面的距离1.2.4 超平面1.2.5 感知机模型1.2.6 感知机的损失函数1.2.7 感知机学习算法1.2.8 训练过程 1.3 简单的神经网络1.4 激活函数1.4.1 sigmoid1.4.2 Tanh1.4.3 RELU1.4.4 Leaky ReLU1.4.5 Maxout1.4.6 ELU1.4.7 softmax 1.5 正则化1.5.1 参数范数惩罚1.5.2 数据扩增1.5.3 噪声添加1.5.4 Dropout1.5.5 早停机制 1.6 深度模型中的优化 二、FastText2.1 预备知识2.1.1 Softmax 回归 2.2 FastText 原理2.3 FastText 实践

    一、神经网络基础

    1.1 前馈神经网络

    1.1.1 神经元模型

    神经网络中最基本的单元就是神经元模型。 细胞体分为两部分,前一部分计算总输入值(即输入信号的加权和,或者说累积电平),后一部分先计算总输入值与该神经元阈值的差值,然后通过激活函数(activation function)的处理,产生输出从轴突传送给其它神经元。M-P神经元模型如下图所示:

    1.1.2 前馈神经网络

    前馈神经网络是一种最简单的神经网络,各神经元分层排列。每个神经元只与前一层的神经元相连。接收前一层的输出,并输出给下一层。各层间没有反馈。

    1.1.3 网络层数

    一般指的是设置或搭建的网络模型有多少层。以上图为例,单隐层前馈网络有输入层、隐藏层、输出层三层;双隐层前馈网络那就是四层网络。(当然也有不把输入层算作网络层数的。)

    1.1.4 输入层

    指的是数据输入模型的第一层

    1.1.5 输出层

    指的是模型的最后一层

    1.1.6 隐藏层

    指的是除去输入层、输出层外的中间层

    1.1.7 隐藏单元

    指的是隐藏层中的单元结构, 也就是神经元

    1.1.8 激活函数

    一般指加权之后的值到输出之间函数,通过激活函数将上一层的输出作为下一层输入之前进行非线性变化,使模型不再是单一的线性变换。 那为什么要用激活函数? 神经网络中激活函数的主要作用是提供网络的非线性建模能力,如不特别说明,激活函数一般而言是非线性函数。假设一个示例神经网络中仅包含线性卷积和全连接运算,那么该网络仅能够表达线性映射,即便增加网络的深度也依旧还是线性映射,难以有效建模实际环境中非线性分布的数据。加入(非线性)激活函数之后,深度神经网络才具备了分层的非线性映射学习能力。因此,激活函数是深度神经网络中不可或缺的部分。

    激活函数可以帮助神经网络隔离噪声点。即激活有用的信息,抑制无关的数据点。

    1.1.9 前馈神经网络与反向传播算法(推导过程)

    参考:https://blog.csdn.net/u010089444/article/details/52555567

    1.2 感知机

    参考:https://www.cnblogs.com/huangyc/p/9706575.html

    1.2.1 感知机的原理

    感知机是二分类的线性模型,其输入是实例的特征向量,输出的是实例的类别,分别是+1和-1,属于判别模型。

    假设训练数据集是线性可分的,感知机学习的目标是求得一个能够将训练数据集正实例点和负实例点完全正确分开的分离超平面。如果是非线性可分的数据,则最后无法获得超平面。

    1.2.2 点到线的距离

    公式中的直线方程为 A x + B y + C = 0 Ax+By+C=0 Ax+By+C=0点 P 的坐标为(x0,y0)

    1.2.3 样本到超平面的距离

    1.2.4 超平面

    超平面是在空间Rd中的一个子空间Rd-1。 在2维空间中的超平面是一条线,在3维空间中的超平面是一个面。

    1.2.5 感知机模型

    1.2.6 感知机的损失函数

    为什么可以不考虑 1 / ∣ ∣ w ∣ ∣ 1/||w|| 1/w 网上有人说1/||w||是个定值,但是个人觉得平面不唯一,这个值肯定也会变。通过参考他人观点结合思考,觉得原因可以列为以下两点。

    1/||w||不影响 yi(w⋅xi+b) 正负的判断,即不影响学习算法的中间过程。因为感知机学习算法是误分类驱动的,这里需要注意的是所谓的“误分类驱动”指的是我们只需要判断−yi(w⋅xi+b)的正负来判断分类的正确与否,而1/||w||并不影响正负值的判断。所以1||w||对感知机学习算法的中间过程可以不考虑。1/||w||不影响感知机学习算法的最终结果。因为感知机学习算法最终的终止条件是所有的输入都被正确分类,即不存在误分类的点。则此时损失函数为0. 对应于 − 1 / ∣ ∣ w ∣ ∣ ∑ i ∈ M y i ( w ⋅ x i + b ) −1/||w||∑i∈Myi(w⋅xi+b) 1/wiMyi(wxi+b),即分子为0.则可以看出1/||w||对最终结果也无影响。 综上所述,即使忽略1/||w||,也不会对感知机学习算法的执行过程产生任何影响。反而还能简化运算,提高算法执行效率。

    1.2.7 感知机学习算法

    感知机学习算法是对上述损失函数进行极小化,求得w和b。但是用普通的基于所有样本的梯度和的均值的批量梯度下降法(BGD)是行不通的,原因在于我们的损失函数里面有限定,只有误分类的M集合里面的样本才能参与损失函数的优化。所以我们不能用最普通的批量梯度下降,只能采用随机梯度下降(SGD)。目标函数如下: 1.原始形式算法 2.对偶形式算法 原始形式和对偶形式的选择

    在向量维数(特征数)过高时,计算内积非常耗时,应选择对偶形式算法加速。在向量个数(样本数)过多时,每次计算累计和就没有必要,应选择原始算法

    1.2.8 训练过程

    我们大概从下图看下感知机的训练过程。

    线性可分的过程:

    线性不可分的过程:

    1.3 简单的神经网络

    首先给网络提供 M 个训练对 (X,Y) ,X 为输入,Y为期望的输出。输入通过激活函数 g(h) 和隐藏层传播到输出层。输出 Y ^ \hat{Y} Y^ 是网络的输出,得到 e r r o r = Y − Y ^ error=Y− \hat{Y} error=YY^ 其损失函数 J(W) 如下: 其中,i 取遍所有输出层的神经元(1 到 N)。然后可以使用 J(W) 的梯度并使用链式法则求导,来计算连接第 i 个输出层神经元到第 j 个隐藏层神经元的权重 Wij 的变化:

    这里,Oj 是隐藏层神经元的输出,hi 表示输出层的输入值。这很容易理解,但现在怎么更新连接第 n 个隐藏层的神经元 k 到第 n+1 个隐藏层的神经元 j 的权值Wjk 过程是相同的:将使用损失函数的梯度和链式法则求导,但这次计算 $$ Wjk 通过二层的全连接网络,实现 mnist 数据集分类任务。

    import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist_path = './MNIST_data/' mnist = input_data.read_data_sets(mnist_path, one_hot=True) # 定义超参数和其他常量 n_input = 784 # 28 * 28 n_classes = 10 max_epochs = 10000 learning_rate = 0.5 batch_size = 10 seed = 0 n_hidden = 30 ## Sigmoid 函数的导数 def sigmaprime(x): return tf.multiply(tf.sigmoid(x), tf.subtract(tf.constant(1.0), tf.sigmoid(x))) # 为训练数据创建占位符 x_in = tf.placeholder(tf.float32, [None, n_input], name='x_in') y = tf.placeholder(tf.float32, [None, n_classes], name='y') # 创建模型 def multilayer_perceptron(x, weight, biases): h_layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['h1']) out_layer_1 = tf.sigmoid(h_layer_1) h_out = tf.add(tf.matmul(out_layer_1, weights['h2']), biases['h2']) return tf.sigmoid(h_out), h_out, out_layer_1, h_layer_1 # 权重 weights = { 'h1':tf.Variable(tf.random_normal([n_input, n_hidden], seed=seed)), 'h2':tf.Variable(tf.random_normal([n_hidden, n_classes], seed=seed))} # 偏置 biases = { 'h1':tf.Variable(tf.random_normal([1, n_hidden], seed=seed)), 'h2':tf.Variable(tf.random_normal([1, n_classes], seed=seed))} # 正向传播 y_hat, h_2, o_1, h_1 = multilayer_perceptron(x_in, weights, biases) # loss function err = y - y_hat loss = tf.reduce_mean(tf.square(err, name='loss')) # 反向传播 delta_2 = tf.multiply(err, sigmaprime(h_2)) delta_w_2 = tf.matmul(tf.transpose(o_1), delta_2) wtd_error = tf.matmul(delta_2, tf.transpose(weights['h2'])) delta_1 = tf.multiply(wtd_error, sigmaprime(h_1)) delta_w_1 = tf.matmul(tf.transpose(x_in), delta_1) eta = tf.constant(learning_rate) # 更新权重 train = [ tf.assign(weights['h1'], tf.add(weights['h1'], tf.multiply(eta, delta_w_1))), tf.assign(biases['h1'], tf.add(biases['h1'], tf.multiply(eta, tf.reduce_mean(delta_1, axis=[0])))), tf.assign(weights['h2'], tf.add(weights['h2'], tf.multiply(eta, delta_w_2))), tf.assign(biases['h2'], tf.add(biases['h2'], tf.multiply(eta, tf.reduce_mean(delta_2, axis=[0])))) ] # 定义精度 acc_mat = tf.equal(tf.argmax(y_hat, 1), tf.argmax(y, 1)) accuracy = tf.reduce_sum(tf.cast(acc_mat, tf.float32)) # train init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) for epoch in range(max_epochs): batch_xs, batch_ys = mnist.train.next_batch(batch_size) _, loss1 = sess.run([train, loss], feed_dict={x_in: batch_xs, y: batch_ys}) if epoch % 1000 == 0: print('Epoch: {0} loss: {1}'.format(epoch, loss1)) acc_test = sess.run(accuracy, feed_dict={x_in: mnist.test.images, y:mnist.test.labels}) acc_train = sess.run(accuracy, feed_dict={x_in: mnist.train.images, y:mnist.train.labels}) # 评估 print('Accuracy Train%: {1} Accuracy Test%: {2}'.format(epoch, acc_train / 600, (acc_test / 100)))

    1.4 激活函数

    常用的激活函数:

    sigmoidtanhReLULeaky ReLUMaxoutELUsoftmax

    1.4.1 sigmoid

    sigmoid 特点: 能将输入的连续实值映射到 (0,1) (0,1)(0,1) 之间。特别的,若非常小的负值,输出为 0;非常大的正值,输出为1。

    sigmoid 缺点:

    激活函数计算量大(指数运算),反向传播求误差梯度时,求导涉及除法对于深层网络,sigmoid 函数反向传播时,很容易就会出现梯度消失的情况(在 sigmoid 接近饱和区时,变换太缓慢,导数趋于 0,这种情况会造成信息丢失),从而无法完成深层网络的训练

    1.4.2 Tanh

    也称为双切正切函数,取值范围为 [-1,1]。tanh 在特征相差明显时的效果会很好,在循环过程中会不断扩大特征效果。

    优点: tanh解决了sigmoid的输出非“零为中心”的问题。

    缺点: 依然有sigmoid函数梯度消失的问题。 依然指数运算。

    1.4.3 RELU

    优点:

    ReLU解决了梯度消失的问题,至少 x 在正区间内,神经元不会饱和。由于ReLU线性、非饱和的形式,在SGD中能够快速收敛。计算速度要快很多。线性计算

    缺点:强制的稀疏处理会减少模型的有效容量(即特征屏蔽太多,导致模型无法学习到有效特征)。

    1.4.4 Leaky ReLU

    优点:

    神经元不会出现死亡的情况。对于所有的输入,不管是大于等于0还是小于0,神经元不会饱和。由于Leaky ReLU线性、非饱和的形式,在SGD中能够快速收敛。计算速度要快很多。只有线性关系。 缺点Leaky ReLU函数中的 α αα,需要通过先验知识人工赋值,通常 α=0.01

    1.4.5 Maxout

    Maxout 是 ReLU 的推广,定义如下: Maxout 网络能够近似任意连续函数,且当w2,b2,…,wn,bn 为0时,退化为ReLU。

    优点:

    Maxout能够缓解梯度消失规避了ReLU神经元死亡的缺点 缺点:增加了参数和计算量。

    1.4.6 ELU

    ELU(Exponential Linear Units,指数线性单元)。它试图将激活函数的输出平均值接近零,从而加快学习速度。同时,它还能通过正值的标识来避免梯度消失的问题。 公式如下: 优点:

    完美解决了死区问题。ELU激活函数的输出均值是接近于零的 缺点:计算较复杂。

    1.4.7 softmax

    softmax 函数将 K 维的实数向量压缩(映射)成另一个 K 维的实数向量,其中向量中的每个元素取值都介于 (0,1) 之间。常用于多分类问题。

    1.5 正则化

    参考 https://blog.csdn.net/xiaoyi_eric/article/details/80909492 https://blog.csdn.net/u012736685/article/details/88858430#_7 首先说说什么是正则化? 讲到为什么需要正则化,就需要了解什么是过拟合问题。以下面图片为例,我们能够看到有两个类别,其中以X代表男生,O代表女生。 我们想要通过学习来得到分类曲线,其中分类曲线能够有效区分男生和女生,现在来分析下上面的三种分类结果。

    **欠拟合:**图1分类明显欠缺,有些男生被分为女生,有些女生被分为男生。**正拟合:**图2虽然有两个男生被分类为女生,但能够理解,毕竟我们人类自己也有分类错误的情况,比如通过化妆,女装等方法。过拟合:图3虽然能够全部分类正确,但结果全部正确就一定好吗?不一定,我们能够看到分类曲线明显过于复杂,模型学习的时候学习了过多的参数项,但其中某些参数项是无用的特征,比如眼睛大小。当我们进行识别测试集数据时,就需要提供更多的特征,如果测试集包含海量的数据,模型的时间复杂度可想而知。

    那什么是正则化呢? 正则化是选择模型的一种方法,具体来说,选择经验风险与模型复杂度同时较小的模型(防止过拟合),这样可以较少泛化误差而不是训练误差。 既然我们已经知道什么是过拟合,那么怎么解决过拟合问题呢?上面有介绍到,模型出现过拟合,是在模型特征上过于复杂。而特征又包含在我们的目标函数f(x)之中,那么只能从目标函数f(x)中寻找解决问题的方法。假设目标函数f(x)和损失函数J0为 对于上式,如果特征项 x 0 , x 1 , x 2 , . . . , x n x_0, x_1, x_2,...,x_n x0,x1,x2,...,xn越多的话,自然 w 0 , w 1 , w 2 , . . . , w n w_0, w_1, w_2,...,w_n w0,w1,w2,...,wn也就越多。先要减少特征的数量,自然减小N也就好了。而N影响的是 X = x 0 , x 1 , x 2 , . . . , x n X=x_0, x_1, x_2,...,x_n X=x0,x1,x2,...,xn W = w 0 , w 1 , w 2 , . . . , w n W=w_0, w_1, w_2,...,w_n W=w0,w1,w2,...,wn两项,那么是从X解决问题还是从W解决问题呢? 如果从X入手解决问题,但训练过程中我们不知道下一个样本X是什么,会怎样的影响目标函数,所以此路不通。那么W如何呢?我们知道W系数是训练过程中通过学习历史数据得到的,和历史数据有关,所以应该可以。现在再回到我们原来的问题,希望减少N的数目,而让N最小化,其实就是让X向量或W向量中项的个数最小化,既然X不行,那么我们可以尝试让W向量中项的个数最小化。如何求解才能让W向量中项的个数最小,我们先简单介绍下0、1、2范数的概念。

    **L0范数:**向量中非零元素的个数,记为 ∣ ∣ W ∣ ∣ 0 ∣∣W∣∣_0 W0**L1范数:**绝对值之和,记为 ∣ ∣ W ∣ ∣ 1 ∣∣W∣∣_1 W1**L2范数:**通常意义上的模,记为 ∣ ∣ W ∣ ∣ 2 ∣∣W∣∣_2 W2

    所以为了防止过拟合,我们需要让 ∣ ∣ W ∣ ∣ 0 ∣∣W∣∣_0 W0 最小,同时让损失函数 J 0 J_0 J0 最小,为了满足两项最小化,可以让 J 0 J_0 J0 ∣ ∣ W ∣ ∣ 0 ∣∣W∣∣_0 W0 之和最小化。但因为 ∣ ∣ W ∣ ∣ 0 ∣∣W∣∣_0 W0 比较难求(NP难问题),我们进而可以转化为求 ∣ ∣ W ∣ ∣ 1 ∣∣W∣∣_1 W1 ∣ ∣ W ∣ ∣ 1 ∣∣W∣∣_1 W1 ∣ ∣ W ∣ ∣ 0 ∣∣W∣∣_0 W0 的最优凸近似,都可以实现稀疏,比较容易求解,这也是为什么可以选用 ∣ ∣ W ∣ ∣ 1 ∣∣W∣∣_1 W1 的原因。最后损失函数后面添加的额外项 ∣ ∣ W ∣ ∣ 1 ∣∣W∣∣_1 W1 ,也就是我们称作的L1正则化,α 含义在后面进行讲解。 说完L0范数和L1范数,就不得不提L2范数。L2范数是指先求向量各元素的平方和,然后再进行求平方根,也就是通常意义上的模。同样,对于正则化问题,我们的目标是让W向量中的每个元素都很小,也就是让L2范数最小。L1范数和L2范数的不同点在于,L1范数会让其中某些元素等于0,而L2范数只是让其中元素接近0,这里有很大不同,我们在后面会进行详细讲解。最后损失函数后面添加的额外项||W||2,也就是我们称作的L2正则化。 常用正则化方法

    参数范数惩罚:L1正则化、L2正则化;数据集增强;噪声添加;early stop;Dropout层

    1.5.1 参数范数惩罚

    参数范数惩罚通过对目标函数 J 添加一个参数范数惩罚 Ω(θ),限制模型的学习能力。

    将正则化欧的目标函数记为 J ~ \tilde{J} J~ 其中 α≥0 是权衡范数惩罚项 Ω 和标准目标函数 J(X;θ) 相对贡献的超参数,通过调整 α 的大小,可以获得不同的参数选择偏好。

    注意:参数包括模型中每一层仿射变换的权重和偏置,我们通常只对权重做惩罚,而不对偏置做正则惩罚。因为精确拟合偏置所需的数据通常比权重少的多,正则化偏置参数可能会导致明显的欠拟合。 任何的规则化算子,如果它在 Wi=0 处不可微,并且可以分解为一个“求和”的形式,则该规则化算子就可以实现稀疏。

    稀疏的好处

    特征选择(Feature Selection):能实现特征的自动选择 稀疏规则化算子会学习地去掉这些对最终输出结果没有关系或者不提供任何信息的特征,也就是把这些特征对应的权重置为0。

    可解释性(Interpretability) 非零权重的特征为输出结果提供的信息是巨大的、决策性的。 1、L0正则化 从直观上看,利用非零参数的个数,可以很好的来选择特征,实现特征稀疏的效果,具体操作时选择参数非零的特征即可。

    但因为L0正则化很难求解,是个NP难问题,因此一般采用L1正则化。L1正则化是L0正则化的最优凸近似,比L0容易求解,并且也可以实现稀疏的效果。 2、L1正则化 L1范数也称叫“稀疏规则算子”(Lasso regularization),L1范数和 L0范数 可以实现稀疏,L1因具有比L0更好的优化求解特性而被广泛应用。 3、L2正则化 L2范数,在回归中称为:“岭回归” (Ridge Regression) 或 “权值衰减weight decay”。

    让L2范数的规则项 ∣ ∣ W ∣ ∣ ∣∣W∣∣ W 最小,可以使得 W W W 的每个元素都很小,都接近于0(不会让它等于0)。而越小的参数说明模型越简单,越简单的模型则越不容易产生过拟合现象。

    1.5.2 数据扩增

    较少过拟合的最简单方法:增加训练集样本,也称数据扩增(data agumentation)。但是由于标注数据昂贵,需要通过其他方式增加样本。

    图像处理:旋转、翻转、放缩、平移等等。GAN(对抗式生成网络)

    1.5.3 噪声添加

    噪声添加:将其直接添加到学习到的权重上。这项技术主要被用于循环神经网络的情况下。 在某些假设下,施加于权重的噪声可以被解释为与更传统的正则化形式等同,鼓励要学习的函数保持稳定。

    1.5.4 Dropout

    Dropout:在用前向传播算法和反向传播算法训练模型时,随机的从全连接DNN网络中去掉一部分隐含层的神经元。

    两种理解:

    减少神经元之间复杂的共适应关系:在每次训练的时候使用dropout,每个神经元有一定的概率被移除,这样可以使得一个神经元的训练不依赖于另外一个神经元,同样也就使得特征之间的协同作用被减弱。 Hinton认为,过拟合可以通过阻止某些特征的协同作用来缓解。 多模型效果平均的方式。对于减少测试集中的错误,我们可以将多个不同神经网络的预测结果取平均,而因为dropout的随机性,在每次dropout后,网络模型可看成不同结构的神经网络,而要训练的参数数目却是不变的,这就解脱了训练多个独立的不同神经网络的时耗问题。在测试输出的时候,将输出权重乘以保留概率1-p%,从而达到类似平均的效果。 左边的图为一个完全的全连接层,右边为应用dropout后的全连接层。 做法

    训练阶段:每次更新参数之前,每个神经元有一定的概率被丢弃,假设为p%,p可以设为50或者根据验证集的表现来选取,输入层的p比较小,保留概率接近于1测试阶段不dropout,保留所有单元的权重,而且要乘以保留概率1-p%,为了保证输出期望一致。 dropout不只用于前馈神经网络,还可以用于图模型,比如玻尔兹曼机。

    1.5.5 早停机制

    早期停止是一种交叉验证策略,将一部分数据集作为验证集(validation set)。 当我们看到验证集上的性能越来越差时,就停止对模型的训练。

    1.6 深度模型中的优化

    这里偷个懒 包含: 1、学习与纯优化有什么不同

    2、神经网络优化中的挑战

    3、基本算法

    4、自适应学习率算法

    5 、优化策略与元算法 参考 : https://blog.csdn.net/u012756814/article/details/79995133 https://cloud.tencent.com/developer/article/1327194

    二、FastText

    fastText是Facebook于2016年开源的一个词向量计算和文本分类工具,在学术上并没有太大创新。但是它的优点也非常明显,在文本分类任务中,FastText(浅层网络)往往能取得和深度网络相媲美的精度,却在训练时间上比深度网络快许多数量级。在标准的多核CPU上, 能够训练10亿词级别语料库的词向量在10分钟之内,能够分类有着30万多类别的50多万句子在1分钟之内。

    接下来首先会介绍一些预备知识,比如softmax、ngram等,然后简单介绍word2vec原理,之后来讲解FastText的原理,并着手使用keras搭建一个简单的fastText分类器,最后会讲一下应用。 这里请点击

    2.1 预备知识

    2.1.1 Softmax 回归

    2.2 FastText 原理

    2.3 FastText 实践

    参考另一篇 https://blog.csdn.net/weixin_40593658/article/details/90451855

    参考: https://blog.csdn.net/u010089444/article/details/52555567 https://blog.csdn.net/xiaoyi_eric/article/details/80909492 https://blog.csdn.net/u012736685/article/details/88858430#_7 https://www.cnblogs.com/huangyc/p/9706575.html

    https://blog.csdn.net/u012756814/article/details/79995133 https://cloud.tencent.com/developer/article/1327194

    最新回复(0)