ResNet网络结构和主要代码解析

更新时间:2023-05-20 09:46:03 阅读: 评论:0

ResNet⽹络结构和主要代码解析
学习了ResNet卷积神经⽹络,总结⼀下对ResNet⽹络结构和主要代码的理解。
ResNet(Residual Neural Network)通过使⽤残差学习单元(Residual Unit),训练了152层深的神经⽹络,在ILSVRC 2015⽐赛中取得3.57%的top-5错误率。ResNet与其他卷积神经⽹络的不同之处在于采⽤残差结抅,原始输⼊信息可以直接传输到后⾯的输出层中,即前⾯⼀层的信息,有⼀定⽐例可以不经过矩阵乘法和⾮线性变换,直接传输到下⼀层,这种⽅法解决了极深⽹络难以训练的问题。
1  ResNet残差学习模块
ResNet的残差学习模块如下图所⽰,具体的⽅法为:假定某段神经⽹络的输⼊是x,期望输出是H(x),如果直接把输⼊x传到输出作为初始结果,此时需要学习的⽬标就是F(x)=H(x)-x,这就是⼀个ResNet的残差学习单元。ResNet相当于将学习⽬标改变了,不再是学习⼀个完整的输出H(x),只是输出和输⼊的差别H(x)-x。传统的卷积层或全连接层在信息传递时,或多或少会存在信息丢失、损耗等问题。ResNet在某种程度上解决了这个问题,通过直接将输⼊信息绕道传到输出,保护信息的完整性,整个⽹络则只需要学习输⼊、输出差别的那⼀部分,简化学习⽬标和难度。
ResNet代码中最核⼼的残差学习模块函数bottleneck如下。
模特英文1)bottleneck函数的输⼊参数中,inputs是输⼊,depth是输出通道数,depth_bottleneck是残差的第1、2层输出通道数,stride是步长。
2)⾸先⽤ slim.utils.last_dimension获取输⼊的最后⼀个维度,即输⼊通道数。接着⽤slim.batch_norm对输⼊进⾏归⼀化(Batch Normalization),并使⽤ReLU函数预激活。然后定义shortcut,即作为⽀线的输⼊x,如果输⼊通道数depth_in和输出通道数depth⼀致,使⽤subsample按步长为stride对inputs进⾏空间上的降采样。如果不⼀致,⽤步长为stride的1x1卷积改变其通道数,使得输出通道数为depth。然后定义residual,即残差,共有3层,先是1个【1x1】卷积,再是1个【3x3】卷积,这两个卷积的输出通道数都是
depth_bottleneck,最后是1个【1x1】、输出通道数为depth的卷积,得到最终的residual。
3)最后将shortcut(输⼊x)和residual(F(x))相加,得到output(输出H(x)),使⽤llect_named_outputs将结果添加进collection并返回output作为函数结果。
def bottleneck(inputs, depth, depth_bottleneck, stride, outputs_collections = None, scope = None):
with tf.variable_scope(scope, 'bottleneck_v2', [inputs]) as sc:海外考试网
关于爱情的英语句子
depth_in = slim.utils.last__shape(), min_rank = 4)
preact = slim.batch_norm(inputs, activation_fn = lu, scope = 'preact')
if depth == depth_in:
shortcut = subsample(inputs, stride, 'shortcut')
el:
shortcut = v2d(preact, depth, [1, 1], stride = stride, normalizer_fn = None, activation_fn = None, scope = 'shortcut')
residual = v2d(preact, depth_bottleneck, [1, 1], stride = 1, scope = 'conv1')
residual = conv2d_same(residual, depth_bottleneck, 3, stride, scope = 'conv2')
residual = v2d(residual, depth, [1, 1], stride = 1, normalizer_fn = None, activation_fn = None, scope = 'conv3')
output = shortcut + residual
return llect_named_outputs(outputs_collections, sc.name, output)
2  152层的ResNet⽹络配置
152层的ResNet有4个残差学习的Block,每个Block的units数量分别为3、8、36和3,总层数为(3+8+36+3)x3+2=152。由Block组成的blocks模块组的代码如下。
对于每个Block,⽐如第⼀个Block的‘’block1’,是这个Block的名称(或scope),bottleneck就是上⾯的残差学习单元,参数[(256, 64, 1)] x 2 + [(256, 64, 2)]是这个Block的列表,其中每个元素都对应⼀个bottleneck残差学习单元,前⾯两个元素都是(256, 64, 1)],最后⼀个是(256, 64, 2)。每个元素都是⼀个三元数组,即(depth,depth_bottleneck,stride)。⽐如对于元素(256,64,2)构建的bottleneck残差学习单元,每个残差学习单元包含三个卷积层,第⼀、⼆个卷积层的输出通道数(depth_bottleneck)为64,第⼀个卷积层的步长为1,第⼆个卷积层的步长stride为2,第三层输出通道数(depth)为256,步长为1。在这个Block中,⼀共有3个bottleneck残差学习单元。其余三个Block中的残差学习单元分别是8个、36个、3个。
def resnet_v2_152(inputs, num_class = None, global_pool = True, reu = None, scope = 'resnet_v2_152'):
blocks = [翻译 百度
Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),nit
blood is thicker than water
Block('block2', bottleneck, [(512, 128, 1)] * 7 + [(512, 128, 2)]),
Block('block3', bottleneck, [(1024, 256, 1)] * 35 + [(1024, 256, 2)]),
Block('block4', bottleneck, [(2048, 512, 1)] * 3)]
return resnet_v2(inputs, blocks, num_class, global_pool, include_root_block = True, reu = reu, scope = scope)
3  堆叠残差学习模块
定义堆叠Block的函数stack_blocks_den。输⼊参数中,net是输⼊,blocks是上⾯由4个残差学习Block组成的列表。使⽤两层循环,逐个Block,逐个残差单元地堆叠。第⼀层循环中,使⽤tf.variable_scope将残差学习单元命名为block1/unit_1的形式。第⼆层循环中,对每个block.args,展开为(depth,depth_bottleneck,stride),然后⽤unit_fn函数顺序地创建并连接所有的残差学习单元。当所有Block中的残差单元堆叠完之后,返回net作为输出。
def stack_blocks_den(net, blocks, outputs_collections = None):
for block in blocks:
with tf.variable_scope(block.scope, 'block', [net]) as sc:免费背单词软件
google 翻译网页for i, unit in enumerate(block.args):
with tf.variable_scope('unit_%d' %(i + 1), values = [net]):
unit_depth, unit_depth_bottleneck, unit_stride = unit
net = block.unit_fn(net, depth = unit_depth,
unit_depth_bottleneck = unit_depth_bottleneck,
stride = unit_stride)
net = llect_named_outputs(outputs_collections, sc.name, net)
return net
4  ResNet主函数
根据上⾯定义好的⽹络的残差学习模块组,⽣成完整的ResNet⽹络结构。输⼊参数中,inputs是输⼊,blocks是定义好的Block类的列表,num_class是最后输出的类数,global_pool是最后⼀层是否加上全局平均池化。如果include_root_block为True,⾸先创建输出通道数为64、步长为2的【7x7】卷积,后⾯接⼀个步长为2的【3x3】最⼤池化,此时图⽚尺⼨缩减为输⼊图⽚的1/4。然后根据上⾯定义的stack_blocks_den堆叠残差学习单元,再⽤tf.reduce_mean实现全局平均池化,根据分类数,添加⼀个输出通道数为
num_class的【1x1】卷积。最后⽤Softmax得到最终分类结果。
def resnet_v2(inputs, blocks, num_class = None, global_pool = True, include_root_block = True, reu = None, scope = None):
with tf.variable_scope(scope, 'resnet_v2', [inputs], reu = reu) as sc:
end_points_collection = sc.original_name_scope + '_end_points'
with slim.arg_scope([v2d, bottleneck, stack_blocks_den], outputs_collections = end_points_collection):
net = inputs
if include_root_block:广州mba培训
with slim.arg_scope([v2d], activation_fn = None, normalizer_fn = None):
net = conv2d_same(net, 64, 7, stride = 2, scope = 'conv1')
net = slim.max_pool2d(net, [3, 3], stride = 2, scope = 'pool1')
net = stack_blocks_den(net, blocks)
net = slim.batch_norm(net, activation_fn = lu, scope = 'postnorm')
if global_pool:
net = tf.reduce_mean(net, [1, 2], name = 'pool5', keep_dims = True)
if num_class is not None:
net = v2d(net, num_class, [1, 1], activation_fn = None, normalizer_fn = None, scope = 'logits')
end_points = vert_collection_to_dict(end_points_collection)make sb
if num_class is not None:
end_points['predictions'] = slim.softmax(net, scope = 'predictions')
return net, end_points
参考⽂献:
1. 《TensorFlow实战》

本文发布于:2023-05-20 09:46:03,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/115653.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:学习   残差   输出   单元   卷积   信息   通道
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图