『壹』 uvos任务经典数据集有哪些
1、MNIST:一个手写数字分类数据集,包含训练集旅槐孙和测试集,每个数据样本由图像数据和标签构成。
2、IMDB:一个电影评论分类数据集,可以用来训练文本分类器拆链。
3、CIFAR-10:一个图像分类数据集,共有10个类别,每个类别包含6000张32*32像素的彩色图像。
4、KITTI:一个自动驾驶数据集,包含高清图像和3D点云数据。
5、SQuAD:一个自然语言问答数据集,用于训练自然语言处明肆理系统。
『贰』 什么是深度学习与机器视觉
深度学习框架,尤其是基于人工神经网络的框架可以追溯到1980年福岛邦彦提出的新认知机[2],而人工神经网络的历史更为久远。1989年,燕乐存(Yann LeCun)等人开始将1974年提出的标准反向传播算法[3]应用于深度神经网络,这一网络被用于手写邮政编码识别。尽管算法可以成功执行,但计算代价非常巨大,神经网路的训练时间达到了3天,因而无法投入实际使用[4]。许多因素导致了这一缓慢的训练过程,其中一种是由于尔根·施密德胡伯(Jürgen Schmidhuber)的学生赛普·霍克赖特(Sepp Hochreiter)于1991年提出的梯度消失问题[5][6]。与此同时,神经网络也受到了其他更加简单模型的挑战,支持向量机等模型在20世纪90年代到21世纪初成为更加流行的机器学习算法。
“深度学习”这一概念从2007年前后开始受到关注。当时,杰弗里·辛顿(Geoffrey Hinton)和鲁斯兰·萨拉赫丁诺夫(Ruslan Salakhutdinov)提出了一种在前馈神经网络中进行有效训练的算法。这一算法将网络中的每一层视为无监督的受限玻尔兹曼机,再使用有监督的反向传播算法进行调优[7]。在此之前的1992年,在更为普遍的情形下,施密德胡伯也曾在递归神经网络上提出一种类似的训练方法,并在实验中证明这一训练方法能够有效提高有监督学习的执行速度[8][9].
自深度学习出现以来,它已成为很多领域,尤其是在计算机视觉和语音识别中,成为各种领先系统的一部分。在通用的用于检验的数据集,例如语音识别中的TIMIT和图像识别中的ImageNet, Cifar10上的实验证明,深度学习能够提高识别的精度。
硬件的进步也是深度学习重新获得关注的重要因素。高性能图形处理器的出现极大地提高了数值和矩阵运算的速度,使得机器学习算法的运行时间得到了显著的缩短[10][11]。
基本概念[编辑]
深度学习的基础是机器学习中的分散表示(distributed representation)。分散表示假定观测值是由不同因子相互作用生成。在此基础上,深度学习进一步假定这一相互作用的过程可分为多个层次,代表对观测值的多层抽象。不同的层数和层的规模可用于不同程度的抽象[1]。
深度学习运用了这分层次抽象的思想,更高层次的概念从低层次的概念学习得到。这一分层结构常常使用贪婪算法逐层构建而成,并从中选取有助于机器学习的更有效的特征[1].
不少深度学习算法都以无监督学习的形式出现,因而这些算法能被应用于其他算法无法企及的无标签数据,这一类数据比有标签数据更丰富,也更容易获得。这一点也为深度学习赢得了重要的优势[1]。
人工神经网络下的深度学习[编辑]
一部分最成功的深度学习方法涉及到对人工神经网络的运用。人工神经网络受到了1959年由诺贝尔奖得主大卫·休伯尔(David H. Hubel)和托斯坦·威泽尔(Torsten Wiesel)提出的理论启发。休伯尔和威泽尔发现,在大脑的初级视觉皮层中存在两种细胞:简单细胞和复杂细胞,这两种细胞承担不同层次的视觉感知功能。受此启发,许多神经网络模型也被设计为不同节点之间的分层模型[12]。
福岛邦彦提出的新认知机引入了使用无监督学习训练的卷积神经网络。燕乐存将有监督的反向传播算法应用于这一架构[13]。事实上,从反向传播算法自20世纪70年代提出以来,不少研究者都曾试图将其应用于训练有监督的深度神经网络,但最初的尝试大都失败。赛普·霍克赖特(Sepp Hochreiter)在其博士论文中将失败的原因归结为梯度消失,这一现象同时在深度前馈神经网络和递归神经网络中出现,后者的训练过程类似深度网络。在分层训练的过程中,本应用于修正模型参数的误差随着层数的增加指数递减,这导致了模型训练的效率低下[14][15]。
为了解决这一问题,研究者们提出了一些不同的方法。于尔根·施密德胡伯(Jürgen Schmidhuber)于1992年提出多层级网络,利用无监督学习训练深度神经网络的每一层,再使用反向传播算法进行调优。在这一模型中,神经网络中的每一层都代表观测变量的一种压缩表示,这一表示也被传递到下一层网络[8]。
另一种方法是赛普·霍克赖特和于尔根·施密德胡伯提出的长短期记忆神经网络(long short term memory,LSTM)[16]。2009年,在ICDAR 2009举办的连笔手写识别竞赛中,在没有任何先验知识的情况下,深度多维长短期记忆神经网络取得了其中三场比赛的胜利[17][18]。
斯文·贝克提出了在训练时只依赖梯度符号的神经抽象金字塔模型,用以解决图像重建和人脸定位的问题[19]。
其他方法同样采用了无监督预训练来构建神经网络,用以发现有效的特征,此后再采用有监督的反向传播以区分有标签数据。辛顿等人于2006年提出的深度模型提出了使用多层隐变量学习高层表示的方法。这一方法使用斯摩棱斯基于1986年提出的受限玻尔兹曼机[20]对每一个包含高层特征的层进行建模。模型保证了数据的对数似然下界随着层数的提升而递增。当足够多的层数被学习完毕,这一深层结构成为一个生成模型,可以通过自上而下的采样重构整个数据集[21]。辛顿声称这一模型在高维结构化数据上能够有效低提取特征[22]。
吴恩达和杰夫·迪恩(Jeff Dean)领导的谷歌大脑(英语:Google Brain)团队创建了一个仅通过YouTube视频学习高层概念(例如猫)的神经网络[23] [24]。
其他方法依赖了现代电子计算机的强大计算能力,尤其是GPU。2010年,在于尔根·施密德胡伯位于瑞士人工智能实验室IDSIA的研究组中,丹·奇雷尚(Dan Ciresan)和他的同事展示了利用GPU直接执行反向传播算法而忽视梯度消失问题的存在。这一方法在燕乐存等人给出的手写识别MNIST数据集上战胜了已有的其他方法[10]。
截止2011年,前馈神经网络深度学习中最新的方法是交替使用卷积层(convolutional layers)和最大值池化层(max-pooling layers)并加入单纯的分类层作为顶端。训练过程也无需引入无监督的预训练[25][26]。从2011年起,这一方法的GPU实现[25]多次赢得了各类模式识别竞赛的胜利,包括IJCNN 2011交通标志识别竞赛[27]和其他比赛。
这些深度学习算法也是最先在某些识别任务上达到和人类表现具备同等竞争力的算法[28]。
深度学习结构[编辑]
深度神经网络是一种具备至少一个隐层的神经网络。与浅层神经网络类似,深度神经网络也能够为复杂非线性系统提供建模,但多出的层次为模型提供了更高的抽象层次,因而提高了模型的能力。深度神经网络通常都是前馈神经网络,但也有语言建模等方面的研究将其拓展到递归神经网络[29]。卷积深度神经网络(Covolutional Neuron Networks, CNN)在计算机视觉领域得到了成功的应用[30]。此后,卷积神经网络也作为听觉模型被使用在自动语音识别领域,较以往的方法获得了更优的结果[31]。
深度神经网络[编辑]
深度神经网络(deep neuron networks, DNN)是一种判别模型,可以使用反向传播算法进行训练。权重更新可以使用下式进行随机梯度下降求解:
其中,为学习率,为代价函数。这一函数的选择与学习的类型(例如监督学习、无监督学习、增强学习)以及激活函数相关。例如,为了在一个多分类问题上进行监督学习,通常的选择是使用Softmax函数作为激活函数,而使用交叉熵作为代价函数。Softmax函数定义为,其中代表类别的概率,而和分别代表对单元和的输入。交叉熵定义为,其中代表输出单元的目标概率,代表应用了激活函数后对单元的概率输出[32]。
深度神经网络的问题[编辑]
与其他神经网络模型类似,如果仅仅是简单地训练,深度神经网络可能会存在很多问题。常见的两类问题是过拟合和过长的运算时间。
深度神经网络很容易产生过拟合现象,因为增加的抽象层使得模型能够对训练数据中较为罕见的依赖关系进行建模。对此,权重递减(正规化)或者稀疏(-正规化)等方法可以利用在训练过程中以减小过拟合现象[33]。另一种较晚用于深度神经网络训练的正规化方法是丢弃法("dropout" regularization),即在训练中随机丢弃一部分隐层单元来避免对较为罕见的依赖进行建模[34]。
反向传播算法和梯度下降法由于其实现简单,与其他方法相比能够收敛到更好的局部最优值而成为神经网络训练的通行方法。但是,这些方法的计算代价很高,尤其是在训练深度神经网络时,因为深度神经网络的规模(即层数和每层的节点数)、学习率、初始权重等众多参数都需要考虑。扫描所有参数由于时间代价的原因并不可行,因而小批量训练(mini-batching),即将多个训练样本组合进行训练而不是每次只使用一个样本进行训练,被用于加速模型训练[35]。而最显著地速度提升来自GPU,因为矩阵和向量计算非常适合使用GPU实现。但使用大规模集群进行深度神经网络训练仍然存在困难,因而深度神经网络在训练并行化方面仍有提升的空间。
深度信念网络[编辑]
一个包含完全连接可见层和隐层的受限玻尔兹曼机(RBM)。注意到可见层单元和隐层单元内部彼此不相连。
深度信念网络(deep belief networks,DBN)是一种包含多层隐单元的概率生成模型,可被视为多层简单学习模型组合而成的复合模型[36]。
深度信念网络可以作为深度神经网络的预训练部分,并为网络提供初始权重,再使用反向传播或者其他判定算法作为调优的手段。这在训练数据较为缺乏时很有价值,因为不恰当的初始化权重会显著影响最终模型的性能,而预训练获得的权重在权值空间中比随机权重更接近最优的权重。这不仅提升了模型的性能,也加快了调优阶段的收敛速度[37]。
深度信念网络中的每一层都是典型的受限玻尔兹曼机(restricted Boltzmann machine,RBM),可以使用高效的无监督逐层训练方法进行训练。受限玻尔兹曼机是一种无向的基于能量的生成模型,包含一个输入层和一个隐层。图中对的边仅在输入层和隐层之间存在,而输入层节点内部和隐层节点内部则不存在边。单层RBM的训练方法最初由杰弗里·辛顿在训练“专家乘积”中提出,被称为对比分歧(contrast divergence, CD)。对比分歧提供了一种对最大似然的近似,被理想地用于学习受限玻尔兹曼机的权重[35]。当单层RBM被训练完毕后,另一层RBM可被堆叠在已经训练完成的RBM上,形成一个多层模型。每次堆叠时,原有的多层网络输入层被初始化为训练样本,权重为先前训练得到的权重,该网络的输出作为新增RBM的输入,新的RBM重复先前的单层训练过程,整个过程可以持续进行,直到达到某个期望中的终止条件[38]。
尽管对比分歧对最大似然的近似十分粗略(对比分歧并不在任何函数的梯度方向上),但经验结果证实该方法是训练深度结构的一种有效的方法[35]。
卷积神经网络[编辑]
主条目:卷积神经网络
卷积神经网络(convolutional neuron networks,CNN)由一个或多个卷积层和顶端的全连通层(对应经典的神经网络)组成,同时也包括关联权重和池化层(pooling layer)。这一结构使得卷积神经网络能够利用输入数据的二维结构。与其他深度学习结构相比,卷积神经网络在图像和语音识别方面能够给出更优的结果。这一模型也可以使用反向传播算法进行训练。相比较其他深度、前馈神经网络,卷积神经网络需要估计的参数更少,使之成为一种颇具吸引力的深度学习结构[39]。
卷积深度信念网络[编辑]
卷积深度信念网络(convolutional deep belief networks,CDBN)是深度学习领域较新的分支。在结构上,卷积深度信念网络与卷积神经网络在结构上相似。因此,与卷积神经网络类似,卷积深度信念网络也具备利用图像二维结构的能力,与此同时,卷积深度信念网络也拥有深度信念网络的预训练优势。卷积深度信念网络提供了一种能被用于信号和图像处理任务的通用结构,也能够使用类似深度信念网络的训练方法进行训练[40]。
结果[编辑]
语音识别[编辑]
下表中的结果展示了深度学习在通行的TIMIT数据集上的结果。TIMIT包含630人的语音数据,这些人持八种常见的美式英语口音,每人阅读10句话。这一数据在深度学习发展之初常被用于验证深度学习结构[41]。TIMIT数据集较小,使得研究者可以在其上实验不同的模型配置。
方法
声音误差率 (PER, %)
随机初始化RNN 26.1
贝叶斯三音子GMM-HMM 25.6
单音子重复初始化DNN 23.4
单音子DBN-DNN 22.4
带BMMI训练的三音子GMM-HMM 21.7
共享池上的单音子DBN-DNN 20.7
卷积DNN 20.0
图像分类[编辑]
图像分类领域中一个公认的评判数据集是MNIST数据集。MNIST由手写阿拉伯数字组成,包含60,000个训练样本和10,000个测试样本。与TIMIT类似,它的数据规模较小,因而能够很容易地在不同的模型配置下测试。Yann LeCun的网站给出了多种方法得到的实验结果[42]。截至2012年,最好的判别结果由Ciresan等人在当年给出,这一结果的错误率达到了0.23%[43]。
深度学习与神经科学[编辑]
计算机领域中的深度学习与20世纪90年代由认知神经科学研究者提出的大脑发育理论(尤其是皮层发育理论)密切相关[44]。对这一理论最容易理解的是杰弗里·艾尔曼(Jeffrey Elman)于1996年出版的专著《对天赋的再思考》(Rethinking Innateness)[45](参见斯拉格和约翰逊[46]以及奎兹和赛杰诺维斯基[47]的表述)。由于这些理论给出了实际的神经计算模型,因而它们是纯计算驱动的深度学习模型的技术先驱。这些理论指出,大脑中的神经元组成了不同的层次,这些层次相互连接,形成一个过滤体系。在这些层次中,每层神经元在其所处的环境中获取一部分信息,经过处理后向更深的层级传递。这与后来的单纯与计算相关的深度神经网络模型相似。这一过程的结果是一个与环境相协调的自组织的堆栈式的转换器。正如1995年在《纽约时报》上刊登的那样,“……婴儿的大脑似乎受到所谓‘营养因素’的影响而进行着自我组织……大脑的不同区域依次相连,不同层次的脑组织依照一定的先后顺序发育成熟,直至整个大脑发育成熟。”[48]
深度结构在人类认知演化和发展中的重要性也在认知神经学家的关注之中。发育时间的改变被认为是人类和其他灵长类动物之间智力发展差异的一个方面[49]。在灵长类中,人类的大脑在出生后的很长时间都具备可塑性,但其他灵长类动物的大脑则在出生时就几乎完全定型。因而,人类在大脑发育最具可塑性的阶段能够接触到更加复杂的外部场景,这可能帮助人类的大脑进行调节以适应快速变化的环境,而不是像其他动物的大脑那样更多地受到遗传结构的限制。这样的发育时间差异也在大脑皮层的发育时间和大脑早期自组织中从刺激环境中获取信息的改变得到体现。当然,伴随着这一可塑性的是更长的儿童期,在此期间人需要依靠抚养者和社会群体的支持和训练。因而这一理论也揭示了人类演化中文化和意识共同进化的现象[50]。
公众视野中的深度学习[编辑]
深度学习常常被看作是通向真正人工智能的重要一步[51],因而许多机构对深度学习的实际应用抱有浓厚的兴趣。2013年12月,Facebook宣布雇用燕乐存为其新建的人工智能实验室的主管,这一实验室将在加州、伦敦和纽约设立分支机构,帮助Facebook研究利用深度学习算法进行类似自动标记照片中用户姓名这样的任务[52]。
2013年3月,杰弗里·辛顿和他的两位研究生亚历克斯·克里泽夫斯基和伊利娅·苏特斯科娃被谷歌公司雇用,以提升现有的机器学习产品并协助处理谷歌日益增长的数据。谷歌同时并购了辛顿创办的公司DNNresearch[53]。
批评[编辑]
对深度学习的主要批评是许多方法缺乏理论支撑。大多数深度结构仅仅是梯度下降的某些变式。尽管梯度下降已经被充分地研究,但理论涉及的其他算法,例如对比分歧算法,并没有获得充分的研究,其收敛性等问题仍不明确。深度学习方法常常被视为黑盒,大多数的结论确认都由经验而非理论来确定。
也有学者认为,深度学习应当被视为通向真正人工智能的一条途径,而不是一种包罗万象的解决方案。尽管深度学习的能力很强,但和真正的人工智能相比,仍然缺乏诸多重要的能力。理论心理学家加里·马库斯(Gary Marcus)指出:
就现实而言,深度学习只是建造智能机器这一更大挑战中的一部分。这些技术缺乏表达因果关系的手段……缺乏进行逻辑推理的方法,而且远没有具备集成抽象知识,例如物品属性、代表和典型用途的信息。最为强大的人工智能系统,例如IBM的人工智能系统沃森,仅仅把深度学习作为一个包含从贝叶斯推理和演绎推理等技术的复杂技术集合中的组成部分[54]。
『叁』 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)
『肆』 sklearn 神经网络 MLPClassifier简单应用与参数说明
MLPClassifier是一个监督学习算法,下图是只有1个隐藏层的MLP模型 ,左侧是输入层,右侧是输出层。
上图的整体结构可以简单的理解为下图所示:
MLP又名多层感知机,也叫人工神经网络(ANN,Artificial Neural Network),除了输入输出层,它中间可以有多个隐藏层,如果没有隐藏层即可解决线性可划分的数据问题。最简单的MLP模型只包含一个隐藏层,即三层的结构,如上图。
从上图可以看到,多层感知机的层与层之间是全连接的(全连接的意思就是:上一层的任何一个神经元与下一层的所有神经元都有连接)。多层感知机最底层是输入层,中间是隐藏层,最后是输出层。
输入层没什么好说,你输入什么就是什么,比如输入是一个n维向量,就有n个神经元。
隐藏层的神经元怎么得来?首先它与输入层是全连接的,假设输入层用向量X表示,则隐藏层的输出就是
f(W1X+b1),W1是权重(也叫连接系数),b1是偏置,函数f 可以是常用的sigmoid函数或者tanh函数:
最后就是输出层,输出层与隐藏层是什么关系?其实隐藏层到输出层可以看成是一个多类别的逻辑回归,也即softmax回归,所以输出层的输出就是softmax(W2X1+b2),X1表示隐藏层的输出f(W1X+b1)。
MLP整个模型就是这样子的,上面说的这个三层的MLP用公式总结起来就是,函数G是softmax
因此,MLP所有的参数就是各个层之间的连接权重以及偏置,包括W1、b1、W2、b2。对于一个具体的问题,怎么确定这些参数?求解最佳的参数是一个最优化问题,解决最优化问题,最简单的就是梯度下降法了(sgd):首先随机初始化所有参数,然后迭代地训练,不断地计算梯度和更新参数,直到满足某个条件为止(比如误差足够小、迭代次数足够多时)。这个过程涉及到代价函数、规则化(Regularization)、学习速率(learning rate)、梯度计算等。
下面写了一个超级简单的实例,训练和测试数据是mnist手写识别数据集:
from sklearn.neural_network import MLPClassifier
import gzip
import pickle
with gzip.open('./mnist.pkl.gz') as f_gz:
train_data,valid_data,test_data = pickle.load(f_gz)
clf = MLPClassifier(solver='sgd',activation = 'identity',max_iter = 10,alpha = 1e-5,hidden_layer_sizes = (100,50),random_state = 1,verbose = True)
clf.fit(train_data[0][:10000],train_data[1][:10000])
print clf.predict(test_data[0][:10])
print(clf.score(test_data[0][:100],test_data[1][:100]))
print(clf.predict_proba(test_data[0][:10]))
参数说明:
参数说明:
1. hidden_layer_sizes :例如hidden_layer_sizes=(50, 50),表示有两层隐藏层,第一层隐藏层有50个神经元,第二层也有50个神经元。
2. activation :激活函数,{‘identity’, ‘logistic’, ‘tanh’, ‘relu’}, 默认relu
- identity:f(x) = x
- logistic:其实就是sigmod,f(x) = 1 / (1 + exp(-x)).
- tanh:f(x) = tanh(x).
- relu:f(x) = max(0, x)
3. solver: {‘lbfgs’, ‘sgd’, ‘adam’}, 默认adam,用来优化权重
- lbfgs:quasi-Newton方法的优化器
- sgd:随机梯度下降
- adam: Kingma, Diederik, and Jimmy Ba提出的机遇随机梯度的优化器
注意:默认solver ‘adam’在相对较大的数据集上效果比较好(几千个样本或者更多),对小数据集来说,lbfgs收敛更快效果也更好。
4. alpha :float,可选的,默认0.0001,正则化项参数
5. batch_size : int , 可选的,默认’auto’,随机优化的minibatches的大小batch_size=min(200,n_samples),如果solver是’lbfgs’,分类器将不使用minibatch
6. learning_rate :学习率,用于权重更新,只有当solver为’sgd’时使用,{‘constant’,’invscaling’, ‘adaptive’},默认constant
- ‘constant’: 有’learning_rate_init’给定的恒定学习率
- ‘incscaling’:随着时间t使用’power_t’的逆标度指数不断降低学习率learning_rate_ ,effective_learning_rate = learning_rate_init / pow(t, power_t)
- ‘adaptive’:只要训练损耗在下降,就保持学习率为’learning_rate_init’不变,当连续两次不能降低训练损耗或验证分数停止升高至少tol时,将当前学习率除以5.
7. power_t: double, 可选, default 0.5,只有solver=’sgd’时使用,是逆扩展学习率的指数.当learning_rate=’invscaling’,用来更新有效学习率。
8. max_iter: int,可选,默认200,最大迭代次数。
9. random_state:int 或RandomState,可选,默认None,随机数生成器的状态或种子。
10. shuffle: bool,可选,默认True,只有当solver=’sgd’或者‘adam’时使用,判断是否在每次迭代时对样本进行清洗。
11. tol:float, 可选,默认1e-4,优化的容忍度
12. learning_rate_int:double,可选,默认0.001,初始学习率,控制更新权重的补偿,只有当solver=’sgd’ 或’adam’时使用。
14. verbose : bool, 可选, 默认False,是否将过程打印到stdout
15. warm_start : bool, 可选, 默认False,当设置成True,使用之前的解决方法作为初始拟合,否则释放之前的解决方法。
16. momentum : float, 默认 0.9,动量梯度下降更新,设置的范围应该0.0-1.0. 只有solver=’sgd’时使用.
17. nesterovs_momentum : boolean, 默认True, Whether to use Nesterov’s momentum. 只有solver=’sgd’并且momentum > 0使用.
18. early_stopping : bool, 默认False,只有solver=’sgd’或者’adam’时有效,判断当验证效果不再改善的时候是否终止训练,当为True时,自动选出10%的训练数据用于验证并在两步连续迭代改善,低于tol时终止训练。
19. validation_fraction : float, 可选, 默认 0.1,用作早期停止验证的预留训练数据集的比例,早0-1之间,只当early_stopping=True有用
20. beta_1 : float, 可选, 默认0.9,只有solver=’adam’时使用,估计一阶矩向量的指数衰减速率,[0,1)之间
21. beta_2 : float, 可选, 默认0.999,只有solver=’adam’时使用估计二阶矩向量的指数衰减速率[0,1)之间
22. epsilon : float, 可选, 默认1e-8,只有solver=’adam’时使用数值稳定值。
属性说明:
- classes_:每个输出的类标签
- loss_:损失函数计算出来的当前损失值
- coefs_:列表中的第i个元素表示i层的权重矩阵
- intercepts_:列表中第i个元素代表i+1层的偏差向量
- n_iter_ :迭代次数
- n_layers_:层数
- n_outputs_:输出的个数
- out_activation_:输出激活函数的名称。
方法说明:
- fit(X,y):拟合
- get_params([deep]):获取参数
- predict(X):使用MLP进行预测
- predic_log_proba(X):返回对数概率估计
- predic_proba(X):概率估计
- score(X,y[,sample_weight]):返回给定测试数据和标签上的平均准确度
-set_params(**params):设置参数。
『伍』 如何制作像mnist,CIFAR-10格式的数据集
MNIST 数据集
混合的国家标准和技术 (简称 MNIST) 由红外研究员,作为基准来比较不同的红外算法创建数据集。 其基本思想是如果你有你想要测试红外的算法或软件的系统,可以运行您的算法或系统针对 MNIST 的数据集和比较您的结果与其他系统以前发布成果。
数据集包含的共 70,000 图像 ; 60,000 训练图像 (用于创建红外模型) 和 10,000 测试图像 (用于评估模型的精度)。 每个 MNIST 图像是一个单一的手写的数字字符的数字化的图片。 每个图像是 28 x 28 像素大小。 每个像素值是 0,表示白色,至 255,表示黑。 中间像素值表示的灰度级。 图 2 显示了训练集的前八位的图像。 对应于每个图像的实际数字是显然对人,但确定数字是非常困难的挑战的计算机。
图 2 首八 MNIST 训练图像
奇怪的是,训练数据和测试数据均存储在两个文件中,而不是在单个文件中。 其中一个文件包含图像的像素值和,另一个包含图像的标签信息 (0 到 9)。 每个的四个文件还包含标头信息,和所有的四个文件都存储在已经使用 gzip 格式压缩的二进制格式。
注意在图 1,该演示程序使用仅 60,000 项目训练集。 测试集的格式是相同的训练集。 MNIST 文件的主存储库是目前位于 yann.lecun.com/exdb/mnist。 培训的像素数据存储在文件火车-图像-idx3-ubyte.gz 和培训标签数据存储在文件火车-标签-idx1-ubyte.gz。 若要运行该演示程序,您需要转到 MNIST 的存储库站点,下载并解压的两个培训数据文件。 将文件解压缩,我用的免费的开源 7-Zip 实用程序。
创建 MNIST 查看器
若要创建 MNIST 演示程序,我发起了 Visual Studio,创建一个名为 MnistViewer 的新 C# Windows 窗体项目。 演示有没有重大的.NET 版本依赖关系,因此,任何版本的 Visual Studio 应该工作。
模板代码加载到 Visual Studio 编辑器后,我设置的 UI 控件。 我添加了两个 TextBox 控件 (textBox1,textBox2) 要坚持两个解压后的培训文件的路径。 我添加一个按钮控件 (button1),并给了它一个标签加载图像。 我添加了两个多个 TextBox 控件 (textBox3,textBox4) 以保存当前图像索引和下一个图像索引的值。 我使用 Visual Studio 设计器,分别设置"NA"和"0,"这些控件的初始值。
我添加了一个 ComboBox 控件 (comboBox1) 的图像放大倍数值。 使用设计器,我去到该控件的项集合,添加字符串"1"到"10"。我添加了第二个按钮控件 (button2),并给了它一个标签的显示下一次。 我添加了 PictureBox 控件 (pictureBox1),将其背景色属性设置为 ControlDark,以便看到控件的轮廓。 我将图片框大小设置为 280 x 280 允许最多 10 倍的放大倍率 (回顾 MNIST 图像是 28 x 28 像素为单位)。 我添加了第五个 (textBox5) 文本框以显示十六进制值的图像,然后将其多行属性设置为 True 和其字体属性设置为 8.25 磅 Courier New 和扩大其大小到 606 x 412。 而且,最后,我添加了一个列表框控件 (listBox1) 的日志记录消息。
后放置 UI 控件拖到 Windows 窗体,添加三个类范围字段:
public partial class Form1 : Form
{
private string pixelFile =
@"C:\MnistViewer\train-images.idx3-ubyte";
private string labelFile =
@"C:\MnistViewer\train-labels.idx1-ubyte";
private DigitImage[] trainImages = null;
...
第一次两个字符串指向解压后的培训数据文件的位置。 你会需要编辑这些要运行演示的两个字符串。 第三个字段是一个程序定义 DigitImage 对象的数组。
我编辑窗体的构造函数略成 textBox1 和 textBox2 地点的文件路径,并给予放大倍数初始值 6:
public Form1()
{
InitializeComponent();
textBox1.Text = pixelFile;
textBox2.Text = labelFile;
comboBox1.SelectedItem = "6";
this.ActiveControl = button1;
}
我用的 ActiveControl 属性来设置初始焦点到 button1 控件,只是为了方便。