书摘:《Keras快速上手:基于Python的深度学习实战》-谢梁;鲁颖;劳虹岚

1准备深度学习的环境

cuDNN是NVIDIA开发的专门强化卷积神经网络模型训练的库,全称为NVIDIACUDADeepNeuralNetworklibrary,支持常见的深度学习软件,比如CNTK、Caffe、Theano、Keras、TensorFlow等。cuDNN对卷积神经网络模型的训练速度能提升2~3倍,

CNMeM是NVIDIA开发的一个显存管理分配软件。预先给深度学习项目分配足够的显存能有效提高训练速度,一般提升10%左右。

2数据收集与处理

TF-IDF(TermFrequency–InverseDocumentFrequency)是一种用于进行信息检索与数据挖掘的常用加权技术,用以评估一个词对于一个段落集或一个语料库中的其中一个段落的重要程度。

Word2Vec是Google推出的用来进行词的向量表达的开源工具包,这个名字也是该工具包所代表的算法的称号。

Word2Vec的主要思想是把词表达为低维度向量的形式,含义相近的词在这个低维度向量空间中的位置相近,而不相关的词则距离较远。

3深度学习简介

大多数神经网络中都包含四类函数:组合函数(CombinationFunction)、激活函数(ActivationFunction)、误差函数(ErrorFunction)和目标函数(ObjectFunction)。

在网络中间将向量映射为标量的函数就被称为组合函数。常见的组合函数包括线性组合函数和基于欧式空间距离的函数,比如在RBF网络中常用的函数。

激活函数通常都是将一个实数域上的值映射到一个有限域中,因此也被称为塌缩函数。比如常见的tanh或者logistic函数,都是将无限的实数域上的数值压缩到(-1,1)或者(0,1)之间的有限域中。如果这个激活函数不做任何变换,则被称为Identity或者线性激活函数。激活函数的主要作用是为隐含层引入非线性。一个只有线性关系隐含层的多层神经网络不会比一般的只包含输入层和输出层的两层神经网络更加强大,因为线性函数的函数仍然是一个线性函数。但是加入非线性以后,多层神经网络的预测能力就得到了显著提高。

对于后向传播算法,激活函数必须可微,而且如果这个函数是在有限域中的话,则效果更好,因此像logistic、tanh、高斯函数等都是比较常见的选择,这类函数也被统称为sigmoid函数。

早期的理论认为sigmoid激活函数通常比threshold激活函数(比如ReLU等激活函数)好。

梯度消亡指的是梯度(误差的信号)随着隐藏层数的增加成指数减小。这是因为在后向传播算法中,对梯度的计算使用链式法则,因此在第n层时需要将前面各层的梯度都相乘,但是由于sigmoid函数的值域在(-1,1)或者(0,1)之间,因此多个很小的数相乘以后第n层的梯度就会接近于0,造成模型训练的困难。

对于输出层,读者应该尽量选择适合因变量分布的激活函数。对于只有0,1取值的双值因变量,logistic函数是一个较好的选择。对于有多个取值的离散因变量,比如0到9数字的识别,softmax激活函数是logistic激活函数的自然衍生。对于有有限值域的连续因变量,logistic或者tanh激活函数都可以用,但是需要将因变量的值域伸缩到logistic或者tanh对应的值域中。如果因变量取值为正,但是没有上限,那么指数函数是一个较好的选择。如果因变量没有有限值域,或者虽然是有限值域但是边界未知,那么最好采用线性函数作为激活函数。

模型输出值p和真实值y之间的差异一般被称为残差或者误差,但是这个值并不能直接用来衡量模型的质量。当一个模型完美的时候(虽然这不可能出现),其误差为0,而当一个模型不够完美的时候,其误差不论为负值还是正值,都偏离0;因此衡量模型质量的是误差偏离0的相对值,即误差函数的值越接近于0,模型的性能越好,反之则模型的性能越差。误差函数也被称为损失函数。常用的误差函数如下。

