⑴ sc-RNA-seq | dropout 的由来以及处理办法
cell-gene矩阵中的零 可能真的是未表达的也可能是由于一些原因未检测到 ,就是零有两种可能,而不同的解释对结果是有影响的。
一般的处理思路有俩:
提出问题的人在某种程度上有责任提出解决办法,或者建议。所以开发了R包,由于只能做聚类就显得有些小众了。
用于单细胞RNA-seq(scRNA-seq)数据的大多数现有降维和聚类包通过heavy modeling和computational machinery 来处理dropouts.
CIDR,一种隐式的插补方法(imputation),减轻scRNA-seq数据中dropout的影响。
CIDR改进了标准主成分分析,并且在聚类精度方面优于最先进的方法,即t-SNE,ZIFA和RaceID。
CIDR通常在几秒钟内完成处理数百个cell的数据集,几分钟内完成处理数千个cell的数据集。
Missing data and technical variability in single-cell RNA-sequencing experiments
github|CIDR
CIDR: Ultrafast and accurate clustering through imputation for single-cell RNA-seq data
⑵ BN和Dropout在训练和测试时的差别
From: https://zhuanlan.hu.com/p/61725100
BN,Batch Normalization,就是在深度神经网络训练过程中使得每一层神经网络的输入保持相近的分布。
BN训练和测试时的参数是一样的嘛?
对于BN,在训练时,是对每一批的训练数据进行归一化,也即用每一批数据的均值和方差。
而在测试时,比如进行一个样本的预测,就并没有batch的概念,因此,这个时候用的均值和方差是全量训练数据的均值和方差,这个可以通过移动平均法求得。
对于BN,当一个模型训练完成之后,它的所有参数都确定了,包括均值和方差,gamma和bata。
BN训练时为什么不用全量训练集的均值和方差呢?
因为在训练的第一个完整epoch过程中是无法得到输入层之外其他层全量训练集的均值和方差,只能在前向传播过程中获取已训练batch的均值和方差。那在一个完整epoch之后可以使用全量数据集的均值和方差嘛?
对于BN,是对每一批数据进行归一化到一个相同的分布,而每一批数据的均值和方差会有一定的差别,而不是用固定的值,这个差别实际上也能够增加模型的鲁棒性,也会在一定程度上减少过拟合。
但是一批数据和全量数据的均值和方差相差太多,又无法较好地代表训练集的分布,因此,BN一般要求将训练集完全打乱,并用一个较大的batch值,去缩小与全量数据的差别。
Dropout 是在训练过程中以一定的概率的使神经元失活,即输出为0,以提高模型的泛化能力,减少过拟合。
Dropout 在训练和测试时都需要嘛?
Dropout 在训练时采用,是为了减少神经元对部分上层神经元的依赖,类似将多个不同网络结构的模型集成起来,减少过拟合的风险。
而在测试时,应该用整个训练好的模型,因此不需要dropout。
Dropout 如何平衡训练和测试时的差异呢?
Dropout ,在训练时以一定的概率使神经元失活,实际上就是让对应神经元的输出为0
假设失活概率为 p ,就是这一层中的每个神经元都有p的概率失活,如下图的三层网络结构中,如果失活概率为0.5,则平均每一次训练有3个神经元失活,所以输出层每个神经元只有3个输入,而实际测试时是不会有dropout的,输出层每个神经元都有6个输入,这样在训练和测试时,输出层每个神经元的输入和的期望会有量级上的差异。
因此在训练时还要对第二层的输出数据除以(1-p)之后再传给输出层神经元,作为神经元失活的补偿,以使得在训练时和测试时每一层输入有大致相同的期望。
dropout部分参考: https://blog.csdn.net/program_developer/article/details/80737724
BN和Dropout单独使用都能减少过拟合并加速训练速度,但如果一起使用的话并不会产生1+1>2的效果,相反可能会得到比单独使用更差的效果。
相关的研究参考论文: Understanding the Disharmony between Dropout and Batch Normalization by Variance Shift
本论文作者发现理解 Dropout 与 BN 之间冲突的关键是网络状态切换过程中存在神经方差的(neural variance)不一致行为。试想若有图一中的神经响应 X,当网络从训练转为测试时,Dropout 可以通过其随机失活保留率(即 p)来缩放响应,并在学习中改变神经元的方差,而 BN 仍然维持 X 的统计滑动方差。这种方差不匹配可能导致数值不稳定(见下图中的红色曲线)。而随着网络越来越深,最终预测的数值偏差可能会累计,从而降低系统的性能。简单起见,作者们将这一现象命名为「方差偏移」。事实上,如果没有 Dropout,那么实际前馈中的神经元方差将与 BN 所累计的滑动方差非常接近(见下图中的蓝色曲线),这也保证了其较高的测试准确率。
作者采用了两种策略来探索如何打破这种局限。一个是在所有 BN 层后使用 Dropout,另一个就是修改 Dropout 的公式让它对方差并不那么敏感,就是高斯Dropout。
第一个方案比较简单,把Dropout放在所有BN层的后面就可以了,这样就不会产生方差偏移的问题,但实则有逃避问题的感觉。
第二个方案来自Dropout原文里提到的一种高斯Dropout,是对Dropout形式的一种拓展。作者进一步拓展了高斯Dropout,提出了一个均匀分布Dropout,这样做带来了一个好处就是这个形式的Dropout(又称为“Uout”)对方差的偏移的敏感度降低了,总得来说就是整体方差偏地没有那么厉害了。
⑶ 谈谈Tensorflow的dropout
Dropout这个概念已经推出4年了,它的详细描述见 论文 。可是呢,它仿佛是个犹抱琵琶半遮面的美女,难以捉摸!!许多文献都对dropout有过描述,但解释的含糊不清,这里呢,我也不打算解释清楚,只是通过tensorflow来看一看dropout的运行机理。
文章分两部分,第一部分介绍tensorflow中的dropout函数,第二部分是我的思考
首先看官方函数定义:
输入是:
输出是:
然后我们看看官方API是怎么说这个函数的:
注意,输出的非0元素是原来的 “1/keep_prob” 倍!说了这么多,下面给一个程序例子:
运行的结果如下:
分析一下运行结果:
特点分析完毕,小总结一下,dropout这个概念看起来好高大上,然而在程序中实现竟然如此简单!说白了,tensorflow中的dropout就是: 使输入tensor中某些元素变为0,其它没变0的元素变为原来的1/keep_prob大小 !
首先引用此篇 博文 的话:
然后,我就自己试了试,看看小型网络中dropout效果到底怎么样,程序片段如下:
网络很简单,形如 784-30-10 的一个网络,只不过在输出层前用dropout处理了一下,训练的数据是MNIST的手写数据集,然后你猜怎么着?采用dropout以后的训练精度 不升反降 ,后来我把网络隐藏层改成100个神经元,结果依旧,看来,我的网络还是太小了,真的如上面那篇博客所说,dropout用不好的话,真是个累赘!
⑷ 如何理解dropout
开篇明义,dropout是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。注意是暂时,对于随机梯度下降来说,由于是随机丢弃,故而每一个mini-batch都在训练不同的网络。
dropout是CNN中防止过拟合提高效果的一个大杀器,但对于其为何有效,却众说纷纭。在下读到两篇代表性的论文,代表两种不同的观点,特此分享给大家。
组合派
参考文献中第一篇中的观点,Hinton老大爷提出来的,关于Hinton在深度学习界的地位我就不再赘述了,光是这地位,估计这一派的观点就是“武当少林”了。注意,派名是我自己起的,各位勿笑。
观点
该论文从神经网络的难题出发,一步一步引出dropout为何有效的解释。大规模的神经网络有两个缺点:
费时
容易过拟合
这两个缺点真是抱在深度学习大腿上的两个大包袱,一左一右,相得益彰,额不,臭气相投。过拟合是很多机器学习的通病,过拟合了,得到的模型基本就废了。而为了解决过拟合问题,一般会采用ensemble方法,即训练多个模型做组合,此时,费时就成为一个大问题,不仅训练起来费时,测试起来多个模型也很费时。总之,几乎形成了一个死锁。
Dropout的出现很好的可以解决这个问题,每次做完dropout,相当于从原始的网络中找到一个更瘦的网络,如下图所示:
因而,对于一个有N个节点的神经网络,有了dropout后,就可以看做是2n个模型的集合了,但此时要训练的参数数目却是不变的,这就解脱了费时的问题。
动机论
⑸ ReLU和Dropout
从解决最小的问题开始。
ReLU家族的激活函数通常是神经网络中激活函数的首选项,其优点在于:
Dropout是一种有效的防止过拟合的方法,该方法的实质是在一次前向传播过程中,随机地丢弃(使失活)网络中的某些神经元。所谓的丢弃神经元,其实是在数据流过每个神经元时,都额外的乘上一个概率p,p的值为0时,当前神经元即被丢弃。随机丢弃神经元的意义在于 使网络不依赖与某一个神经元或某一种神经元组合 ,因为每次随机丢弃都会使网络产生新的结构。
Dropout通常用于神经网络的全连接层,因为在卷积层、池化层等部分网络已经是稀疏的,并且具有完备的理论解释(权重共享、感受野等),而全连接层是稠密的,使用Dropout减少参数量能有效地改变其泛化能力。下面是使用tensorflow(v1)的一个简单示例:
⑹ 卷积神经网络
关于花书中卷积网络的笔记记录于 https://www.jianshu.com/p/5a3c90ea0807 。
卷积神经网络(Convolutional Neural Network,CNN或ConvNet)是一种具有 局部连接、权重共享 等特性的深层前馈神经网络。卷积神经网络是受生物学上感受野的机制而提出。 感受野(Receptive Field) 主要是指听觉、视觉等神经系统中一些神经元的特性,即 神经元只接受其所支配的刺激区域内的信号 。
卷积神经网络最早是主要用来处理图像信息。如果用全连接前馈网络来处理图像时,会存在以下两个问题:
目前的卷积神经网络一般是由卷积层、汇聚层和全连接层交叉堆叠而成的前馈神经网络,使用反向传播算法进行训练。 卷积神经网络有三个结构上的特性:局部连接,权重共享以及汇聚 。这些特性使卷积神经网络具有一定程度上的平移、缩放和旋转不变性。
卷积(Convolution)是分析数学中一种重要的运算。在信号处理或图像处理中,经常使用一维或二维卷积。
一维卷积经常用在信号处理中,用于计算信号的延迟累积。假设一个信号发生器每个时刻t 产生一个信号 ,其信息的衰减率为 ,即在 个时间步长后,信息为原来的 倍。假设 ,那么在时刻t收到的信号 为当前时刻产生的信息和以前时刻延迟信息的叠加:
我们把 称为 滤波器(Filter)或卷积核(Convolution Kernel) 。假设滤波器长度为 ,它和一个信号序列 的卷积为:
信号序列 和滤波器 的卷积定义为:
一般情况下滤波器的长度 远小于信号序列长度 ,下图给出一个一维卷积示例,滤波器为 :
二维卷积经常用在图像处理中。因为图像为一个两维结构,所以需要将一维卷积进行扩展。给定一个图像 和滤波器 ,其卷积为:
下图给出一个二维卷积示例:
注意这里的卷积运算并不是在图像中框定卷积核大小的方框并将各像素值与卷积核各个元素相乘并加和,而是先把卷积核旋转180度,再做上述运算。
在图像处理中,卷积经常作为特征提取的有效方法。一幅图像在经过卷积操作后得到结果称为 特征映射(Feature Map) 。
最上面的滤波器是常用的高斯滤波器,可以用来对图像进行 平滑去噪 ;中间和最下面的过滤器可以用来 提取边缘特征 。
在机器学习和图像处理领域,卷积的主要功能是在一个图像(或某种特征)上滑动一个卷积核(即滤波器),通过卷积操作得到一组新的特征。在计算卷积的过程中,需要进行卷积核翻转(即上文提到的旋转180度)。 在具体实现上,一般会以互相关操作来代替卷积,从而会减少一些不必要的操作或开销。
互相关(Cross-Correlation)是一个衡量两个序列相关性的函数,通常是用滑动窗口的点积计算来实现 。给定一个图像 和卷积核 ,它们的互相关为:
互相关和卷积的区别仅在于卷积核是否进行翻转。因此互相关也可以称为不翻转卷积 。当卷积核是可学习的参数时,卷积和互相关是等价的。因此,为了实现上(或描述上)的方便起见,我们用互相关来代替卷积。事实上,很多深度学习工具中卷积操作其实都是互相关操作。
在卷积的标准定义基础上,还可以引入滤波器的 滑动步长 和 零填充 来增加卷积多样性,更灵活地进行特征抽取。
滤波器的步长(Stride)是指滤波器在滑动时的时间间隔。
零填充(Zero Padding)是在输入向量两端进行补零。
假设卷积层的输入神经元个数为 ,卷积大小为 ,步长为 ,神经元两端各填补 个零,那么该卷积层的神经元数量为 。
一般常用的卷积有以下三类:
因为卷积网络的训练也是基于反向传播算法,因此我们重点关注卷积的导数性质:
假设 。
, , 。函数 为一个标量函数。
则由 有:
可以看出, 关于 的偏导数为 和 的卷积 :
同理得到:
当 或 时, ,即相当于对 进行 的零填充。从而 关于 的偏导数为 和 的宽卷积 。
用互相关的“卷积”表示,即为(注意 宽卷积运算具有交换性性质 ):
在全连接前馈神经网络中,如果第 层有 个神经元,第 层有 个神经元,连接边有 个,也就是权重矩阵有 个参数。当 和 都很大时,权重矩阵的参数非常多,训练的效率会非常低。
如果采用卷积来代替全连接,第 层的净输入 为第 层活性值 和滤波器 的卷积,即:
根据卷积的定义,卷积层有两个很重要的性质:
由于局部连接和权重共享,卷积层的参数只有一个m维的权重 和1维的偏置 ,共 个参数。参数个数和神经元的数量无关。此外,第 层的神经元个数不是任意选择的,而是满足 。
卷积层的作用是提取一个局部区域的特征,不同的卷积核相当于不同的特征提取器。
特征映射(Feature Map)为一幅图像(或其它特征映射)在经过卷积提取到的特征,每个特征映射可以作为一类抽取的图像特征。 为了提高卷积网络的表示能力,可以在每一层使用多个不同的特征映射,以更好地表示图像的特征。
在输入层,特征映射就是图像本身。如果是灰度图像,就是有一个特征映射,深度 ;如果是彩色图像,分别有RGB三个颜色通道的特征映射,深度 。
不失一般性,假设一个卷积层的结构如下:
为了计算输出特征映射 ,用卷积核 分别对输入特征映射 进行卷积,然后将卷积结果相加,并加上一个标量偏置 得到卷积层的净输入 再经过非线性激活函数后得到输出特征映射 。
在输入为 ,输出为 的卷积层中,每个输出特征映射都需要 个滤波器以及一个偏置。假设每个滤波器的大小为 ,那么共需要 个参数。
汇聚层(Pooling Layer)也叫子采样层(Subsampling Layer),其作用是进行特征选择,降低特征数量,并从而减少参数数量。
常用的汇聚函数有两种:
其中 为区域 内每个神经元的激活值。
可以看出,汇聚层不但可以有效地减少神经元的数量,还可以使得网络对一些小的局部形态改变保持不变性,并拥有更大的感受野。
典型的汇聚层是将每个特征映射划分为 大小的不重叠区域,然后使用最大汇聚的方式进行下采样。汇聚层也可以看做是一个特殊的卷积层,卷积核大小为 ,步长为 ,卷积核为 函数或 函数。过大的采样区域会急剧减少神经元的数量,会造成过多的信息损失。
一个典型的卷积网络是由卷积层、汇聚层、全连接层交叉堆叠而成。
目前常用卷积网络结构如图所示,一个卷积块为连续 个卷积层和 个汇聚层( 通常设置为 , 为 或 )。一个卷积网络中可以堆叠 个连续的卷积块,然后在后面接着 个全连接层( 的取值区间比较大,比如 或者更大; 一般为 )。
目前,整个网络结构 趋向于使用更小的卷积核(比如 和 )以及更深的结构(比如层数大于50) 。此外,由于卷积的操作性越来越灵活(比如不同的步长),汇聚层的作用变得也越来越小,因此目前比较流行的卷积网络中, 汇聚层的比例也逐渐降低,趋向于全卷积网络 。
在全连接前馈神经网络中,梯度主要通过每一层的误差项 进行反向传播,并进一步计算每层参数的梯度。在卷积神经网络中,主要有两种不同功能的神经层:卷积层和汇聚层。而参数为卷积核以及偏置,因此 只需要计算卷积层中参数的梯度。
不失一般性,第 层为卷积层,第 层的输入特征映射为 ,通过卷积计算得到第 层的特征映射净输入 ,第 层的第 个特征映射净输入
由 得:
同理可得,损失函数关于第 层的第 个偏置 的偏导数为:
在卷积网络中,每层参数的梯度依赖其所在层的误差项 。
卷积层和汇聚层中,误差项的计算有所不同,因此我们分别计算其误差项。
第 层的第 个特征映射的误差项 的具体推导过程如下:
其中 为第 层使用的激活函数导数, 为上采样函数(upsampling),与汇聚层中使用的下采样操作刚好相反。如果下采样是最大汇聚(max pooling),误差项 中每个值会直接传递到上一层对应区域中的最大值所对应的神经元,该区域中其它神经元的误差项的都设为0。如果下采样是平均汇聚(meanpooling),误差项 中每个值会被平均分配到上一层对应区域中的所有神经元上。
第 层的第 个特征映射的误差项 的具体推导过程如下:
其中 为宽卷积。
LeNet-5虽然提出的时间比较早,但是是一个非常成功的神经网络模型。基于LeNet-5 的手写数字识别系统在90年代被美国很多银行使用,用来识别支票上面的手写数字。LeNet-5 的网络结构如图:
不计输入层,LeNet-5共有7层,每一层的结构为:
AlexNet是第一个现代深度卷积网络模型,其首次使用了很多现代深度卷积网络的一些技术方法,比如采用了ReLU作为非线性激活函数,使用Dropout防止过拟合,使用数据增强来提高模型准确率等。AlexNet 赢得了2012 年ImageNet 图像分类竞赛的冠军。
AlexNet的结构如图,包括5个卷积层、3个全连接层和1个softmax层。因为网络规模超出了当时的单个GPU的内存限制,AlexNet 将网络拆为两半,分别放在两个GPU上,GPU间只在某些层(比如第3层)进行通讯。
AlexNet的具体结构如下:
在卷积网络中,如何设置卷积层的卷积核大小是一个十分关键的问题。 在Inception网络中,一个卷积层包含多个不同大小的卷积操作,称为Inception模块。Inception网络是由有多个inception模块和少量的汇聚层堆叠而成 。
v1版本的Inception模块,采用了4组平行的特征抽取方式,分别为1×1、3× 3、5×5的卷积和3×3的最大汇聚。同时,为了提高计算效率,减少参数数量,Inception模块在进行3×3、5×5的卷积之前、3×3的最大汇聚之后,进行一次1×1的卷积来减少特征映射的深度。如果输入特征映射之间存在冗余信息, 1×1的卷积相当于先进行一次特征抽取 。
⑺ CNN之Lenet5
LeNet诞生于 1994 年,是最早的卷积神经网络之一,并且推动了深度学习领域的发展。
LeNet-5是Yann LeCun等人在多次研究后提出的最终卷积神经网络结构,主要用于手写数字识别
LeNet5的网络结构如下所示:
LeNet-5包含七层,不包括输入,每一层都包含可训练参数(权重),当时使用的输入数据是32*32像素的图像。下面逐层介绍LeNet-5的结构,并且,卷积层将用Cx表示,子采样层则被标记为Sx,全连接层被标记为Fx,其中x是层索引。
该层使用了6个卷积核,每个卷积核的大小为5×5,这样就得到了6个feature map(特征图)。
每个卷积核(5×5)与原始的输入图像(32×32)进行卷积,这样得到的feature map(特征图)大小为(32-5+1)×(32-5+1)= 28×28
卷积核与输入图像按卷积核大小逐个区域进行匹配计算,匹配后原始输入图像的尺寸将变小,因为边缘部分卷积核无法越出界,只能匹配一次,匹配计算后的尺寸变为Cr×Cc=(Ir-Kr+1)×(Ic-Kc+1),其中Cr、Cc,Ir、Ic,Kr、Kc分别表示卷积后结果图像、输入图像、卷积核的行列大小。
由于参数(权值)共享的原因,对于同个卷积核每个神经元均使用相同的参数,因此,参数个数为(5×5+1)×6= 156,其中5×5为卷积核参数,1为偏置参数
卷积后的图像大小为28×28,因此每个特征图有28×28个神经元,每个卷积核参数为(5×5+1)×6,因此,该层的连接数为(5×5+1)×6×28×28=122304
这一层主要是做池化或者特征映射(特征降维),池化单元为2×2,因此,6个特征图的大小经池化后即变为14×14。池化单元之间没有重叠,在池化区域内进行聚合统计后得到新的特征值,因此经2×2池化后,每两行两列重新算出一个特征值出来,相当于图像大小减半,因此卷积后的28×28图像经2×2池化后就变为14×14。
这一层的计算过程是:2×2 单元里的值相加,然后再乘以训练参数w,再加上一个偏置参数b(每一个特征图共享相同的w和b),然后取sigmoid值(S函数:0-1区间),作为对应的该单元的值。卷积操作与池化的示意图如下:
S2层由于每个特征图都共享相同的w和b这两个参数,因此需要2×6=12个参数
下采样之后的图像大小为14×14,因此S2层的每个特征图有14×14个神经元,每个池化单元连接数为2×2+1(1为偏置量),因此,该层的连接数为(2×2+1)×14×14×6 = 5880
C3层有16个卷积核,卷积模板大小为5×5。
与C1层的分析类似,C3层的特征图大小为(14-5+1)×(14-5+1)= 10×10
需要注意的是,C3与S2并不是全连接而是部分连接,有些是C3连接到S2三层、有些四层、甚至达到6层,通过这种方式提取更多特征,连接的规则如下表所示:
例如第一列表示C3层的第0个特征图(feature map)只跟S2层的第0、1和2这三个feature maps相连接,计算过程为:用3个卷积模板分别与S2层的3个feature maps进行卷积,然后将卷积的结果相加求和,再加上一个偏置,再取sigmoid得出卷积后对应的feature map了。其它列也是类似(有些是3个卷积模板,有些是4个,有些是6个)。因此,C3层的参数数目为(5×5×3+1)×6 +(5×5×4+1)×9 +5×5×6+1 = 1516
卷积后的特征图大小为10×10,参数数量为1516,因此连接数为1516×10×10= 151600
与S2的分析类似,池化单元大小为2×2,因此,该层与C3一样共有16个特征图,每个特征图的大小为5×5。
与S2的计算类似,所需要参数个数为16×2 = 32
连接数为(2×2+1)×5×5×16 = 2000
该层有120个卷积核,每个卷积核的大小仍为5×5,因此有120个特征图。由于S4层的大小为5×5,而该层的卷积核大小也是5×5,因此特征图大小为(5-5+1)×(5-5+1)= 1×1。这样该层就刚好变成了全连接,这只是巧合,如果原始输入的图像比较大,则该层就不是全连接了。
与前面的分析类似,本层的参数数目为120×(5×5×16+1) = 48120
由于该层的特征图大小刚好为1×1,因此连接数为48120×1×1=48120
F6层有84个单元,之所以选这个数字的原因是来自于输出层的设计,对应于一个7×12的比特图,如下图所示,-1表示白色,1表示黑色,这样每个符号的比特图的黑白色就对应于一个编码。
该层有84个特征图,特征图大小与C5一样都是1×1,与C5层全连接。
由于是全连接,参数数量为(120+1)×84=10164。跟经典神经网络一样,F6层计算输入向量和权重向量之间的点积,再加上一个偏置,然后将其传递给sigmoid函数得出结果。
由于是全连接,连接数与参数数量一样,也是10164。
Output层也是全连接层,共有10个节点,分别代表数字0到9。如果第i个节点的值为0,则表示网络识别的结果是数字i。
该层采用径向基函数(RBF)的网络连接方式,假设x是上一层的输入,y是RBF的输出,则RBF输出的计算方式是:
上式中的Wij的值由i的比特图编码确定,i从0到9,j取值从0到7×12-1。RBF输出的值越接近于0,表示当前网络输入的识别结果与字符i越接近。
由于是全连接,参数个数为84×10=840
由于是全连接,连接数与参数个数一样,也是840
from skimage import io,transform
import os
import glob
import numpy as np
import tensorflow as tf
#将所有的图片重新设置尺寸为32*32
w = 32
h = 32
c = 1
#mnist数据集中训练数据和测试数据保存地址
train_path = "E:/data/datasets/mnist/train/"
test_path = "E:/data/datasets/mnist/test/"
#读取图片及其标签函数
'''os.listdir()返回指定的文件夹包含的文件或文件夹的名字,存放于一个列表中;os.path.isdir()判断某一路径是否为目录
enumerate()将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,数据下标和相应数据'''
def read_image(path):
label_dir = [path+x for x in os.listdir(path) if os.path.isdir(path+x)]
images = []
labels = []
for index,folder in enumerate(label_dir):
for img in glob.glob(folder+'/*.png'):
print("reading the image:%s"%img)
image = io.imread(img)
image = transform.resize(image,(w,h,c))
images.append(image)
labels.append(index)
return np.asarray(images,dtype=np.float32),np.asarray(labels,dtype=np.int32)
#读取训练数据及测试数据
train_data,train_label = read_image(train_path)
test_data,test_label = read_image(test_path)
#打乱训练数据及测试数据 np.arange()返回一个有终点和起点的固定步长的排列,
train_image_num = len(train_data)
train_image_index = np.arange(train_image_num) ##起始点0,结束点train_image_num,步长1,返回类型array,一维
np.random.shuffle(train_image_index)
train_data = train_data[train_image_index]
train_label = train_label[train_image_index]
test_image_num = len(test_data)
test_image_index = np.arange(test_image_num)
np.random.shuffle(test_image_index)
test_data = test_data[test_image_index]
test_label = test_label[test_image_index]
#搭建CNN 此函数可以理解为形参,用于定义过程,在执行的时候再赋具体的值,形参名X,y_
x = tf.placeholder(tf.float32,[None,w,h,c],name='x')
y_ = tf.placeholder(tf.int32,[None],name='y_')
def inference(input_tensor,train,regularizer):
#第一层:卷积层,过滤器的尺寸为5×5,深度为6,不使用全0补充,步长为1。
#尺寸变化:32×32×1->28×28×6
'''参数的初始化:tf.truncated_normal_initializer()或者简写为tf.TruncatedNormal()、tf.RandomNormal() 去掉_initializer,大写首字母即可
生成截断正态分布的随机数,这个初始化方法好像在tf中用得比较多mean=0.0, stddev=1.0 正态分布
http://www.mamicode.com/info-detail-1835147.html'''
with tf.variable_scope('layer1-conv1'):
conv1_weights = tf.get_variable('weight',[5,5,c,6],initializer=tf.truncated_normal_initializer(stddev=0.1))
conv1_biases = tf.get_variable('bias',[6],initializer=tf.constant_initializer(0.0))
conv1 = tf.nn.conv2d(input_tensor,conv1_weights,strides=[1,1,1,1],padding='VALID')
relu1 = tf.nn.relu(tf.nn.bias_add(conv1,conv1_biases))
#第二层:池化层,过滤器的尺寸为2×2,使用全0补充,步长为2。
#尺寸变化:28×28×6->14×14×6
with tf.name_scope('layer2-pool1'):
pool1 = tf.nn.max_pool(relu1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
#第三层:卷积层,过滤器的尺寸为5×5,深度为16,不使用全0补充,步长为1。
#尺寸变化:14×14×6->10×10×16
with tf.variable_scope('layer3-conv2'):
conv2_weights = tf.get_variable('weight',[5,5,6,16],initializer=tf.truncated_normal_initializer(stddev=0.1))
conv2_biases = tf.get_variable('bias',[16],initializer=tf.constant_initializer(0.0))
conv2 = tf.nn.conv2d(pool1,conv2_weights,strides=[1,1,1,1],padding='VALID')
relu2 = tf.nn.relu(tf.nn.bias_add(conv2,conv2_biases))
#第四层:池化层,过滤器的尺寸为2×2,使用全0补充,步长为2。
#尺寸变化:10×10×6->5×5×16
with tf.variable_scope('layer4-pool2'):
pool2 = tf.nn.max_pool(relu2,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
#将第四层池化层的输出转化为第五层全连接层的输入格式。第四层的输出为5×5×16的矩阵,然而第五层全连接层需要的输入格式
#为向量,所以我们需要把代表每张图片的尺寸为5×5×16的矩阵拉直成一个长度为5×5×16的向量。
#举例说,每次训练64张图片,那么第四层池化层的输出的size为(64,5,5,16),拉直为向量,nodes=5×5×16=400,尺寸size变为(64,400)
pool_shape = pool2.get_shape().as_list()
nodes = pool_shape[1]*pool_shape[2]*pool_shape[3]
reshaped = tf.reshape(pool2,[-1,nodes])
#第五层:全连接层,nodes=5×5×16=400,400->120的全连接
#尺寸变化:比如一组训练样本为64,那么尺寸变化为64×400->64×120
#训练时,引入dropout,dropout在训练时会随机将部分节点的输出改为0,dropout可以避免过拟合问题。
#这和模型越简单越不容易过拟合思想一致,和正则化限制权重的大小,使得模型不能任意拟合训练数据中的随机噪声,以此达到避免过拟合思想一致。
#本文最后训练时没有采用dropout,dropout项传入参数设置成了False,因为训练和测试写在了一起没有分离,不过大家可以尝试。
'''tf.matmul()这个函数是专门矩阵或者tensor乘法,而不是矩阵元素对应元素相乘
tf.multiply()两个矩阵中对应元素各自相乘
tf.nn.dropout(x, keep_prob):TensorFlow里面为了防止或减轻过拟合而使用的函数,它一般用在全连接层,
x:指输入;keep_prob: 设置神经元被选中的概率,使输入tensor中某些元素变为0,其它没变0的元素变为原来的1/keep_prob大小,可以想象下,比如某些元素弃用
在初始化时keep_prob是一个占位符,keep_prob = tf.placeholder(tf.float32).
tensorflow在run时设置keep_prob具体的值,例如keep_prob: 0.5,train的时候才是dropout起作用的时候
keep_prob: A scalar Tensor with the same type as x. The probability that each element is kept.'''
with tf.variable_scope('layer5-fc1'):
fc1_weights = tf.get_variable('weight',[nodes,120],initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer != None:
tf.add_to_collection('losses',regularizer(fc1_weights))
fc1_biases = tf.get_variable('bias',[120],initializer=tf.constant_initializer(0.1))
fc1 = tf.nn.relu(tf.matmul(reshaped,fc1_weights) + fc1_biases)
if train:
fc1 = tf.nn.dropout(fc1,0.5)
#第六层:全连接层,120->84的全连接
#尺寸变化:比如一组训练样本为64,那么尺寸变化为64×120->64×84
'''tf.add_to_collection:把变量放入一个集合,把很多变量变成一个列表
tf.get_collection:从一个结合中取出全部变量,是一个列表
tf.add_n:把一个列表的东西都依次加起来'''
with tf.variable_scope('layer6-fc2'):
fc2_weights = tf.get_variable('weight',[120,84],initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer != None:
tf.add_to_collection('losses',regularizer(fc2_weights))
fc2_biases = tf.get_variable('bias',[84],initializer=tf.truncated_normal_initializer(stddev=0.1))
fc2 = tf.nn.relu(tf.matmul(fc1,fc2_weights) + fc2_biases)
if train:
fc2 = tf.nn.dropout(fc2,0.5)
#第七层:全连接层(近似表示),84->10的全连接
#尺寸变化:比如一组训练样本为64,那么尺寸变化为64×84->64×10。最后,64×10的矩阵经过softmax之后就得出了64张图片分类于每种数字的概率,
#即得到最后的分类结果。
with tf.variable_scope('layer7-fc3'):
fc3_weights = tf.get_variable('weight',[84,10],initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer != None:
tf.add_to_collection('losses',regularizer(fc3_weights))
fc3_biases = tf.get_variable('bias',[10],initializer=tf.truncated_normal_initializer(stddev=0.1))
logit = tf.matmul(fc2,fc3_weights) + fc3_biases
return logit
#正则化,交叉熵,平均交叉熵,损失函数,最小化损失函数,预测和实际equal比较,tf.equal函数会得到True或False,
#accuracy首先将tf.equal比较得到的布尔值转为float型,即True转为1.,False转为0,最后求平均值,即一组样本的正确率。
#比如:一组5个样本,tf.equal比较为[True False True False False],转化为float型为[1. 0 1. 0 0],准确率为2./5=40%。
'''规则化可以帮助防止过度配合,提高模型的适用性。(让模型无法完美匹配所有的训练项。)(使用规则来使用尽量少的变量去拟合数据)
规则化就是说给需要训练的目标函数加上一些规则(限制),让他们不要自我膨胀。
TensorFlow会将L2的正则化损失值除以2使得求导得到的结果更加简洁
如tf.contrib.layers.apply_regularization/l1_regularizer/l2_regularizer/sum_regularizer
https://blog.csdn.net/liushui94/article/details/73481112
sparse_softmax_cross_entropy_with_logits()是将softmax和cross_entropy放在一起计算
https://blog.csdn.net/ZJRN1027/article/details/80199248'''
regularizer = tf.contrib.layers.l2_regularizer(0.001)
y = inference(x,False,regularizer)
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=y_)
cross_entropy_mean = tf.rece_mean(cross_entropy)
loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))
train_op = tf.train.AdamOptimizer(0.001).minimize(loss)
correct_prediction = tf.equal(tf.cast(tf.argmax(y,1),tf.int32),y_)
accuracy = tf.rece_mean(tf.cast(correct_prediction,tf.float32))
#每次获取batch_size个样本进行训练或测试
def get_batch(data,label,batch_size):
for start_index in range(0,len(data)-batch_size+1,batch_size):
slice_index = slice(start_index,start_index+batch_size)
yield data[slice_index],label[slice_index]
#创建Session会话
with tf.Session() as sess:
#初始化所有变量(权值,偏置等)
sess.run(tf.global_variables_initializer())
#将所有样本训练10次,每次训练中以64个为一组训练完所有样本。
#train_num可以设置大一些。
train_num = 10
batch_size = 64
for i in range(train_num):
train_loss,train_acc,batch_num = 0, 0, 0
for train_data_batch,train_label_batch in get_batch(train_data,train_label,batch_size):
_,err,acc = sess.run([train_op,loss,accuracy],feed_dict={x:train_data_batch,y_:train_label_batch})
train_loss+=err;train_acc+=acc;batch_num+=1
print("train loss:",train_loss/batch_num)
print("train acc:",train_acc/batch_num)
test_loss,test_acc,batch_num = 0, 0, 0
for test_data_batch,test_label_batch in get_batch(test_data,test_label,batch_size):
err,acc = sess.run([loss,accuracy],feed_dict={x:test_data_batch,y_:test_label_batch})
test_loss+=err;test_acc+=acc;batch_num+=1
print("test loss:",test_loss/batch_num)
print("test acc:",test_acc/batch_num)
⑻ Multi-Sample Dropout
1. 模型结构
orginal dropout : 对单个样本,进行单次drop out。
2. 思想
stacking方法中的子模型 。事实证明,用 多个子模型 做模型 融合 可以提高模型的性能。
训练时,对原始数据进行变换,创建出多个分身。分身可能是带噪音,可能是不完整(此方法)。从而提高泛化能力。
3. 实现方法
训练阶段,每次dropout首先会随机的选取50%(这个比例可以自己设置)的神经元,其他50%被丢弃。
通过多次的dropout,从特征中选择了不同的 特征子集 进行训练,相当于重采样。
再通过共享的全连接层和loss层。
loss:每条样本,多个分身,得到的多个loss的平均值最小。
4. 优点
加快收敛,性能提升。dropout只使用在最后的几层,而全连接层的训练时间较快。因此,对比更大的 mini-batch,虽然可以达到相同的效果,但是实际上会增加计算的耗时。
实现简单:在 dropout 层后复制部分训练网络,并在这些复制的全连接层之间共享权重就可以了,无需新运算符。
5. 发散
传统的机器学习算法,如排序中常用的树模型。stack思想下,得到了不同的树。如果就用一棵树呢??泛化能力能变强吗?
Stacking是通过 一个 元分类器或者元回归器来 整合多个 分类模型或回归模型的集成学习技术。基础模型利用整个训练集做训练,元模型将基础模型的特征作为特征进行训练。(N->1) 。基础模型通常包含不同的学习算法,因此stacking通常是异质集成。
6. 缺点
1)模型的设计,存在训练和预测 不一致问题 。训练时,Dropout 往(某些层的)输入加上了乘性噪声。而预测时,理论上,应该是对同一个输入多次传入模型中(模型不关闭Dropout),然后把多次的预测结果平均值作为最终的预测结果。实际上,预测的时候用的是关闭Dropout的单模型,两者未必等价,这就是Dropout的训练预测不一致问题。
2)损失函数的设计,只有交叉熵。如果只有交叉熵这一项,模型的训练结果是“不同的Dropout下,目标类的得分都大于非目标类的得分”。
链接:https://kexue.fm/archives/8496
⑼ 神经网络dropout什么意思啊
dropout是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。注意是暂时,对于随机梯度下降来说,由于是随机丢弃,故而每一个mini-batch都在训练不同的网络。
然而Hinton在2012年文献:《Improving neural networks by preventing co-adaptation of feature detectors》提出了,在每次训练的时候,随机让一半的特征检测器停过工作,这样可以提高网络的泛化能力,Hinton又把它称之为dropout。
⑽ AI数学基础18——常见的正则化方法
1,L2 regularization(权重衰减) L2正则化就是在代价函数后面再加上一个正则化项λ ,使得权重在更新的时候,乘以一个小于1的因子(1-a(λ/m)),这个可以防止W过大。正则化项里面有一个系数1/2,1/2经常会看到,主要是为了后面求导的结果方便,后面那一项求导会产生一个2,与1/2相乘刚好凑整。
过拟合的时候,拟合函数的系数往往非常大。过拟合,就是拟合函数需要顾忌每一个点,最终形成的拟合函数波动很大。在某些很小的区间里,函数值的变化很剧烈。这就意味着函数在某些小区间里的导数值(绝对值)非常大,由于自变量值可大可小,所以只有系数足够大,才能保证导数值很大
L2 Regularization 防止了系数W过大,也就防止了拟合函数导数值过大,也就防止了函数导数值波动过大,也就解决了过拟合问题。
L2正则化是训练深度学习模型中最常用的一种解决过拟合问题的方法。
2,L1 regularization, L1正则化的正则项是所有权重w的绝对值的和,乘以λ/n(这里不像L2正则化项那样,需要再乘以1/2);消除过拟合的原因与L2类似。使用频率没有L2正则化高。
3,Dropout正则化
L1、L2正则化是通过修改代价函数来实现的,而Dropout则是通过修改神经网络本身来实现的。
Dropout是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。注意是暂时,对于随机梯度下降来说,由于是随机丢弃,故而每一个mini-batch都在训练不同的网络。
运用了dropout的训练过程,相当于训练了很多个只有半数隐层单元的神经网络(后面简称为“半数网络”),每一个这样的半数网络,都可以给出一个分类结果,这些结果有的是正确的,有的是错误的。随着训练的进行,大部分半数网络都可以给出正确的分类结果,那么少数的错误分类结果就不会对最终结果造成大的影响。
dropout率的选择:经过交叉验证, 隐含节点dropout率等于0.5的时候效果最好 ,原因是0.5的时候dropout随机生成的网络结构最多
具体细节,推荐Alex和Hinton的论文《 ImageNet Classification with Deep Convolutional Neural Networks 》
4,数据集扩增(data augmentation)
在深度学习方法中,更多的训练数据,意味着可以用更深的网络,训练出更好的模型。
但是很多时候,收集更多的数据意味着需要耗费更多的人力物力,非常困难。
所以,可以在原始数据上做些改动,得到更多的数据,以图片数据集举例,可以做各种变换,如:
1,水平翻转或任意角度旋转;2,裁剪;3,添加噪声
更多数据意味着什么?
用50000个MNIST的样本训练SVM得出的accuracy94.48%,用5000个MNIST的样本训练NN得出accuracy为93.24%,所以更多的数据可以使算法表现得更好。在机器学习中,算法本身并不能决出胜负,不能武断地说这些算法谁优谁劣,因为数据对算法性能的影响很大。
5,提前停止训练神经网络(Early Stop)
在一个适中的迭代次数,W不是很大的时候,dev set error接近最小,train set error适中的时候,提前停止训练,如下图所示
参考文献:Andrew Ng《Prractical aspects of Deep learning》1.1~1.8