实验3 卷积神经网络

实验3 卷积神经网络

学号:111 姓名:XXX

实验目的

1.通过本实验让学生了解卷积神经网络的结构特性、原理和应用领域,并构造CNN完成fasion_MNIST的图像分类。
2.掌握残差网络和迁移学习的基本原理,使用ResNet18完成上述分类任务,并对两个模型的性能进行对比分析

实验要求:

(1)编码规范
(2)代码高效
(3)注释充分,程序可读性好
(4)程序无bug
(5)方法接口规范定义

实验内容

基于keras,使用卷积神经网络(CNN)进行手写数字识别,可视化分类结果,并对分类性能评估和可视化

实验步骤

1CNN原理

1.1全连接问题

考虑到使用全连接前馈网络来处理图像时,会出现如下问题:

  1. 模型参数过多,容易发生过拟合。 在全连接前馈网络中,隐藏层的每个神经元都要跟该层所有输入的神经元相连接。随着隐藏层神经元数量的增多,参数的规模也会急剧增加,导致整个神经网络的训练效率非常低,也很容易发生过拟合。

  2. 难以提取图像中的局部不变性特征。 自然图像中的物体都具有局部不变性特征,比如尺度缩放、平移、旋转等操作不影响其语义信息。而全连接前馈网络很难提取这些局部不变性特征。

1.2 CNN特性及应用

卷积神经网络(Convolutional Neural Network,CNN)是受生物学上感受野机制的启发而提出的。目前的卷积神经网络一般是由卷积层、汇聚层和全连接层交叉堆叠而成的前馈神经网络,有三个结构上的特性:局部连接、权重共享以及汇聚。这些特性使得卷积神经网络具有一定程度上的平移、缩放和旋转不变性。和前馈神经网络相比,卷积神经网络的参数更少。卷积神经网络主要应用在图像和视频分析的任务上,其准确率一般也远远超出了其他的神经网络模型。近年来卷积神经网络也广泛地应用到自然语言处理、推荐系统等领域。

1.3 二维卷积运算原理

在神经网络中,卷积运算的主要作用是抽取特征,卷积核是否进行翻转并不会影响其特征抽取的能力。特别是当卷积核是可学习的参数时,卷积和互相关在能力上是等价的。因此,为方便起见,会直接用互相关来代替卷积。

说明:

在本案例之后的描述中,除非特别声明,卷积一般指“互相关”。

对于一个输入矩阵 X ∈ R M × N \mathbf X\in\Bbb{R}^{M\times N} XRM×N和一个滤波器 W ∈ R U × V \mathbf W \in\Bbb{R}^{U\times V} WRU×V,它们的卷积为