交叉熵可以被解释为映射到最可能的类别的概率的对数。因此,当预测值的分布和实际因变量的分布尽可能一致时,交叉熵最小。

目标函数是需要在训练阶段直接最小化的那个函数。

批量,即Batch,是深度学习中的一个重要概念。批量通常指两个不同的概念——如果对应的是模型训练方法,那么批量指的是将所有数据处理完以后一次性更新权重或者参数的估计;如果对应的是模型训练中的数据,那么批量通常指的是一次输入供模型计算用的数据量。这两个概念有着紧密的关系。

在离线学习中,所有的数据都可以被反复获取,比如上面的批量学习就是离线学习的一种。而在在线学习中,每个观测值在处理以后会被遗弃,同时参数得到更新。

离线学习有如下几个优点。对于任何固定个数的参数,目标函数都可以直接被计算出来,因此很容易验证模型训练是否在朝着所需要的方向发展。计算精度可以达到任意合理的程度。可以使用各种不同的算法来避免出现局部最优的情况。可以采用训练、验证、测试三分法对模型的普适度进行验证。可以计算预测值及其置信区间。

在深度学习中,采用sigmoid激活函数的隐藏层或者输出层的神经元通常在计算网络输入时加入一个偏移值,称为Bias。对于线性输出神经元,偏移项就是回归中的截距项。

三个常见的“标准化”数据处理动作。(1)重放缩(Rescaling):通常指将一个向量加上或者减去一个常量,再乘以或者除以一个常量。比如将华氏温度转换为摄氏温度就是一个重放缩的过程。(2)规范化(Normalization):通常指将一个向量除以其范数,比如采用欧式空间距离,则用向量的方差作为范数来规范化向量。在深度学习中,规范化通常采用极差为范数,即将向量减去最小值,并除以其极差,从而使数值范围在0到1之间。(3)标准化(Standardization):通常指将一个向量移除其位置和规模的度量。比如一个服从正态分布的向量,可以减去其均值,并除以其方差来标准化数据,从而获得一个服从标准正态分布的向量。

4Keras入门

Keras针对几种常见的输入深度学习模型和输入数据形态,提供了几个易于使用的工具来处理数据,包括针对序列模型的数据预处理、针对文字输入的数据处理,以及针对图片输入的数据处理。所有函数都在Keras.preprocessing这个库里面,分别有text、sequence和image三个子库。

在文字的建模实践中,一般都需要把原始文字拆解成单字、单词或者词组,然后将这些拆分后的要素进行索引、标记化供机器学习算法使用。这种预处理叫作标注(Tokenize)。

对于已经读入的文字的预处理包含以下几个步骤。(1)文字拆分。(2)建立索引。(3)序列补齐(Padding)。(4)转换为矩阵。(5)使用标注类批量处理文本文件。所有跟文字相关的预处理函数都在Keras.preprocessing.text这个子库里。但是这是为英文文字设计的,如果是处理中文,因为中英文的差异,建议使用结巴分词里提供的切分函数cut来进行文字拆分。

根据结巴分词的介绍,其使用了如下算法来进行中文分词。基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图(DAG)。采用动态规划查找最大概率路径,找出基于词频的最大切分组合。对于未登录词,采用了基于汉字成词能力的HMM模型,使用Viterbi算法。

完成分词以后,得到的单字或者单词并不能直接用于建模,还需要将它们转换成数字序号,才能进行后续处理。这就是建立索引。建立索引的方法很简单,对于拆分出来的每一个单字或者单词,排序之后编号即可。

建立索引也可以使用OneHot编码法,即对于K个不同的单字或者单词,依次设定一个1到K之间的数值来索引这K个单字或者单词构成的词汇表。

一般要将大量不同的数据映射到一个有限空间中,通常采用的方法都是哈希表,one_hot函数也不例外。

