本周CS230在lecture5中主要讲了一下深度学习在医疗诊断方面的应用,感觉挺有意义的,个人认为属于激励我们去学好基础知识然后进行应用的一堂课吧。coursera上主要是讲了卷积神经网络、残差网络,以及介绍了一些经典的网络结构例如LeNet-5、AlexNet、VGG-16、GoogLeNet等;作业涵盖了从基础的手动搭建CNN的前向传播、反向传播,到基于TensorFlow来构建CNN、ResNet模型并且应用。前一部分的作业主要偏理解,后一部分的作业是在理解了原理之后对框架代码的熟悉。

目录

  • 回顾知识点
    • 1. 卷积层(Convolutional layers)
    • 2. 池化层(Pooling layers)
    • 3. 卷积网络的特点
    • 4. 残差网络(Residual networks)
  • 作业代码
    • 1. Convolutional Model: step by step
    • 2. Convolutional Model: application
    • 3. Convolutional Model: the happy house
    • 4. Residual Networks

回顾知识点

1. 卷积层(Convolutional layers)

在实际运用中一个卷积层通常是指一个卷积+激活+池化,但是这样讨论的卷积层指的单纯是卷积。

  • 卷积运算
    在普通的神经网络中一般用神经元来进行信息的传入与输出,在卷积层中神经单元改为“过滤器”或者“卷积核”,它用一个矩阵(对二维卷积层)来表示,若记这个过滤器的长和宽为fff,则它就是一个f×ff\times ff×f的矩阵。用这个过滤器来遍历地与输入数据对应进行互相关(cross-correlation)运算,即对应元素相乘然后相加。在最简单的形式下,它对二维输入数据和过滤器做互相关运算然后加上偏差项,注意互相关运算是没有交换律的卷积运算,也就是不对卷积核进行翻转,许多机器学习的库实现的是互相关但是称之为卷积。
    下面是未加偏差项的互相关运算,灰色方框内为计算过程(假设偏差项为1,则输出变为18 16 21 21):

    若输入数据是多个通道的,则相应的过滤器也是多个通道,然后输出结果依然维数不变,是把多个通道的相加在一起(红色的部分):

  • Padding
    为了解决经过卷积层之后的输出大小越来越小,以及边缘丢失信息的问题,需要对图片边缘用空白像素来填充,即Padding。

    没有使用Padding的卷积称为“Valid”卷积。输入输出的大小变化为:(n×n)∗(f×f)→(n−f+1)×(n−f+1)(n\times n) * (f\times f)\to (n-f+1)\times(n-f+1)(n×n)∗(f×f)→(n−f+1)×(n−f+1)使用了Padding并且令输入与输出大小保持一致的卷积称为“Same”卷积。输入输出的大小变化为:((n+2p)×(n+2p))∗(f×f)→(n+2p−f+1)×(n+2p−f+1)((n+2p)\times (n+2p)) * (f\times f)\to (n+2p-f+1)\times(n+2p-f+1)((n+2p)×(n+2p))∗(f×f)→(n+2p−f+1)×(n+2p−f+1)要使得输入与输出大小保持一致,即n+2p−f+1=n+2pn+2p-f+1=n+2pn+2p−f+1=n+2p,所以此时p=f−12p={f-1\over2}p=2f−1​

  • Stride
    表示每次过滤器窗口移动的步长,记为sss,则输入输出的大小变化为:((n+2p)×(n+2p))∗(f×f)→⌊n+2p−fs+1⌋×⌊n+2p−fs+1⌋((n+2p)\times (n+2p)) * (f\times f)\to \lfloor{n+2p-f\over s}+1\rfloor\times\lfloor{n+2p-f\over s}+1\rfloor((n+2p)×(n+2p))∗(f×f)→⌊sn+2p−f​+1⌋×⌊sn+2p−f​+1⌋注意结果需要向下取整。

  • 卷积层的前向传播
    上一层的输出数据为这一层的输入数据,记为A[l−1]A^{[l-1]}A[l−1],假设大小为nH[l−1]×nW[l−1]×nC[l−1]n_H^{[l-1]}\times n_W^{[l-1]}\times n_C^{[l-1]}nH[l−1]​×nW[l−1]​×nC[l−1]​,C表示通道。
    由于过滤器的通道数需要和数据匹配,假设过滤器长宽均为f[l]f^{[l]}f[l],则过滤器大小为f[l]×f[l]×nC[l−1]f^{[l]}\times f^{[l]}\times n_C^{[l-1]}f[l]×f[l]×nC[l−1]​
    假设该层采用nC[l]n_C^{[l]}nC[l]​个过滤器,则这一层的输出数据Z[l]Z^{[l]}Z[l]的大小为nH[l]×nW[l]×nC[l]n_H^{[l]}\times n_W^{[l]}\times n_C^{[l]}nH[l]​×nW[l]​×nC[l]​,其中nH[l]=⌊nH[l−1]+2p[l]−f[l]s[l]+1⌋n_H^{[l]}=\lfloor{n_H^{[l-1]}+2p^{[l]}-f^{[l]}\over s^{[l]}}+1\rfloornH[l]​=⌊s[l]nH[l−1]​+2p[l]−f[l]​+1⌋
    其实总结起来依然是A[l−1]∗W[l]+b[l]=Z[l]A^{[l-1]}*W^{[l]}+b^{[l]}=Z^{[l]}A[l−1]∗W[l]+b[l]=Z[l],但是这里的∗*∗是卷积运算,WWW是过滤器的参数,bbb是偏差项。卷积前后的维度变化为(nH[l−1]×nW[l−1]×nC[l−1])∗(f[l]×f[l]×nC[l−1])→(nH[l]×nW[l]×nC[l])(n_H^{[l-1]}\times n_W^{[l-1]}\times n_C^{[l-1]})\ *\ (f^{[l]}\times f^{[l]}\times n_C^{[l-1]})\to (n_H^{[l]}\times n_W^{[l]}\times n_C^{[l]})(nH[l−1]​×nW[l−1]​×nC[l−1]​) ∗ (f[l]×f[l]×nC[l−1]​)→(nH[l]​×nW[l]​×nC[l]​)过滤器的那些数就是我们需要训练的参数WWW,然后每个过滤器需要加上一个偏差项bbb,所以这一层总共的参数个数为:f[l]×f[l]×nC[l−1]×nC[l]+nC[l]f^{[l]}\times f^{[l]}\times n_C^{[l-1]}\times n_C^{[l]}+n_C^{[l]}f[l]×f[l]×nC[l−1]​×nC[l]​+nC[l]​

  • 卷积层的反向传播
    任务:已知卷积层的梯度dZ[l]dZ^{[l]}dZ[l],求dA[l−1],dW[l],db[l]dA^{[l-1]},dW^{[l]},db^{[l]}dA[l−1],dW[l],db[l](注意下述有的没带上标,但没有歧义不影响理解)。
    作业中其实给出来了梯度的计算公式,即:dA+=∑h=0nH∑w=0nWWc×dZhwdWc+=∑h=0nH∑w=0nWaslice×dZhwdb=∑h∑wdZhw\begin{aligned}dA&+=\sum_{h=0}^{n_H}\sum_{w=0}^{n_W}W_c\times dZ_{hw}\\ dW_c&+=\sum_{h=0}^{n_H}\sum_{w=0}^{n_W}a_{slice}\times dZ_{hw}\\ db&=\sum_{h}\sum_{w}dZ_{hw}\end{aligned}dAdWc​db​+=h=0∑nH​​w=0∑nW​​Wc​×dZhw​+=h=0∑nH​​w=0∑nW​​aslice​×dZhw​=h∑​w∑​dZhw​​其中WcW_cWc​是某一过滤器的参数,dZhwdZ_{hw}dZhw​是dZ[l]dZ^{[l]}dZ[l]中第hhh行和第www列的梯度,是一个标量,aslicea_{slice}aslice​是AAA中滑动窗口用于生成ZijZ_{ij}Zij​的那个切片。
    对于上面公式给的太直接,一下子理解起来太困难,所以在参考了四张图彻底搞懂CNN反向传播算法这一文后,梳理了下对于CNN反向传播的理解。
    在全连接的反向传播中,因为z[l]=w[l]⋅a[l−1]+b[l]z^{[l]}=w^{[l]}\cdot a^{[l-1]}+b^{[l]}z[l]=w[l]⋅a[l−1]+b[l],根据链式法则:da=wT⋅dz,dw=dz⋅aT,db=dzda=w^T\cdot dz, \ \ \ \ dw=dz\cdot a^T,\ \ \ \ db=dzda=wT⋅dz,    dw=dz⋅aT,    db=dz在CNN中,先将前向传播按照原本的卷积运算将数据和权重都展开成全连接的前向传播形式,然后用全连接的反向传播公式来推导卷积的反向传播:

    所以用这样的方式来理解中间过程,然后可以忽略中间的展开再恢复的过程,直接用小窗口滑动来一点点填充梯度,所以就需要上述梯度的计算公式中的“+=”符号来实现。这里草稿中给出的例子是无padding,s=1s=1s=1时单个通道的情况,多通道只是分开通道进行相同的处理,而对于sss为其他值时也是一模一样的套用,假如有padding,则只需要对dAdAdA初始化也进行相应的padding操作,然后按照上述步骤,最后对算出来的dAdAdA去掉padding即可,思路是一样的。此处的代码在下面作业1中的conv_backward函数实现。

  • 1×1卷积
    1×1卷积,有时也被称为Network in Network。通常在通道数很多的时候它可以用来压缩通道数量并减少计算,可以增加模型的非线性性,也用于GoogLeNet等网络中。

