一、残差神经网络——ResNet的详述

1.1残差模块——Residual bloack

通过在一个浅层网络基础上叠加 y=x 的层(称identity mappings,恒等映射),可以让网络随深度增加而不退化。

这反映了多层非线性网络无法逼近恒等映射网络。但是,不退化不是我们的目的,我们希望有更好性能的网络。

resnet学习的是残差函数F(x) = H(x) - x, 这里如果F(x) = 0, 那么就是上面提到的恒等映射。事实上,

resnet是“shortcut connections”的在connections是在恒等映射下的特殊情况,它没有引入额外的参数和计算复杂度。

假如优化目标函数是逼近一个恒等映射, 而不是0映射, 那么学习找到对恒等映射的扰动会比重新学习一个映射函数要容易。

残差函数一般会有较小的响应波动,表明恒等映射是一个合理的预处理。

残差模块小结:

非常深的网络很难训练,存在梯度消失和梯度爆炸问题,学习 skip connection它可以从某一层获得激活,然后迅速反馈给另外一层甚至更深层,利用 skip connection可以构建残差网络ResNet来训练更深的网络,ResNet网络是由残差模块构建的。

上图中,是一个两层的神经网络,在l层进行激活操作,得到a[l+1],再次进行激活得到a[l+2]。由下面公式:

a[l+2] 加上了 a[l]的残差块,即:残差网络中,直接将a[l]向后拷贝到神经网络的更深层,在ReLU非线性激活前面

加上a[l],a[l]的信息直接达到网络深层。使用残差块能够训练更深层的网络,构建一个ResNet网络就是通过将很多

这样的残差块堆积在一起,形成一个深度神经网络。

(三)残差网络——ResNet

上图中是用5个残差块连接在一起构成的残差网络,用梯度下降算法训练一个神经网络,若没有残差,会发现

随着网络加深,训练误差先减少后增加,理论上训练误差越来越小比较好。而对于残差网络来讲,随着层数增加,

训练误差越来越减小,这种方式能够到达网络更深层,有助于解决梯度消失和梯度爆炸的问题,让我们训练更深网络

同时又能保证良好的性能。

残差网络有很好表现的原因举例:

假设有一个很大的神经网络,输入矩阵为X,输出激活值为a[l],加入给这个网络额外增加两层,最终输出结果为a[l+2],

可以把这两层看做一个残差模块,在整个网络中使用ReLU激活函数,所有的激活值都大于等于0。

对于大型的网络,无论把残差块添加到神经网络的中间还是末端,都不会影响网络的表现。

残差网络起作用的主要原因是:It’s so easy for these extra layers to learn the itentity function.

这些残差块学习恒等函数非常容易。可以确定网络性能不受影响,很多时候甚至可以提高学习效率。

模型构建好后进行实验,在plain上观测到明显的退化现象,而且ResNet上不仅没有退化,34层网络的效果反而比18层的更好,而且不仅如此,ResNet的收敛速度比plain的要快得多。

实际中,考虑计算的成本,对残差块做了计算优化,即将两个3x3的卷积层替换为1x1 + 3x3 + 1x1,
如下图。新结构中的中间3x3的卷积层首先在一个降维1x1卷积层下减少了计算,然后在另一个1x1的卷积层下做了还原,既保持了精度又减少了计算量。

这相当于对于相同数量的层又减少了参数量,因此可以拓展成更深的模型。于是作者提出了50、101、152层的ResNet,而且不仅没有出现退化问题,错误率也大大降低,同时计算复杂度也保持在很低的程度。

这个时候ResNet的错误率已经把其他网络落下几条街了,但是似乎还并不满足,于是又搭建了更加变态的1202层的网络,对于这么深的网络,优化依然并不困难,但是出现了过拟合的问题,这是很正常的,作者也说了以后会对这个1202层的模型进行进一步的改进。

二、ResNet在Keras框架下的实现

(一)概况

利用残差神经网络ResNet构建一个很深度的卷积神经网络。理论上,很深的神经网络代表着复杂的函数,实际上它们很难训练,而ResNet比其他很深的神经网络训练起来更加实际可行。

1、构建基本的ResNet模块。

2、把这些ResNet模块集成在一起,实现和训练一个用于图像分类的最先进的神经网络。

3、该ResNet网络在深度学习框架 Keras下构建完成。