最终索引之后的文字信息会被按照索引编号放入多维矩阵中用来建模。这个多维矩阵的行宽对应于所有拆分后的单字或者单词,但是在将索引放入矩阵中之前,需要先进行序列补齐的工作。这是因为将一段话拆分成单一的词以后,丢失了重要的上下文信息,因此将上下文的一组词放在一起建模能保持原来的上下文信息,从而提高建模的质量。

序列补齐分两种情况。

第一种情况是自然的文本序列,比如微博或者推特上的一段话,都是一个自然的单字或者单词序列,而待建模的数据是由很多微博或者推特组成的,或者对一组文章进行建模,每篇文章中的每一句话构成一个文本序列。这个时候每句话的长度不一,需要进行补齐为统一长度。第二种情况是将一个由K个(K较大)具备一定顺序的单词串拆分成小块的连续子串,每个子串只有M个(M<K)单词。

所有的建模都只能使用多维矩阵,因此最后必须将索引过的文字元素转换成可以用于建模的矩阵。Keras提供了两种方法。第一种方法是使用pad_sequences函数。

第二种方法是使用下面将要介绍的标注类来进行。

当批量处理文本文件时,需要一种更高效的方法。Keras提供了一个标注类(Tokenizerclass)来进行文本处理。

另外一种对序列数据的处理方法叫作跳跃语法(SkipGram)模型。这是TomasMikolov在2013年提出的单词表述(WordRepresentation)模型,它把每个单词映射到一个M维的空间,它有一个更著名的别名,即Word2Vec。

在Keras的预处理模块中有一个skipgrams的函数,将一个词向量索引标号按照两种可选方式转化为一系列两两元素的组合(w1,w2)和标注z。如果w2跟w1是紧挨着的,则标注z为1,为正样本;如果w2是从不相邻的其他元素中随机抽取的,则标注z为负样本。

Keras为图片数据的输入提供了一个很好的接口,即Keras.preprocessing.image.ImageDataGenerator类。这个类生成一个数据生成器(Generator)对象,依照循环批量产生对应于图像信息的多维矩阵。

在Keras中设定了两类深度学习模型:一类是序列模型(Sequential类);一类是通用模型(Model类)。

通用模型可以用来设计非常复杂、任意拓扑结构的神经网络,例如有向无环网络、共享层网络等。类似于序列模型,通用模型通过函数化的应用接口来定义模型。

对于序列模型和通用模型,它们的主要差异在于如何定义从输入层到输出层的各层结构。首先,在序列模型里,是先定义序列模型对象的;而在通用模型中是先定义从输入层到输出层各层要素的,包括尺寸结构。其次,在序列模型中,当有了一个模型对象以后,可以通过add方法对其依次添加各层信息,包括激活函数和网络尺寸来定义整个神经网络;而在通用模型中,是通过不停地封装含有各层网络结构的函数作为参数来定义网络结构的。最后,在序列模型中,各层只能依次线性添加;而在通用模型中,因为采用了封装的概念,可以在原有的网络结构上应用新的结构来快速生成新的模型,因此灵活度要高很多,特别是在具有多种类型的输入数据的情况下,比如在Keras手册中就举了一个教神经网络看视频进行自然语言问答的例子。在这个例子中,输入数据有两种:一是视频图像;二是自然语言的提问。首先通过构造多层卷积神经网络使用序列模型来对图像编码,然后将这个模型放入TimeDistributed函数中建立视频编码,最后使用LSTM对编码建模,同时对自然语言也进行从文字到向量的转换,在合并两个网络以后,将合并的网络作为参数输入下一个全连接层进行计算,并输出可能的回答。

Keras预先定义了很多对象用于帮助构造Keras的网络结构,比如常用的激活函数、参数初始化方法、正则化方法等。

选择。Keras提供了大量预定义好的激活函数,方便定制各种不同的网络结构。在Keras中使用激活对象有两种方法:一是单独定义一个激活层;二是在前置层里面通过激活选项来定义所需的激活函数。

