matlab粗集理论代码实现_深度学习——基础理论、底层理解、代码实现

4b222e6e8a4ca8d12d03b9bc5a23a4b6.png
不使用任何现有的深度学习框架,尽可能仅使用最基本的数学知识和Python库,从零了解深度学习核心问题的数学原理,从零创建一个经典的深度学习网络。远离黑盒,加深对深度学习的理解。【图片水印来自我的个人博客】

第一章 python入门

    • 数据类型:Python中的type()函数
    • 列表(数组):
>>>a = [1, 2, 3, 4, 5] # 生成列表
>>> a[0:2] # 获取索引为0到2(不包括2!)的元素
[1, 2]
>>> a[1:] # 获取从索引为1的元素到最后一个元素
[2, 3, 4, 5]
>>> a[:3] # 获取从第一个元素到索引为3(不包括3!)的元素
[1, 2, 3]
>>> a[:-1] # 获取从第一个元素到最后一个元素的 前一个元素之间的元素
[1, 2, 3, 4]
>>> a[:-2] # 获取从第一个元素到最后一个元素的前二个元素之间的元素
[1, 2, 3]
    • 字典:
>>> me = {'height':180} # 生成字典
>>> me['height']# 访问元素
180
>>> me['weight'] = 70 # 添加新元素
>>> print(me)
{'height': 180, 'weight': 70}
    • 类:

3bb0fc3d27adaffb784e7a2d956f69aa.png
    • eg.

7e44f06f5f98bd836ace1d4d6c1c9ec6.png
    • NumPy:
      • numpy数组和python数组的区别
        • Numpy是专门针对数组的操作和运算进行了设计
        • 其数组的存储效率和输入输出性能远优于Python中的嵌套列表
    • 生成NumPy数组,需要使用np.array()方法。
      • np.array()接收Python 列表作为参数,生成NumPy数组(numpy.ndarray)。
      • >>> x = np.array([1.0, 2.0, 3.0])
      • >>> print(x) [ 1. 2. 3.]
      • >>> type(x)
      • <class 'numpy.ndarray'>
    • 广播:
      • 在NumPy数组的各个元素和标量之间进行运算。
      • >>> x = np.array([1.0, 2.0, 3.0])
      • >>> x / 2.0
      • array([ 0.5, 1. , 1.5])

193bd8234fe15a8e583912904406213a.png
    • N维数组:
      • >>> A = np.array([[1, 2], [3, 4]])
      • >>> A.shape (2, 2)
      • >>> A.dtype #矩阵元素的数据类型可以通过dtype查看
      • dtype('int64')
      • 乘法:
        • >>> B = np.array([[3, 0],[0, 6]])
        • >>> A * B #各元素相乘
        • array([[ 3, 0],
          • [ 0, 24]])
    • 访问元素:【多维数组】

9e5dcd231ccf613b5e49e1b0bd91bbbc.png
    • 使用数组访问各个元素:

48b59e395962b5d7d7ce3a8d00580d29.png
    • 获取满足一定条件的元素:【要从X中抽出 大于15的元素】

bd30540e00a1240b452606c1f3b6c857.png
    • argmax()
      • p = np.argmax(y_batch, axis=1)
      • 我们给定了参数axis=1。这指定了在100 × 10的数组中,沿着第1维方向(以 第1维为轴)找到值最大的元素的索引(第0维对应第1个维度)
    • Matplotlib:
      • 使用Matplotlib可以轻松地绘制图形和实现数据的可视化。
      • pyplot模块绘制图形:
        • 绘制sin(x)和cos(x):

6534740cf1489f7978f87f94c467e325.png

cf1ef3d1157a658992bf089629143c26.png
    • image模块的imread()方法读入图像:

f4fde13effa0ea471ce2cc93aa1dc922.png

第二章 感知机

      • 神经网络(深度学习)的起源
      • 使用单层感知机可以实现与门、与非门、或门三种逻辑电路,但是无法实现异或门。
      • 感知机的绝妙之处在于它可以“叠加层”(通过叠加层来表示异或门是本节的要点)。
      • 感知机通过叠加层能够进行非线性的表示,理论上还可以表示计算机进行的处理。

第三章 神经网络

    • 我们把最左边的一列称为输入层,最右边的一列称为输出层,中间的一列称为中间层
    • 依次称为第0层、第 1层、第2层。以下是一个“2层网络”:

4089a718817a57eb918a8fd6b167ba4a.png
    • b是被称为偏置的参数,用于控制神经元被激活的容易程度
    • w1 和w2是表示各个信号的权重的参数,用于控制各个信号的重要性
    • 激活函数(activation function):连接感知机和神经网络的桥梁。
      • h(x)函数会将输入信号的总和转换为输出信号,激活函数的 作用在于决定如何来激活输入信号的总和。

2be236f4f63fa33cfa68c68e464b6503.png

0d461712abbbbe968beaecd0ea787e89.png
    • sigmoid函数:
      • 神经网络中经常使用的一个激活函数就是式(3.6)表示的sigmoid函数