近年来,神经网络已变得更深,与最先进的网络从几层(如AlexNet)到一百层。一个非常深的网络的主要好处是:它可以代表非常复杂的函数。它还可以从许多不同层次的抽象中学习特征,从边缘(在较低的层)到非常复杂的特性(在更深的层次)。然而,使用更深层的网络并不总是有用的。训练它们巨大的障碍就是梯度消失:很深的网络往往梯度信号变为零的速度快,从而使梯度下降法非常地慢。更特别的是,在梯度下降,当你从最后一层BackProp回到第一层,每一步乘以权重矩阵,从而梯度以指数方式迅速减为为零(或者,在罕见的情况下,成倍的增长,迅速“爆炸”为非常大的值)。

在训练过程中,可能会看到前面层的梯度的量级或标准减小到零的速度很快,如下图所示:

(二)、构建残差块

在ResNet中,”shortcut” 或 “skip connection” 使得梯度反向传播到更前面的层:下图中左边的图片展示了神经网络的主路径“main path”,右侧的图片为“main path”添加了一个“short cut”,通过堆叠这些ResNet模块,可以构建很深的神经网络。

带有“shortcut”的ResNet模块,使得它对每一个模块很容易学习到恒等函数“identy function”,这意味着你可以叠加额外ResNet模块而对训练集的性能产生风险小的危害。还有一些证据表明,学习恒等函数“identy function” 甚至比“skip connection” 对于梯度消失问题更有帮助,且更能说明ResNets表现出色。在ResNet中使用两种主要类型的模块,主要取决于输入/输出尺寸是相同还是不同。

1、恒等残差块——The identity block

The identity block是ResNets中使用的标准块,对应于输入激活(例如 a [1])与输出激活具有相同维度(例如a [l +2])。

(1)、两层恒等残差块

下图展示了ResNets的两层的恒等残差块 identity block:

上面的路径是“shortcut path”,下面的路径是“main path”,在这个图中,同样也进行了CONV2D和ReLU操作,为了加速训练的速度也加入了Batch正则化“Batch Norm”,Batch Norm在Keras框架中就一句代码。

(2)、三层恒等残差块

在下面的这个例子中,将实际上实现一个略微更强大的版本,这个跳转连接“跳过”3个隐藏层而不是2层。

(3)、下面是细节的步骤:

a、主路径的第一部分:

第一个CONV2D的过滤器F1大小是(1*1),步长s大小为(1*1),卷积填充padding=”valid”即无填充卷积。

将这一部分命名为conv_name_base+’2a’,初始化时利用种子为seed=0。

第一个BatchNorm是在通道/厚度的轴上进行标准化,并命名为bn_name_base+'2a'.

应用ReLU激活函数,这里没有超参数。

b、主路径的第二部分:

第二个CONV2D的过滤器F2大小是(f*f),步长s大小为(1*1),卷积填充padding=”same”即相同卷积。

将这一部分命名为conv_name_base’2b’,初始化时利用种子为seed=0。

第二个BatchNorm是在通道/厚度的轴上进行标准化,并命名为bn_name_base+'2b'.

应用ReLU激活函数,这里没有超参数。

c、主路径的第三部分:

第三个CONV2D的过滤器F3大小是(1*1),步长s大小为(1*1),卷积填充padding=”valid“即无填充卷积。

将这一部分命名为conv_name_base+’2c’,初始化时利用种子为seed=0。

第三个BatchNorm是在通道/厚度的轴上进行标准化,并命名为bn_name_base +'2c'.

这一部分中没有应用ReLU激活函数。

d、最后部分:

将shortcut和输入一起添加到模块中,然后再应用ReLU激活函数,这里没有超参数。

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. # Author:ZhengzhengLiu
  4. #构建50层的ResNet神经网络实现图像的分类
  5. #深度学习框架 Keras中实现
  6. import numpy as np
  7. import tensorflow as tf
  8. from keras import layers
  9. from keras.layers import Input,Add,Dense,Activation,ZeroPadding2D,\
  10. BatchNormalization,Flatten,Conv2D,AveragePooling2D,MaxPooling2D,GlobalMaxPooling2D
  11. from keras.models import Model,load_model
  12. from keras.preprocessing import image
  13. from keras.utils import layer_utils
  14. from keras.utils.data_utils import get_file
  15. from keras.applications.imagenet_utils import preprocess_input
  16. from keras.utils.vis_utils import model_to_dot
  17. from keras.utils import plot_model
  18. from keras.initializers import glorot_uniform
  19. import pydoc
  20. from IPython.display import SVG
  21. from resnets_utils import *
  22. import scipy.misc
  23. from matplotlib.pyplot import imshow
  24. import keras.backend as K
  25. K.set_image_data_format("channels_last")
  26. K.set_learning_phase(1)
  27. #恒等模块——identity_block
  28. def identity_block(X,f,filters,stage,block):
  29. """
  30. 三层的恒等残差块
  31. param :
  32. X -- 输入的张量,维度为(m, n_H_prev, n_W_prev, n_C_prev)
  33. f -- 整数,指定主路径的中间 CONV 窗口的形状(过滤器大小)
  34. filters -- python整数列表,定义主路径的CONV层中的过滤器
  35. stage -- 整数,用于命名层,取决于它们在网络中的位置
  36. block --字符串/字符,用于命名层,取决于它们在网络中的位置
  37. return:
  38. X -- 三层的恒等残差块的输出,维度为:(n_H, n_W, n_C)
  39. """
  40. #定义基本的名字
  41. conv_name_base = "res"+str(stage)+block+"_branch"
  42. bn_name_base = "bn"+str(stage)+block+"_branch"
  43. #过滤器
  44. F1,F2,F3 = filters
  45. #保存输入值,后面将需要添加回主路径
  46. X_shortcut = X
  47. #主路径第一部分
  48. X = Conv2D(filters=F1,kernel_size=(1,1),strides=(1,1),padding="valid",
  49. name=conv_name_base+"2a",kernel_initializer=glorot_uniform(seed=0))(X)
  50. X = BatchNormalization(axis=3,name=bn_name_base+"2a")(X)
  51. X = Activation("relu")(X)
  52. # 主路径第二部分
  53. X = Conv2D(filters=F2,kernel_size=(f,f),strides=(1,1),padding="same",
  54. name=conv_name_base+"2b",kernel_initializer=glorot_uniform(seed=0))(X)
  55. X = BatchNormalization(axis=3,name=bn_name_base+"2b")(X)
  56. X = Activation("relu")(X)
  57. # 主路径第三部分
  58. X = Conv2D(filters=F3,kernel_size=(1,1),strides=(1,1),padding="valid",
  59. name=conv_name_base+"2c",kernel_initializer=glorot_uniform(seed=0))(X)
  60. X = BatchNormalization(axis=3,name=bn_name_base+"2c")(X)
  61. # 主路径最后部分,为主路径添加shortcut并通过relu激活
  62. X = layers.add([X,X_shortcut])
  63. X = Activation("relu")(X)
  64. return X
  65. tf.reset_default_graph()
  66. with tf.Session() as sess:
  67. np.random.seed(1)
  68. A_prev = tf.placeholder("float",shape=[3,4,4,6])
  69. X = np.random.randn(3,4,4,6)
  70. A = identity_block(A_prev,f=2,filters=[2,4,6],stage=1,block="a")
  71. sess.run(tf.global_variables_initializer())
  72. out = sess.run([A],feed_dict={A_prev:X,K.learning_phase():0})
  73. print("out = "+str(out[0][1][1][0]))
  74. #运行结果:
  75. out = [0.19716813 0. 1.3561227 2.1713073 0. 1.3324987 ]

2、卷积残差块——The convolutional block

(1)、综述

ResNet的convolutional_block是另一种类型的残差块,当输入和输出尺寸不匹配时,可以使用这种类型的块。

与identity block恒等残差块不同的地方是:在shortcut路径中是一个CONV2D的层。

shortcut路径中的CONV2D层用于将输入x调整为不同的尺寸,以便在添加shortcut残差块的值返回到主路径时需要最后添加的尺寸相匹配(与矩阵Ws的作用相同)。例如,要将激活值维度的高度和宽度缩小2倍,可以使用步长为2的1x1卷积。shortcut路径上的CONV2D层路径不使用任何非线性激活函数。 它的主要作用是只应用一个(学习的)线性函数来减小输入的尺寸,使得尺寸匹配后面的添加步骤。

(2)、convolutional_block的细节步骤

a、主路径第一部分

第一个CONV2D的过滤器F1大小是(1*1),步长s大小为(s*s),卷积填充padding=”valid”即无填充卷积。

将这一部分命名为conv_name_base+’2a’。

第一个BatchNorm是在通道/厚度的轴上进行标准化,并命名为bn_name_base+'2a'.

应用ReLU激活函数,这里没有超参数。

b、主路径第二部分