初始化对象(Initializer)用于随机设定网络层激活函数中的权重值或者偏置项的初始值,包括kernel_initializer和bias_initializer。好的权重初始化值能帮助加快模型收敛速度。Keras预先定义了很多不同的初始化对象,包括:Zeros,将所有参数值都初始化为0。Ones,将所有参数值都初始化为1。Constant(value=1),将所有参数值都初始化为某一个常量,比如这里设置为1。RandomNormal,将所有参数值都按照一个正态分布所生成的随机数来初始化。正态分布的均值默认为0,而标准差默认为0.05。可以通过mean和stddev选项来修改。TruncatedNormal,使用一个截断正态分布生成的随机数来初始化参数向量,默认参数均值为0,标准差为0.05。对于均值的两个标准差之外的随机数会被遗弃并重新取样。这种初始化方法既有一定的多样性,又不会产生特别偏的值,因此是比较推荐的方法。针对不同的常用分布选项,Keras还提供了两个基于这种方法的特例,即glorot_normal和he_normal。前者的标准差不再是0.05,而是输入向量和输出向量的维度的函数:其中n1是输入向量的维度,而n2是输出向量的维度;后者的标准差只是输入向量的维度的函数:RandomUniform,按照均匀分布所生成的随机数来初始化参数值,默认的分布参数最小值为-0.05,最大值为0.05,可以通过minval和maxval选项分别修改。针对常用的分布选项,Keras还提供了两个基于这个分布的特例即glorot_uniform和he_uniform。前者均匀分布的上下限是输入向量和输出向量的维度的函数:而在后者上下限只是输入向量的维度的函数:自定义,用户可以自定义一个与参数维度相符合的初始化函数。下面的例子来自于Keras手册,使用后台的正态分布函数生成一组初始值,在定义网络层的时候调用这个函数即可。

在建模的时候,正则化是防止过度拟合的一个很常用的手段。在神经网络中也提供了正则化的手段,分别应用于权重参数、偏置项以及激活函数,对应的选项分别是kernel_regularizer、bias_reuglarizier和activity_regularizer。它们都可以应用Keras.regularizier.Regularizer对象,这个对象提供了定义好的一阶、二阶和混合的正则化方法,分别将前面的Regularizier替换为l1(x)、l2(x)和l1_l2(x1,x2),其中x或者x1,x2为非负实数,表明正则化的权重。

核心层(CoreLayer)是构成神经网络最常用的网络层的集合,包括:全连接层、激活层、放弃层、扁平化层、重构层、排列层、向量反复层、Lambda层、激活值正则化层、掩盖层。所有的层都包含一个输入端和一个输出端,中间包含激活函数以及其他相关参数等。(1)全连接层。在神经网络中最常见的网络层就是全连接层,在这个层中实现对神经网络里面的神经元的激活。

(2)激活层。激活层是对上一层的输出应用激活函数的网络层,这是除应用activation选项之外,另一种指定激活函数的方式。其用法很简单,只要在参数中指明所需的激活函数即可,预先定义好的函数直接引用其名字的字符串,或者使用TensorFlow和Theano自带的激活函数。

(3)放弃层。放弃层(Dropout)是对该层的输入向量应用放弃策略。在模型训练更新参数的步骤中,网络的某些隐含层节点按照一定比例随机设置为不更新状态,但是权重仍然保留,从而防止过度拟合。

(4)扁平化层。扁化层(Flatten)是将一个维度大于或等于3的高维矩阵按照设定“压扁”为一个二维的低维矩阵。

(5)重构层。重构层(Reshape)的功能和Numpy的Reshape方法一样,将一定维度的多维矩阵重新排列构造为一个新的保持同样元素数量但是不同维度尺寸的矩阵。

(6)排列层。排列层(Permute)按照给定的模式来排列输入向量的维度。这个方法在连接卷积网络和时间递归网络的时候非常有用。其参数是输入矩阵的维度编号在输出矩阵中的位置。

