Python 深度学习(一)(1)https://developer.aliyun.com/article/1512028
生成上述图像的代码如下:
#The user can modify the values of the weight w #as well as biasValue1 and biasValue2 to observe #how this plots to different step functions import numpy import matplotlib.pyplot as plt weightValue = 1000 #to be modified to change where the step function starts biasValue1 = 5000 #to be modified to change where the step function ends biasValue2 = -5000 plt.axis([-10, 10, -1, 10]) print ("The step function starts at {0} and ends at {1}" .format(-biasValue1/weightValue, -biasValue2/weightValue)) y1 = 1.0/(1.0 + numpy.exp(-weightValue*x - biasValue1)) y2 = 1.0/(1.0 + numpy.exp(-weightValue*x - biasValue2)) #to be modified to change the height of the step function w = 7 y = y1*w-y2*w plt.plot(x, y, lw=2, color='black') plt.show()
反向传播算法
我们已经看到了神经网络是如何将输入映射到确定的输出,取决于固定的权重。一旦神经网络的架构被定义(前馈,隐藏层数量,每层神经元数量),以及一旦为每个神经元选择了活动函数,我们需要设置权重,这将定义网络中每个神经元的内部状态。我们将看到如何为 1 层网络设置这些权重,然后如何将其扩展到深度前馈网络。对于深度神经网络,用于设置权重的算法称为反向传播算法,我们将在本节中讨论和解释这个算法,因为这是多层前馈神经网络中最重要的主题之一。然而,我们将首先快速讨论一层神经网络的情况。
我们需要理解的一般概念是:每个神经网络都是函数的近似,因此每个神经网络都不等于期望的函数,而是会有一些差异。这个差异被称为误差,目标是最小化这个误差。由于误差是神经网络中的权重的函数,我们希望在权重方面最小化误差。误差函数是许多权重的函数;因此它是许多变量的函数。数学上,此函数为零的点集因此代表一个超曲面,为了在这个超曲面上找到最小值,我们需要选择一个点,然后沿着最小值方向跟随一条曲线。
线性回归
我们已经在第一章介绍了线性回归,但由于我们现在处理的是许多变量,为了简化事情,我们将引入矩阵表示法。让x是输入;我们可以将x视为一个向量。在线性回归的情况下,我们将考虑一个单输出神经元y;因此,权重w的集合是一个与x的维度相同的向量。然后,激活值被定义为内积**。
让我们假设对于每个输入值x,我们想要输出一个目标值t,而对于每个x,神经网络将输出一个值y,由选择的激活函数定义,在这种情况下,绝对值差异(y-t)表示预测值和特定输入示例x的实际值之间的差异。如果我们有m个输入值x[i],每个值都将有一个目标值t[i]。在这种情况下,我们使用均方误差计算误差,其中每个y[i]是w的函数。因此,误差是w的函数,并且通常用*J(w)*表示。
如前所述,这表示了与w的维度相等的超曲面(我们隐式地也考虑了偏差),对于每个w[j],我们需要找到一个曲线,该曲线将导致表面的最小值。曲线沿特定方向增加的方向由其对该方向的导数给出,在这种情况下由以下公式给出:
为了朝着最小值移动,我们需要按照设置的相反方向移动每个w[j]。
让我们计算以下:
如果,那么,因此
提示
符号有时可能令人困惑,特别是第一次看到它时。输入由向量x^i 给出,其中上标表示第 i 个示例。由于x和w是向量,下标表示向量的j^th 坐标。y^i 然后表示给定输入x^i 的神经网络输出,而t^i 表示目标值,即与输入x[i]对应的期望值。
为了朝向最小值移动,我们需要将每个权重按其导数方向移动一小步长 l,称为学习速率,通常远小于 1,(例如 0.1 或更小)。因此,我们可以重新定义导数并将“2”合并到学习率中,以获得以下给出的更新规则:
或者,更一般地,我们可以将更新规则写成矩阵形式如下:
在这里,(也称为 nabla)代表偏导数的向量。这个过程通常被称为梯度下降。
提示
是偏导数的向量。我们可以将对w的更新规则分别写为每个其分量wj,也可以用矩阵形式写出更新规则,其中,用代替为每个j写出偏导数。
最后一点;更新可以在计算所有输入向量后进行,但在某些情况下,权重可以在每个示例之后或在一定预设数量的示例后进行更新。
逻辑回归
在逻辑回归中,输出不是连续的;相反,它被定义为一组类。在这种情况下,激活函数不会像之前那样是恒等函数,而是我们将使用逻辑 sigmoid 函数。正如我们之前看到的,逻辑 sigmoid 函数输出(0,1)中的实值,因此它可以被解释为概率函数,这也是为什么在 2 类分类问题中它可以运行得很好的原因。在这种情况下,目标可以是两个类别中的一个,而输出表示它是其中两个类别之一(比如t=1)的概率。
提示
再次,符号可能令人困惑。t是我们的目标,它可以在这个例子中有两个值。这两个值通常被定义为类别 0 和类别 1。这些值 0 和 1 不应与逻辑 sigmoid 函数的值混淆,后者是介于 0 和 1 之间的连续实值函数。sigmoid 函数的实际值表示输出属于类别 0 或类别 1 的概率。
如果a是之前定义的神经元激活值,让我们用 s(a)表示逻辑 sigmoid 函数,因此,对于每个示例 x,给定权重w时输出为类别y的概率是:
我们可以更简洁地将方程写为如下形式:
由于对每个样本x^i,概率P(t[i]|x[i]*, w)*是独立的,全局概率如下:
如果我们取前述方程的自然对数(将乘积变为和),我们得到如下结果:
目标现在是最大化这个对数以获得预测正确结果的最高概率。通常,这是通过使用梯度下降最小化由J(w)= -log(P(y¦ x *,w))定义的损失函数J(w)*来实现的,就像前面的情况一样。
与以前一样,我们计算相对于权重w[j]的损失函数的导数,得到:
提示
要理解最后一个等式,让我们提醒读者以下事实:
因此,根据链式法则:
同样:
通常,在多类输出t的情况下,其中t是一个向量(t[1],*…, t[n]),我们可以使用 = 来推导出权重的更新方程:
这类似于我们对线性回归所看到的更新规则。
反向传播
在单层情况下,权重调整很容易,因为我们可以使用线性或逻辑回归,并同时调整权重以获得更小的错误(最小化成本函数)。对于多层神经网络,我们可以对连接最后隐藏层与输出层的权重使用类似的论证,因为我们知道输出层的期望值,但我们无法对隐藏层做同样的操作,因为预先我们并不知道隐藏层神经元的值应该是什么。相反,我们计算最后一个隐藏层的误差,并估计前一层的误差,从最后一层向第一层反向传播误差,因此得名反向传播。
反向传播是最难理解的算法之一,但所需的只是对基本微分和链式法则的一些知识。首先让我们引入一些符号。我们用J表示成本(误差),用y表示被定义为在激活值a上的活动函数(例如,y 可以是逻辑 Sigmoid),它是权重w和输入x的函数。让我们也定义w[i,j],i^(th)输入值和jth 输出之间的权重。在这里,我们比对 1 层网络更泛化地定义输入和输出:如果w[i,j]连接一个前馈网络中的连续两层,我们将"输入"称为第一层包含的神经元,"输出"称为第二层包含的神经元。为了不使符号过于繁重,并且不必指出每个神经元在哪一层,我们假设第i个输入y[i]始终在包含第j^(th)输出 y[j]的层之前的那一层。
提示
请注意,字母y既用于表示输入,也用于表示活动函数的输出。 y[j]是下一层的输入,而 y[j]是活动函数的输出,但它也是下一层的输入。因此,我们可以将 y[j]'s 视为 y[j]'s 的函数。
我们还使用下标i和j,其中我们始终将带有下标i的元素归属于包含下标j的元素的层之前的那一层。
图 10
在这个例子中,第 1 层表示输入,第 2 层表示输出,所以 w[i,j] 是连接一层中的 y[j] 值和下一层中的 y[j] 值的数值。
使用这个符号表示法和导数的链式法则,我们可以为我们神经网络的最后一层写出以下结果:
既然我们知道 ,我们有以下结果:
如果 y 是之前定义的逻辑 S 型函数,我们将得到与前一节末尾已经计算过的相同结果,因为我们知道成本函数,我们可以计算所有的导数。
对于前面的层,相同的公式成立:
实际上,a j 是活动函数,我们知道,这是权重的一个函数。y[j] 值,是“第二”层神经元的活动函数,是其激活值的函数,当然,成本函数是我们选择的活动函数的函数。
提示
即使我们有几个层,我们总是集中在连续层对中,因此,或许有点滥用符号,我们总是有一个“第一”层和一个“第二”层,就像图 10 中的那样,它是“输入”层和“输出”层。
既然我们知道 ,并且我们知道 是我们可以计算的活动函数的导数,我们只需要计算导数 。让我们注意到,这是相对于“第二”层的激活函数的误差的导数,如果我们可以计算出最后一层的这个导数,并且有一个允许我们计算下一层的导数的公式,我们可以从最后一层开始计算所有导数并向后移动。
让我们注意到,正如我们通过 y[j] 定义的那样,它们是“第二”层神经元的激活值,但它们也是活动函数,因此是第一层激活值的函数。因此,应用链式法则,我们有以下结果:
再次,我们可以计算 和 ,因此一旦我们知道 ,我们可以计算 ,由于我们可以计算出最后一层的 ,我们可以向后移动并计算任何一层的 ,因此可以计算出任何一层的 。
总结一下,如果我们有一系列层,其中
然后我们有了这两个基本方程,第二个方程中的求和应该是对从y j到任何神经元的传出连接的总和。
通过使用这两个方程,我们可以计算对每层成本的导数。
如果我们设置,表示成本对激活值的变化,我们可以将看作是y[j]神经元的误差。我们可以重写
这意味着。这两个方程给出了看待反向传播的另一种方式,即成本对激活值的变化,并提供了一种计算这种变化的公式,以便我们知道了如何为以下层的任何层计算这种变化:
我们还可以组合这些方程并证明:
更新权重的反向传播算法然后在每一层上给出
在最后一节,我们将提供一个代码示例,以帮助理解和应用这些概念和公式。
工业应用
在上一章中,我们提到了一些机器学习应用的例子。神经网络,特别是具有相似应用的神经网络。我们将回顾一些应用程序,它们在 1980 年代末和 1990 年代初变得流行之后使用了这些应用程序,后者发现了反向传播,并且可以训练更深的神经网络。
信号处理
在信号处理领域,神经网络有许多应用。神经网络最早的应用之一是抑制电话线上的回声,特别是在 1957 年由伯纳德·威德罗和马西安·霍夫开发,特别是在洲际电话中。Adaline 使用恒等函数作为其训练的激活函数,并寻求最小化激活和目标值之间的均方误差。Adaline 经过训练,通过将输入信号应用于* Adaline (滤波器)和电话线来消除电话线上的回声。电话线输出和 Adaline *输出之间的差异是误差,用于训练网络并从信号中消除噪声(回声)。
医疗
该网络是由安德森于 1986 年开发的,其背后的思想是存储有关每种情况的症状、诊断和治疗信息的大量医疗记录。该网络经过训练,可以对不同症状的最佳诊断和治疗进行预测。
最近,IBM 利用深度神经网络开发了一个神经网络,可以预测可能的心脏衰竭,阅读医生的笔记,类似于经验丰富的心脏病专家。
自动驾驶汽车
1989 年,Nguyen 和 Widrow,以及 1990 年,Miller、Sutton 和 Werbos 开发了一个可以为大型拖车提供倒车到装货码头的方向指示的神经网络。神经网络由两个模块组成:第一个模块能够使用多层的神经网络计算新的位置,通过学习卡车对不同信号的反应。这个神经网络称为仿真器。第二个模块称为控制器,通过使用仿真器来了解其位置,学习给出正确的指令。近年来,自动驾驶汽车已经取得了巨大进步,并且已经成为现实,尽管更复杂的深度学习神经网络与来自摄像头、GPS、激光雷达和声纳单元的输入一起使用。
商业
1988 年,Collins、Ghosh 和 Scofield 开发了一个神经网络,可以用来评估是否应该批准和发放抵押贷款。利用抵押贷款评估员的数据,神经网络被训练来确定是否应该给予申请人贷款。输入是一些特征,如申请人的就业年限、收入水平、受抚养人数、财产的评估价值等等。
模式识别
我们已经多次讨论了这个问题。神经网络已经被应用的一个领域是字符识别。比如,这可以用于数字的识别,也可以用于手写邮政编码的识别。
语音产生
1986 年,Sejnowski 和 Rosenberg 提出了广为人知的 NETtalk 示例,通过阅读书面文字来产生口语。NETtalk 的要求是一组书面文字及其发音的示例。输入包括要发音的字母以及它前面和后面的字母(通常是三个),训练是使用最常见的单词及其语音转录进行的。在实现中,该网络首先学习识别元音和辅音,然后学习识别单词的开头和结尾。通常需要多次迭代才能使发音变得清晰,其进展有时类似于孩子学习如何发音单词。
一个用于 xor 函数的神经网络的代码示例
这是一个众所周知的事实,也是我们已经提到过的,即单层神经网络无法预测 XOR 函数。单层神经网络只能对线性可分集进行分类,然而,正如我们所见,通用逼近定理指出,一个具有足够复杂架构的 2 层网络可以近似任何函数。我们现在将创建一个隐藏层中具有两个神经元的神经网络,并演示如何模拟 XOR 函数。但是,我们将编写代码,让读者可以简单地修改它以允许任意数量的层和每层的神经元,以便读者可以尝试模拟不同的情景。我们还将使用双曲正切函数作为此网络的活动函数。为了训练网络,我们将实现之前讨论过的反向传播算法。
我们只需要导入一个库,numpy
,尽管如果读者希望可视化结果,我们还建议导入matplotlib
。因此,代码的前几行是:
import numpy from matplotlib.colors import ListedColormap import matplotlib.pyplot as plt
接下来我们定义我们的活动函数及其导数(在本示例中我们使用tanh(x)
):
def tanh(x): return (1.0 - numpy.exp(-2*x))/(1.0 + numpy.exp(-2*x)) def tanh_derivative(x): return (1 + tanh(x))*(1 - tanh(x))
接下来我们定义NeuralNetwork
类:
class NeuralNetwork:
为了遵循 Python 语法,NeuralNetwork
类中的任何内容都必须缩进。我们定义了NeuralNetwork
类的“构造函数”,即其变量,这在本例中将是神经网络的架构,即有多少层以及每层有多少个神经元,并且我们还将随机初始化权重为介于负 1 和正 1 之间。net_arch
将是一个包含每层神经元数量的一维数组:例如[2,4,1]表示具有两个神经元的输入层,具有四个神经元的隐藏层和具有一个神经元的输出层。
由于我们正在研究 XOR 函数,因此对于输入层,我们需要有两个神经元,对于输出层,只需要一个神经元:
#net_arch consists of a list of integers, indicating #the number of neurons in each layer, i.e. the network #architecture def __init__(self, net_arch): self.activity = tanh self.activity_derivative = tanh_derivative self.layers = len(net_arch) self.steps_per_epoch = 1000 self.arch = net_arch self.weights = [] #range of weight values (-1,1) for layer in range(self.layers - 1): w = 2*numpy.random.rand(net_arch[layer] + 1, net_arch[layer+1]) - 1 self.weights.append(w)
在此代码中,我们已定义活动函数为双曲正切函数,并定义了其导数。我们还定义了每个时期应有多少个训练步骤。最后,我们初始化了权重,确保我们也初始化了稍后将添加的偏置的权重。接下来,我们需要定义fit
函数,这个函数将训练我们的网络。在最后一行中,nn
代表NeuralNetwork
类,predict
是我们稍后将定义的NeuralNetwork
类中的函数:
#data is the set of all possible pairs of booleans #True or False indicated by the integers 1 or 0 #labels is the result of the logical operation 'xor' #on each of those input pairs def fit(self, data, labels, learning_rate=0.1, epochs=100): #Add bias units to the input layer ones = numpy.ones((1, data.shape[0])) Z = numpy.concatenate((ones.T, data), axis=1) training = epochs*self.steps_per_epoch for k in range(training): if k % self.steps_per_epoch == 0: print('epochs: {}'.format(k/self.steps_per_epoch)) for s in data: print(s, nn.predict(s))
我们在这里所做的一切只是在输入数据中添加了一个“1”(始终开启的偏置神经元),并设置了代码以在每个时期结束时打印结果,以便跟踪我们的进度。我们现在将继续设置我们的前向传播:
sample = numpy.random.randint(data.shape[0]) y = [Z[sample]] for i in range(len(self.weights)-1): activation = numpy.dot(y[i], self.weights[i]) activity = self.activity(activation) #add the bias for the next layer activity = numpy.concatenate((numpy.ones(1), numpy.array(activity))) y.append(activity) #last layer activation = numpy.dot(y[-1], self.weights[-1]) activity = self.activity(activation) y.append(activity)
我们将在每个步骤后更新我们的权重,因此我们随机选择其中一个输入数据点,然后设置前向传播,为每个神经元设置激活,然后在激活值上应用tanh(x)
。由于我们有一个偏差,我们将偏差添加到我们的矩阵 y 中,该矩阵跟踪每个神经元的输出值。
现在我们进行错误的反向传播以调整权重:
#error for the output layer error = labels[sample] - y[-1] delta_vec = [error * self.activity_derivative(y[-1])] #we need to begin from the back, #from the next to last layer for i in range(self.layers-2, 0, -1): error = delta_vec[-1].dot(self.weights[i][1:].T) error = error*self.activity_derivative(y[i][1:]) delta_vec.append(error) #Now we need to set the values from back to front delta_vec.reverse() #Finally, we adjust the weights, #using the backpropagation rules for i in range(len(self.weights)): layer = y[i].reshape(1, nn.arch[i]+1) delta = delta_vec[i].reshape(1, nn.arch[i+1]) self.weights[i] +=learning_rate*layer.T.dot(delta)
这结束了我们的反向传播算法;我们所要做的只是编写一个预测函数来检查结果:
def predict(self, x): val = numpy.concatenate((numpy.ones(1).T, numpy.array(x))) for i in range(0, len(self.weights)): val = self.activity(numpy.dot(val, self.weights[i])) val = numpy.concatenate((numpy.ones(1).T, numpy.array(val))) return val[1]
在这一点上,我们只需要按照下面的主函数进行编写:
if __name__ == '__main__': numpy.random.seed(0) #Initialize the NeuralNetwork with #2 input neurons #2 hidden neurons #1 output neuron nn = NeuralNetwork([2,2,1]) X = numpy.array([[0, 0], [0, 1], [1, 0], [1, 1]]) #Set the labels, the correct results for the xor operation y = numpy.array([0, 1, 1, 0]) #Call the fit function and train the network #for a chosen number of epochs nn.fit(X, y, epochs=10) print "Final prediction" for s in X: print(s, nn.predict(s))
注意numpy.random.seed(0)
的用法。这只是为了确保权重初始化在不同运行中的一致性,以便比较结果,但对于神经网络的实现并不是必需的。
这结束了代码,结果应该是一个四维数组,例如:(0.003032173692499,0.9963860761357,0.9959034563937,0.0006386449217567),表明神经网络学会了输出应该是(0,1,1,0)。
读者可以略微修改我们之前在本书中使用的plot_decision_regions function
中创建的代码,看看不同的神经网络如何根据所选择的架构区分不同的区域。
输出图片将如下图所示。圆代表(True,True)和(False,False)的输入,而三角形代表(True,False)和(False,True)的输入对于 XOR 函数。
同一图,左边是缩小的,右边是放大选择的输入。神经网络学会了分离这些点,创建了一个含有两个True输出值的带状区域。
不同的神经网络架构(例如,实现具有不同隐藏层中神经元数量的网络,或者具有不止一个隐藏层)可能产生不同的分离区域。为了实现这一点,读者只需要改变代码中的一行nn = NeuralNetwork([2,2,1]).
。第一个2
必须保留(输入不变),但可以修改第二个2
以表示不同隐藏层中的神经元数量。添加另一个整数将添加一个带有所添加的整数指示的神经元数的新的隐藏层。最后的1
不能修改。例如,([2,4,3,1])
将表示一个 3 层神经网络,第一个隐藏层中有四个神经元,第二隐藏层中有三个神经元。
然后读者会发现,虽然解决方案是一样的,但是根据所选择的架构,分离区域的曲线会有所不同。实际上,选择nn = NeuralNetwork([2,4,3,1])
将给出以下图形:
例如,选择nn = NeuralNetwork([2,4,1])
会产生以下结果:
因此,神经网络的架构定义了神经网络解决手头问题的方式,不同的架构提供了不同的方法(尽管它们可能都会产生相同的结果),类似于人类思维过程可以沿着不同的路径达到相同的结论。我们现在准备更仔细地研究深度神经网络及其应用。
摘要
在本章中,我们详细介绍了神经网络,并提到了它们在与其他竞争算法相比的成功。神经网络由它们所属的“单元”或神经元,以及属于它们的连接或权重组成,这些权重表征了不同神经元之间通信的强度以及它们的活动函数,即神经元如何处理信息。我们讨论了如何创建不同的架构,以及神经网络如何可以具有许多层,以及为什么内部(隐藏)层很重要。我们解释了信息如何通过基于权重和定义的活动函数从输入流向输出,最后我们展示了如何定义一种称为反向传播的方法来“调整”权重以提高所需的准确性。我们还提到了许多神经网络被应用的领域。
在下一章中,我们将继续讨论深度神经网络,特别是我们将解释“深度”一词的含义,就像深度学习一样,我们将解释它不仅仅是指网络中隐藏层的数量,更重要的是指神经网络学习的质量。为此,我们将展示神经网络如何学习识别特征并将它们组合成识别对象的表示,这将为使用神经网络进行无监督学习打开大门。我们还将描述几个重要的深度学习库,最后,我们将提供一个具体的例子,说明我们如何应用神经网络进行数字识别。
第三章:深度学习基础
在第一章机器学习-简介中,我们介绍了机器学习及其一些应用,并简要讨论了一些可用于实现机器学习的算法和技术。在第二章神经网络中,我们专注于神经网络;我们已经表明 1 层网络太简单,只能处理线性问题,而且我们介绍了通用逼近定理,展示了只有一个隐层的 2 层神经网络能以任意程度逼近 R*[n]*的紧致子集上的任何连续函数。
在本章中,我们将介绍深度学习和深度神经网络,也就是至少有两个或更多个隐层的神经网络。读者可能会想知道为什么要使用多个隐层,考虑到通用逼近定理,并无不合理之处,因为在很长一段时间内使用的神经网络非常浅,只有一个隐层。答案是 2 层神经网络确实可以以任意程度逼近任何连续函数,然而,增加层次也增加了可能更加难以模拟的复杂性,并且可能需要更多的神经元来模拟浅层网络。还有另一个更重要的原因是深度学习的术语“深度”并不仅仅指网络的深度或神经网络的层数,而是指“学习”的水平。在深度学习中,神经网络不仅仅是学习在给定输入X的情况下预测输出Y,而且还能理解输入的基本特征。在深度学习中,神经网络能够对构成输入示例的特征进行抽象化,理解示例的基本特征,并根据这些特征进行预测。在深度学习中,存在其他基本机器学习算法或浅层神经网络中缺乏的抽象层面。
在本章中,我们将涵盖以下主题:
- 什么是深度学习?
- 深度学习的基本概念
- 深度学习的应用
- GPU 与 CPU 对比
- 流行的开源库
什么是深度学习?
2012 年,Alex Krizhevsky,Ilya Sutskever 和 Geoff Hinton 在《神经信息处理系统》(NIPS)(2012)的《ImageNet 分类与深度卷积神经网络》一文中,写道:
“值得注意的是,如果移除一个卷积层,我们网络的性能会下降。例如,移除任何一个中间层都会导致网络的 top-1 性能损失约为 2%。所以深度确实对于实现我们的结果至关重要。”
在这个重要的论文中,他们明确提到了深度网络中隐藏层的数量的重要性。Krizheysky、Sutskever 和 Hilton 谈到了卷积层,我们将在第五章,图像识别中讨论它们,但基本问题仍然存在:这些隐藏层到底做什么?
一个典型的英语谚语是一张图片胜过千言万语。让我们使用这种方法来理解深度学习是什么。在 H. Lee、R. Grosse、R. Ranganath 和 A. Ng,用于可扩展无监督学习分层表示的卷积深度置信网络,发表于 2009 年国际机器学习会议(ICML)的论文中(参见web.eecs.umich.edu/~honglak/icml09-ConvolutionalDeepBeliefNetworks.pdf
),作者使用了一些图片,我们在这里复制了一些。
在他们的例子中,他们展示了不同类别的对象和/或动物的神经网络图片,并且网络学习了每个类别的一些基本特征。例如,网络可以学习一些非常基本的形状,如线条或边缘,这些是每个类别都共有的。然而,在下一层,网络可以学习这些线条和边缘如何组合在一起,以使每个类别的图像具有眼睛或车轮等特征。这类似于人类视觉皮层的工作方式,我们的大脑从简单的线条和边缘开始越来越复杂地识别特征。
深度神经网络中的隐藏层也是通过逐层理解更加复杂的特征来工作的。如果我们想要定义什么是一个人脸,我们需要定义它的部分:眼睛、鼻子、嘴巴,然后我们需要上升到更高的层次,并定义它们相对于彼此的位置:两只眼睛在顶部的中间位置,处于同样的高度,鼻子在中间,嘴巴在下方中间位置,位于鼻子下方。深度神经网络通过自我学习来捕捉这些特征,首先学习图像的组成部分,然后学习它们的相对位置等等,就像在图像 1 和图像 2 中,我们可以看到深层抽象在每一层中的作用。一些深度学习网络实际上可以被看作是生成算法,例如受限玻尔兹曼机(RBMs),而不仅仅是一个预测算法,因为它们学会生成一个信号,然后根据已学习的生成假设进行预测。随着我们在本章中逐步深入,我们将使这个概念更加清晰。
Python 深度学习(一)(3)https://developer.aliyun.com/article/1512030