2. 池化层(Pooling layers)

  • 池化层用来缩减模型的大小(主要是减少数据的长和宽,以此减少后面的参数),提高计算速度,同时提高所提取特征的鲁棒性。类似卷积的小窗口滑动,池化层也有过滤器,但是它却没有参数。按照过滤器的作用主要分为两种:max pooling和average pooling。

  • max pooling
    顾名思义,它就是在给定了过滤器大小后,按照这个窗口大小依次过滤选择窗口中最大值返回,例如,下图是s=2,f=2s=2,f=2s=2,f=2时的情形,其效果相当于高度和宽度缩减一半,对所有的通道进行相同操作,因此通道数不变。一般来说,池化层不用padding,经过池化后数据大小变化为(nH×nW×nC)→f,s(⌊nH−fs+1⌋×⌊nH−fs+1⌋×nC)(n_H\times n_W\times n_C)\xrightarrow{f,s} (\lfloor{n_H-f\over s}+1\rfloor\times \lfloor{n_H-f\over s}+1\rfloor\times n_C)(nH​×nW​×nC​)f,s​(⌊snH​−f​+1⌋×⌊snH​−f​+1⌋×nC​)这样的最大化运算的实际作用就是,如果在过滤器中提取到某个特征,那么保留其最大值。如果在这个窗口没有这个特征,那么其中的最大值也还是很小,所以池化后的数据还是保留了原始数据的明显特征但是减少了数据维度。

  • average pooling
    将上述取最大的运算改为取平均运算即可换成average pooling。目前来说,最大池化比平均池化更常用,但常常对于很深的神经网络也有例外。

  • 池化层的反向传播
    已知池化层输出的梯度dAdAdA,求池化层输入的梯度dA_prevdA\_prevdA_prev。
    由于池化层通常会缩小数据的size,反向传播需要将size较小的dAdAdA还原成之前大小的dA_prevdA\_prevdA_prev。如果是max pooling,则对每一次窗口的移动,都将该梯度传递给之前取最大值的位置,其余位置为0,例如:

    如果是average pooling,则对每一次窗口的移动,所有位置都取该梯度的平均值,例如:

3. 卷积网络的特点

  • 参数共享(parameter sharing)
    每个过滤器都很小(相对于数据的size来说),参数也很少,但是一个过滤器可以将这个通道的所有像素点都扫描一遍,这个过滤器主要检测的特征对于图像的其他部分来说这种检测也是有效的,因此即使和全连接相比,卷积网络显著地减少了参数,极大地改善了模型的存储需求,减少了训练花销,但是也不会影响整体模型的性能,这些过滤器依然可以很好地检测到特征。

  • 连接的稀疏性(sparsity of connections)
    经过卷积后的输出只与输入的一小部分有关,非交互的部分改变不会影响输出的这一小部分的值,这种交互的稀疏性允许网络可以通过只描述稀疏交互的基石来高效地描述多个变量的复杂交互。

  • 平移等变(equivariant representations)
    卷积结构满足若输入平移,输出也以同样的方式平移的特性,假设图片向左移动几个像素,过滤器依然可以检测到非常相似的特征,依然可以输出相同的标签,这样的网络十分稳健。

4. 残差网络(Residual networks)

  • 对于普通的网络(Plain network)随着层数的增加,理论上训练误差会越来越小,但是实际上训练误差是先下降然后会上升,这是因为随着网络越来越复杂,训练变得越来越难,也容易出现梯度消失或者爆炸的问题,残差网络就能较好的解决这个问题。
  • ResNets是由残差块(Residual block)构建的,一个残差块一般包含一个主路径和一个跳跃连接(Skip connection / Short cut)。主路径就是一般的顺序连接的网络传播的路径,跳跃连接指的是某一层的激活可以迅速反馈给另外一层,即使是相隔很远的更深层。例如:

    这个灰色的线就是跳跃连接,此时a[l+2]=g(z[l+2]+a[l])a^{[l+2]}=g(z^{[l+2]}+a^{[l]})a[l+2]=g(z[l+2]+a[l]),而不是a[l+2]=g(z[l+2])a^{[l+2]}=g(z^{[l+2]})a[l+2]=g(z[l+2])。这样的一个结构就称为一个残差块。残差网络就是包含这样的带有跳跃连接的残差块组成。

作业代码

1. Convolutional Model: step by step

主要写出padding、卷积层和池化层的前向、反向传播函数。