(7)向量反复层。顾名思义,向量反复层就是将输入矩阵重复多次。

(8)Lambda层。Lambda层可以将任意表达式包装成一个网络层对象。参数就是表达式,一般是一个函数,可以是一个自定义函数,也可以是任意已有的函数。

(9)激活值正则化层。这个网络层的作用是对输入的损失函数更新正则化。(10)掩盖层。该网络层主要使用在跟时间有关的模型中,比如LSTM。其作用是输入张量的时间步,在给定位置使用指定的数值进行“屏蔽”,用以定位需要跳过的时间步。

针对常见的卷积操作,Keras提供了相应的卷积层API,包括一维、二维和三维的卷积操作、切割操作、补零操作等。卷积在数学上被定义为作用于两个函数f和g上的操作来生成一个新的函数z。这个新的函数是原有两个函数的其中一个(比如f)在另一个(比如g)的值域上的积分或者加权平均。

卷积操作分为一维、二维和三维,对应的方法分别是Conv1D、Conv2D和Conv3D,这些方法有同样的选项,只是作用于不同维度的数据上,因此适用于不同的业务情景。

一维卷积通常被称为时域卷积,因为其主要应用在以时间排列的序列数据上,其使用卷积核对一维数据的邻近信号进行卷积操作来生成一个张量。二维卷积通常被称为空域卷积,一般应用在与图像相关的输入数据上,也是使用卷积核对输入数据进行卷积操作的。三维卷积也执行同样的操作。

Conv1D、Conv2D和Conv3D的选项几乎相同。filters:卷积滤子输出的维度,要求整数。kernel_size:卷积核的空域或时域窗长度。要求是整数或整数的列表,或者是元组。如果是单一整数,则应用于所有适用的维度。strides:卷积在宽或者高维度的步长。要求是整数或整数的列表,或者是元组。如果是单一整数,则应用于所有适用的维度。如果设定步长不为1,则dilation_rate选项的取值必须为1。padding:补齐策略,取值为valid、same或causal。causal将产生因果(膨胀的)卷积,即output[t]不依赖于input[t+1:],在不能违反时间顺序的时序信号建模时有用。请参考WaveNet:AGenerativeModelforRawAudio,section2.1.。valid代表只进行有效的卷积,即对边界数据不处理。same代表保留边界处的卷积结果,通常会导致输出shape与输入shape相同。data_format:数据格式,取值为channels_last或者channels_first。这个选项决定了数据维度次序,其中channels_last对应的数据维度次序是(批量数,高,宽,频道数),而channels_first对应的数据维度次序为(批量数,频道数,高,宽)。activation:激活函数,为预定义或者自定义的激活函数名,请参考前面的“网络层对象”部分的介绍。如果不指定该选项,将不会使用任何激活函数(即使用线性激活函数:a(x)=x)。dilation_rate:该选项指定扩张卷积(DilatedConvolution)中的扩张比例。要求为整数或由单个整数构成的列表/元组,如果dilation_rate不为1,则步长一项必须设为1。use_bias:指定是否使用偏置项,取值为True或者False。kernel_initializer:权重初始化方法,为预定义初始化方法名的字符串,或用于初始化权重的函数。请参考前面的“网络层对象”部分的介绍。bias_initializer:偏置初始化方法,为预定义初始化方法名的字符串,或用于初始化偏置的函数。请参考前面的“网络层对象”部分的介绍。kernel_regularizer:施加在权重上的正则项,请参考前面的关于网络层对象中正则项的介绍。bias_regularizer:施加在偏置项上的正则项,请参考前面的关于网络层对象中正则项的介绍。activity_regularizer:施加在输出上的正则项,请参考前面的关于网络层对象中正则项的介绍。kernel_constraints:施加在权重上的约束项,请参考前面的关于网络层对象中约束项的介绍。bias_constraints:施加在偏置项上的约束项,请参考前面的关于网络层对象中约束项的介绍。