3cd54ee0b3cbce9dbf997caff5708bf8.png
    • def sigmoid(x):
      • return 1 / (1 + np.exp(-x))
    • sigmoid函数是一条平滑的曲线,输出随着输入发生连续性的变化。
    • 而阶跃函数以0为界,输出发生急剧性的变化。
    • sigmoid函数的平滑性对神经网络的学习具有重要意义。
    • 神经网络中流动的是连续的实数值信号。
    • 神经网络的激活函数必须使用非线性函数
    • 为什么不能使用线性函数呢?
      • 因为使用线性函数的话,加深神经网络的层数就没有意义了。
      • 线性函数的问题在于,不管如何加深层数,总是存在与之等效的“无隐藏层的神经网络”。
    • ReLU函数:
      • sigmoid函数很早就开始被使用了,而最近则主要使用ReLU(Rectified Linear Unit)函数。

8bd616b9ca806f8b59a5e6657f2c4b75.png
      • def relu(x):

return np.maximum(0, x)

    • 多维数组的运算
      • 数组的维数可以通过np.dim()函数获得:

5dcb7b3cdb5fdbfc33ec67c12de4890a.png
        • 注意,这里的A.shape的结果是个元组(tuple)。这是因为一维数组的情况下也要返回和多维数组的情况下一致的结果。例如,二维数组时返回的 是元组(4,3),三维数组时返回的是元组(4,3,2),因此一维数组时也同样以 元组的形式返回结果。下面我们来生成一个二维数组。
      • 矩阵乘法:

b8b6c24df3f0db7a22d72b73665db8d7.png
>>> A = np.array([[1, 2], [3, 4]])
>>> B = np.array([[3, 0],[0, 6]])
>>> A*B
array([[ 3, 0],
[ 0, 24]]) >>> np.dot(A,B) #多维数组的点积 array([[ 3, 12], [ 9, 24]])
    • 符号确认

ba93efa59c0e451c31889b0be4d413fd.png

7aa46c3012a1aeeafbb5f71257fa0a0c.png
    • 三层神经网络前向传递代码实现小结:

970a0d33f6bf8f515811ee0303f2c797.png
def identity_function(x): return x def sigmoid(x): return 1 / (1 + np.exp(-x)) def init_network(): network = {} network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]]) network['b1'] = np.array([0.1, 0.2, 0.3]) network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]]) network['b2'] = np.array([0.1, 0.2]) network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]]) network['b3'] = np.array([0.1, 0.2]) return network def forward(network, x): W1, W2, W3 = network['W1'], network['W2'], network['W3'] b1, b2, b3 = network['b1'], network['b2'], network['b3'] a1 = np.dot(x, W1) + b1 z1 = sigmoid(a1) a2 = np.dot(z1, W2) + b2 z2 = sigmoid(a2) a3 = np.dot(z2, W3) + b3 y = identity_function(a3) return y network = init_network() x = np.array([1.0, 0.5]) y = forward(network, x) print(y) # [ 0.31682708 0.69627909]
    • 输出层的设计
      • 神经网络可以用在分类问题和回归问题上,不过需要根据情况改变输出层的激活函数。一般而言,回归问题【预测连续数值】用恒等函数,分类问题用softmax函数
      • softmax函数:

923b45dcd6fa75c6b7ecaab3c3c78a6f.png
        • softmax函数 的输出通过箭头与所有的输入信号相连。这是因为,从式(3.10)可以看出, 输出层的各个神经元都受到所有输入信号的影响。

81b11859d7598715d770e5ccc6e3bf26.png

ac47e35af6b485f225a46d2087f9598f.png
    • 实现softmax函数时的注意事项:
      • 由于e^x计算存在指数爆炸,对于很多时候x很大的情况,容易出现错误。
      • 但是分子分母的exp()中同加一个常数,不影响结果(推导如下)

1e9253c7cb27933a9ef11e7d307b4fcf.png
      • 所以,通过减去输入信号中的最大值,可以实现正确计算:
      • 正确的softmax如下:

f5c52ee2b83ee087d139b57fd3a2a374.png
      • softmax函数的输出是0.0到1.0之间的实数。并且,softmax 函数的输出值的总和是1。输出总和为1是softmax函数的一个重要性质。正因为有了这个性质,我们才可以把softmax函数的输出解释为“概率”。
      • 但是:

一般而言,神经网络只把输出值最大的神经元所对应的类别作为识别结果。

并且,即便使用softmax函数,输出值最大的神经元的位置也不会变。因此, 神经网络在进行分类时,输出层的softmax函数可以省略。在实际的问题中, 由于指数函数的运算需要一定的计算机运算量,因此输出层的softmax函数一般会被省略

在输出层使用softmax函数是因为它和神经网络的学习有关系(详细内容请参考下一章)。

    • MNIST数据集 手写数字识别
      • 批处理

d5f681ff6ce5879982690d85da044eda.png

        • 输入数据的形状为100 × 784,输出数据的形状为 100 × 10。这表示输入的100张图像的结果被一次性输出了。
          比如,x[0]和y[0]中保存了第0张图像及其推理结果,x[1]和y[1]中保存了第1张图像及 其推理结果,等等。
          这种打包式的输入数据称为批(batch)。批有“捆”的意思,图像就如同纸币一样扎成一捆。

cd5ef67069a3b704282930f9b2e4b639.png

第四章 神经网络的学习

  • 前几章讲神经网络一个现有模型的正向工作过程,这一章主要讲神经网络的学习。这里所说的“学习”是指从训练数据中 自动获取最优权重参数的过程。
  • 从数据中学习【利用数据决定参数值】
    • 数据驱动