第二个CONV2D的过滤器F2大小是(f*f),步长s大小为(1*1),卷积填充padding=”same”即相同卷积。

将这一部分命名为conv_name_base+’2b’,初始化时利用种子为seed=0。

第二个BatchNorm是在通道/厚度的轴上进行标准化,并命名为bn_name_base+'2b'.

应用ReLU激活函数,这里没有超参数。

c、主路径第三部分

第三个CONV2D的过滤器 F3大小是(1*1),步长s大小为(1*1),卷积填充padding=”valid“即无填充卷积。

将这一部分命名为 conv_name_base+’2c’,初始化时利用种子为seed=0。

第三个BatchNorm是在通道/厚度的轴上进行标准化,并命名为bn_name_base+'2c'.

这一部分中没有应用ReLU激活函数。

d、shortcut 路径

该部分CONV2D的过滤器 F3大小是(1*1),步长s大小为(s*s),卷积填充 padding=”valid“即无填充卷积。

将这一部分命名为conv_name_base+’1’。

该部分BatchNorm是在通道/厚度的轴上进行标准化,并命名为bn_name_base+'1'

e、最后部分

将shortcut和输入一起添加到模块中,然后再应用ReLU激活函数,这里没有超参数。

  1. #卷积残差块——convolutional_block
  2. def convolutional_block(X,f,filters,stage,block,s=2):
  3. """
  4. param :
  5. X -- 输入的张量,维度为(m, n_H_prev, n_W_prev, n_C_prev)
  6. f -- 整数,指定主路径的中间 CONV 窗口的形状(过滤器大小)
  7. filters -- python整数列表,定义主路径的CONV层中的过滤器
  8. stage -- 整数,用于命名层,取决于它们在网络中的位置
  9. block --字符串/字符,用于命名层,取决于它们在网络中的位置
  10. s -- 整数,指定使用的步幅
  11. return:
  12. X -- 卷积残差块的输出,维度为:(n_H, n_W, n_C)
  13. """
  14. # 定义基本的名字
  15. conv_name_base = "res" + str(stage) + block + "_branch"
  16. bn_name_base = "bn" + str(stage) + block + "_branch"
  17. # 过滤器
  18. F1, F2, F3 = filters
  19. # 保存输入值,后面将需要添加回主路径
  20. X_shortcut = X
  21. # 主路径第一部分
  22. X = Conv2D(filters=F1, kernel_size=(1, 1), strides=(s, s), padding="valid",
  23. name=conv_name_base + "2a", kernel_initializer=glorot_uniform(seed=0))(X)
  24. X = BatchNormalization(axis=3, name=bn_name_base + "2a")(X)
  25. X = Activation("relu")(X)
  26. # 主路径第二部分
  27. X = Conv2D(filters=F2, kernel_size=(f, f), strides=(1, 1), padding="same",
  28. name=conv_name_base + "2b", kernel_initializer=glorot_uniform(seed=0))(X)
  29. X = BatchNormalization(axis=3, name=bn_name_base + "2b")(X)
  30. X = Activation("relu")(X)
  31. # 主路径第三部分
  32. X = Conv2D(filters=F3, kernel_size=(1, 1), strides=(1, 1), padding="valid",
  33. name=conv_name_base + "2c", kernel_initializer=glorot_uniform(seed=0))(X)
  34. X = BatchNormalization(axis=3, name=bn_name_base + "2c")(X)
  35. #shortcut路径
  36. X_shortcut = Conv2D(filters=F3,kernel_size=(1,1),strides=(s,s),padding="valid",
  37. name=conv_name_base+"1",kernel_initializer=glorot_uniform(seed=0))(X_shortcut)
  38. X_shortcut = BatchNormalization(axis=3,name=bn_name_base+"1")(X_shortcut)
  39. # 主路径最后部分,为主路径添加shortcut并通过relu激活
  40. X = layers.add([X, X_shortcut])
  41. X = Activation("relu")(X)
  42. return X
  43. tf.reset_default_graph()
  44. with tf.Session() as test:
  45. np.random.seed(1)
  46. A_prev = tf.placeholder("float", [3, 4, 4, 6])
  47. X = np.random.randn(3, 4, 4, 6)
  48. A = convolutional_block(A_prev, f = 2, filters = [2, 4, 6], stage = 1, block = 'a')
  49. test.run(tf.global_variables_initializer())
  50. out = test.run([A], feed_dict={A_prev: X, K.learning_phase(): 0})
  51. print("out = " + str(out[0][1][1][0]))
  52. #运行结果:
  53. out = [0.09018463 1.2348977 0.46822017 0.0367176 0. 0.65516603]