除上面介绍的卷积层以外,还有一些特殊的卷积层,比如SeparableConv2D、Conv2DTranspose、UpSampling1D、UpSampling2D、UpSampling3D、ZeroPadding1D、ZeroPadding2D、ZeroPadding3D等,

池化(Pooling)是在卷积神经网络中对图像特征的一种处理,通常在卷积操作之后进行。池化的目的是为了计算特征在局部的充分统计量,从而降低总体的特征数量,防止过度拟合和减少计算量。

Keras的池化层按照计算的统计量分为最大统计量池化和平均统计量池化;按照维度分为一维、二维和三维池化层;按照统计量计算区域分为局部池化和全局池化。

(1)最大统计量池化方法:

(2)平均统计量池化方法:这个方法的选项和数据格式要求跟最大化统计量池化方法一样,只是池化方法使用局部平均值而不是局部最大值作为充分统计量,

(3)全局池化方法:该方法应用全部特征维度的统计量来代表特征,因此会压缩数据维度。

在局部池化方法中,输出维度和输入维度是一样的,只是特征的维度尺寸因为池化变小;但是在全局池化方法中,输出维度小于输入维度,如在二维全局池化方法中输入维度为(样本数,频道数,行,列),全局池化以后行和列的维度都被压缩到全局统计量中,因此输出维度只有(样本数,频道数)二维。

循环层(RecurrentLayer)用来构造跟序列有关的神经网络。但是其本身是一个抽象类,无法实例化对象,在使用时应该使用LSTM,GRU和SimpleRNN三个子类来构造网络层。

简单循环层。SimpleRNN是循环层的一个子类,用来构造全连接的循环层,是循环网络最直接的应用,使用recurrent.SimipleRNN来调用。长短记忆层。LSTM是循环层的另一个子类,和简单循环层相比,其隐藏状态的权重网络稀疏。带记忆门的循环层(GRU)。

嵌入层(EmbeddingLayer)是使用在模型第一层的一个网络层,其目的是将所有索引标号映射到致密的低维向量中,

合并层是指将多个网络产生的张量通过一定方法合并在一起,

合并层支持不同的合并方法,包括:元素相加(merge.Add)、元素相乘(merge.Multiply)、元素取平均(merge.Average)、元素取最大(merge.Maximum)、叠加(merge.Concatenate)、矩阵相乘(merge.Dot)。

奇异值矩阵分解是一种基本的数学工具,被应用于大量的数据挖掘算法中,比较有名的有协同过滤(CollaborativeFiltering),PCA回归

矩阵分解的目的是解析矩阵的结构,提取重要信息,去除噪声,实现数据压缩等。比如在奇异值矩阵分解中,信息都集中在头几个特征向量中,使用这几个向量有可能较好地(即均方差尽可能小地)复原原来的矩阵,同时只需要保留较少的数据。

SVD基于以下线性代数定理:任何m×n的实数矩阵X可以表示为如下三个矩阵的乘积:m×r的酉矩阵U,被称为左特征向量矩阵;r×r的对角阵S,被称为特征值矩阵;r×n的酉矩阵VT,被称为右特征向量矩阵,其中r≤n。

5推荐系统

矩阵分解可以认为是一种信息压缩。这里有两种理解。第一种理解,用户和内容不是孤立的,用户喜好有相似性,内容也有相似性。压缩是把用户和内容数量化,压缩成k维的向量。

第二种理解,从深度学习的角度,用户表示输入层(UserRepresentation)通常用OneHot编码,这没问题,但是通过第一层全连接神经网络就可以到达隐藏层,就是所谓的嵌入层(EmbeddingLayer),也就是我们之前提到的向量压缩过程。

从机器学习的角度来说,模型是为了抓住数据的主要特征,去掉噪声。越复杂、越灵活的模型带来的噪声越多,降低维度则可以有效地避免过度拟合现象的出现。