y i , j = ∑ u = 0 U − 1 ∑ v = 0 V − 1 w u v x i + u , j + v 。( 3.1 ) y_{i,j}=\sum_{u=0}^{U-1} \sum_{v=0}^{V-1} w_{uv}x_{i+u,j+v}。(3.1) yi,j=u=0U1v=0V1wuvxi+u,j+v。(3.1


说明:

图3.1 给出了卷积计算的示例。


图3.1:卷积操作的计算过程

经过卷积运算后,最终输出矩阵大小则为

M ′ = M − U + 1 , ( 3.2 ) M' = M - U + 1,(3.2) M=MU+1,3.2
N ′ = N − V + 1. ( 3.3 ) N' = N - V + 1.(3.3) N=NV+1.3.3

可以发现,使用卷积处理图像,会有以下两个特性:

  1. 在卷积层(假设是第 l l l层)中的每一个神经元都只和前一层(第 l − 1 l-1 l1层)中某个局部窗口内的神经元相连,构成一个局部连接网络,这也就是卷积神经网络的局部连接特性。
  2. 由于卷积的主要功能是在一个图像(或特征图)上滑动一个卷积核,所以作为参数的卷积核 W ∈ R U × V \mathbf W \in\Bbb{R}^{U\times V} WRU×V对于第 l l l层的所有的神经元都是相同的,这也就是卷积神经网络的权重共享特性。

2 CNN时装分类

#导入第三方库
from keras.layers import Input, Dense
from keras.models import Model
from keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt

2.1 数据集读取
import tensorflow as tf
from tensorflow import keras
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

mnist = keras.datasets.fashion_mnist
(train_x, train_y), (test_x, test_y) = mnist.load_data()
print(train_x.shape)  # (60000, 28, 28)
print(train_y.shape)  # (60000,)
print(test_x.shape)  # (10000, 28, 28)
print(test_y.shape)  # (10000,)
(60000, 28, 28)
(60000,)
(10000, 28, 28)
(10000,)
2.2数据预处理
X_train, X_test = tf.cast(train_x / 255.0, tf.float32), tf.cast(test_x / 255.0, tf.float32)
Y_train, Y_test = tf.cast(train_y, tf.int16), tf.cast(test_y, tf.int16)

class_names = ["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat",
               "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]
class_names[Y_train[0]]
X_train.shape


TensorShape([60000, 28, 28])

样本可视化

import matplotlib.pyplot as plt
import numpy as np
import os

# Where to save the figures
PROJECT_ROOT_DIR = "."
CHAPTER_ID = "ann"
IMAGES_PATH = os.path.join(PROJECT_ROOT_DIR, "images", CHAPTER_ID)
os.makedirs(IMAGES_PATH, exist_ok=True)
def save_fig(fig_id, tight_layout=True, fig_extension="png", resolution=300):
    path = os.path.join(IMAGES_PATH, fig_id + "." + fig_extension)
    print("Saving figure", fig_id)
    if tight_layout:
        plt.tight_layout()
    plt.savefig(path, format=fig_extension, dpi=resolution)
    
    
n_rows = 4
n_cols = 10
plt.figure(figsize=(n_cols * 1.2, n_rows * 1.2))
for row in range(n_rows):
    for col in range(n_cols):
        index = n_cols * row + col
        plt.subplot(n_rows, n_cols, index + 1)
        plt.imshow(X_train[index], cmap="binary", interpolation="nearest")
        plt.axis('off')
        plt.title(class_names[Y_train[index]], fontsize=12)
plt.subplots_adjust(wspace=0.2, hspace=0.5)
save_fig('fashion_mnist_plot', tight_layout=False)
plt.show()
Saving figure fashion_mnist_plot

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PKhNrIJB-1681869288222)(%E5%AE%9E%E9%AA%8C3%20%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C_files/%E5%AE%9E%E9%AA%8C3%20%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C_20_1.png)]

2.3模型构建
# 首先创建一个 Sequential 对象 model, 添加卷积层 1 ,
model = tf.keras.Sequential([

    # unit 1
    # 添加卷积层 1 , 卷积核数量为 16, 卷积核的大小为 3 x 3,
    tf.keras.layers.Conv2D(16, kernel_size=(3, 3), padding="same", activation=tf.nn.relu, input_shape=(28, 28, 1)),
    # 添加池化层 1, 采用最大池化, 池化模板尺寸为 (2, 2)
    tf.keras.layers.MaxPool2D(pool_size=(2, 2)),

    # unit 2
    # 添加卷积层 2 , 卷积核数量为 32, 卷积核的大小为 3 x 3, 由于直接接收上一层的输出, 所以这里无需对输入形状进行设置
    tf.keras.layers.Conv2D(32, kernel_size=(3, 3), padding="same", activation=tf.nn.relu),
    # 添加池化层 2, 采用最大池化, 池化模板尺寸为 (2, 2)
    tf.keras.layers.MaxPool2D(pool_size=(2, 2)),
    # 至此, 特征层构建完成.

    # unit 3
    # 添加 Flatten 层, 将池化层的输出的三维张量转化为一维张量
    tf.keras.layers.Flatten(),

    # unit 4
    # 最后, 再添加一个隐含层核一个输出层, 隐含层中的结点个数为 128 ,
    tf.keras.layers.Dense(128, activation="relu"),
    # 输出层中的结点个数为 10
    tf.keras.layers.Dense(10, activation="softmax")

])