import numpy as np
import h5py
import matplotlib.pyplot as pltnp.random.seed(1)# padding 用0来填充
def zero_pad(X, pad):X_pad = np.pad(X, ((0,0),(pad,pad),(pad,pad),(0,0)), mode='constant', constant_values=0)return X_pad# 检查函数
np.random.seed(1)
x = np.random.randn(4, 3, 3, 2)
x_pad = zero_pad(x, 2)fig, axarr = plt.subplots(1, 2)
axarr[0].set_title('x')
axarr[0].imshow(x[0,:,:,0])
axarr[1].set_title('x_pad')
axarr[1].imshow(x_pad[0,:,:,0])# 卷积层前向传播
def conv_forward(A_prev, W, b, hparameters):"""Implements the forward propagation for a convolution function(n_H_prev, n_W_prev, n_C_prev) * (f, f, n_C_prev) --(n_H, n_W, n_C)Arguments:A_prev -- output activations of the previous layer, numpy array of shape (m, n_H_prev, n_W_prev, n_C_prev)W -- Weights, numpy array of shape (f, f, n_C_prev, n_C)b -- Biases, numpy array of shape (1, 1, 1, n_C)hparameters -- python dictionary containing "stride" and "pad"Returns:Z -- conv output, numpy array of shape (m, n_H, n_W, n_C)cache -- cache of values needed for the conv_backward() function"""m, n_H_prev, n_W_prev, n_C_prev = A_prev.shapes = hparameters['stride']p = hparameters['pad']    f = W.shape[0]n_H = (n_H_prev + 2*p - f) // s + 1n_W = (n_W_prev + 2*p - f) // s + 1n_C = b.shape[-1]Z = np.zeros((m, n_H, n_W, n_C))# paddingA_pad = zero_pad(A_prev, p)for i in range(m):i_A_prev = A_pad[i] # (n_H_prev, n_W_prev, n_C_prev)for h in range(n_H):for w in range(n_W):for c in range(n_C):slice_A_prev = i_A_prev[h*s:f+h*s, w*s:f+w*s, :]product = slice_A_prev * W[:, :, :, c] #(f, f, n_C_prev)Z[i, h, w, c] = np.sum(product) + b[0, 0, 0, c]# 为反向传播准备cache = (A_prev, W, b, hparameters)return Z, cache# 检查函数
np.random.seed(1)
A_prev = np.random.randn(10,4,4,3)
W = np.random.randn(2,2,3,8)
b = np.random.randn(1,1,1,8)
hparameters = {"pad" : 2,"stride": 2}Z, cache_conv = conv_forward(A_prev, W, b, hparameters)
print("Z's mean =", np.mean(Z))
print("Z[3,2,1] =", Z[3,2,1])
print("cache_conv[0][1][2][3] =", cache_conv[0][1][2][3])# 池化层前向传播
def pool_forward(A_prev, hparameters, mode="max"):"""Implements the forward pass of the pooling layer(n_H_prev, n_W_prev, n_C) * (f, f, n_C) --(n_H, n_W, n_C)Arguments:A_prev -- Input data, numpy array of shape (m, n_H_prev, n_W_prev, n_C_prev)hparameters -- python dictionary containing "f" and "stride"mode -- the pooling mode you would like to use, defined as a string ("max" or "average")Returns:A -- output of the pool layer, a numpy array of shape (m, n_H, n_W, n_C)cache -- cache used in the backward pass of the pooling layer, contains the input and hparameters """m, n_H_prev, n_W_prev, n_C = A_prev.shapef = hparameters['f']s = hparameters['stride']n_H = (n_H_prev - f) // s + 1n_W = (n_W_prev - f) // s + 1A = np.zeros((m, n_H, n_W, n_C))for i in range(m):i_A_prev = A_prev[i] # (n_H_prev, n_W_prev, n_C)for h in range(n_H):for w in range(n_W):for c in range(n_C):slice_A_prev = i_A_prev[h*s:f+h*s, w*s:f+w*s, c] # (f,f,1)if mode=='max':A[i, h, w, c] = np.max(slice_A_prev)else:A[i, h, w, c] = np.mean(slice_A_prev)cache = (A_prev, hparameters)return A, cache# 检查函数
np.random.seed(1)
A_prev = np.random.randn(2, 4, 4, 3)
hparameters = {"stride" : 2, "f": 3}A, cache = pool_forward(A_prev, hparameters)
print("mode = max")
print("A =", A)
print()
A, cache = pool_forward(A_prev, hparameters, mode = "average")
print("mode = average")
print("A =", A)   # 卷积层的反向传播,这里不含激活
def conv_backward(dZ, cache):"""Implement the backward propagation for a convolution functionArguments:dZ -- gradient of the cost with respect to the output of the conv layer (Z), numpy array of shape (m, n_H, n_W, n_C)cache -- cache of values needed for the conv_backward(), output of conv_forward()Returns:dA_prev -- gradient of the cost with respect to the input of the conv layer (A_prev),numpy array of shape (m, n_H_prev, n_W_prev, n_C_prev)dW -- gradient of the cost with respect to the weights of the conv layer (W)numpy array of shape (f, f, n_C_prev, n_C)db -- gradient of the cost with respect to the biases of the conv layer (b)numpy array of shape (1, 1, 1, n_C)"""A_prev, W, b, hparameters = cachem, n_H, n_W, n_C = dZ.shapem, n_H_prev, n_W_prev, n_C_prev = A_prev.shapef = W.shape[0]s = hparameters['stride']p = hparameters['pad']    dA_prev = np.zeros((m, n_H_prev, n_W_prev, n_C_prev))dW = np.zeros((f, f, n_C_prev, n_C))db = np.zeros((1, 1, 1, n_C))dA_prev_pad = zero_pad(dA_prev, p)A_prev_pad = zero_pad(A_prev, p)for i in range(m):i_dA_prev_pad = dA_prev_pad[i]i_A_prev_pad = A_prev_pad[i]for h in range(n_H):for w in range(n_W):for c in range(n_C):slice_A_prev = i_A_prev_pad[h*s:f+h*s, w*s:f+w*s, :] # (f, f, n_C_prev)i_dA_prev_pad[h*s:f+h*s, w*s:f+w*s, :] += W[:, :, :, c] * dZ[i, h, w, c] # (f, f, n_C_prev) * (1, 1, 1)dW[:, :, :, c] += slice_A_prev * dZ[i, h, w, c]db[:, :, :, c] += dZ[i, h, w, c]dA_prev[i] = dA_prev_pad[i, p:-p, p:-p, :]return dA_prev, dW, db# 测试
np.random.seed(1)
dA, dW, db = conv_backward(Z, cache_conv)
print("dA_mean =", np.mean(dA))
print("dW_mean =", np.mean(dW))
print("db_mean =", np.mean(db))# 池化层的反向传播
def pool_backward(dA, cache, mode = "max"):"""Implements the backward pass of the pooling layerArguments:dA -- gradient of cost with respect to the output of the pooling layer, same shape as A (m, n_H, n_W, n_C)cache -- cache output from the forward pass of the pooling layer, contains the layer's input and hparameters mode -- the pooling mode you would like to use, defined as a string ("max" or "average")Returns:dA_prev -- gradient of cost with respect to the input of the pooling layer, same shape as A_prev"""A_prev, hparameters = cachem, n_H, n_W, n_C = dA.shapef = hparameters['f']s = hparameters['stride']dA_prev = np.zeros(A_prev.shape)for i in range(m):i_dA = dA[i] # (n_H, n_W, n_C)i_A_prev = A_prev[i] # (n_H_prev, n_W_prev, n_C)for h in range(n_H):for w in range(n_W):for c in range(n_C):if mode=='max':dA_prev[i, h*s:f+h*s, w*s:f+w*s, c] += (i_A_prev[h*s:f+h*s, w*s:f+w*s, c]==np.max(i_A_prev[h*s:f+h*s, w*s:f+w*s, c])) * i_dA[h, w, c]else:dA_prev[i, h*s:f+h*s, w*s:f+w*s, c] += np.ones((f, f)) * (i_dA[h, w, c] / (f * f))return dA_prev# 测试
np.random.seed(1)
A_prev = np.random.randn(5, 5, 3, 2)
hparameters = {"stride" : 1, "f": 2}
A, cache = pool_forward(A_prev, hparameters)
dA = np.random.randn(5, 4, 2, 2)dA_prev = pool_backward(dA, cache, mode = "max")
print("mode = max")
print('mean of dA = ', np.mean(dA))
print('dA_prev[1,1] = ', dA_prev[1,1])
print()
dA_prev = pool_backward(dA, cache, mode = "average")
print("mode = average")
print('mean of dA = ', np.mean(dA))
print('dA_prev[1,1] = ', dA_prev[1,1])