三、在Keras框架下构建50层的残差卷积神经网络ResNet


50层的残差卷积神经网络ResNet的细节部分:

0、为输入224*224*3填充大小为(3*3)的zero_padding。

1、第一阶段,输出大小为:56*56*64

2、第二阶段,输出大小为:56*56*256

3、第三阶段,输出大小为:28*28*512

4、第四阶段,输出大小为:14*14*1024

5、第五阶段,输出大小为:7*7*2048

6、最后阶段,输出6个类别

注意:

(1)正如在Keras教程中所看到的,在事先训练模型之前,需要通过编译模型来配置学习过程。

(2)模型训练20次epches,批样本数目batch_size = 32,在单个CPU上运行大概每个epoch需5分钟。

(3)当训练足够数量的迭代时,ResNet50是一个强大的图像分类模型。

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. # Author:ZhengzhengLiu
  4. #构建50层的ResNet神经网络实现图像的分类
  5. #深度学习框架 Keras中实现
  6. import numpy as np
  7. import tensorflow as tf
  8. from keras import layers
  9. from keras.layers import Input,Add,Dense,Activation,ZeroPadding2D,\
  10. BatchNormalization,Flatten,Conv2D,AveragePooling2D,MaxPooling2D,GlobalMaxPooling2D
  11. from keras.models import Model,load_model
  12. from keras.preprocessing import image
  13. from keras.utils import layer_utils
  14. from keras.utils.data_utils import get_file
  15. from keras.applications.imagenet_utils import preprocess_input
  16. from keras.utils.vis_utils import model_to_dot
  17. from keras.utils import plot_model
  18. from keras.initializers import glorot_uniform
  19. import pydoc
  20. from IPython.display import SVG
  21. from resnets_utils import *
  22. import scipy.misc
  23. from matplotlib.pyplot import imshow
  24. import keras.backend as K
  25. K.set_image_data_format("channels_last")
  26. K.set_learning_phase(1)
  27. #恒等模块——identity_block
  28. def identity_block(X,f,filters,stage,block):
  29. """
  30. 三层的恒等残差块
  31. param :
  32. X -- 输入的张量,维度为(m, n_H_prev, n_W_prev, n_C_prev)
  33. f -- 整数,指定主路径的中间 CONV 窗口的形状
  34. filters -- python整数列表,定义主路径的CONV层中的过滤器数目
  35. stage -- 整数,用于命名层,取决于它们在网络中的位置
  36. block --字符串/字符,用于命名层,取决于它们在网络中的位置
  37. return:
  38. X -- 三层的恒等残差块的输出,维度为:(n_H, n_W, n_C)
  39. """
  40. #定义基本的名字
  41. conv_name_base = "res"+str(stage)+block+"_branch"
  42. bn_name_base = "bn"+str(stage)+block+"_branch"
  43. #过滤器
  44. F1,F2,F3 = filters
  45. #保存输入值,后面将需要添加回主路径
  46. X_shortcut = X
  47. #主路径第一部分
  48. X = Conv2D(filters=F1,kernel_size=(1,1),strides=(1,1),padding="valid",
  49. name=conv_name_base+"2a",kernel_initializer=glorot_uniform(seed=0))(X)
  50. X = BatchNormalization(axis=3,name=bn_name_base+"2a")(X)
  51. X = Activation("relu")(X)
  52. # 主路径第二部分
  53. X = Conv2D(filters=F2,kernel_size=(f,f),strides=(1,1),padding="same",
  54. name=conv_name_base+"2b",kernel_initializer=glorot_uniform(seed=0))(X)
  55. X = BatchNormalization(axis=3,name=bn_name_base+"2b")(X)
  56. X = Activation("relu")(X)
  57. # 主路径第三部分
  58. X = Conv2D(filters=F3,kernel_size=(1,1),strides=(1,1),padding="valid",
  59. name=conv_name_base+"2c",kernel_initializer=glorot_uniform(seed=0))(X)
  60. X = BatchNormalization(axis=3,name=bn_name_base+"2c")(X)
  61. # 主路径最后部分,为主路径添加shortcut并通过relu激活
  62. X = layers.add([X,X_shortcut])
  63. X = Activation("relu")(X)
  64. return X
  65. tf.reset_default_graph()
  66. with tf.Session() as sess:
  67. np.random.seed(1)
  68. A_prev = tf.placeholder("float",shape=[3,4,4,6])
  69. X = np.random.randn(3,4,4,6)
  70. A = identity_block(A_prev,f=2,filters=[2,4,6],stage=1,block="a")
  71. sess.run(tf.global_variables_initializer())
  72. out = sess.run([A],feed_dict={A_prev:X,K.learning_phase():0})
  73. print("out = "+str(out[0][1][1][0]))
  74. #卷积残差块——convolutional_block
  75. def convolutional_block(X,f,filters,stage,block,s=2):
  76. """
  77. param :
  78. X -- 输入的张量,维度为(m, n_H_prev, n_W_prev, n_C_prev)
  79. f -- 整数,指定主路径的中间 CONV 窗口的形状(过滤器大小,ResNet中f=3)
  80. filters -- python整数列表,定义主路径的CONV层中过滤器的数目
  81. stage -- 整数,用于命名层,取决于它们在网络中的位置
  82. block --字符串/字符,用于命名层,取决于它们在网络中的位置
  83. s -- 整数,指定使用的步幅
  84. return:
  85. X -- 卷积残差块的输出,维度为:(n_H, n_W, n_C)
  86. """
  87. # 定义基本的名字
  88. conv_name_base = "res" + str(stage) + block + "_branch"
  89. bn_name_base = "bn" + str(stage) + block + "_branch"
  90. # 过滤器
  91. F1, F2, F3 = filters
  92. # 保存输入值,后面将需要添加回主路径
  93. X_shortcut = X
  94. # 主路径第一部分
  95. X = Conv2D(filters=F1, kernel_size=(1, 1), strides=(s, s), padding="valid",
  96. name=conv_name_base + "2a", kernel_initializer=glorot_uniform(seed=0))(X)
  97. X = BatchNormalization(axis=3, name=bn_name_base + "2a")(X)
  98. X = Activation("relu")(X)
  99. # 主路径第二部分
  100. X = Conv2D(filters=F2, kernel_size=(f, f), strides=(1, 1), padding="same",
  101. name=conv_name_base + "2b", kernel_initializer=glorot_uniform(seed=0))(X)
  102. X = BatchNormalization(axis=3, name=bn_name_base + "2b")(X)
  103. X = Activation("relu")(X)
  104. # 主路径第三部分
  105. X = Conv2D(filters=F3, kernel_size=(1, 1), strides=(1, 1), padding="valid",
  106. name=conv_name_base + "2c", kernel_initializer=glorot_uniform(seed=0))(X)
  107. X = BatchNormalization(axis=3, name=bn_name_base + "2c")(X)
  108. #shortcut路径
  109. X_shortcut = Conv2D(filters=F3,kernel_size=(1,1),strides=(s,s),padding="valid",
  110. name=conv_name_base+"1",kernel_initializer=glorot_uniform(seed=0))(X_shortcut)
  111. X_shortcut = BatchNormalization(axis=3,name=bn_name_base+"1")(X_shortcut)
  112. # 主路径最后部分,为主路径添加shortcut并通过relu激活
  113. X = layers.add([X, X_shortcut])
  114. X = Activation("relu")(X)
  115. return X
  116. tf.reset_default_graph()
  117. with tf.Session() as test:
  118. np.random.seed(1)
  119. A_prev = tf.placeholder("float", [3, 4, 4, 6])
  120. X = np.random.randn(3, 4, 4, 6)
  121. A = convolutional_block(A_prev, f = 2, filters = [2, 4, 6], stage = 1, block = 'a')
  122. test.run(tf.global_variables_initializer())
  123. out = test.run([A], feed_dict={A_prev: X, K.learning_phase(): 0})
  124. print("out = " + str(out[0][1][1][0]))
  125. #50层ResNet模型构建
  126. def ResNet50(input_shape = (64,64,3),classes = 6):
  127. """
  128. 构建50层的ResNet,结构为:
  129. CONV2D -> BATCHNORM -> RELU -> MAXPOOL -> CONVBLOCK -> IDBLOCK*2 -> CONVBLOCK -> IDBLOCK*3
  130. -> CONVBLOCK -> IDBLOCK*5 -> CONVBLOCK -> IDBLOCK*2 -> AVGPOOL -> TOPLAYER
  131. param :
  132. input_shape -- 数据集图片的维度
  133. classes -- 整数,分类的数目
  134. return:
  135. model -- Keras中的模型实例
  136. """
  137. #将输入定义为维度大小为 input_shape的张量
  138. X_input = Input(input_shape)
  139. # Zero-Padding
  140. X = ZeroPadding2D((3,3))(X_input)
  141. # Stage 1
  142. X = Conv2D(64,kernel_size=(7,7),strides=(2,2),name="conv1",kernel_initializer=glorot_uniform(seed=0))(X)
  143. X = BatchNormalization(axis=3,name="bn_conv1")(X)
  144. X = Activation("relu")(X)
  145. X = MaxPooling2D(pool_size=(3,3),strides=(2,2))(X)
  146. # Stage 2
  147. X = convolutional_block(X,f=3,filters=[64,64,256],stage=2,block="a",s=1)
  148. X = identity_block(X,f=3,filters=[64,64,256],stage=2,block="b")
  149. X = identity_block(X,f=3,filters=[64,64,256],stage=2,block="c")
  150. #Stage 3
  151. X = convolutional_block(X,f=3,filters=[128,128,512],stage=3,block="a",s=2)
  152. X = identity_block(X,f=3,filters=[128,128,512],stage=3,block="b")
  153. X = identity_block(X,f=3,filters=[128,128,512],stage=3,block="c")
  154. X = identity_block(X,f=3,filters=[128,128,512],stage=3,block="d")
  155. # Stage 4
  156. X = convolutional_block(X,f=3,filters=[256,256,1024],stage=4,block="a",s=2)
  157. X = identity_block(X,f=3,filters=[256,256,1024],stage=4,block="b")
  158. X = identity_block(X,f=3,filters=[256,256,1024],stage=4,block="c")
  159. X = identity_block(X,f=3,filters=[256,256,1024],stage=4,block="d")
  160. X = identity_block(X,f=3,filters=[256,256,1024],stage=4,block="e")
  161. X = identity_block(X,f=3,filters=[256,256,1024],stage=4,block="f")
  162. #Stage 5
  163. X = convolutional_block(X,f=3,filters=[512,512,2048],stage=5,block="a",s=2)
  164. X = identity_block(X,f=3,filters=[256,256,2048],stage=5,block="b")
  165. X = identity_block(X,f=3,filters=[256,256,2048],stage=5,block="c")
  166. #最后阶段
  167. #平均池化
  168. X = AveragePooling2D(pool_size=(2,2))(X)
  169. #输出层
  170. X = Flatten()(X) #展平
  171. X = Dense(classes,activation="softmax",name="fc"+str(classes),kernel_initializer=glorot_uniform(seed=0))(X)
  172. #创建模型
  173. model = Model(inputs=X_input,outputs=X,name="ResNet50")
  174. return model
  175. #运行构建的模型图
  176. model = ResNet50(input_shape=(64,64,3),classes=6)
  177. #编译模型来配置学习过程
  178. model.compile(optimizer="adam",loss="categorical_crossentropy",metrics=["accuracy"])
  179. #加载数据集
  180. X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()
  181. # Normalize image vectors
  182. X_train = X_train_orig/255.
  183. X_test = X_test_orig/255.
  184. # Convert training and test labels to one hot matrices
  185. Y_train = convert_to_one_hot(Y_train_orig, 6).T
  186. Y_test = convert_to_one_hot(Y_test_orig, 6).T
  187. print ("number of training examples = " + str(X_train.shape[0]))
  188. print ("number of test examples = " + str(X_test.shape[0]))
  189. print ("X_train shape: " + str(X_train.shape))
  190. print ("Y_train shape: " + str(Y_train.shape))
  191. print ("X_test shape: " + str(X_test.shape))
  192. print ("Y_test shape: " + str(Y_test.shape))
  193. #训练模型
  194. model.fit(X_train,Y_train,epochs=20,batch_size=32)
  195. #测试集性能测试
  196. preds = model.evaluate(X_test,Y_test)
  197. print("Loss = "+str(preds[0]))
  198. print("Test Accuracy ="+str(preds[1]))si

