[关闭]
@w460461339 2019-02-20T18:12:47.000000Z 字数 3739 阅读 938

Tensorflow5:RCNN,指数下降LearningRate,MovingAverage

Tensorflow


1、RCNN基本逻辑

RCNN分四步:

1、利用selective_search在图上找到候选框。
2、利用特征提取器对每个候选框提取特征。
3、对提取到的特征,送入SVM进行分类。
4、对提取到的特征,送入回归网络,进行位置精修。

在程序设计上,主要有这么几步:

1、获取原始特征提取器,用image-net上训练的也行。
2、在自己的数据集上对特征提取器进行fine_tune。
3、去除特征提取器最后的fc分类层。
4、利用Selective_search进行候选框选择。
5、对每个候选框,利用3中的特征提取器提取特征,得到【特征向量,label】这样的数据,以及【特征向量,ground_truth】的数据
6、利用5中得到的【特征向量,label】数据,训练SVM。
7、利用5中得到的【特征向量,ground_truth】数据,训练边框回归。
8、完事。

2、代码阅读

它的程序设计的很巧妙:

1、利用一个Solver类,来统一处理网络训练/预测过程中,共通的:
    1.1 可视化参数,比如tensorboard的参数等。
    1.2 持久化参数,比如模型的保存路径等。
    1.3 训练参数:
        1.3.1 学习率,都使用指数下降的学习率
        1.3.2 移动平均,都使用移动平均

2、在Solver类中,通过:is_training,is_fineturn,is_Reg来控制状态:
    2.1 初始特征提取器训练状态:is_training=True,is_fineturn=False,is_Reg=False
    2.2 fine_tune训练状态:is_training=True,is_fineturn=True,is_Reg=False
    2.3 回归网络训练状态:is_training=True,is_fineturn=False,is_Reg=True

3、在网络设计上,也采用上述的控制方案,对于基提取器,采用,is_training=True,is_fineturn=False,is_SVM=False来控制:
    3.1 初始特征提取器训练状态:is_training=True,is_fineturn=False,is_SVM=False
    3.2 Fine_tune训练状态:is_training=True,is_fineturn=True,is_SVM=False
        此状态下,最后一层FC的输出个数不同。
    3.3 SVM特征提取器状态:is_training=False,is_fineturn=False,is_SVM=True
        此状态下,移除最后一层FC。(这里si_fineturn无所谓了)

3、细节问题

其实这里的selective_search就是起到了anchors的作用。

我们用selective_search拿到碎片的时候,就是拿到了一个个的anchors。

我们计算gt和anchors的偏移量,然后让我们预测框的偏移量,尽可能的和【gt与anchors的偏移量】靠近,就完事了。

这里要求,selective_search每次的结果都要一样才行啊…

  1. no_object_loss = tf.reduce_mean(tf.square((1-y_true[:,0])*y_pred[:,0]))
  2. object_loss = tf.reduce_mean(tf.square(y_true[:,0]*(y_pred[:,0]-1)))
  3. loss = (tf.reduce_mean(y_true[:,0] * ( tf.reduce_sum(tf.square(y_true[:,1:5]-y_pred[:,1:5])
  4. ,1) ) )
  5. + no_object_loss
  6. + object_loss
  7. )

这里是我觉得问题最大的地方。y_pred是一个[None,5]的tensor,y_pred[None,0]表示是否是前景,y_pred[None,1:5]表示坐标参数。

上面它显然是想通过真实的前景概率*坐标的MSE+前景/背景的分类loss来计算总的loss。

但是,问题出在他计算前景/背景的分类loss上,y_pred[None,0]没有经过sigmoid啊…输出并不是一个概率值,而且他的这部分

  1. no_object_loss = tf.reduce_mean(tf.square((1-y_true[:,0])*y_pred[:,0]))
  2. object_loss = tf.reduce_mean(tf.square(y_true[:,0]*(y_pred[:,0]-1)))

算得是个啥啊…根本看不懂啊…

  1. self.global_step = tf.get_variable('global_step',[],initializer=tf.constant_initializer(0),trainable=False)
  2. # learning_rate 在这里定义
  3. self.learning_rate = tf.train.exponential_decay(
  4. self.initial_learning_rate,
  5. self.global_step,
  6. self.decay_step,
  7. self.decay_rate,
  8. self.staircase,
  9. name='learning_rate'
  10. )
  11. self.optimizer = tf.train.AdamOptimizer(learning_rate=self.learning_rate)\
  12. .minimize(self.net.total_loss,global_step=self.global_step)

2、那么下面就是具体的操作过程了:

    2.1 通过tf.train.ExponentialMovingAverage获得一个滑动平均的操作符ema。
    2.2 通过ema.apply指定哪些参数需要运用到滑动平均方法。
    2.3 由于滑动平均需要在参数更新后使用,因此通过tf.control_dependencies([ops])指定顺序,
        那么就会先运行self.optimizer,再运行self.average_op
    2.4 另外,由于两者其实没有实质的依赖关系,因此通过tf.group将他们绑在一起,
        那么当train_op执行的时候,会先执行self.optimizer,再执行self.average_op
        (所以 tf.group其实是将没有关系的两个操作,让它们可以一起执行)
  1. # 用滑动平均,帮助预测的时候更准
  2. # 1、得到滑动平均操作符
  3. self.ema = tf.train.ExponentialMovingAverage(decay=0.99)
  4. # 2、选定要滑动平均的对象
  5. self.average_op = self.ema.apply(tf.trainable_variables())
  6. # 3、指定顺序,绑定操作符
  7. with tf.control_dependencies([self.optimizer]):
  8. self.train_op = tf.group(self.average_op)
  1. '''
  2. 1、指定self.optimizer这个op,会在self.average_op之前运行。
  3. 2、将self.average_op和self.optimizer绑定成一个op。
  4. 因为两者没有依赖关系,我光运行self.average_op不会运行self.optimizer,所以要绑在一起执行。
  5. '''
  6. with tf.control_dependencies([self.optimizer]):
  7. self.train_op = tf.group(self.average_op)
  1. net = slim.dropout(net,keep_prob=keep_prob,is_training=is_training,scope='dropout9')
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注