TensorFlow-Slim 一些用法笔记

Table of Contents

一 slim.separable_conv2d

二  slim.arg_scope

三 slim中的图像预处理文件: preprocessing_factory.py

四 slim.assign_from_checkpoint_fn

五 slim.batch_norm



一 slim.separable_conv2d

函数原型如下:

slim.separable_conv2d(inputs,
                        num_outputs,
                        kernel_size,
                        depth_multiplier,
                        strides=1,
                        padding='SAME',
                        data_format='NHWC'
                        rate=1,
                        activation_fn=tf.nn.relu
                        pointwise_initializer=None, 
                        weights_regularizer=None, 
                        biases_initializer=None,
                        biases_regularizer=None,
                        reuse=None,
                        variables_collections=None,
                        outputs_collections=None,
                        trainable=True,
                        scope=None
                        )

下面仅仅介绍几个重要参数和调用方法。

  • inputs   一个四维的tensor  其shape形如 [batch_size, height, width, channels]
  • num_outputs   是pointwise conv2d的输出通道数目
  • kernel_size       是一个列表,里面装着卷积核的高和宽,形如  [kernel_height, kernel_width]
  • depth_multiplier   这个看过论文的人都该知道了,影响depthwise conv2d的输出结果,输出的通道数为该值乘上输入的                                      channels

调用方法如下,来自于slim的mobilenet实现。

        net = slim.separable_conv2d(net, None,kernel,
                                      depth_multiplier=1,
                                      stride=layer_stride,
                                      rate=layer_rate,
                                      normalizer_fn=slim.batch_norm,
                                      scope=end_point)

这个的num_output为None,请看官方解释。

 If is None, then we skip the pointwise convolution stage.

意思就是说如果num_output为None,这个函数就相当于是执行了depthwise conv2d,而没有执行pointwise conv2d。

 

二  slim.arg_scope

slim由于高封装性,所以参数数目就很多了,如果每一次运用诸如conv2d,batch_norm等具有相同参数的函数,都要重复写这些参数的实参赋值,肯定是谷歌的工程师不愿意见到的,于是有了slim.arg_scope。

slim.arg_scope([funcs],**parameters)

这个原型并非摘自源码,funcs指的是一些函数名称,用逗号隔开;parameter是funcs中都有的形参。

我们先看一段实例。

 with slim.arg_scope([slim.conv2d,slim.separable_conv2d],
                        weights_initializer = weight_init,
                        activation_fn= tf.nn.relu6, normalizer_fn=slim.batch_norm):

slim.conv2d和slim.separable_conv2d中都有如上所示的形参,所以通过sllim.arg_scope可以将这些形参设置到函数中,只要在with所属的作用域内部,我们使用conv2d都不需要设置上面那些形参了。

另外,如果你想在某些操作设置形参的方式和arg_scope中不一致,只需要显示的(explictly),直接的(directly)设置就行了。而且这个函数支持嵌套。见如下代码:

    with slim.arg_scope([slim.conv2d,slim.separable_conv2d],
                        weights_initializer = weight_init,
                        activation_fn= tf.nn.relu6, normalizer_fn=slim.batch_norm):
        with slim.arg_scope([slim.batch_norm],**batch_norm_parames):
            with slim.arg_scope([slim.conv2d],weights_regularizer=regularizer):
                with slim.arg_scope([slim.separable_conv2d],
                                    weights_regularizer=depthwise_regularizer) as sc:

观察发现,最外层的arg_scope中设置了多个函数中共有的形参,里面层仅仅对单个函数的某些形参单独设置。

 

三 slim中的图像预处理文件: preprocessing_factory.py

这个文件中有个核心函数 

get_preprocessing(model_name,is_training=is_training)

slim提供了几个主流网络的预处理方式,当然这些文件也适用于其他网络,可能需要小修小改。

比如源码中这样使用:

image_preprocessing_fn = preprocessing_factory.get_preprocessing(
      'mobilenet_v1', is_training=is_training)

这里就获得了'mobilenet_V1'的预处理方式。接着调用:

image = image_preprocessing_fn(image, FLAGS.image_size, FLAGS.image_size)
  • image是一个三维的tensor,其实就是图像的那三维信息

image_size是图像的宽和高的数值,是一个数字,函数里面

使用了两次,就是说处理之后的图像高和宽都是指定的image_size

之后就可以用  tf.train.batch函数变成能用于训练的tensor了。

 

四 slim.assign_from_checkpoint_fn

我们平常使用tf.Saver类也是挺方便的,但是Saver在restore的时候有个问题,如果ckpt中记录的图结构或者一小部分tensor 的name和我们程序里面构建的图不一样,那么就无法导入权重值。这时slim提供的这个函数就可以很好解决这个问题。