model.summary()
Model: "sequential_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d_2 (Conv2D)           (None, 28, 28, 16)        160       
                                                                 
 max_pooling2d_2 (MaxPooling  (None, 14, 14, 16)       0         
 2D)                                                             
                                                                 
 conv2d_3 (Conv2D)           (None, 14, 14, 32)        4640      
                                                                 
 max_pooling2d_3 (MaxPooling  (None, 7, 7, 32)         0         
 2D)                                                             
                                                                 
 flatten_1 (Flatten)         (None, 1568)              0         
                                                                 
 dense_2 (Dense)             (None, 128)               200832    
                                                                 
 dense_3 (Dense)             (None, 10)                1290      
                                                                 
=================================================================
Total params: 206,922
Trainable params: 206,922
Non-trainable params: 0
_________________________________________________________________
2.4模型训练
# 配置模型训练方法
model.compile(optimizer='adam',  # 优化器
              loss='sparse_categorical_crossentropy',  # 损失函数
              metrics=['sparse_categorical_accuracy'])  # 模型训练时, 我们希望输出的评测指标

# 训练模型
history = model.fit(X_train, Y_train, batch_size=64, epochs=5, validation_split=0.2)
Epoch 1/5
750/750 [==============================] - 14s 17ms/step - loss: 0.5026 - sparse_categorical_accuracy: 0.8181 - val_loss: 0.3761 - val_sparse_categorical_accuracy: 0.8651
Epoch 2/5
750/750 [==============================] - 14s 18ms/step - loss: 0.3313 - sparse_categorical_accuracy: 0.8802 - val_loss: 0.3135 - val_sparse_categorical_accuracy: 0.8873
Epoch 3/5
750/750 [==============================] - 14s 19ms/step - loss: 0.2842 - sparse_categorical_accuracy: 0.8975 - val_loss: 0.2940 - val_sparse_categorical_accuracy: 0.8939
Epoch 4/5
750/750 [==============================] - 14s 19ms/step - loss: 0.2543 - sparse_categorical_accuracy: 0.9070 - val_loss: 0.2777 - val_sparse_categorical_accuracy: 0.8992
Epoch 5/5
750/750 [==============================] - 14s 19ms/step - loss: 0.2292 - sparse_categorical_accuracy: 0.9166 - val_loss: 0.2535 - val_sparse_categorical_accuracy: 0.9087
2.5 模型性能评估
# 使用测试集中的数据来评估模型性能
# verbose=2 表示输出进度条进度
model.evaluate(X_test, Y_test, batch_size=64, verbose=2)

157/157 - 1s - loss: 0.2695 - sparse_categorical_accuracy: 0.9042 - 681ms/epoch - 4ms/step





[0.269504576921463, 0.90420001745224]
2.6.模型可视化
import pandas as pd

pd.DataFrame(history.history).plot(figsize=(8, 5))
plt.grid(True)
plt.gca().set_ylim(0, 1)
#save_fig("keras_cNN_learning_curves_plot")
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5rgPAwk5-1681869288224)(%E5%AE%9E%E9%AA%8C3%20%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C_files/%E5%AE%9E%E9%AA%8C3%20%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C_28_0.png)]

# 下面再随机取出测试集中的任意 10 个数据进行识别
plt.figure()
for i in range(10):
    num = np.random.randint(1, 10000)

    plt.subplot(2, 5, i + 1)
    plt.axis("off")
    plt.imshow(test_x[num], cmap="gray")
    demo = model.predict(tf.reshape(X_test[num], (1, 28, 28, 1)))
    y_pred = np.argmax(demo)
    plt.title("y= " + str(test_y[num]) + "\n" + "y_pred=" + str(y_pred))
    plt.suptitle("随机取出测试集中的任意10个数据进行识别", fontsize=20, color="red", backgroundcolor="yellow")