c7a06477a5d46bac51511c26c78d58ef.png

      • 训练数据(监督数据),泛化能力,过拟合(over fitting)
    • 损失函数:
      • 损失函数是表示神经网络性能的“恶劣程度”的指标,即当前的 神经网络对监督数据在多大程度上不拟合,在多大程度上不一致。
        “使性能的恶劣程度达到最小”和“使性 能的优良程度达到最大”是等价的,不管是用“恶劣程度”还是“优 良程度”,做的事情本质上都是一样的。
      • 均方误差:(mean squared error)
        • 可以用作损失函数的函数有很多,其中最有名的是均方误差(mean squared)

8b275c82176a1c6981422254d1ead2ed.png

b50cabb664de59fa323ab2dc8b924bc2.png

  • 注意,对于普通数组来说,一定要转换为numpy数组
  • 交叉熵误差(cross entropy error)

1ea8d4f011c5341529678a3ee31cb9bb.png

4a89d4cad5bb87964e3fee7904dd02ec.png

  • mini-batch学习
    • 计算损失函数时必须将所有的训练数据作为对象。也就是说,如果训练数据有100个的话,我们就要把这100个损失函数的总和作为学习的指标。
    • 其实就是把求单个数据的损失函数的式(4.2)扩大到了N份数据,不过最后还要除以N进行正规化。
      通过除以N,可以求单个数据的“平均损失函数”。
      通过这样的平均化,可以获得和训练数据的数量无关的统一指标。
      比如,即便训练数据有1000个或10000个,也可求得单个数据的平均损失函数。

89097ddfd56489924278e2dbdcb56f33.png

    • 但是,如果遇到大数据, 数据量会有几百万、几千万之多,这种情况下以全部数据为对象计算损失函数是不现实的。
      因此,我们从全部数据中选出一部分,作为全部数据的“近似”。神经网络的学习也是从训练数据中选出一批数据(称为mini-batch,小批量),然后对每个mini-batch进行学习。比如,从60000个训练数据中随机选择100笔,再用这100笔数据进行学习。
      这种学习方式称为mini-batch学习
      • NumPy的np.random.choice():

73712bed2a9f4d066d64f7d1b64213bc.png
        • 使用np.random.choice()可以从指定的数字中随机选择想要的数字。
          比如, np.random.choice(60000, 10)会从0到59999之间随机选择10个数字。我们可以得到一个包含被选数据的索引的数组。
        • 之后,我们只需指定这些随机选出的索引,取出mini-batch,然后使用 这个mini-batch计算损失函数即可。
  • mini-batch版交叉熵误差的实现【在二维数组中取数】【生成一个batch_size*t]的矩阵

3ae3c6c735eea1dfb4bb36c3b7f061ce.png
  • 为何要设定损失函数
    • (1)寻找最优参数(权重和偏置)时, 要寻找使损失函数的值尽可能小的参数。
    • (2)为了找到使损失函数的值尽可能小 的地方,需要计算参数的导数(确切地讲是梯度)
    • (3)然后以这个导数为指引, 逐步更新参数的值。
    • 对于某一个权重参数:如果导数的值为负,通过使该权重参数向正方向改变,可以减小损失函数的值;反过来,如果导数的值为正, 则通过使该权重参数向负方向改变,可以减小损失函数的值。
    • 为什么不能用识别精度(准确率)作为指标?
      • 是因为这样一来绝大多数地方的导数都会变为0,导致参数无法更新【因为识别精度对微小的参数变化基本上没有什么反应,即便有反应,它的值也是不连续地、突然地变化。】
  • 数值微分【梯度是什么、有什么性质】
    • 导数:某个瞬间的变化量
      • 利用微小的差分求导数的过程称为数值微分(numerical differentiation)
      • 而基于数学式的推导求导数的过程,则用“解析 性”(analytic)一词。解析性求导得到的导数是不含误差的“真的导数”。
    • 梯度

719f843d9e22130a5fab18c931d9ef0d.png
      • 对于函数:

ab79eb02253cfec5c14a893654f5c679.png
      • 的梯度实现:

fbe9f55c8b3b56384df464c2a01f153e.png
    • 梯度(下降)法寻最优参数

a2c8aaa13b3c83edfd32dd4b8efb5e94.png

      • η表示更新量,在神经网络的学习中,称为学习率(learningrate)。比如0.01或0.001。

b08ddf1ddc6859ea07ba3ba850107030.png
    • 神经网络的梯度

99a16984f57cbda9848463ff666d9c99.png
  • 学习算法的实现
    • 如何设置权重参数的初始值这个问题是关系到神经网络能否成功学习的重要问题:
      • 权重使用符合高斯 分布的随机数进行初始化,偏置使用0进行初始化。
    • params:保存神经网络的参数的字典型变量
    • grads:保存梯度的字典型变量
    • __init__(self, input_size, hidden_size, output_size):初始化
    • predict(self, x)
    • loss(self, x, t) 参数x是图像数据,t是正确解标签
    • accuracy(self, x, t)
    • numerical_gradient(self, x, t):计算权重参数的梯度
    • 使用MNIST数据集进行学习:

67171ff46becbc0f925d61464e1edb6a.png
  • epoch是一个单位。一个epoch表示学习中所有训练数据均被使用过 一次时的更新次数。

第5章 误差反向传播法

  • 数值微 分虽然简单,也容易实现,但缺点是计算上比较费时间。
    本章将学习一 个能够高效计算权重参数梯度的方法——误差反向传播法。
  • 正确理解误差反向传播法:
    • 一种是基于数学式【书籍多是以此展开】
    • 另一种是基于计算图(computational graph)
  • 计算图
    • 局部计算:无论全局的计算有多么复杂, 各个步骤所要做的就是对象节点的局部计算
    • 链式法则:

9e9e903a7e0f41689e71758b4151a844.png

e5db4cfd68c1ec85e2ffa2a62a4a6138.png
  • 即:

19b8da0cf6b75f9fde2e42aec467bc09.png
  • 乘法层的实现:

967217a6dbd12a9f9c90af55834ba244.png

    • 举例:

4744ca0c71d7dd09d8045c58db67f4b9.png
  • 加法层的实现:
    • 注意:加法层不需要刻意初始化【没有需要保留的东西】

c8969651ebf3333baab288742575c08b.png

d75ad479a2c3171da882dbfe406d92bb.png

57995824b77f997e1d8ae976466dacc8.png

  • 激活函数层的实现:
    • ReLU层

bf75b1b8d48872dd22d2d144be46c083.png

872d8683df65da9641a82882278913d8.png

  • 如果正向传播时的输入值小于等于0,则反向传播的值为0。

因此,反向传播中会使用正向传播时保存的mask,将从上游传来的dout的 mask中的元素为True的地方设为0。

  • ReLU层的作用就像电路中的开关一样。正向传播时,有电流通过 的话,就将开关设为ON;没有电流通过的话,就将开关设为OFF。 反向传播时,开关为ON的话,电流会直接通过;开关为OFF的话,则不会有电流通过。
  • Sigmoid层【为了反向传播而刻意构造的奇妙层】

a3b7efea980cc637b212c42f51577470.png

fe8fe3d1905364990b1f70a4aa75b3c9.png
  • Affine/Softmax层的实现
    • Affine层

神经网络的正向传播中进行的矩阵的乘积运算在几何学领域被称为“仿射变换”,这里将进行仿射变换的处理实现为“Affine层”。

052c7bd09660adcf9773d9e54da64a5c.png

  • Softmax-with-Loss 层

e6fd26964cb49821e225a66a6b55c5e9.png

    • 神经网络中进行的处理有推理(inference)和学习两个阶段。神经网 络的推理通常不使用Softmax层【只需要给出一个答案,对得分最大值感兴趣】不过,神经网络的学习阶段则需要Softmax层
    • Softmax层的反向传播得到了 (y1 − t1,y2 − t2,y3 − t3)这样“漂亮”的结果【不是偶然】

142f02023cb91805fad2ca59dd79798c.png
  • 误差反向传播法的实现
    • 神经网络学习的全貌图

前提

神经网络中有合适的权重和偏置,调整权重和偏置以便拟合训练数据的过程称为学习。

神经网络的学习分为下面4个步骤。

步骤1(mini-batch)
从训练数据中随机选择一部分数据。 步骤2(计算梯度)
计算损失函数关于各个权重参数的梯度。 步骤3(更新参数)
将权重参数沿梯度方向进行微小的更新。 步骤4(重复)
重复步骤1、步骤2、步骤3。
  • 误差反向传播法可以快速高效地计算梯度。

fd0101f3ac477b170fa0292b010b574e.png

9e9b0494f9b69017ae3d4e6c7b1fcc50.png

  • OrderedDict是有序字典,“有序”是指它可以 记住向字典里添加元素的顺序。
  • 使用了误差反向传播法的神经网络学习的实现。 和之前相比,不同之处仅在于通过误差反向传播法求梯度这一点。

5605abecf6936eb4f3cf7c3f65825290.png

第6章 与学习相关的技巧

  • 参数的更新
    • 随机梯度下降法(stochastic gradient descent), 简称SGD。

75138d4493a266c0af95eaaf764a26e7.png

这里,进行初始化时的参数lr表示learning rate(学习率)。这个学习率会保存为实例变量。此外,代码段中还定义了update(params, grads)方法, 这个方法在SGD中会被反复调用。参数params和grads(与之前的神经网络的实现一样)是字典型变量,按params['W1']、grads['W1']的形式,分别保存了权重参数和它们的梯度。

70a4a20e61f29cf3e157e8d28e110b0d.png

SGD低效的根本原因:

在y轴方向的坡度大,而x轴方向的坡度小的情况下,梯度的方向并没有指向最小值的方向(并没有指向(0, 0))。

4abc3d2584c68c98a0a2fd078abb5a2e.png

  • Momentum(动量)

Momentum方法给人的感觉就像是小球在地面上滚动。

e50e4ec359ab1406bff886586fa0307b.png

524161f4bfbc8d9a91b56add1dc3f739.png
  • AdaGrad
    • 被称为学习率衰减(learning rate decay)
    • AdaGrad会记录过去所有梯度的平方和。因此,学习越深入,更新的幅度就越小。【梯度平方和累加,开根号后作分母】实际上,如果无止境地学习,更新量就会变为0, 完全不再更新。为了改善这个问题,可以使用RMSProp