2. Convolutional Model: application

使用TensorFlow来搭建CNN。

import numpy as np
import h5py
import matplotlib.pyplot as plt
import tensorflow as tf
from cnn_utils import *# Loading the data (signs)
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()# Example of a picture
index = 15
plt.imshow(X_train_orig[index])
print ("y = " + str(np.squeeze(Y_train_orig[:, index])))# 数据处理
X_train = X_train_orig / 255. # (1080, 64, 64, 3)
X_test = X_test_orig / 255.  # (120, 64, 64, 3)
Y_train = Y_train_orig.T
Y_test = Y_test_orig.T'''=========== Sequential构建模型 ==========='''
del model #删除现有模型model = tf.keras.Sequential()
# 建立模型
model.add(tf.keras.layers.Conv2D(filters=8, kernel_size=4, strides=(1,1), padding='same', activation='relu'))
model.add(tf.keras.layers.MaxPool2D(pool_size=(8, 8), padding='same'))
model.add(tf.keras.layers.Conv2D(filters=16, kernel_size=2, strides=(1,1), padding='same', activation='relu'))
model.add(tf.keras.layers.MaxPool2D(pool_size=(4, 4), padding='same'))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(6, activation='softmax'))# 编译
model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.000969),loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),metrics=['sparse_categorical_accuracy'])# 训练
history = model.fit(X_train, Y_train,batch_size=64, epochs=300)# 查看模型
model.summary()# 画出loss曲线
losses = history.history['loss']
accs = history.history['sparse_categorical_accuracy']
x = range(1, 301)
plt.plot(x, losses, 'b-')
plt.title('Loss on training set')
plt.xlabel('epochs')
plt.ylabel('loss')
plt.legend()
plt.show# 在测试集上的loss和精度
test_result = model.evaluate(X_test, Y_test)
l = test_result[0]
acc = test_result[1]
print('\nloss: %.4f, accuracy:% .2f%%' % (l, acc*100))
# loss: 0.2529, accuracy: 90.00%'''============ 在自己的图片上试试效果 ============ '''
from skimage.transform import resize
# 读入图片并显示
my_image = plt.imread('image/myimage4.jpg')
plt.imshow(my_image)
# 显示图片大小
my_image.shape
# 调整像素
my_image = resize(my_image, output_shape=(64,64))
# 模型预测类别
model.predict_classes(my_image.reshape(1, 64, 64, 3))

