因为最近要看一篇ResNet版本的SNN网络,所以去了解了一下ResNet。这是一种深度残差网络,
def _block(self, x, n_out, n, init_stride=2, is_training=True, scope="block"):
with tf.variable_scope(scope):
h_out = n_out // 4
out = self._bottleneck(x, h_out, n_out, stride=init_stride,
is_training=is_training, scope="bottlencek1")
for i in range(1, n):
out = self._bottleneck(out, h_out, n_out, is_training=is_training,
scope=("bottlencek%s" % (i + 1)))
return out
def _bottleneck(self, x, h_out, n_out, stride=None, is_training=True, scope="bottleneck"): #一个残差单元
""" A residual bottleneck unit"""
n_in = x.get_shape()[-1]
if stride is None:
stride = 1 if n_in == n_out else 2
with tf.variable_scope(scope): #建立一个变量空间域
h = conv2d(x, h_out, 1, stride=stride, scope="conv_1")
h = batch_norm(h, is_training=is_training, scope="bn_1")
h = tf.nn.relu(h)
h = conv2d(h, h_out, 3, stride=1, scope="conv_2")
h = batch_norm(h, is_training=is_training, scope="bn_2")
h = tf.nn.relu(h)
h = conv2d(h, n_out, 1, stride=1, scope="conv_3")
h = batch_norm(h, is_training=is_training, scope="bn_3")
if n_in != n_out:
shortcut = conv2d(x, n_out, 1, stride=stride, scope="conv_4")
shortcut = batch_norm(shortcut, is_training=is_training, scope="bn_4")
else:
shortcut = x
return tf.nn.relu(shortcut + h)
这是ResNet的核心,残差网络块,他是基于bottleneck残差单元的基础上来做的,首先解释一下残差单元是什么:
残差单元:他是在卷积的基础上改的,它是用原数据进行3次卷积操作先生成一个结果,再用原数据进行一次卷积操作,生成另一个数据,最后这个残差单元的结果就是两者合。至于为什么要这么做,大家可以从问题出发,为什么要提出这个ResNet网络?它的提出是用来解决为什么深层网络的训练效果比浅层训练的效果更差呢?当然不会是过拟合的问题,深层网络到最后存在着梯度消失或者爆炸的问题,这时候identify的引入,会加强特征效果,虽然会减缓训练速度,但一定程度上肯定会强化训练效果。
h = batch_norm(h, is_training=is_training, scope="bn_1")
这一句代码是批归一化,这是一个和以前的cnn不一样的东西,他是在每一次经过一个卷积层都要做的一件事,这个函数使结果x=wx+b各个维度均值为0,且方差为1。他也可以用来解决梯度消失或者爆炸的问题,通过规范化让激活函数分布在线性区间,让每一层的输入有一个稳定的分布会有利于网络的训练。