plt.show()
1/1 [==============================] - 0s 67ms/step
1/1 [==============================] - 0s 22ms/step
1/1 [==============================] - 0s 20ms/step
1/1 [==============================] - 0s 20ms/step
1/1 [==============================] - 0s 23ms/step
1/1 [==============================] - 0s 31ms/step
1/1 [==============================] - 0s 20ms/step
1/1 [==============================] - 0s 22ms/step
1/1 [==============================] - 0s 17ms/step
1/1 [==============================] - 0s 23ms/step

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cSYlmNDx-1681869288224)(%E5%AE%9E%E9%AA%8C3%20%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C_files/%E5%AE%9E%E9%AA%8C3%20%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C_29_1.png)]

2.7模型优化
from keras.layers import Input, Dense
from keras.models import Sequential
model = Sequential()
units = 28*28
# 定义输入层,全连接网络,输入维度是784,有633个神经元,激活函数是Sigmoid
model.add(Dense(input_dim=units,units=units,activation='relu'))
for i in range(3):
    # 定义隐藏层
    model.add(Dense(units=units,activation='relu'))
# 定义输出层,有10个神经元,也就是10个输出,激活函数是Softmax
model.add(Dense(units=10,activation='softmax'))
model.summary()
Model: "sequential_3"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_9 (Dense)             (None, 784)               615440    
                                                                 
 dense_10 (Dense)            (None, 784)               615440    
                                                                 
 dense_11 (Dense)            (None, 784)               615440    
                                                                 
 dense_12 (Dense)            (None, 784)               615440    
                                                                 
 dense_13 (Dense)            (None, 10)                7850      
                                                                 
=================================================================
Total params: 2,469,610
Trainable params: 2,469,610
Non-trainable params: 0
_________________________________________________________________

3.ResNet34残差网络

3.1 残差网络原理

残差网络(Residual Network,ResNet)是在神经网络模型中给非线性层增加直连边的方式来缓解梯度消失问题,从而使训练深度神经网络变得更加容易。

在残差网络中,最基本的单位为残差单元

假设 f ( x ; θ ) f(\mathbf x;\theta) f(x;θ)为一个或多个神经层,残差单元在 f ( ) f() f()的输入和输出之间加上一个直连边

不同于传统网络结构中让网络 f ( x ; θ ) f(x;\theta) f(x;θ)去逼近一个目标函数 h ( x ) h(x) h(x),在残差网络中,将目标函数 h ( x ) h(x) h(x)拆为了两个部分:恒等函数 x x x和残差函数 h ( x ) − x h(x)-x h(x)x

R e s B l o c k f ( x ) = f ( x ; θ ) + x , ( 5.22 ) \mathrm{ResBlock}_f(\mathbf x) = f(\mathbf x;\theta) + \mathbf x,(5.22) ResBlockf(x)=f(x;θ)+x,5.22

其中 θ \theta θ为可学习的参数。

一个典型的残差单元如图3.2所示,由多个级联的卷积层和一个跨层的直连边组成。


图3.2:残差单元结构

一个残差网络通常有很多个残差单元堆叠而成。构建一个在计算机视觉中非常典型的残差网络:ResNet34,并重复上一节中的手写体数字识别任务。

模型构建

在本节中,我们先构建ResNet34的残差单元,然后在组建完整的网络。

残差单元

这里,我们实现一个算子ResBlock来构建残差单元,其中定义了use_residual参数,用于在后续实验中控制是否使用残差连接。


残差单元包裹的非线性层的输入和输出形状大小应该一致。如果一个卷积层的输入特征图和输出特征图的通道数不一致,则其输出与输入特征图无法直接相加。为了解决上述问题,我们可以使用 1 × 1 1 \times 1 1×1大小的卷积将输入特征图的通道数映射为与级联卷积输出特征图的一致通道数。