3. Convolutional Model: the happy house

也是使用TensorFlow搭建CNN,并且加入batch norm、dropout等。

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from kt_utils import *# 导入数据
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()# 查看样例
index = 5
plt.imshow(X_train_orig[index])
print(Y_train_orig[0, index])# 处理数据
X_train = X_train_orig / 255
X_test = X_test_orig / 255
Y_train = Y_train_orig.T
Y_test = Y_test_orig.T'''================ Sequential ============='''
model = tf.keras.Sequential()# Padding -> Conv -> BN -> ReLu -> Dropout -> Maxpool ->
# -> Conv -> BN -> ReLu -> Dropout -> Maxpool -> Flatten -> Dense
model.add(tf.keras.layers.ZeroPadding2D((3, 3)))model.add(tf.keras.layers.Conv2D(32, (7, 7), strides=(1, 1)))
model.add(tf.keras.layers.BatchNormalization(axis=3))
model.add(tf.keras.layers.Activation('relu'))
model.add(tf.keras.layers.Dropout(rate=0.2))
model.add(tf.keras.layers.MaxPool2D((2, 2)))model.add(tf.keras.layers.Conv2D(64, (3, 3), strides=(1, 1)))
model.add(tf.keras.layers.BatchNormalization(axis=3))
model.add(tf.keras.layers.Activation('relu'))
model.add(tf.keras.layers.Dropout(rate=0.1))
model.add(tf.keras.layers.MaxPool2D((2, 2)))model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))# 编译模型
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])# 训练
history = model.fit(X_train, Y_train, epochs=40, batch_size=16)# 模型评价
model.evaluate(X_test, Y_test)
# [0.11056036631266276, 0.94666666]losses = history.history['loss']
ep = range(1, 41)
plt.title('learning rate')
plt.plot(ep, losses, 'r-')
plt.xlabel('epochs')
plt.ylabel('loss')
plt.legend(['loss'])
plt.show()# 在自己图片上测试
from skimage.transform import resize
image = plt.imread('image/myimage9.jpg')
plt.imshow(image)
image = resize(image, (64, 64))
model.predict_classes(image.reshape(1, 64, 64, 3))'''============== 函数式 =============='''
del modelInput = tf.keras.Input(shape=(64, 64, 3))x = tf.keras.layers.ZeroPadding2D((3, 3))(Input)x = tf.keras.layers.Conv2D(32, (7, 7), strides=(1, 1))(x)
x = tf.keras.layers.BatchNormalization(axis=3)(x)
x = tf.keras.layers.Activation('relu')(x)
x = tf.keras.layers.Dropout(rate=0.2)(x)
x = tf.keras.layers.MaxPool2D((2, 2))(x)x = tf.keras.layers.Conv2D(64, (3, 3), strides=(1, 1))(x)
x = tf.keras.layers.BatchNormalization(axis=3)(x)
x = tf.keras.layers.Activation('relu')(x)
x = tf.keras.layers.Dropout(rate=0.1)(x)
x = tf.keras.layers.MaxPool2D((2, 2))(x)x = tf.keras.layers.Flatten()(x)
Output = tf.keras.layers.Dense(1, activation='sigmoid')(x)model = tf.keras.Model(inputs=Input, outputs=Output)# 编译模型
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])# 训练
history = model.fit(X_train, Y_train, epochs=40, batch_size=16)# 模型评价
model.evaluate(X_test, Y_test)
# [0.11056036631266276, 0.94666666]losses = history.history['loss']
ep = range(1, 41)
plt.title('learning rate')
plt.plot(ep, losses, 'r-')
plt.xlabel('epochs')
plt.ylabel('loss')
plt.legend(['loss'])
plt.show()# 在自己图片上测试
from skimage.transform import resize
image = plt.imread('image/myimage10.jpg')
plt.imshow(image)
image = resize(image, (64, 64))
model.predict(image.reshape(1, 64, 64, 3))
plt.imshow(image)

4. Residual Networks

基于TensorFlow使用ResNet搭建一个拥有50层的CNN,体会残差网络对梯度消失带来的好处,可以建立很深的网络。主要使用函数式API来构建模型。

