1. 程式人生 > >深度學習雜記(3)resnet殘差塊

深度學習雜記(3)resnet殘差塊

深度學習的resnet的原理比較容易懂,但是具體的程式碼構建還是有些複雜,尤其是在tensorflow 的框架下構建比較複雜,在今天的博文中主要介紹了殘差單元的構建:

import collections
import tensorflow as tf
import tensorflow.contrib.slim as slim
def subsample(inputs,factor,scope=None):
    if(factor==1):
        return inputs
    else:
        return slim.max_pool2d(inputs,[1,1],stride=factor,scope=scope)

上述這段程式碼的目的是為了構建一個降取樣的函式,目的是為了使輸入通道相同的preact的shape經過池化,shape達到一樣

def conv2d_same(inputs, num_outputs, kernel_size, stride, scope=None):
    if(stride==1):
        return slim.conv2d(inputs,num_outputs,kernel_size,stride=1,padding='SAME',scope=scope)
    else:
        net = slim.conv2d(inputs, num_outputs, 3, stride=1, padding='SAME')
        net = subsample(net, factor=stride)
        return net;

若stride==1,則對其做一個卷積取值,相當於全連線神經網路的作用,否則則是對其進行3*3卷積之後採取降取樣使得shortcut和residual的shape保持一致

def bottleneck(inputs, depth, depth_bottleneck, stride,
               outputs_collections=None, scope=None):
    """
    Args:
      inputs: A tensor of size [batch, height, width, channels].
      depth、depth_bottleneck:、stride三個引數是前面blocks類中的args
      rate: An integer, rate for atrous convolution.
      outputs_collections: 是收集end_points的collection
    """
    with tf.variable_scope(scope, 'bottleneck_v2', ) as sc:
        depth_in = slim.utils.last_dimension(inputs.get_shape(), min_rank=4)  # 最後一個維度,即輸出通道數
        preact = slim.batch_norm(inputs, activation_fn=tf.nn.relu, scope='preact')

        if depth == depth_in:
            # 如果殘差單元的輸入通道數和輸出通道數一致,那麼按步長對inputs進行降取樣
            shortcut = subsample(inputs, stride, 'shortcut')
        else:
            # 如果不一樣就按步長和1*1的卷積改變其通道數,使得輸入、輸出通道數一致
            shortcut = slim.conv2d(preact, depth, [1, 1], stride=stride,
                                   normalizer_fn=None, activation_fn=None,
                                   scope='shortcut')

        # 先是一個1*1尺寸,步長1,輸出通道數為depth_bottleneck的卷積
        residual = slim.conv2d(preact, depth_bottleneck, [1, 1], stride=1, scope='conv1')
        # 然後是3*3尺寸,步長為stride,輸出通道數為depth_bottleneck的卷積
        residual = conv2d_same(residual, depth_bottleneck, 3, stride, scope='conv2')
        # 最後是1*1卷積,步長1,輸出通道數depth的卷積,得到最終的residual。最後一層沒有正則項也沒有啟用函式
        residual = slim.conv2d(residual, depth, [1, 1], stride=1,
                               normalizer_fn=None, activation_fn=None,
                               scope='conv3')

        # 將降取樣的結果和residual相加
        output = shortcut + residual

        return slim.utils.collect_named_outputs(outputs_collections, sc.name, output)

最後是整個殘差塊的設計。