1 × 1 1 \times 1 1×1卷积:与标准卷积完全一样,唯一的特殊点在于卷积核的尺寸是 1 × 1 1 \times 1 1×1,也就是不去考虑输入数据局部信息之间的关系,而把关注点放在不同通道间。通过使用 1 × 1 1 \times 1 1×1卷积,可以起到如下作用:

  • 实现信息的跨通道交互与整合。考虑到卷积运算的输入输出都是3个维度(宽、高、多通道),所以 1 × 1 1 \times 1 1×1卷积实际上就是对每个像素点,在不同的通道上进行线性组合,从而整合不同通道的信息;
  • 对卷积核通道数进行降维和升维,减少参数量。经过 1 × 1 1 \times 1 1×1卷积后的输出保留了输入数据的原有平面结构,通过调控通道数,从而完成升维或降维的作用;
  • 利用 1 × 1 1 \times 1 1×1卷积后的非线性激活函数,在保持特征图尺寸不变的前提下,大幅增加非线性。
    残差网络就是将很多个残差单元串联起来构成的一个非常深的网络。ResNet18 的网络结构如图3.3所示。

图3.3:残差网络

其中为了便于理解,可以将ResNet18网络划分为6个模块:

  • 第一模块:包含了一个步长为2,大小为 7 × 7 7 \times 7 7×7的卷积层,卷积层的输出通道数为64,卷积层的输出经过批量归一化、ReLU激活函数的处理后,接了一个步长为2的 3 × 3 3 \times 3 3×3的最大汇聚层;
  • 第二模块:包含了两个残差单元,经过运算后,输出通道数为64,特征图的尺寸保持不变;
  • 第三模块:包含了两个残差单元,经过运算后,输出通道数为128,特征图的尺寸缩小一半;
  • 第四模块:包含了两个残差单元,经过运算后,输出通道数为256,特征图的尺寸缩小一半;
  • 第五模块:包含了两个残差单元,经过运算后,输出通道数为512,特征图的尺寸缩小一半;
  • 第六模块:包含了一个全局平均汇聚层,将特征图变为 1 × 1 1 \times 1 1×1的大小,最终经过全连接层计算出最后的输出。
3.2模型构建
# 导入相关的工具包
from keras import layers, activations


# 定义ResNet的残差块
class Residual(tf.keras.Model):
    # 指明残差块的通道数,是否使用1*1卷积,步长
    def __init__(self, num_channels, use_1x1conv=False, strides=1):
        super(Residual, self).__init__()
        # 卷积层:指明卷积核个数,padding,卷积核大小,步长
        self.conv1 = layers.Conv2D(num_channels,
                                   padding='same',
                                   kernel_size=3,
                                   strides=strides)
        # 卷积层:指明卷积核个数,padding,卷积核大小,步长
        self.conv2 = layers.Conv2D(num_channels, kernel_size=3, padding='same')
        if use_1x1conv:
            self.conv3 = layers.Conv2D(num_channels,
                                       kernel_size=1,
                                       strides=strides)
        else:
            self.conv3 = None
        # 指明BN层
        self.bn1 = layers.BatchNormalization()
        self.bn2 = layers.BatchNormalization()

    # 定义前向传播过程
    def call(self, X):
        # 卷积,BN,激活
        Y = activations.relu(self.bn1(self.conv1(X)))
        # 卷积,BN
        Y = self.bn2(self.conv2(Y))
        # 对输入数据进行1*1卷积保证通道数相同
        if self.conv3:
            X = self.conv3(X)
        # 返回与输入相加后激活的结果
        return activations.relu(Y + X)