import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from resnets_utils import *# 导入数据
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()# 查看样例
index = 5
plt.imshow(X_train_orig[index])
print(Y_train_orig[0, index])# 处理数据
X_train = X_train_orig / 255
X_test = X_test_orig / 255
Y_train = Y_train_orig.T
Y_test = Y_test_orig.T# identity_block
def identity_block(X, f, filters):"""Implementation of the identity block as defined in Figure 3Arguments:X -- input tensor of shape (m, n_H_prev, n_W_prev, n_C_prev)f -- integer, specifying the shape of the middle CONV's window for the main pathfilters -- python list of integers, defining the number of filters in the CONV layers of the main pathReturns:X -- output of the convolutional block, tensor of shape (n_H, n_W, n_C)"""f1, f2, f3 = filtersx = tf.keras.layers.Conv2D(f1, (1, 1), strides=(1, 1))(X)x = tf.keras.layers.BatchNormalization(axis=3)(x)x = tf.keras.layers.Activation('relu')(x)x = tf.keras.layers.Conv2D(f2, (f, f), strides=(1, 1), padding='same')(x)x = tf.keras.layers.BatchNormalization(axis=3)(x)x = tf.keras.layers.Activation('relu')(x)x = tf.keras.layers.Conv2D(f3, (1, 1), strides=(1, 1))(x)x = tf.keras.layers.BatchNormalization(axis=3)(x)x = tf.keras.layers.Add()([x, X])x = tf.keras.layers.Activation('relu')(x)return x# convolutional_block
def convolutional_block(X, f, filters, s):"""Implementation of the convolutional block as defined in Figure 4Arguments:X -- input tensor of shape (m, n_H_prev, n_W_prev, n_C_prev)f -- integer, specifying the shape of the middle CONV's window for the main pathfilters -- python list of integers, defining the number of filters in the CONV layers of the main paths -- Integer, specifying the stride to be usedReturns:X -- output of the convolutional block, tensor of shape (n_H, n_W, n_C)"""f1, f2, f3 = filtersx = tf.keras.layers.Conv2D(f1, (1, 1), strides=(s, s))(X)x = tf.keras.layers.BatchNormalization(axis=3)(x)x = tf.keras.layers.Activation('relu')(x)x = tf.keras.layers.Conv2D(f2, (f, f), strides=(1, 1), padding='same')(x)x = tf.keras.layers.BatchNormalization(axis=3)(x)x = tf.keras.layers.Activation('relu')(x)x = tf.keras.layers.Conv2D(f3, (1, 1), strides=(1, 1))(x)x = tf.keras.layers.BatchNormalization(axis=3)(x)x_short_cut = tf.keras.layers.Conv2D(f3, (1, 1), strides=(s, s))(X)x_short_cut = tf.keras.layers.BatchNormalization(axis=3)(x_short_cut)x = tf.keras.layers.Add()([x, x_short_cut])x = tf.keras.layers.Activation('relu')(x)return x# del model
# 建立模型
Input = tf.keras.Input(shape=(64, 64, 3))# zero-padding
x = tf.keras.layers.ZeroPadding2D((3, 3))(Input)# stage 1 (1层)
x = tf.keras.layers.Conv2D(64, (7, 7), strides=(2, 2))(x)
x = tf.keras.layers.BatchNormalization(axis=3)(x)
x = tf.keras.layers.Activation('relu')(x)
x = tf.keras.layers.MaxPool2D((3, 3), strides=(2, 2))(x)# stage 2 (3+3*2层)
x = convolutional_block(x, f=3, filters=[64, 64, 256], s=1)
x = identity_block(x, f=3, filters=[64, 64, 256])
x = identity_block(x, f=3, filters=[64, 64, 256])# stage 3 (3+3*3层)
x = convolutional_block(x, f=3, filters= [128, 128, 512], s=2)
x = identity_block(x, f=3, filters=[128, 128, 512])
x = identity_block(x, f=3, filters=[128, 128, 512])
x = identity_block(x, f=3, filters=[128, 128, 512])# stage 4 (3+3*5层)
x = convolutional_block(x, f=3, filters= [256, 256, 1024], s=2)
x = identity_block(x, f=3, filters=[256, 256, 1024])
x = identity_block(x, f=3, filters=[256, 256, 1024])
x = identity_block(x, f=3, filters=[256, 256, 1024])
x = identity_block(x, f=3, filters=[256, 256, 1024])
x = identity_block(x, f=3, filters=[256, 256, 1024])# stage 5 (3+3*2层)
x = convolutional_block(x, f=3, filters=[512, 512, 2048], s=2)
x = identity_block(x, f=3, filters=[512, 512, 2048])
x = identity_block(x, f=3, filters=[512, 512, 2048])# average pooling
x = tf.keras.layers.AveragePooling2D((2, 2))(x)# flatten
x = tf.keras.layers.Flatten()(x)# dense (1层)
Output = tf.keras.layers.Dense(6, activation='softmax')(x)model = tf.keras.Model(inputs=Input, outputs=Output, name='ResNet50')# 编译
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])# 训练
model.fit(X_train, Y_train, epochs=2, batch_size=32)# 测试集表现
preds = model.evaluate(X_test, Y_test)
print("Loss = " + str(preds[0]))
print("Test Accuracy = " + str(preds[1]))
# Loss = 5.5064460436503095
# Test Accuracy = 0.16666667