该方法并不是将过去所有的梯度一视同仁地相加,而是逐渐地遗忘过去的梯度,在做加法运算时将新梯度的信息更多地反映出来。 这种操作从专业上讲,称为“指数移动平均”,呈指数函数式地减小过去的梯度的尺度。

4848b03ddc9071fe50b64c1d055d4bb3.png

54870961aa96bd8ac35109d64d7c90f5.png
  • Adam
    • Momentum参照小球在碗中滚动的物理规则进行移动,AdaGrad为参数的每个元素适当地调整更新步伐。如果将这两个方法融合在一起会怎么样这就是Adam]方法的基本思路
    • 超参数的“偏置校正”

d4bf30694f4b1d368ceefdfc1a1b3e32.png
  • 权重的初始值
    • 可以将权重初始值设为0吗【不能】
      • 后面我们会介绍抑制过拟合、提高泛化能力的技巧——权值衰减(weightdecay)
      • 在这之前的权重初始值都是像0.01 * np.random.randn(10, 100)这样,使用 由高斯分布生成的值乘以0.01后得到的值(标准差为0.01的高斯分布)。
      • 因为如果有多个神经元都输出几乎相同的值,那它们就没有存在的意义了——表现力受限
      • Xavier的论文中,为了使各层的激活值呈现出具有相同广度的分布,推导了合适的权重尺度。推导出的结论是,如果前一层的节点数为n,则初始值使用标准差为1/根号n 的分布【sigmoid或tanh】

3a049dedda7146d1a299e9ebad068008.png

ecc770e0c102a83b0e555f43398d8307.png
  • ReLU的权重初始值:根号(2/n)【因为ReLU的负值区域的值 为0,为了使它更有广度,所以需要2倍的系数。】

afd7710418eb68a881e58a33c1acd271.png
  • 在神经网络的学习中,权重初始值非常重要。
    很多时候权重初始值的设定关系到神经网络的学习能否成功。
    权重初始值的重要性容易被忽视, 而任何事情的开始(初始值)总是关键的

6cf8c90d65c6f65ac5127f7dbd64f3dc.png
  • Batch Normalization
    • 为了使各层拥有适当的广度,“强制性”地调整激活值的分布会怎样呢
    • 引人注目的原因——以下优点:
      • • 可以使学习快速进行(可以增大学习率)。
      • • 不那么依赖初始值(对于初始值不用那么神经质)。
      • • 抑制过拟合(降低Dropout等的必要性)。
    • Batch Norm的思路是调整各层的激活值分布使其拥有适当的广度。为此,要向神经网络中插入对数据分布进行正规化的层,即Batch Normalization层(下文简称Batch Norm层)

434597e67a54108c9014d6879c30ba18.png
  • 正则化
    • 过拟合
    • 发生过拟合的原因,主要有以下两个。
      • • 模型拥有大量参数、表现力强。
      • • 训练数据少。
    • 权值衰减:经常被使用的一种抑制过拟合的方法
      • 很多过拟合原本就是因为权重参数取值过大才发生的。【对权重W进行惩罚】
    • Dropout
      • 如果网络的模型变得很复杂,只用权值衰减就难以应对了。在这种情况下,我们经常会使用Dropout 方法
      • Dropout是一种在学习的过程中随机删除神经元的方法

be92b530543e69684970ad70e77f8465.png
      • 每次正向传播时,self.mask中都会以False的形式保存要删除的神经元。self.mask会随机生成和x形状相同的数组,并将值比 dropout_ratio大的元素设为True。反向传播时的行为和ReLU相同。也就是说, 正向传播时传递了信号的神经元,反向传播时按原样传递信号;正向传播时没有传递信号的神经元,反向传播时信号将停在那里。
      • 集成学习:
        • 就是让多个模型单 独进行学习,推理时再取多个模型的输出的平均值【可以理解为:dropout将集成学习的效果通过一个网络实现了】
  • 超参数的验证
    • 超参数包括:
      • 比如各层的神经元数量batch大小参数更新时的学习率权值衰减
    • 不能使用测试数据评估超参数的性能,调整超参数时,必须使用超参数专用的确认数据
    • 用于调整超参数的数据,一般称为验证数据(validation data)
    • 20%作为验证数据(混淆-分割取出)
    • 超参数的最优化
      • 有报告[15] 显示,在进行神经网络的超参数的最优化时,与网格搜索等有规律的搜索相比,随机采样的搜索方式效果更好。这是因为在多个超参数中,各个超参数对最终的识别精度的影响程度不同。
      • 在超参数的搜索中,需要尽早放弃那些不符合逻辑的超参数。 于是,在超参数的最优化中,减少学习的epoch,缩短一次评估所需的时间 是一个不错的办法。

48a36de11c78d9dc22f268c0b908b3ce.png
      • 在超参数的最优化中,如果需要更精炼的方法,可以使用贝叶斯最优化(Bayesian optimization)。贝叶斯最优化运用以贝叶斯定理为中心的数学理论,能够更加严密、高效地进行最优化。

第7章 卷积神经网络