一般批量大小为几百,迭代次数可以达到上百到几百范围。损失一般一开始会下降得比较快,随后慢慢下降。通常做法是等损失稳定下来后再结束训练会比较好。

训练数据拟合得好,只能说明算法本身是在做正确的优化事情,并不能说明模型在未知的数据集上是否是好的,也不能说明模型抓住了本质,排除了噪声。

交替最小二乘法的想法很简单,我们要解决的是分解矩阵M近似等于两个新矩阵A和B的乘积,限制条件是A、B的值不能太大,并且部分M的数据已知。类似于坐标下降法(CoordinateDescent)的想法,我们可以先固定A,这样求B就是一个最小二乘法的问题。类似的,得到了B以后固定B,再求A,循环迭代。如果最后A、B都收敛,即它们在两次迭代间的变换小于一个阈值时,就可以认为找到了问题的解。

宽深模型适用的场合是有多个特征,有些特征需要用交叉项特征合成(宽度模型),而有些特征需要进行高维抽象(深度模型)。宽深模型很好地结合了宽度模型和深度模型,同时具有记忆性和普适性,从而提高准确率。

协同过滤的含义是,利用众人的数据协助推断。一个经典的例子是,很多人买了牛奶的同时都买了面包,已知你买了牛奶,那么给你推荐面包就是很自然的事情。在实际数据上,这种方法效果一般,原因是类似于亚马逊等网站的商品太多了,用户之间很少能找到有很多重复的商品项,所以相似用户的构造会不准确。因而类似的规则便有很多噪声。

因子分解机是谷歌研究科学家S.Rendle教授提出的。它是矩阵分解的推广,可以使用多维特征变量。

玻尔兹曼向量机是谷歌副总裁、深度学习的开山鼻祖GeoffreyHinton提出的。该模型建立了电影及其表征之间的概率联系。从用户的行为可以推断出用户对于电影表征的偏好的概率表示;反过来,这些电影表征的偏好又可以用来给用户推荐电影。这种概率联系是通过RBM模型学出来的。

评判模型一般有两种指标:线上和线下。

线上需要设计实验,基于一定的随机规则对用户、设备或者浏览器Cookie进行分组,然后设定一些指标,观察这些指标在实验期运用新模型是否比旧模型好。

线上指标的优点是快速和因果关系明确;缺点是无法测试对长期目标的影响,并且容易不太稳定,受比如新奇效果(NoveltyEffect)或者实验渗透率的影响。

通常的做法是,在线下建模型的时候,用线下指标给出一个最好的模型。然后,把这个新模型和现有的在线模型拿到线上去,进行数据收集和统计分析,利用短期指标给出是否要推广新模型的结论。

在推荐系统中,评分类的数据一般用均方差(MeanSquaredError)作为评判标准;而对于隐含回馈数据,一般用基于信息检索的概念中的精确率(推荐10部电影,用户看了几部)和召回率(用户感兴趣的5部电影,是否都在推荐列表里)作为最常用的指标。

6图像识别

卷积神经网络(见图6.3)是一种自动化特征提取的机器学习模型。

神经网络就是建立了这样一个映射关系,或者称为函数。它通过建立网状结构,辅以矩阵的加、乘等运算,最后输出每个图像属于每个类别的概率,并且取概率最高的作为我们的决策依据。

用深度学习解决图像识别的问题,从直观上讲,是一个从细节到抽象的过程。

抽象就是把图像中的各种零散的特征通过某种方式汇总起来,形成新的特征,而利用这些新的特征更容易区分图像的类别。

深度神经网络最上层的特征是最抽象的。

后向传播算法的本质是高等代数里的链式法则。其原理就是机器不断通过现有参数在批量数据上所得到的标注和这些批量数据的真实标注的差距,给网络指示怎么调整网络模型和过滤器,即各种参数,从而在下一次批量数据上表现更好一些。下一次批量数据经过调整后的模型可能仍有很大的误差,网络会提示怎么进一步调整模型的权重和过滤器。这样不断反复,最终等过滤器和网络权重稳定下来,网络的训练就完成了。