四、在tensorflow框架下构建残差卷积神经网络ResNet V2

ResNet V2中的残差学习单元为 bottleneck,与ResNet V1的主要区别在于:

1、在每一层前都使用了Batch Normalization;2、对输入进行preactivation,而不是在卷积进行激活函数处理。

(一)基础知识应用

1、Python内建的集合模块——collections

残差神经网络—代码详解相关推荐

  1. Resnet50残差网络代码详解

    Resnet50是Resnet残差网络系列的代表网络,由Kaiming于2016年发表于CVPR 论文地址:CVPR 2016 Open Access Repository 参考代码:https:// ...

  2. DeepLearning tutorial(4)CNN卷积神经网络原理简介+代码详解

    FROM: http://blog.csdn.net/u012162613/article/details/43225445 DeepLearning tutorial(4)CNN卷积神经网络原理简介 ...

  3. [Pytorch系列-61]:循环神经网络 - 中文新闻文本分类详解-3-CNN网络训练与评估代码详解

    作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客 本文网址:https://blog.csdn.net/HiWangWenBing/article/detai ...

  4. 基于神经网络的依存句法分析总结及代码详解

    上一篇文章CS224n之句法分析总结,介绍了句法分析以及具体的依存分析中的arc-standard算法.arc-standard系统是transition systems中最流行的一个系统之一.而本文 ...

  5. 基于U-Net的的图像分割代码详解及应用实现

    摘要 U-Net是基于卷积神经网络(CNN)体系结构设计而成的,由Olaf Ronneberger,Phillip Fischer和Thomas Brox于2015年首次提出应用于计算机视觉领域完成语 ...

  6. 【2023年第十一届泰迪杯数据挖掘挑战赛】B题:产品订单的数据分析与需求预测 建模及python代码详解 问题二

    相关链接 [2023年第十一届泰迪杯数据挖掘挑战赛]B题:产品订单的数据分析与需求预测 建模及python代码详解 问题一 [2023年第十一届泰迪杯数据挖掘挑战赛]B题:产品订单的数据分析与需求预测 ...

  7. 将卷积引入transformer中VcT(Introducing Convolutions to Vision Transformers)的pytorch代码详解

    文章目录 1. Motivation: 2. Method 2.1 Convolutional Token Embedding 模块 2.2 Convolutional Projection For ...

  8. 【CV】Pytorch一小时入门教程-代码详解

    目录 一.关键部分代码分解 1.定义网络 2.损失函数(代价函数) 3.更新权值 二.训练完整的分类器 1.数据处理 2. 训练模型(代码详解) CPU训练 GPU训练 CPU版本与GPU版本代码区别 ...

  9. DeepLearning tutorial(3)MLP多层感知机原理简介+代码详解

    FROM:http://blog.csdn.net/u012162613/article/details/43221829 @author:wepon @blog:http://blog.csdn.n ...