61c0c6861c44ace0c03b3debf77c4a60.png
  • 卷积层
    • 全连接层存在的问题
      • 数据的形状被“忽视”:高、长、通道方向上的3维形状被拉平为1维数据。
      • 空间信息之间的关联被忽视,无法利用与形状相关的信息。
      • 而卷积层可以保持形状不变。中间过程不改变维度。有可能正确理解图像数据。
    • 卷积运算
      • 卷积运算相当于图像处理中的“滤波器运算”
      • 有的文献中也会用“核”这个词来表示这里所说的“滤波器”。
      • 偏置通常只有1个(1 × 1),这个值会被加到应用了滤波器的所有元素上。
      • 填充(padding):“幅度为1的填充”是指用幅度为1像素0填充周围。使用填充主要是为了调整输出的大小。
      • 步幅(stride):应用滤波器的位置间隔

ca3c946fec2e6a9b2062defb4db5dd08.png

无法除尽:四舍五入

  • 三维数据:按通道进行数据和滤波器的卷积运算

f6a3154e8093ef0a10dcca49c6125602.png
    • 输入数据和滤波器的通道数 必须相同
    • 书写顺序为(channel, height, width):(C, H,W)【从大到小,从行到列】
  • 结合方块思考——纵向卷积

5cf1e47d86397e30d7e58fbc9db28421.png
    • 在这个例子中,数据输出是1张特征图。所谓1张特征图,换句话说,就是通道数为1的特征图。那么,如果要在通道方向上也拥有多个卷积运算的输出,该怎么做呢?为此,就需要用到多个滤波器(权重)

64ac7d727ba7ed71f2d5dd9684d0b6e2.png
    • 滤波器的权重数据要按(output_channel, input_ channel, height, width)的顺序书写。比如,通道数为3、大小为5 × 5的滤 波器有20个时,可以写成(20, 3, 5, 5)。
    • 每个通道只有一个偏置。这里,偏置的形状是(FN, 1, 1)

ba71fbbcf19cca6f66d944f215b93bb5.png
    • 批处理:批处理将N次的处理汇总成了1次进行

3d42c3898869244514b6628c9a247a30.png
  • 池化层
    • 池化是缩小高、长方向上的空间的运算。比如,进行将2 × 2的区域集约成1个元素的处理,缩小空间大小。

56895d83736ccf3eef342d7e1346b657.png
      • 一般来说,池化的窗口大小会 和步幅设定成相同的值。比如,3 × 3的窗口的步幅会设为3,4 × 4的窗口 的步幅会设为4等。
      • 除了Max池化之外,还有Average池化等。在图像识别领域,主要使用Max池化。
    • 池化层的特征
      • 没有要学习的参数
      • 通道数不发生变化
      • 对微小的位置变化具有鲁棒性(健壮)【对于像素偏离具有鲁棒性】如下所示:

77fc9f6b692c8604701afdb97b922300.png
  • 卷积层和池化层的实现
    • 基于im2col的展开
      • 如果老老实实地实现卷积运算,估计要重复好几层的for语句。这样的实现有点麻烦,而且,NumPy中存在使用for语句后处理变慢的缺点(NumPy 中,访问元素时最好不要用for语句)
      • im2col是一个函数,将输入数据展开以适合滤波器(权重)。
      • im2col (input_data, filter_h, filter_w, stride=1, pad=0)
      • 把包含 批数量的4维数据转换成了2维数据:

404672deedec889faedec6743aaa33aa.png
      • 实际的卷积运算中,滤波器的应用区域几乎都是重叠的【步幅原因】,使用im2col展开后元素个数会多于原方块的元素个数。因此,使用im2col的实现存在比普通的实现消耗更多内存的缺点。但是,可以有效地利用线性代数库。
      • im2col这个名称是“image to column”的缩写,翻译过来就是“从 图像到矩阵”的意思。Caffe、Chainer等深度学习框架中有名为 im2col的函数,并且在卷积层的实现中,都使用了im2col。

b288a16dfefa80072e0b1b336f0ced21.png
      • 不要忘记reshape
    • 卷积层的实现

2c3f945a2ad5902fc764af65b0de291c.png
      • 第一个是批大小为1、通道为3的7 × 7的数据,
      • 7*7->通过卷积(5*5的卷积核)变成了3*3=9。所以高是9
      • 而一个多通道卷积核会产生:5*5*3=75个数据,所以宽是75

225d0e8ba6a3ac051d9c36a7cf8b2488.png
      • 卷积层的初始化方法将滤波器(权重)、偏置、步幅、填充作为参数接收。滤波器是(FN, C, FH, FW)的4维形状。另外,FN、C、FH、FW分别是Filter Number(滤波器数量)、Channel、Filter Height、Filter Width的缩写
      • 这里通过reshape(FN,-1)将参数指定为-1,这是 reshape的一个便利的功能。通过在reshape时指定为-1,reshape函数会自动计算-1维度上的元素个数,以使多维数组的元素个数前后一致。比如, (10, 3, 5, 5)形状的数组的元素个数共有750个,指定reshape(10,-1)后,就 会转换成(10, 75)形状的数组。【配合transpose使用有奇效】

6b5ca9c13f89b0fdac15e2fac49ba3f6.png
      • 那么问题来了:reshape的工作原理和处理顺序到底是咋样的:
        • reshape 如果不带参数,则优先对行进行处理。测试如下:

65632ae226660d71ea56b3132c6fb3a4.png
        • 所以,是先N,然后HW,最后才C。【有疑问】
      • 在进行卷积层的反向传播时,必须进行im2col 的逆处理——col2im函数.
    • 池化层的实现
      • 池化层的实现和卷积层相同,都使用im2col展开输入数据。不过,池化的情况下,在通道方向上是独立的,这一点和卷积层不同。具体地讲,如图 池化的应用区域按通道单独展开。【不然求最大值会被其他通道的混淆】

e47d824d7f8c014cfb40b74603fe69b3.png
      • 像这样展开之后,只需对展开的矩阵求各行的最大值,并转换为合适的形状即可

12f835228bba3404b2ad876845391048.png

3969f74ba7db17fa4e20027aacda3f3c.png
  • CNN的实现
  • CNN的可视化
    • 如果堆叠了多层卷积层,则随着层次加深,提取的信息也愈加复杂、抽象,这是深度学习中很有意思的一个地方。最开始的层对简单的边缘有响应,接下来的层对纹理有响应,再后面的层对更加复杂的物体部件有响应。也就是说,随着层次加深,神经元从简单的形状向“高级”信息 变化。换句话说,就像我们理解东西的“含义”一样,响应的对象在逐渐变化。【如果可以模拟人脑,说不定对于计算机视觉可以有更进一步的突破】

f8e514dab5a2c9a7dc313916fc4eceed.png
  • 具有代表性的CNN
    • LeNet
      • LeNet在1998年被提出,是进行手写数字识别的网络。如图7-27所示,它有连续的卷积层和池化层(正确地讲,是只“抽选元素”的子采样层),最后经全连接层输出结果。

00d2064da7030dccbe0bd9e6eb45819b.png
      • 和“现在的CNN”相比,LeNet有几个不同点。第一个不同点在于激活函数。LeNet中使用sigmoid函数,而现在的CNN中主要使用ReLU函数。 此外,原始的LeNet中使用子采样(subsampling)缩小中间数据的大小,而现在的CNN中Max池化是主流。
    • AlexNet
      • 在LeNet问世20多年后,AlexNet被发布出来。AlexNet是引发深度学 习热潮的导火线,不过它的网络结构和LeNet基本上没有什么不同,如图

f270b05a05f5ef7c823057cb6bacd588.png
      • AlexNet叠有多个卷积层和池化层,最后经由全连接层输出结果。虽然 结构上AlexNet和LeNet没有大的不同,但有以下几点差异。
        • 激活函数使用ReLU
        • 使用进行局部正规化的LRN(Local Response Normalization)层。
        • 使用Dropout(6.4.3节)。
    • LeNet和AlexNet没有太大的不同。但是, 围绕它们的环境和计算机技术有了很大的进步
    • GPU和大数据给这些课题带来了希望。

第8章 深度学习

  • 加深网络

c3b0670c7d79308e64486fa969f1ed1e.png
    • 使用He初始值作为权重的初始值,使用Adam更新权重参数。除此之外还有如下特点:

• 基于3×3的小型滤波器的卷积层。

• 激活函数是ReLU。

• 全连接层的后面使用Dropout层

• 基于Adam的最优化。

• 使用He初始值作为权重初始值。

  • 对于MNIST数据集,层不用特别深就获得了(目前)最高的识别精度。
  • 一般认为,这是因为对于手写数字识别这样一个比较简单的任务,没有必要将网络的表现力提高到那么高的程度。因此,可以说加深层的好处并不大。而之后要介绍的大规模的一般物体识别的情况, 因为问题复杂,所以加深层对提高识别精度大有裨益。

c78f9272464f7ed7cd821f9c7ab51d73.png
  • 参考刚才排行榜中前几名的方法,可以发现进一步提高识别精度的技术和线索。比如,集成学习学习率衰减Data Augmentation(数据扩充)等都有助于提高识别精度。尤其是Data Augmentation,虽然方法很简单,但在提高识别精度上效果显著。 Data Augmentation基于算法“人为地”扩充输入图像(训练图像)。具体地说,如图8-4所示,对于输入图像,通过施加旋转、垂直或水平方向上的移动等微小变化,增加图像的数量【类似的方法还有:施加亮度等外观上的变化、放大缩小等尺度上的变化、裁剪、翻转】。这在数据集的图像数量有限时尤其有效。

6b95a03a710829f65460a8526b863dad.png
  • 加深层的动机
    • 大规模图像识别的比赛结果中层越深,识别性能也越高。
    • 就是与没有加深层的网络相比,加深了层的网络可以 用更少的参数达到同等水平(或者更强)的表现力,如:

f028e88676611ba7a64c3330a64da033.png
      • 一次5 × 5的卷积运算的区域可以由两次3 × 3的卷积运算抵充。并且, 相对于前者的参数数量25(5 × 5),后者一共是18(2 × 3 × 3),通过叠加卷积层,参数数量减少了。而且,这个参数数量之差会随着层的加深而变大。
      • 比如,重复三次3 × 3的卷积运算时,参数的数量总共是27。而为了用一次卷积运算“观察”与之相同的区域,需要一个7 × 7的滤波器,此时的参数数量是49。
      • 叠加小型滤波器来加深网络的好处是可以减少参数的数量,扩大感受野(receptive field,给神经元施加变化的某个局部空间区域)。并且, 通过叠加层,将ReLU等激活函数夹在卷积层的中间,进一步提高 了网络的表现力。这是因为向网络添加了基于激活函数的“非线性” 表现力,通过非线性函数的叠加,可以表现更加复杂的东西。
      • 加深层的另一个好处就是使学习更加高效
    • VGG

