tensorflow

【深度学习】神经网络入门(最通俗的理解神经网络)

先从回归(Regression)问题说起。我在本吧已经看到不少人提到如果想实现强AI,就必须让机器学会观察并总结规律的言论。具体地说,要让机器观察什么是圆的,什么是方的,区分各种颜色和形状,然后根据这些特征对某种事物进行分类或预测。其实这就是回归问题。 如何解决回归问题?我们用眼睛看到某样东西,可以一下子看出它的一些基本特征。可是计算机呢?它看到的只是一堆数字而已,因此要让机器从事物的特征中找到规律,其实是一个如何在数字中找规律的问题。 例:假如有一串数字,已知前六个是1、3、5、7,9,11,请问第七个是几? 你一眼能看出来,是13。对,这串数字之间有明显的数学规律,都是奇数,而且是按顺序排列的。 那么这个呢?前六个是0.14、0.57、1.29、2.29、3.57、5.14,请问第七个是几? 这个就不那么容易看出来了吧!我们把这几个数字在坐标轴上标识一下,可以看到如下图形: 用曲线连接这几个点,延着曲线的走势,可以推算出第七个数字——7。 由此可见,回归问题其实是个曲线拟合(Curve Fitting)问题。那么究竟该如何拟合?机器不可能像你一样,凭感觉随手画一下就拟合了,它必须要通过某种算法才行。 假设有一堆按一定规律分布的样本点,下面我以拟合直线为例,说说这种算法的原理。 如果你觉得这篇文章看起来稍微还有些吃力,或者想要系统地学习人工智能,那么推荐你去看床长人工智能教程。非常棒的大神之作,教程不仅通俗易懂,而且很风趣幽默。点击这里可以查看教程。 其实很简单,先随意画一条直线,然后不断旋转它。每转一下,就分别计算一下每个样本点和直线上对应点的距离(误差),求出所有点的误差之和。这样不断旋转,当误差之和达到最小时,停止旋转。说得再复杂点,在旋转的过程中,还要不断平移这条直线,这样不断调整,直到误差最小时为止。这种方法就是著名的梯度下降法(Gradient Descent)。为什么是梯度下降呢?在旋转的过程中,当误差越来越小时,旋转或移动的量也跟着逐渐变小,当误差小于某个很小的数,例如0.0001时,我们就可以收工(收敛, Converge)了。啰嗦一句,如果随便转,转过头了再往回转,那就不是梯度下降法。 我们知道,直线的公式是y=kx+b,k代表斜率,b代表偏移值(y轴上的截距)。也就是说,k可以控制直线的旋转角度,b可以控制直线的移动。强调一下,梯度下降法的实质是不断的修改k、b这两个参数值,使最终的误差达到最小。 求误差时使用 累加(直线点-样本点)^2,这样比直接求差距 累加(直线点-样本点) 的效果要好。这种利用最小化误差的平方和来解决回归问题的方法叫最小二乘法(Least Square Method)。 问题到此使似乎就已经解决了,可是我们需要一种适应于各种曲线拟合的方法,所以还需要继续深入研究。 我们根据拟合直线不断旋转的角度(斜率)和拟合的误差画一条函数曲线,如图: 从图中可以看出,误差的函数曲线是个二次曲线,凸函数(下凸, Convex),像个碗的形状,最小值位于碗的最下端。如果在曲线的最底端画一条切线,那么这条切线一定是水平的,在图中可以把横坐标轴看成是这条切线。如果能求出曲线上每个点的切线,就能得到切线位于水平状态时,即切线斜率等于0时的坐标值,这个坐标值就是我们要求的误差最小值和最终的拟合直线的最终斜率。 这样,梯度下降的问题集中到了切线的旋转上。切线旋转至水平时,切线斜率=0,误差降至最小值。 切线每次旋转的幅度叫做学习率(Learning Rate),加大学习率会加快拟合速度,但是如果调得太大会导致切线旋转过度而无法收敛。 [学习率其实是个预先设置好的参数,不会每次变化,不过可以影响每次变化的幅度。] 注意:对于凹凸不平的误差函数曲线,梯度下降时有可能陷入局部最优解。下图的曲线中有两个坑,切线有可能在第一个坑的最底部趋于水平。 微分就是专门求曲线切线的工具,求出的切线斜率叫做导数(Derivative),用dy/dx或f’(x)表示。扩展到多变量的应用,如果要同时求多个曲线的切线,那么其中某个切线的斜率就叫偏导数(Partial Derivative),用∂y/∂x表示,∂读“偏(partial)”。由于实际应用中,我们一般都是对多变量进行处理,我在后面提到的导数也都是指偏导数。 以上是线性回归(Linear Regression)的基本内容,以此方法为基础,把直线公式改为曲线公式,还可以扩展出二次回归、三次回归、多项式回归等多种曲线回归。下图是Excel的回归分析功能。 在多数情况下,曲线回归会比直线回归更精确,但它也增加了拟合的复杂程度。 直线方程y=kx+b改为二次曲线方程y=ax^2+bx+c时,参数(Parameter)由2个(分别是k、b)变为3个(分别是a、b、c),特征(Feature)由1个(x)变为2个(x^2和x)。三次曲线和复杂的多项式回归会增加更多的参数和特征。 前面讲的是总结一串数字的规律,现实生活中我们往往要根据多个特征(多串数字)来分析一件事情,每个原始特征我们都看作是一个维度(Dimension)。例如一个学生的学习成绩好坏要根据语文、数学、英语等多门课程的分数来综合判断,这里每门课程都是一个维度。当使用二次曲线和多变量(多维)拟合的情况下,特征的数量会剧增,特征数=维度^2/2 这个公式可以大概计算出特征增加的情况,例如一个100维的数据,二次多项式拟合后,特征会增加到100*100/2=5000个。 下面是一张50*50像素的灰度图片,如果用二次多项式拟合的话,它有多少个特征呢?——大约有3百万! 它的维度是50*50=2500,特征数=2500*2500/2=3,125,000。如果是彩色图片,维度会增加到原来的3倍,那么特征数将增加到接近3千万了! 这么小的一张图片,就有这么巨大的特征量,可以想像一下我们的数码相机拍下来的照片会有多大的特征量!而我们要做的是从十万乃至亿万张这样的图片中找规律,这可能吗? 很显然,前面的那些回归方法已经不够用了,我们急需找到一种数学模型,能够在此基础上不断减少特征,降低维度。 于是,“人工神经网络(ANN, Artificial Neural Network)”就在这样苛刻的条件下粉墨登场了,神经科学的研究成果为机器学习领域开辟了广阔的道路。 神经元 有一种假说:“智能来源于单一的算法(One Learning Algorithm)”。如果这一假说成立,那么利用单一的算法(神经网络)处理世界上千变万化的问题就成为可能。我们不必对万事万物进行编程,只需采用以不变应万变的策略即可。有越来越多的证据证明这种假说,例如人类大脑发育初期,每一部分的职责分工是不确定的,也就是说,人脑中负责处理声音的部分其实也可以处理视觉影像 下图是单个神经元(Neuron),或者说一个脑细胞的生理结构: 下面是单个神经元的数学模型,可以看出它是生理结构的简化版,模仿的还挺像: 解释一下:+1代表偏移值(偏置项, Bias Units);X1,X2,X2代表初始特征;w0,w1,w2,w3代表权重(Weight),即参数,是特征的缩放倍数;特征经过缩放和偏移后全部累加起来,此后还要经过一次激活运算然后再输出。激活函数有很多种,后面将会详细说明。 举例说明: X1*w1+X2*w2+…+Xn*wn这种计算方法称为加权求和(Weighted Sum)法,此方法在线性代数里极为常用。加权求和的标准数学符号是,不过为了简化,我在教程里使用女巫布莱尔的符号表示, 刚好是一个加号和一个乘号的组合。 这个数学模型有什么意义呢?下面我对照前面那个 y=kx+b 直线拟合的例子来说明一下。 这时我们把激活函数改为Purelin(45度直线),Purelin就是y=x,代表保持原来的值不变。 这样输出值就成了 Y直线点 = b + X直线点*k,即y=kx+b。看到了吧,只是换了个马甲而已,还认的出来吗?下一步,对于每个点都进行这种运算,利用Y直线点和Y样本点计算误差,把误差累加起来,不断地更新b、k的值,由此不断地移动和旋转直线,直到误差变得很小时停住(收敛)。这个过程完全就是前面讲过的梯度下降的线性回归。

