0%

机器学习-ResNet

ResNet(Residual Network)是一个深度卷积神经网络架构,由Kaiming He等人在2015年提出。它通过使用残差块(Residual Block)来解决深层网络的退化问题,允许在训练更深的神经网络时仍然能够获得更好的性能。

ResNet引入了”跳跃连接”或”残差连接”的概念,即通过将前一层的输出直接添加到后续层的输出中,以便网络能够学习残差(剩余部分)。这种结构有助于避免梯度消失和梯度爆炸问题,使网络更容易优化。ResNet的核心思想是:通过层与层之间的直接捷径,网络可以学习原始输入和残差之间的映射,从而更轻松地适应更深的层次。

深度网络的退化问题至少说明深度网络不容易训练。但是我们考虑这样一个事实:现在你有一个浅层网络,你想通过向上堆积新层来建立深层网络,一个极端情况是这些增加的层什么也不学习,仅仅复制浅层网络的特征,即这样新层是恒等映射(Identity mapping)。在这种情况下,深层网络应该至少和浅层网络性能一样,也不应该出现退化现象。好吧,你不得不承认肯定是目前的训练方法有问题,才使得深层网络很难去找到一个好的参数。

这个有趣的假设让何博士灵感爆发,他提出了残差学习来解决退化问题。对于一个堆积层结构(几层堆积而成)当输入为时其学习到的特征记为,现在我们希望其可以学习到残差,这样其实原始的学习特征是。之所以这样是因为残差学习相比原始特征直接学习更容易。当残差为0时,此时堆积层仅仅做了恒等映射,至少网络性能不会下降,实际上残差不会为0,这也会使得堆积层在输入特征基础上学习到新的特征,从而拥有更好的性能。残差学习的结构如图4所示。这有点类似与电路中的“短路”,所以是一种短路连接(shortcutconnection)。

以下是一个使用Python和TensorFlow库实现ResNet的简化版本的示例代码:

首先,确保已安装 tensorflow 库,可以通过以下命令安装:

1
pip install tensorflow

接下来,使用下面的代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import tensorflow as tf
from tensorflow.keras.layers import Input, Conv2D, BatchNormalization, ReLU, Add, GlobalAveragePooling2D, Dense
from tensorflow.keras.models import Model

def residual_block(x, filters, kernel_size=3, stride=1):
shortcut = x
# 第一个卷积层
x = Conv2D(filters, kernel_size, strides=stride, padding='same')(x)
x = BatchNormalization()(x)
x = ReLU()(x)
# 第二个卷积层
x = Conv2D(filters, kernel_size, strides=1, padding='same')(x)
x = BatchNormalization()(x)
# 添加残差连接
if stride != 1 or shortcut.shape[-1] != filters:
shortcut = Conv2D(filters, kernel_size=1, strides=stride, padding='valid')(shortcut)
shortcut = BatchNormalization()(shortcut)
x = Add()([x, shortcut])
x = ReLU()(x)
return x

def build_resnet(input_shape, num_classes, num_blocks_list):
input_layer = Input(shape=input_shape)
x = Conv2D(64, 7, strides=2, padding='same')(input_layer)
x = BatchNormalization()(x)
x = ReLU()(x)
x = tf.keras.layers.MaxPooling2D(pool_size=3, strides=2, padding='same')(x)

for num_blocks in num_blocks_list:
for _ in range(num_blocks):
x = residual_block(x, 64)

x = GlobalAveragePooling2D()(x)
x = Dense(num_classes, activation='softmax')(x)

model = Model(inputs=input_layer, outputs=x)
return model

# 构建ResNet模型
input_shape = (224, 224, 3) # 输入图像大小
num_classes = 1000 # 分类类别数
num_blocks_list = [2, 2, 2, 2] # 每个stage的残差块数量
resnet_model = build_resnet(input_shape, num_classes, num_blocks_list)

# 打印模型结构
resnet_model.summary()

在上述代码中,我们定义了一个residual_block函数来实现残差块的构建,然后使用build_resnet函数来构建简化版本的ResNet模型。通过设置不同的num_blocks_list,可以调整每个stage中的残差块数量。最终,我们打印出ResNet模型的结构概要。