发布时间:2025-07-31
点击次数: 残差网络(ResNet)由何恺明等人提出,解决了深层神经网络训练误差不降反升的问题。其核心是残差块,通过拟合残差映射简化优化,输入可跨层传播。ResNet沿用VGG的3×3卷积设计,含4个残差块模块,结构简单。如ResNet-18有18层,还有更深的型号。在Fashion-MNIST上训练验证了其有效性,深刻影响了深度神经网络设计。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

让我们先思考一个问题:对神经网络模型添加新的层,充分训练后的模型是否只可能更有效地降低训练误差?理论上,原模型解的空间只是新模型解的空间的子空间。也就是说,如果我们能将新添加的层训练成恒等映射f(x)=x,新模型和原模型将同样有效。由于新模型可能得出更优的解来拟合训练数据集,因此添加层似乎更容易降低训练误差。然而在实践中,添加过多的层后训练误差往往不降反升。即使利用批量归一化带来的数值稳定性使训练深层模型更加容易,该问题仍然存在。针对这一问题,何恺明等人提出了残差网络(ResNet) [1]。它在2015年的ImageNet图像识别挑战赛夺魁,并深刻影响了后来的深度神经网络的设计。
让我们聚焦于神经网络局部。如图5.9所示,设输入为x。假设我们希望学出的理想映射为f(x),从而作为图5.9上方激活函数的输入。左图虚线框中的部分需要直接拟合出该映射f(x),而右图虚线框中的部分则需要拟合出有关恒等映射的残差映射f(x)−x。残差映射在实际中往往更容易优化。以本节开头提到的恒等映射作为我们希望学出的理想映射f(x)。我们只需将图5.9中右图虚线框内上方的加权运算(如仿射)的权重和偏差参数学成0,那么f(x)即为恒等映射。实际中,当理想映射f(x)极接近于恒等映射时,残差映射也易于捕捉恒等映射的细微波动。图5.9右图也是ResNet的基础块,即残差块(residual block)。在残差块中,输入可通过跨层的数据线路更快地向前传播。
ResNet沿用了VGG全3×3卷积层的设计。残差块里首先有2个有相同输出通道数的3×3卷积层。每个卷积层后接一个批量归一化层和ReLU激活函数。然后我们将输入跳过这2个卷积运算后直接加在最后的ReLU激活函数前。这样的设计要求2个卷积层的输出与输入形状一样,从而可以相加。如果想改变通道数,就需要引入一个额外的1×1卷积层来将输入变换成需要的形状后再做相加运算。
残差块的实现如下。它可以设定输出通道数、是否使用额外的1×1卷积层来修改通道数以及卷积层的步幅。
In [ ]import paddleimport paddle.nn as nnimport numpy as npimport warnings
warnings.filterwarnings("ignore", category=Warning) # 过滤报警信息class Residual(nn.Layer):
def __init__(self, num_channels, num_filters, use_1x1conv=False, stride=1):
super(Residual, self).__init__()
self.use_1x1conv = use_1x1conv
model = [
nn.Conv2D(num_channels, num_filters, 3, stride=stride, padding=1),
nn.BatchNorm2D(num_filters),
nn.ReLU(),
nn.Conv2D(num_filters, num_filters, 3, stride=1, padding=1),
nn
.BatchNorm2D(num_filters),
]
self.model = nn.Sequential(*model) if use_1x1conv:
model_1x1 = [nn.Conv2D(num_channels, num_filters, 1, stride=stride)]
self.model_1x1 = nn.Sequential(*model_1x1) def forward(self, X):
Y = self.model(X) if self.use_1x1conv:
X = self.model_1x1(X) return paddle.nn.functional.relu(X + Y)
下面我们来查看输入和输出形状一致的情况。
In [ ]blk = Residual(3, 3)
X = paddle.to_tensor(np.random.uniform(-1., 1., [4, 3, 6, 6]).astype('float32'))
Y = blk(X)print(Y.shape)
[4, 3, 6, 6]
我们也可以在增加输出通道数的同时减半输出的高和宽。
Openflow
一键极速绘图,赋能行业工作流
88
查看详情
In [ ]
blk = Residual(3, 6, use_1x1conv=True, stride=2)
X = paddle.to_tensor(np.random.uniform(-1., 1., [4, 3, 6, 6]).astype('float32'))
Y = blk(X)print(Y.shape)
[4, 6, 3, 3]
GoogLeNet在后面接了4个由Inception块组成的模块。ResNet则使用4个由残差块组成的模块,每个模块使用若干个同样输出通道数的残差块。第一个模块的通道数同输入通道数一致。由于之前已经使用了步幅为2的最大池化层,所以无须减小高和宽。之后的每个模块在第一个残差块里将上一个模块的通道数翻倍,并将高和宽减半。
下面我们来实现这个模块。注意,这里对第一个模块做了特别处理。
In [ ]class ResnetBlock(nn.Layer):
def __init__(self, num_channels, num_filters, num_residuals, first_block=False):
super(ResnetBlock, self).__init__()
model = [] for i in range(num_residuals): if i == 0: if not first_block:
model += [Residual(num_channels, num_filters, use_1x1conv=True, stride=2)] else:
model += [Residual(num_channels, num_filters)] else:
model += [Residual(num_filters, num_filters)]
self.model = nn.Sequential(*model) def forward(self, X):
return self.model(X)
class ResNet(nn.Layer):
def __init__(self, num_classes=10):
super(ResNet, self).__init__() # ResNet的前两层跟之前介绍的GoogLeNet中的一样:
# 在输出通道数为64、步幅为2的7×77卷积层后接步幅为2的3×3的最大池化层。
# 不同之处在于ResNet每个卷积层后增加的批量归一化层。
model = [
nn.Conv2D(1, 64, 7, stride=2, padding=3),
nn.BatchNorm2D(64),
nn.ReLU(),
nn.MaxPool2D(kernel_size=3, stride=2, padding=1)
] # 接着我们为ResNet加入所有残差块。这里每个模块使用2个残差块。
model += [
ResnetBlock(64, 64, 2, first_block=True),
ResnetBlock(64, 128, 2),
ResnetBlock(128, 256, 2),
ResnetBlock(256, 512, 2)
] # 最后,与GoogLeNet一样,加入全局平均池化层后接上全连接层输出。
model += [
nn.AdaptiveAvgPool2D(output_size=1),
nn.Flatten(start_axis=1, stop_axis=-1),
nn.Linear(512, num_classes),
]
self.model = nn.Sequential(*model) def forward(self, X):
Y = self.model(X) return Y
rn = ResNet()
X = paddle.to_tensor(np.random.uniform(-1., 1., [4, 1, 96, 96]).astype('float32'))
Y = rn(X)print(Y.shape)
[4, 10]
这里每个模块里有4个卷积层(不计算1×1卷积层),加上最开始的卷积层和最后的全连接层,共计18层。这个模型通常也被称为ResNet-18。通过配置不同的通道数和模块里的残差块数可以得到不同的ResNet模型,例如更深的含152层的ResNet-152。虽然ResNet的主体架构跟GoogLeNet的类似,但ResNet结构更简单,修改也更方便。这些因素都导致了ResNet迅速被广泛使用。
在训练ResNet之前,我们来观察一下输入形状在ResNet不同模块之间的变化。
In [ ]resnet = ResNet(10) param_info = paddle.summary(resnet, (1, 1, 96, 96))print(param_info)
-------------------------------------------------------------------------------
Layer (type) Input Shape Output Shape Param #
===============================================================================
Conv2D-26 [[1, 1, 96, 96]] [1, 64, 48, 48] 3,200
BatchNorm2D-22 [[1, 64, 48, 48]] [1, 64, 48, 48] 256
ReLU-12 [[1, 64, 48, 48]] [1, 64, 48, 48] 0
MaxPool2D-2 [[1, 64, 48, 48]] [1, 64, 24, 24] 0
Conv2D-27 [[1, 64, 24, 24]] [1, 64, 24, 24] 36,928
BatchNorm2D-23 [[1, 64, 24, 24]] [1, 64, 24, 24] 256
ReLU-13 [[1, 64, 24, 24]] [1, 64, 24, 24] 0
Conv2D-28 [[1, 64, 24, 24]] [1, 64, 24, 24] 36,928
BatchNorm2D-24 [[1, 64, 24, 24]] [1, 64, 24, 24] 256
Residual-11 [[1, 64, 24, 24]] [1, 64, 24, 24] 0
Conv2D-29 [[1, 64, 24, 24]] [1, 64, 24, 24] 36,928
BatchNorm2D-25 [[1, 64, 24, 24]] [1, 64, 24, 24] 256
ReLU-14 [[1, 64, 24, 24]] [1, 64, 24, 24] 0
Conv2D-30 [[1, 64, 24, 24]] [1, 64, 24, 24] 36,928
BatchNorm2D-26 [[1, 64, 24, 24]] [1, 64, 24, 24] 256
Residual-12 [[1, 64, 24, 24]] [1, 64, 24, 24] 0
ResnetBlock-5 [[1, 64, 24, 24]] [1, 64, 24, 24] 0
Conv2D-31 [[1, 64, 24, 24]] [1, 128, 12, 12] 73,856
BatchNorm2D-27 [[1, 128, 12, 12]] [1, 128, 12, 12] 512
ReLU-15 [[1, 128, 12, 12]] [1, 128, 12, 12] 0
Conv2D-32 [[1, 128, 12, 12]] [1, 128, 12, 12] 147,584
BatchNorm2D-28 [[1, 128, 12, 12]] [1, 128, 12, 12] 512
Conv2D-33 [[1, 64, 24, 24]] [1, 128, 12, 12] 8,320
Residual-13 [[1, 64, 24, 24]] [1, 128, 12, 12] 0
Conv2D-34 [[1, 128, 12, 12]] [1, 128, 12, 12] 147,584
BatchNorm2D-29 [[1, 128, 12, 12]] [1, 128, 12, 12] 512
ReLU-16 [[1, 128, 12, 12]] [1, 128, 12, 12] 0
Conv2D-35 [[1, 128, 12, 12]] [1, 128, 12, 12] 147,584
BatchNorm2D-30 [[1, 128, 12, 12]] [1, 128, 12, 12] 512
Residual-14 [[1, 128, 12, 12]] [1, 128, 12, 12] 0
ResnetBlock-6 [[1, 64, 24, 24]] [1, 128, 12, 12] 0
Conv2D-36 [[1, 128, 12, 12]] [1, 256, 6, 6] 295,168
BatchNorm2D-31 [[1, 256, 6, 6]] [1, 256, 6, 6] 1,024
ReLU-17 [[1, 256, 6, 6]] [1, 256, 6, 6] 0
Conv2D-37 [[1, 256, 6, 6]] [1, 256, 6, 6] 590,080
BatchNorm2D-32 [[1, 256, 6, 6]] [1, 256, 6, 6] 1,024
Conv2D-38 [[1, 128, 12, 12]] [1, 256, 6, 6] 33,024
Residual-15 [[1, 128, 12, 12]] [1, 256, 6, 6] 0
Conv2D-39 [[1, 256, 6, 6]] [1, 256, 6, 6] 590,080
BatchNorm2D-33 [[1, 256, 6, 6]] [1, 256, 6, 6] 1,024
ReLU-18 [[1, 256, 6, 6]] [1, 256, 6, 6] 0
Conv2D-40 [[1, 256, 6, 6]] [1, 256, 6, 6] 590,080
BatchNorm2D-34 [[1, 256, 6, 6]] [1, 256, 6, 6] 1,024
Residual-16 [[1, 256, 6, 6]] [1, 256, 6, 6] 0
ResnetBlock-7 [[1, 128, 12, 12]] [1, 256, 6, 6] 0
Conv2D-41 [[1, 256, 6, 6]] [1, 512, 3, 3] 1,180,160
BatchNorm2D-35 [[1, 512, 3, 3]] [1, 512, 3, 3] 2,048
ReLU-19 [[1, 512, 3, 3]] [1, 512, 3, 3] 0
Conv2D-42 [[1, 512, 3, 3]] [1, 512, 3, 3] 2,359,808
BatchNorm2D-36 [[1, 512, 3, 3]] [1, 512, 3, 3] 2,048
Conv2D-43 [[1, 256, 6, 6]] [1, 512, 3, 3] 131,584
Residual-17 [[1, 256, 6, 6]] [1, 512, 3, 3] 0
Conv2D-44 [[1, 512, 3, 3]] [1, 512, 3, 3] 2,359,808
BatchNorm2D-37 [[1, 512, 3, 3]] [1, 512, 3, 3] 2,048
ReLU-20 [[1, 512, 3, 3]] [1, 512, 3, 3] 0
Conv2D-45 [[1, 512, 3, 3]] [1, 512, 3, 3] 2,359,808
BatchNorm2D-38 [[1, 512, 3, 3]] [1, 512, 3, 3] 2,048
Residual-18 [[1, 512, 3, 3]] [1, 512, 3, 3] 0
ResnetBlock-8 [[1, 256, 6, 6]] [1, 512, 3, 3] 0
AdaptiveAvgPool2D-2 [[1, 512, 3, 3]] [1, 512, 1, 1] 0
Flatten-3 [[1, 512, 1, 1]] [1, 512] 0
Linear-2 [[1, 512]] [1, 10] 5,130
===============================================================================
Total params: 11,186,186
Trainable params: 11,170,570
Non-trainable params: 15,616
-------------------------------------------------------------------------------
Input size (MB): 0.04
Forward/backward pass size (MB): 10.77
Params size (MB): 42.67
Estimated Total Size (MB): 53.47
-------------------------------------------------------------------------------
{'total_params': 11186186, 'trainable_params': 11170570}
下面我们在Fashion-MNIST数据集上训练ResNet。
In [ ]import paddleimport paddle.vision.transforms as Tfrom paddle.vision.datasets import FashionMNIST# 数据集处理transform = T.Compose([
T.Resize(96),
T.Transpose(),
T.Normalize([127.5], [127.5]),
])
train_dataset = FashionMNIST(mode='train', transform=transform)
val_dataset = FashionMNIST(mode='test', transform=transform)# 模型定义model = paddle.Model(ResNet(10))# 设置训练模型所需的optimizer, loss, metricmodel.prepare(
paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters()),
paddle.nn.CrossEntropyLoss(),
paddle.metric.Accuracy(topk=(1, 5)))# 启动训练、评估model.fit(train_dataset, val_dataset, epochs=2, batch_size=64, log_freq=100)
The loss value printed in the log is the current step, and the metric is the *erage value of previous step. Epoch 1/2 step 100/938 - loss: 0.3613 - acc_top1: 0.7612 - acc_top5: 0.9820 - 3s/step step 200/938 - loss: 0.4060 - acc_top1: 0.7972 - acc_top5: 0.9881 - 3s/step step 300/938 - loss: 0.3635 - acc_top1: 0.8171 - acc_top5: 0.9908 - 3s/step step 400/938 - loss: 0.3369 - acc_top1: 0.8292 - acc_top5: 0.9926 - 3s/step step 500/938 - loss: 0.2733 - acc_top1: 0.8390 - acc_top5: 0.9937 - 3s/step step 600/938 - loss: 0.1964 - acc_top1: 0.8469 - acc_top5: 0.9943 - 3s/step
以上就是《动手学深度学习》Paddle 版源码-5.11章(ResNet)的详细内容,更多请关注其它相关文章!
# latte
# type
# ai
# 佛山seo优化手段
# 酒馆推广营销
# 龙华快速提高关键词排名
# 网站推广专员的升迁状况
# 专业seo优化价格多少
# 无线宝推广营销策划书
# 肖家河推广营销
# 机械行业网站优化多少钱
# 可口可乐营销推广策略
# 快速入门seo广告推广
# 来袭
# 营收
# 框中
# 更容易
# 右图
# 等人
# 让我们
# 恒等
# 中文网
# 第一个
相关栏目:
【
行业新闻62819 】
【
科技资讯67470 】
相关推荐:
马斯克回应人工智能拯救世界:人类已处于“半机器人”状态
全媒封面丨⑤商汤科技:原创AI算法“发电厂”
看似低调,实则稳健:字节在AI路上会遇到什么?
讯飞星火大模型实现升级 助力通用人工智能人才培养
机器人 展才能
编程版GPT狂飙30星,AutoGPT危险了!
全新升级的广州麦当劳:面积最大餐厅正式引入智慧机器人
利好来了,AI再起一波?
ChatGPT只讲这25个笑话!实验上千次有90%重复,网友:幽默是人类最后的尊严
李开复官宣新公司「零一万物」,进军 AI 2.0
美图第二届影像节发布七款AI影像创作工具
提高开发效率:AmazonCodeWhisperer与Amazon Glue的集成和生成式AI的应用
国内AI大模型“安卓时刻”到来!阿里云通义千问免费、开源、可商用
MetaGPT AI 模型开源:可模拟软件公司开发过程,生成高质量代码
AMD在ChinaJoy展示全新的锐龙AI笔记本,开创了人工智能领域的新时代!
李开复:未来几年,人工智能会革了所有人的命,除非你这么做
马斯克:将来机器人比人类多!特斯拉机器人亮相人工智能大会
AYANEO AIR 1S 掌机 7 月 9 日发布:R7 7840U + OLED 屏
携程发布旅游行业垂直大模型 梁建章:AI策略是做可靠的内容 放心的推荐
国内阅读行业首款对话式AI应用“阅爱聊”封闭内测
一文读懂自动驾驶的激光雷达与视觉融合感知
如何用AI重塑你的工作流(一)
在心理治疗中用VR技术,治疗成效显著提高
前特斯拉总监、OpenAI大牛Karpathy:我被自动驾驶分了心,AI智能体才是未来!
AI+音乐如何“生成”动听旋律?一起揭秘世界人工智能大会开场曲
世界上第一个完全由人工智能驱动的图像编辑器!
WHEE安装教程
美图公司影像节或发布AI设计新品
科学家称,面对人工智能,人类未来或只有灭亡与虚拟永生两个选择
2025VR&AR显示技术峰会视频解析: 歌尔光学展示最新一代VR/AR光学模组
探索人工智能和物联网的动态融合
GPT-4最全攻略来袭!OpenAI官方发布,六个月攒下来的使用经验都在里面了
【机智云物联网低功耗转接板】远程环境数据采集探索
复旦发布「新闻推荐生态系统模拟器」SimuLine:单机支持万名读者、千名创作者、100+轮次推荐
深圳人工智能企业超1900家
华为HarmonyOS 4将集|成人|工智能大型模型
将上下文长度扩展到256k,无限上下文版本的LongLLaMA来了?
Dubbo负载均衡策略之 一致性哈希
边喷火边跳踢踏舞,机器狗最新技能爆火全网!网友直呼真·热狗
iPhone两秒出图,目前已知的最快移动端Stable Diffusion模型来了
午报 | 字节跳动要造机器人;东方甄选首次启动自有APP|直播|
腾讯汤道生:大模型只是起点,产业落地是AI更大的应用场景
智能公司为何纷纷投身机器人领域?
Vision Pro 太贵,苹果基于 iPhone 的 VR 头显专利曝光
DragGAN开源三天Star量23k,这又来一个DragDiffusion
生成式人工智能如何改变云安全的游戏规则
利用AI技术更好地发展农村电商
美图设计室2.0什么时候上线
用AI升级会议体验!思必驰多款会议产品亮相全球智博会!
百度举办AIGC创作沙龙,现场传授AI绘画“咒语”技巧