# ResNet网络中模块的构成
class ResnetBlock(tf.keras.layers.Layer):
    # 网络层的定义:输出通道数(卷积核个数),模块中包含的残差块个数,是否为第一个模块
    def __init__(self,num_channels, num_residuals, first_block=False):
        super(ResnetBlock, self).__init__()
        # 模块中的网络层
        self.listLayers=[]
        # 遍历模块中所有的层
        for i in range(num_residuals):
            # 若为第一个残差块并且不是第一个模块,则使用1*1卷积,步长为2(目的是减小特征图,并增大通道数)
            if i == 0 and not first_block:
                self.listLayers.append(Residual(num_channels, use_1x1conv=True, strides=2))
            # 否则不使用1*1卷积,步长为1 
            else:
                self.listLayers.append(Residual(num_channels))      
    # 定义前向传播过程
    def call(self, X):
        # 所有层依次向前传播即可
        for layer in self.listLayers.layers:
            X = layer(X)
        return X


# 构建ResNet网络
class ResNet(tf.keras.Model):
    # 初始化:指定每个模块中的残差快的个数
    def __init__(self,num_blocks):
        super(ResNet, self).__init__()
        # 输入层:7*7卷积,步长为2
        self.conv=layers.Conv2D(64, kernel_size=7, strides=2, padding='same')
        # BN层
        self.bn=layers.BatchNormalization()
        # 激活层
        self.relu=layers.Activation('relu')
        # 最大池化层
        self.mp=layers.MaxPool2D(pool_size=3, strides=2, padding='same')
        # 第一个block,通道数为64
        self.resnet_block1=ResnetBlock(64,num_blocks[0], first_block=True)
        # 第二个block,通道数为128
        self.resnet_block2=ResnetBlock(128,num_blocks[1])
        # 第三个block,通道数为256
        self.resnet_block3=ResnetBlock(256,num_blocks[2])
        # 第四个block,通道数为512
        self.resnet_block4=ResnetBlock(512,num_blocks[3])
        # 全局平均池化
        self.gap=layers.GlobalAvgPool2D()
        # 全连接层:分类
        self.fc=layers.Dense(units=10,activation=tf.keras.activations.softmax)
    # 前向传播过程
    def call(self, x):
        # 卷积
        x=self.conv(x)
        # BN
        x=self.bn(x)
        # 激活
        x=self.relu(x)
        # 最大池化
        x=self.mp(x)
        # 残差模块
        x=self.resnet_block1(x)
        x=self.resnet_block2(x)
        x=self.resnet_block3(x)
        x=self.resnet_block4(x)
        # 全局平均池化
        x=self.gap(x)
        # 全链接层
        x=self.fc(x)
        return x
# 模型实例化:指定每个block中的残差块个数 
mynet=ResNet([2,2,2,2])

# 观察一下输入形状在ResNet的架构
X = tf.random.uniform(shape=(1,  224, 224 , 1))
y = mynet(X)
mynet.summary()
 
Model: "res_net"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d_4 (Conv2D)           multiple                  3200      
                                                                 
 batch_normalization (BatchN  multiple                 256       
 ormalization)                                                   
                                                                 
 activation (Activation)     multiple                  0         
                                                                 
 max_pooling2d_4 (MaxPooling  multiple                 0         
 2D)                                                             
                                                                 
 resnet_block (ResnetBlock)  multiple                  148736    
                                                                 
 resnet_block_1 (ResnetBlock  multiple                 526976    
 )                                                               
                                                                 
 resnet_block_2 (ResnetBlock  multiple                 2102528   
 )                                                               
                                                                 
 resnet_block_3 (ResnetBlock  multiple                 8399360   
 )                                                               
                                                                 
 global_average_pooling2d (G  multiple                 0         
 lobalAveragePooling2D)                                          
                                                                 
 dense_14 (Dense)            multiple                  5130      
                                                                 
=================================================================
Total params: 11,186,186
Trainable params: 11,178,378
Non-trainable params: 7,808
_________________________________________________________________
3.3模型训练

