从上一篇开始,咱们终于进入到了TensorFlow机器学习的世界。采用第一个分类算法进行手写数字识别获得了一个91%左右的识别率结果,进展可喜,但成绩尚不能使人满意。
结果不满意的缘由,固然仍是算法太简单了。尽管咱们都已经接受了“全部问题均可以用数学公式来描述”这个观点,但直接把一幅图片展开的784个数字做为方程式参数进行一个线性运算+非线性分类器就叫作“人工智能”怎么都感受那么不靠谱...至于能获得91%不高的识别率,从这个意义上说,彷佛都使人有点不太相信。这个不相信不是指91%过低了,而是这种玩笑通常的计算就有91%的准确率有点奇幻啊。
其实数学的魅力就是这样,看起来公式简单,但上一节就说了,你别忘了是784维啊,手工计算确定会疯掉的。
若是利用上一篇介绍的小程序,把咱们图像识别程序学习过程完成后所计算的权重矩阵W的10个维度都转换成28x28分辨率的图片(还记得吧,咱们的权重矩阵W是784x10,其中784就是28x28得来的),而后作一些着色渲染,看到的会是这个样子:
其中红色的部分表明权重是负值,蓝色的部分表明权重是正值。
以字符0为例,图中红色的部分表明,若是要识别的图片,上面这个位置有手写痕迹的话,那这幅图片更趋向于不太多是字符0。而蓝色的部分,则表明若是一样位置有手写痕迹的话,那图片更趋向于多是字符0。这样所有28x28=784个数据都用这种方式计算,最后的结果,固然就表明更接近字符0的可能性。这就是这个程序图像识别的基本原理。
咱们在这里把这个权重图给出来的缘由,就是虽然这个算法简单,但能更清晰的表现“机器学习”的数学含义。接下来的“神经网络算法”及其它算法,由于复杂度高,单纯结果的权重每每已经不能用这种直观的方式表达出来了。html
在官方MNIST的案例中,神经网络的部分是直接跳过了的。由于随着技术的发展,在图像识别这个问题上已经有了更好的算法,就是“卷积神经网络”,这个实现咱们下一篇再讲。
实际上我以为,“神经网络”这个概念不管如何是跨不过去的,否则后期的不少概念都没法讲下去或者讲了也没法让人理解。科学老是这样,大多时候即使没有巅峰突破,普通的工做也并不是能够省略,否则就成为了空中楼阁。
“神经网络”的诞生是天然选择的结果,人脑就是由无数个神经元组成的,有资料说大概接近900亿个,是天文数字的级别。这些神经网络的传导和反射支撑着现代人类全部的智力和行为。
在人工智能尚未足够现代理论支撑的年代,仿照人脑“神经网络”的工做模式,创建“人工神经网络”进行机器学习是很天然的事情。而且在实践中的结果也很是使人兴奋,因此从并不很长的AI历史上,“人工神经网络”算统治了至关不短的时间。以致于对于不少非专业人士来说,“神经网络”已经成了AI标志性的概念。
模仿人脑神经元细胞的基本工做方式,下图示意了一个“人工神经网络”基本单元的工做方式:
每个这样的计算节点,都有n维的输入,在其中完成一个相似上一个源码样例中的线性计算,而后汇总输出,这个输出会再链接到下一级的计算节点。不少个这样的计算节点汇总完成一组计算,这样成为一“层”。上一层的输出,成为下一层的输入,多个层次累计起来,完成最终的机器学习过程。
在这些多层的计算中,第一层承担了全部原始数据的输入,所以叫作“输入层”;最后一层完成结果的输出,叫作“输出层”;中间的部分承担上一层的结果,通过计算完成下一层的输入,但对用户来说实际是不可见的,叫作“隐藏层”。这几个概念之后你在看各类资料的时候会常常看到,你须要知道这些概念指的是什么。
上图示意了神经网络的多种变形和组合后的网络模式。这种“仿生学”通常的组合模式取得了使人惊喜的效果。从数学的计算结构上很是的清晰,但内部多节点组合以后的数学机理实际上至今也没有哪篇论文描述的很是清楚。你能够理解为:经过增长计算节点、更多的体现和保持每一个数据和其它数据之间的微小关系甚至多层互动以后的关系,从而更准确的完成对结果的计算。python
有了已经内置的神经网络算法实现以后,普通用户对于算法的内部数学实现确定关心的更少了,这里也只说一个重点。
线性回归方程中,咱们使用梯度降低法解方程,每一次计算均可以经过代价函数的表现决定咱们下一个计算的走向。
在多层神经网络中,这种解方程方式显然不灵了。由于最终的结果,跟最初的输入,中间隔了多个隐藏层。
所以“人工神经网络”的求解主要依赖“反向传播”的方式来进行求解,大意是指最后一层得出结果后,经过这一层的代价函数修正本层的权重W和偏移b,并把信号反向传递到上一层,从而让上一层也能够调整本身层的W/b,逐次反向传播,一直到输入层。算法
前面一个独立神经节点的示意图中,你可能注意到了除了咱们上一个例子中熟悉过的线性公式。
其后部还有一个“Threshold unit”,也就是“阀值单元”。在真实的世界中,咱们的大脑不太可能对于任何须要处理的问题,都动用所有的大脑。
而根据上面那副“人工神经网络”示意图能够看出,全部的节点,虽然有层的划分,其实是全链接的。
全链接的意思也就是对于任何一个输入,事实上全部的单元都会参与计算,这显然也是不合常理的。
那每一个节点最后的阀值单元,就是用来决定对于某个任务,本节点是否参与以及以何种方法参与到最终的计算中。这个动做,在机器学习中也称为“激活函数”。
经常使用的激活函数有好多种,好比咱们前面提过的sigmoid函数,上一次提到它是由于这个函数能够用于作0、1分类。这个函数的输入值若是小于0.5,则输出为0;输入大于0.5,则输入为1。
还有tanh激活函数,输入小于0则输出0,输入大于0,则输出1。
最后则是本次咱们会采用的激活函数ReLu,它的输入若是小于0,则输出0,输入若是大于0,则原样输出。
这些数学特征,决定了所采用的神经元单元以何种方式参与到总体的计算。具体如何选择,依赖于咱们要解决的问题。若是问题比较复杂,没法一下想清楚如何取舍怎么办?那,这么易用的工具和框架,这么小的代码量,都试一遍又何妨?小程序
#!/usr/bin/env python # -*- coding=UTF-8 -*- import input_data mnist = input_data.read_data_sets('MNIST_data', one_hot=True) import tensorflow as tf sess = tf.InteractiveSession() #对W/b作初始化有利于防止算法陷入局部最优解, #文档上讲是为了打破对称性和防止0梯度及神经元节点恒为0等问题,数学原理是相似问题 #这两个初始化单独定义成子程序是由于多层神经网络会有屡次调用 def weight_variable(shape): #填充“权重”矩阵,其中的元素符合截断正态分布 #能够有参数mean表示指定均值及stddev指定标准差 initial = tf.truncated_normal(shape, stddev=0.1) return tf.Variable(initial) def bias_variable(shape): #用0.1常量填充“偏移量”矩阵 initial = tf.constant(0.1, shape=shape) return tf.Variable(initial) #定义占位符,至关于tensorFlow的运行参数, #x是输入的图片矩阵,y_是给定的标注标签,有标注必定是监督学习 x = tf.placeholder("float", shape=[None, 784]) y_ = tf.placeholder("float", shape=[None, 10]) #定义输入层神经网络,有784个节点,1024个输出, #输出的数量是本身定义的,要跟第二层节点的数量吻合 W1 = weight_variable([784, 1024]) b1 = bias_variable([1024]) #使用relu算法的激活函数,后面的公式跟前一个例子相同 h1 = tf.nn.relu(tf.matmul(x, W1) + b1) #定义第二层(隐藏层)网络,1024输入,512输出 W2 = weight_variable([1024, 512]) b2 = bias_variable([512]) h2 = tf.nn.relu(tf.matmul(h1, W2) + b2) #定义第三层(输出层),512输入,10输出,10也是咱们但愿的分类数量 W3 = weight_variable([512, 10]) b3 = bias_variable([10]) #最后一层的输出一样用softmax分类(也算是激活函数吧) y3=tf.nn.softmax(tf.matmul(h2, W3) + b3) #交叉熵代价函数 cross_entropy = -tf.reduce_sum(y_*tf.log(y3)) #这里使用了更加复杂的ADAM优化器来作"梯度最速降低", #前一个例子中咱们使用的是:GradientDescentOptimizer train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy) #计算正确率以评估效果 correct_prediction = tf.equal(tf.argmax(y3,1), tf.argmax(y_,1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) #tf初始化及全部变量初始化 sess.run(tf.global_variables_initializer()) #进行20000步的训练 for i in range(20000): #每批数据50组 batch = mnist.train.next_batch(50) #每100步进行一次正确率计算并显示中间结果 if i%100 == 0: train_accuracy = accuracy.eval(feed_dict={ x:batch[0], y_: batch[1]}) print "step %d, training accuracy %g"%(i, train_accuracy) #使用数据集进行训练 train_step.run(feed_dict={x: batch[0], y_: batch[1]}) #完成模型训练给出最终的评估结果 print "test accuracy %g"%accuracy.eval(feed_dict={ x: mnist.test.images, y_: mnist.test.labels})
这个程序中使用了3层的神经网络,通过20000*50个数据的训练,最终正确率能够达到96%以上,比上一个例子有了明显的进步。
实际上一个例子和本例,最终咱们都使用的tf.nn.softmax()函数。看到其中的“nn”没有,这是“Neural Networks”的缩写,也就是说,不只本例是神经网络算法,其实上一个例子,一样也使用了神经网络算法。
若是是之前没有TensorFlow的年代,这种特色咱们能在算法源码中看的一清二楚,而如今,很容易就会忽略掉。
那么上一例中,咱们实际上使用的是只有“一层”的神经网络算法,数学公式简化后,也就是普通的线性算法,而后通过非线性的softmax分类。
本例则毫无疑问是一个经典的神经网络算法,3层分别是784个输入->(输入层)1024个节点->(隐藏层)512节点->(输出层)10节点输出。
神经网络每一层之间是如何链接起来的呢?很简单,就如同程序中所示,每一层在公式那一行,其中计算时所引用的变量,是上一层输出的变量,就等于将各层进行了连接。TensorFlow会自动在这个计算图中上一层以后,添加上这一层的节点。
为了获得更好的识别结果,咱们还采用了AdamOptimizer优化器进行“梯度最速降低”。TensorFlow中内置了好几种算法,数学实现能够参考最下面的参考连接。
那么神经网络的设计,究竟应当采用多少层网络?每层多少个节点?
这个目前没统一的标准,通常而言,层数越多、节点越多,就能够获得更好的识别率,但同时这个模型的工做速度也会越慢。还可能会有更大的“过拟合”风险。过拟合咱们后面再介绍。
并且识别率的一点点增长,每每会须要更多的计算节点,成本不必定划算。
并不像增长一整层那样剧烈的资源消耗增长,在一个层中适当增长节点数一般是比较划算的方法,具体状况,也是要靠实验测试和科学评估的来决定。
多层的神经网络,由于网络深度的增长,也被称为“深度神经网络”(Deep Neural Networks / DNN),这个简写常常会跟CNN(卷积神经网络)、RNN(循环神经网络)一块儿出现。网络
最近为了写这个系列,在网上翻找参考资料,另外也试图寻找一些现成的图片帮助概念的解释行文。结果在不少介绍机器学习的文章中,发现大量的谬误,读之冷汗不绝啊。
这也提醒我,一方面我尽力的校对并再次厘清概念,防止本文出现相似的低级错误。固然水平所限,不免仍然有一些错误没法发现或者认知自己就有误,欢迎各界高手指正也让我不断进步。
另一方面整体感受,多是发展“大跃进”的缘由,并且毕竟国内的基础水平进展偏慢、偏晚,不少译文及“教程”是概念错误的重灾区。
本来由于我主要面对身边及国内的读者,但愿尽量引用的参考资料都来自中文资料,但到了今天决定完全放弃这个想法。能有质量至关的中文资料更好,若是没有,也只好引用一些国外的资料,毕竟不只仅水平上,只说认真程度上就彻底无法比。
我想这可能也是当前国内技术界广泛应当重视的问题。水平是一方面,态度则是更重要的一方面。今天在这里写出来,但愿跟你们共勉。app
此外是关于本文的结构,看上去每一篇的篇幅差异比较大。这一点主要是为了知识点的连贯性。好比第四篇,不少概念不连续介绍下来,恐怕在阅读源码阶段会碰到不少困难,只好放的比较长。在阅读的时候能够根据本身的状况作一些取舍及控制一下进度。框架
(待续...)机器学习
TensorFlow中文社区
Tensorflow 搭建本身的神经网络 (莫烦 Python 教程视频)
Overview of Artificial Neural Networks and its Applications
基于神经网络的激活函数和相应的数学介绍
An overview of gradient descent optimization algorithmside