TensorFlow学习(十):图像预处理

更新时间: 2018.6.2 增加了通过 tf.image 进行数据增强的内容,非常重要,可以直接跳到第四节。 之前做的一些任务都是从.csv文件里面读取数据来处理,这些元素都已经是处理好的值了,所以很方便。但是更多时候,我们是要从硬盘上的图片直接来做处理,所以,这里需要用到一些基本的图像处理有关的函数了。OpenCV肯定是可以使用的,但是tensorflow本身也提供了一些好用的函数。 因为通过Tensorflow完成图像有关的任务太多了,所以了解一点Tensorflow中自带的图像处理有关的函数是很有必要的。 Tensorflow中内置的图像处理的函数肯定没有OpenCV那么多那么强大啦,但是仅仅是作为简单的预处理的话,完全是够用了。 主要使用的模块就是tf.image,所以首先要是先把官方文档列出来:Module: tf.image,然后接下来就是按照图片处理的顺序来分别讲解各个函数的使用。 本节的完整测试代码,可以在我的GitHub:LearningTensorFlow/12.ImageProcess/上找到。 一.图像的编解码 Ⅰ.概览 下面是tensorflow自带编解码部分的函数,这里一起列出来,但是并不会全部都详细讲,因为使用方式大同小异,在例子中只是详细讲其中一个,其他的都可以类比或者看文档写出来,实在是很简单,就不需要多花笔墨。 decode_gif(…): Decode the first frame of a GIF-encoded image to a uint8 tensor. decode_jpeg(…): Decode a JPEG-encoded image to a uint8 tensor. decode_png(…): Decode a PNG-encoded image to a uint8 or uint16 tensor. decode_image(…): Convenience function for decode_gif, decode_jpeg, and decode_png. encode_jpeg(…): JPEG-encode an image. encode_png(…): PNG-encode an image. 在这一步,要是只是想把某个或者某些个文件读到ndarray中去,推荐更加高效的做法,就是使用matplot.image中的imread()方法,或者opencv中的方法,都是很简单无脑的。 比如在这里,我文件夹下面有个叫做“1.jpg”的文件,那么就可以用比较简单的方法得到: 二.数据转化和形状变换 这一步的目的是什么呢?首先,很多图像像素默认是int类型的,在tensorflow里面,float类型的数据更加适合处理,然后形状来说,我们知道,对于图片来说,一个网络的输入尺寸是固定的,而训练的时候图片的尺寸确不一定是固定的,所以有必要用各种方式把图片尺寸转换为固定的适合网络输入的格式。 Ⅰ.数据类型转化 convert_image_dtype(image,dtype,saturate=False,name=None)