最新文章

  1. Oracle PL/SQL之令人不解的提示(nls_date_format)
  2. yolov5 v3.0训练出现KeyError错误
  3. 死锁产生的条件+排除死锁的方法
  4. ClearTextBox.Text
  5. SharePoint学习札记[6] — WebPart之基础
  6. vc给exe更改图标
  7. 线下实战(这次包含北京)
  8. HDU1856More is better(并查集)
  9. 【LOJ10034】图书管理(哈希表,字符串)
  10. http请求转为https请求 java_如何将Javaweb工程的访问协议由http改为https及通过域名访问?...
  11. matlab显示和输出语句,matlab输出语句是什么,
  12. 最新声音鉴定鉴卡引流神器PHP源码
  13. 阿拉伯数字转化成大写金额
  14. ABB伺服驱动调试(三)
  15. 百度,360,搜狗,必应浏览器网站收录提交(SEO优化)
  16. 洛谷 P1560 [USACO5.2]蜗牛的旅行Snail Trails
  17. Mybatis to_date方法(ORACLE)
  18. Java 方式实现词云显示
  19. 北京图王软件开发有限公司产品介绍-Visual Graph专业图形引擎
  20. C语言中关于float、double、long double精度及数值范围理解

热门文章

  1. 全面解析|搞懂Nginx这一篇就够了
  2. 使用PowerDesigner设计表
  3. 二、肿瘤发展进程、全基因组突变发生顺序(The evolutionary history of 2,658 cancers)
  4. 单芯片如何解决语音播报+显示驱动,实现缩短产品开发周期简化和降低综合BOM成本?
  5. 基于Abaqus的修正剑桥模型的vumat子程序开发
  6. Redis实战学习--缓存首页图标类型
  7. 差点死掉3次,被兄弟骗进传销组织,北漂反转... | 人生如戏,全靠运气!
  8. python的f是什么意思_python中f是什么
  9. ubuntu启动、关闭、重启服务service命令
  10. 靶场设备常见的报靶方式有哪些