Stanford CS230深度学习(五)CNN和ResNet相关推荐

  1. Stanford CS230深度学习(二)手动搭建DNN

    这篇博客主要是对第二次课进行学习总结,并完成lecture2中要求的C1M3以及C1M4的编程作业.课程资源详见Stanford CS230深度学习(一) 由于这个课的编程作业基本上是一边给任务一边给 ...

  2. Stanford CS230深度学习(一)

    斯坦福CS230可以作为深度学习的入门课,最近我也在跟着看视频.完成编程作业.首先列出使用的资源链接,然后给出第一课的理解和编程作业的代码. 所有资料如下: 一.课程连接: b站课堂讲授版:Stanf ...

  3. Stanford CS230深度学习(七)RNN和LSTM

    在CS230的lecture 7中主要讲了神经网络的解释性,包括: 显著性图saliency maps(计算pre-softmax分数关于输入层的梯度并可视化) 遮挡敏感性occlusion sens ...

  4. Stanford CS230深度学习(六)目标检测、人脸识别和神经风格迁移

    在CS230的lecture 6中主要吴恩达老师讲述了一些关于机器学习和深度学习的tips,用一个触发词台灯的例子教我们如何快速的解决实际中遇到的问题,这节课主要是偏思维上的了解,还是要实际问题实际分 ...

  5. Stanford CS230深度学习(四)TensorFlow2.1

    本周CS230的课程主要是介绍了GAN相关的一些东西,但是这个需要深入了解,所以本次博客主要对coursera上的课程以及作业进行总结. 目录 一.一些重要的概念 1.深度学习中的超参数 2.Batc ...

  6. Stanford CS230深度学习(八)词嵌入与文本情感分析

    在CS230的lecture 8中主要吴恩达老师如何阅读文献,以及一些职业建议,都是一些比较实用的建议和指导. 关于阅读文献,吴恩达老师提倡先列出一个这个领域的文献列表,可能只包含几篇文章,然后精读其 ...

  7. Stanford CS230深度学习(三)调参、正则化和优化算法

    lecture3中主要讲了如何构建一个ML/DL任务,主要包括:选择问题.获得数据.设计模型.训练模型.测试模型.部署以及维护.然后coursera中的课程主要讲实际的应用例如调参.正则化等,以及几个 ...

  8. Stanford CS230深度学习(九)注意力机制和语音识别

    在CS230的lecture 9中主要讲了深度强化学习(Deep Reinforcement Learning)大体上是如何实施的,以及一些应用场景.课后coursera上遗留的最后C5M3的课程及其 ...

  9. ​【斯坦福出品】吴恩达CS230深度学习课小抄来了 | 附下载

    这份人气深度学习秘籍,涵盖了吴恩达老师斯坦福大学CS230深度学习课程重点, 篇幅短 & 内容精简.并配备大量高清插图,不怕你看不下去,就怕看得停不下来.目前,清单地址已经公开,还有PDF版可 ...

最新文章

  1. CodeForces - 613D Kingdom and its Cities(虚树+贪心)
  2. 一位大牛的JAVA学习资料
  3. VS2005代码格式化
  4. Enterprise Library 中加密数据库连接字符串
  5. 聪明人:三不管,四不说,五不帮!
  6. h2事务与mysql_H2数据库事务提交失败
  7. java同步synchronized,锁
  8. 基于java的音乐网站的设计与实现
  9. js正则表达式检验经纬度
  10. let存在变量提升么?
  11. 最新emoji表情代码大全_2020最新霜降早上好祝福语动态表情图片大全带字 温馨的霜降问候语免打字图片...
  12. JS 怎么将一个对象的值作为另一个对象的key
  13. 银河麒麟V10安装虚拟机
  14. 为什么很多人家里不准备尺子了?手机怎么测量长度?
  15. 风的UV分量转成风向风速(C#)
  16. 一文理解PF、PFC、PPFC、APFC原理
  17. 远程代答系统如何自动代答题?
  18. 打造宜居 Ubuntu16.04
  19. 可转债新规内容及影响
  20. Qcom wifi sar架构

热门文章

  1. UIAlertController 类似相册拍照弹出框
  2. emacs在windows下打开报错原因
  3. 一步一步搭建hibernate4+ spring+ struts2
  4. Selenium WebDriver之JavaScript
  5. 中国象棋程序的设计与实现(七)--心得体会和开发日志
  6. 【7.9校内test】T1挖地雷
  7. Scalaz(38)- Free :Coproduct-Monadic语句组合
  8. 在Android中调用KSOAP2库访问webservice服务出现的服务端传入参数为null的问题解决
  9. Android ViewPager 重复数据问题的解决方法
  10. java.lang.IllegalStateException: Failed to load ApplicationContext selenium 异常 解决