# 由于fashion数据集是三维的(60000, 28, 28),而cifar10 数据集是四维的,而此网络是用来识别四维的数据所所以需要将3维的输入扩展维4维的输入
X_train = np.expand_dims(X_train, axis=3)
X_test = np.expand_dims(X_test, axis=3)

# 指定优化器,损失函数和评价指标
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01, momentum=0.0)

mynet.compile(optimizer=optimizer,
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

              
# 模型训练:指定训练数据,batchsize,epoch,验证集
mynet.fit(X_train, Y_train,batch_size=128,epochs=3,verbose=1,validation_split=0.1)

Epoch 1/3
422/422 [==============================] - 1002s 2s/step - loss: 0.4671 - accuracy: 0.8296 - val_loss: 0.5155 - val_accuracy: 0.8108
Epoch 2/3
422/422 [==============================] - 994s 2s/step - loss: 0.3113 - accuracy: 0.8833 - val_loss: 0.3279 - val_accuracy: 0.8780
Epoch 3/3
422/422 [==============================] - 978s 2s/step - loss: 0.2546 - accuracy: 0.9042 - val_loss: 0.3532 - val_accuracy: 0.8710





<keras.callbacks.History at 0x2278370d6a0>
3.4模型评价
# 指定测试数据
mynet.evaluate(X_test,Y_test,verbose=1)

313/313 [==============================] - 9s 30ms/step - loss: 0.3657 - accuracy: 0.8658





[0.36566558480262756, 0.8658000230789185]

添加了残差连接后,模型收敛曲线更平滑。
从输出结果看,和不使用残差连接相比,添加了残差连接后,模型效果有了一定的提升。

4. 实验总结

  • 理论上,在网络中添加新的层得到的新模型可能会更好地拟合训练数据集,因此添加层似乎更容易降低训练误差。然而在事件中,添加过多的层后训练误差反而会升高。
  • 残差映射可以更容易地学习同一函数,例如将权重层中的参数近似为零。
  • 利用残差块可以训练出一个有效的深层神经网络:输入可以通过层间的残余连接更快地向前传播。
  • 这里每个模块里有4个卷积层(不计算 1×1卷积层),加上最开始的卷积层和最后的全连接层,共计18层。
  • 通过配置不同的通道数和模块里的残差块数可以得到不同的ResNet模型.
  • 非常非常深的神经网络是很难训练的,因为存在梯度消失和梯度爆炸问题。跳跃连接能够有效的解决这一问题,可以从某一层网络层获取激活,然后迅速反馈给另外一层,甚至是神经网络的更深层。
# 指定测试数据
mynet.evaluate(X_test,Y_test,verbose=1)

313/313 [==============================] - 9s 30ms/step - loss: 0.3657 - accuracy: 0.8658





[0.36566558480262756, 0.8658000230789185]

添加了残差连接后,模型收敛曲线更平滑。
从输出结果看,和不使用残差连接相比,添加了残差连接后,模型效果有了一定的提升。

4. 实验总结

  • 理论上,在网络中添加新的层得到的新模型可能会更好地拟合训练数据集,因此添加层似乎更容易降低训练误差。然而在事件中,添加过多的层后训练误差反而会升高。
  • 残差映射可以更容易地学习同一函数,例如将权重层中的参数近似为零。
  • 利用残差块可以训练出一个有效的深层神经网络:输入可以通过层间的残余连接更快地向前传播。
  • 这里每个模块里有4个卷积层(不计算 1×1卷积层),加上最开始的卷积层和最后的全连接层,共计18层。
  • 通过配置不同的通道数和模块里的残差块数可以得到不同的ResNet模型.
  • 非常非常深的神经网络是很难训练的,因为存在梯度消失和梯度爆炸问题。跳跃连接能够有效的解决这一问题,可以从某一层网络层获取激活,然后迅速反馈给另外一层,甚至是神经网络的更深层。
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值