卷积神经网络是深度学习的一种模型。它和一般的深度学习模型的主要区别是对模型有两个强假设。一般的深度学习模型只是假设模型有几层,每层有几个节点,然后把上下层之间的节点全部连接起来,这种模型的优点是灵活,缺点是灵活带来的副作用,即过度拟合。

过滤器一般需要的参数比较少,比如5×5×3的过滤器需要75个参数就可以了。这和多层神经网络相比,相当于我们只是把隐含层和局部输入联系在一起,而这两层之间的权重只需要75个参数。其他超过这个局部范围的区域的网络权重都是0。

第二个是局部像素的相关性,即局部区域的像素值一般差的不太多。基于此衍生了一种处理技术——MaxPooling,即在局部,比如在224×224的格子里,取局部区域像素值的最大值。

从另一个角度看,任何一个卷积神经网络其实都是通过对整个神经网络权重附加参数共享这一限制而实现的。所以卷积神经网络和全连接神经网络是可以相互转换的。

一般一个卷积层包括3个部分:卷积步骤、非线性变化(一般是relu、tanh、sigmoid等)和MaxPooling。有的网络还包括了Dropout这一步。总结来说,一些流行的卷积神经网络,比如LeNet、VGG16等,都是通过构造多层的卷积层,使得原来“矮胖”型的图像输入层(224×224×3)立体,变成比如1×1×4096之类的“瘦长”型立体,最后做一个单层的网络,把“瘦长”型立体和输出层(类别)联系在一起。

在局部扫描的过程中,有一个参数叫步长,就是指过滤器以多大的跨度上下或左右平移地扫描。

对于经由过滤器局部扫描后的卷积层图像,由于处理边界不同,一般有两种处理方式。一种是在局部扫描过程中对图像边界以外的一层或多层填上0,平移的时候可以将其移出边界到达0的区域。这样的好处是在以1为步长的局部扫描完以后,所得的新图像和原图像长宽一致,被称作zeropadding(samepadding)。另一种是不对边界外做任何0的假定,所有平移都在边界内,被称作validpadding,使用这种方式通常扫描完的图像尺寸会比原来的小。

7自然语言情感分析

进行情感分析有如下难点:第一,文字非结构化,有长有短,很难适合经典的机器学习分类模型。第二,特征不容易提取。文字可能是谈论这个主题的,也可能是谈论人物、商品或事件的。人工提取特征耗费的精力太大,效果也不好。第三,词与词之间有联系,把这部分信息纳入模型中也不容易。

深度学习适合做文字处理和语义理解,是因为深度学习结构灵活,其底层利用词嵌入技术可以避免文字长短不均带来的处理困难。使用深度学习抽象特征,可以避免大量人工提取特征的工作。深度学习可以模拟词与词之间的联系,有局部特征抽象化和记忆功能。

第一,文字分词。英语分词可以按照空格分词,中文分词可以参考jieba。第二,建立字典,给每个词标号。第三,把段落按字典翻译成数字,变成一个array。

为了克服文字长短不均和将词与词之间的联系纳入模型中的困难,人们使用了一种技术——词嵌入。简单说来,就是给每个词赋一个向量,向量代表空间里的点,含义接近的词,其向量也接近,这样对于词的操作就可以转化为对于向量的操作了,在深度学习中,这被叫作张量(tensor)。

从优化的角度讲,深度学习网络还有其他一些梯度下降优化方法,比如Adagrad等。它们的本质都是解决在调整神经网络模型过程中如何控制学习速度的问题。

8文字生成

基于深度学习的检索式对话系统在后两点上有较大的改进。通过机器学习,可以实现软匹配,不需要询问语句模式一定要在库里出现,如果通过对词汇和其组织顺序的建模发现有较高概率匹配的数据点,就能实现比较好的回应。其次,深度学习方法提供了更高的灵活性,能够实现记忆和识别等功能。