9b35dc451b4357815f55a65593c7ebad.png

基于3×3的小型滤波器的卷积层的运算是连续进行的。如图8-9所示,重复进行“卷积层重叠2次到4次,再通过池化层将大小减半”的处理,最后经由全连接层输出结果。

  • GoogLeNet
    • GoogLeNet在横向上有“宽度”,这称为“Inception结构”
    • Inception结构使用了多个大小不同的滤波器(和池化), 最后再合并它们的结果。

a97b964b06d894cb243d84872e998353.png

2e6fa4cdcddc098ea73336293f4a430e.png
  • ResNet
    • 在深度学习中,过度加深层的话,很多情况下学习将不能顺利进行,导致最终性能不佳。【反向传播时梯度消失/爆炸】
    • 导入了“快捷结构“

df9dc68d1c54ce6a97262a01f9382ff5.png
  • 迁移学习
    • 实践中经常会灵活应用使用ImageNet这个巨大的数据集学习到的权重数据。将学习完的权重(的一部分)复制到其他神经网络,进行再学习(fine tuning)。迁移学习在手头数据集较少时非常有效。
  • 深度学习的高速化
    • AlexNex中,大多数时间都被耗费在卷积层上。卷积层的处理时间加起来占GPU整体的95%,占CPU整体的89%!

5131bbf0f6533fff60ca6c4d498aa48f.png
    • NVIDIA提供的CUDA这个面向GPU计算的综合开发环境。
    • 相比按小规模的单位进行计算,GPU更擅长计算大规模的汇总好的数据。也就是说,通过基于im2col以大型矩阵的乘积的方式汇总计算, 更容易发挥出GPU的能力。
    • 分布式学习
      • TensorFlow可以实现多个GPU分布式计算
    • 运算精度的位数缩减
      • 内存容量、总线带宽等也有可能成为瓶颈。
        • 大量的权重参数或中间数据放在内存
        • GPU(或者CPU)总线的数据超过某个限制时,总线带宽会成为瓶颈
      • 所以希望尽可能减少流经网络的数据的位数。
      • 基于神经网络的健壮性:我们已经知道深度学习并不那么需要数值精度的位数
      • Python中一般使用64位的浮点数。NumPy中提供了16位的半精度浮点数类型
  • 深度学习的应用案例
    • 物体检测
      • 物体检测需要从图像中确定类别的位置, 而且还有可能存在多个物体。
      • R-CNN

aa3979eeda4bff85cc2dcf9e5bb9a644.png
    • 图像分割
      • 之前实现的神经网络是对图像整体进行了分类,要将它落实到像素水平的话,该怎么做呢
      • 有人提出了一个名为FCN(Fully Convolutional Network)的方法:一次forward处理,对所有像素进行分类
      • 将全连接层替换成发挥相同作用的卷积层。FCN的特征在于最后导入了扩大空间大小的处理。基于这个处理,变小了的中间数据可以一下子扩大到和输入图像一样的大小。

e13227fe2318dd829c43bb8cb97ed63f.png
    • 图像标题的生成
      • 基于深度学习生成图像标题的代表性方法:NIC(NeuralImage Caption)模型。
      • NIC基于CNN从图像中提取特征,并将特征传给RNN。RNN以特征为初始值,递归生成文本。
      • 我们将组合图像和自然语言等多种信息进行的处理称为多模态处理
  • 深度学习的未来
    • 图像风格变换:
      • 在学习过程中使网络的中间数据近似内容图像的中间数据。
      • 此外,为了从风格图像中吸收风格,导入了风格矩阵的概念。通过在学习过程中减小风格矩阵的偏差,就可以使输入图像接近梵高的风格。
    • 图像的生成:
      • DCGAN【无监督学习】

其技术要点是使用了Generator(生成者)和Discriminator(识别者)这两个神经网络。

Generator生成近似真品的图像,Discriminator判别它是不是真图像(是Generator生成的图像还是实际拍摄的图像)。像这样,通过让两者以竞争的方式学习,Generator会学习到 更加精妙的图像作假技术,Discriminator则会成长为能以更高精度辨别真假的鉴定师。

两者互相切磋、共同成长,这是GAN(Generative Adversarial Network)这个技术的有趣之处。在这样的切磋中成长起来的Generator最终会掌握画出足以以假乱真的图像的能力(或者说有这样的可能)。

  • 自动驾驶
    • 高精度化、高速化,像素分割
  • Deep Q-Network(强化学习)
    • DQN【Deep Q-Network】

d1b3ac50061b7b0d32edd278c3d75beb.png
  • AlphaGo技术的内部也用了深度学习和强化学习。AlphaGo学习了3000万个专业棋手的棋谱,并且不停地重复自己和自己的对战,积累了大量的学习经验。

感谢阅读,希望能对你有帮助:)

欢迎访问我的
github主页:myGithub
CSDN主页:二十四桥明月夜的博客- CSDN博客
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值