该函数的用法有两个步骤,第一步:

    slim_init_fn = slim.assign_from_checkpoint_fn(
        FLAGS.fine_tune_checkpoint,
        variables_to_restore,
        ignore_missing_vars=True)

第一个参数是ckpt文件的地址+文件名;variable_to_restore是需要加载权值的tensor,最后一个参数设置为TRUE,则如果variable_to_restore中记录的tensor在ckpt中没有,那么就不对该tensor赋值了,直接忽视。

第二步:得到的这slim_init_fn其实是个函数,还需要如下方式调用。

slim_init_fn(sess)

也就是说这个函数只能在一个session中使用。

2019.1.8


五 slim.batch_norm

在TensorFlow中想运用BN其实是很麻烦的事情。我们先看下源码 tf.layers.batch_normalization 自带的一段注释。

Note: when training, the moving_mean and moving_variance need to be updated.
  By default the update ops are placed in `tf.GraphKeys.UPDATE_OPS`, so they
  need to be added as a dependency to the `train_op`. Also, be sure to add
  any batch_normalization ops before getting the update_ops collection.
  Otherwise, update_ops will be empty, and training/inference will not work
  properly. For example:

  ```python
    x_norm = tf.layers.batch_normalization(x, training=training)

    # ...

    update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
    with tf.control_dependencies(update_ops):
      train_op = optimizer.minimize(loss)

不想看英文或者看不明白就看我这一段。我们试想一下BN的操作:计算每一个mini batch中所有图片的均值和方差,然后所有的图片都用这两个值做normalization。我们在训练的时候确实执行的是上述操作,但是如果在测试的时候,我们仍这么做,最终结果就带上了batch自身的影响。比如说a这张图片被shuffle到了一个batch-1中,得到了一个结果;然后a放在另一个不同的batch中,可能会得到不同的解果,原因就是bn计算了一个batch的mean和var, 但是这两个参数是随着batch的改变而改变的。为了消除这种影响,我们在测试的时候,BN使用的mean值和var值是固定的,来自于在训练的时候计算的滑动平均值。但是有个问题,滑动平均值不是训练参数,它不会在训练过程中像权重一样更新,所以需要人为的告诉程序,要在反向传播之前计算更新滑动平均值。

具体做法就是:

    update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
    with tf.control_dependencies(update_ops):
      train_op = optimizer.minimize(loss)

先获得在Graph中update_ops集合中的更新滑动平均值得操作。之后我们只要强制的通过tf.control_dependencies把这个操作加入到图中,告诉程序,执行train_op操作之前,要先执行update_ops。

如果你不要上面的操作,你会发现你的训练出来的模型,在测试的时候精度会很低,并且is_training参数必须是True才能让结果变成正常的,但实际上这样做还是让模型计算每个batch的mean和var,实际结果是受到batch 自身干扰的。

接下来就来看看slim中的batch_norm的用法吧。

import tensorflow as tf
from tensorflow.contrib import slim
import numpy as np
def BN_arg_scope(is_training=True,
                 weight_decay=0.00004,
                 stddev=0.09,
                 batch_norm_decay=0.9997,
                 batch_norm_epslion=0.001):
    batch_norm_parames={
        'center': True,
        'scale' : True,
        'decay' : batch_norm_decay,
        'epslion' : batch_norm_epslion
    }

    if is_training:
        batch_norm_parames['is_training']=is_training
    with slim.arg_scope([slim.fully_connected],normalizer_fn=slim.batch_norm):
        with slim.arg_scope([slim.batch_norm],**batch_norm_parames) as sc:
            return sc

def inference(inputs):
    net=slim.fully_connected(inputs,32)
    net=slim.fully_connected(net,64)
    net=slim.fully_connected(net,2,activation_fn=None)
    net=slim.softmax(net)
    return net

def main():
    data=np.random.rand(100)
    label=np.ones([100,],np.int32)
    with slim.arg_scope(BN_arg_scope()):
        data=tf.convert_to_tensor(data)
        label=tf.convert_to_tensor(label)
        label_one_hot=slim.one_hot_encoding(label,num_classes=2)
        logits=inference(data)
        loss=tf.reduce_mean(tf.square(logits-label),axis=[0,1])
        opt=tf.train.GradientDescentOptimizer(0.01)
        update_ops=tf.get_collection(tf.GraphKeys.UPDATE_OPS)
        with tf.control_dependencies(update_ops):
            train_op=opt.minimize(loss)

        with tf.Session() as sess:
            '''
            #自己的训练代码
            '''

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值