非识不可C3D模型详解

想了解C3D模型必然先看论文,结合tf版github代码看效果更好。【该论文很久之前的了,追新的可以不看】

总体:

作者提出的一个关键点就是3维卷积,每层都是3*3*3卷积核,这种结构考虑到了时空特征,因而效果较好。

二维卷积核在图像上做卷积得到的自然是图像,在多帧图像上得到的还是图像(因为将他们视为了不同的通道,可以参考Two-stream,这个网络就是将每帧提取光流信息,最后做卷积,只是增加了通道而已,损失了时间信息),而三维卷积是直接就是三维卷积核,得到的是三维体,保留了时间信息。

网络结构:

所有的视频都被分割成clips,帧resize为(128,171),输入维度为(None,nframes,128,171,3),每个clip有nframes帧,这里nframes=16,一个有意思的点是这个输入的HW在训练中会随机crop成(112,112)【关于crop可以参考下pytorch的版本】,这种操作有点像attention的效果【关于attention,我也不太懂,没重点看,举个例子,人的眼睛总是能看到最突出的特征,而忽略不太重要的特征】,这种操作使得训练中的数据的数据都有或多或少的改变,数据量变相增加了,模型更有鲁棒性。

网络有5个卷积层及池化层,每个卷积层都紧跟着池化层(似乎是基本结构,VGG不就是如此吗),2个dense层,最后接一个softmax,其中卷积核个数分别为64,128,256,256,256。所有的卷积核都有时间深度d(这个是不同的),大小为d*k*k。

卷积层的padding为适当的,可以是same或valid,步长为1,这样能够保证通过卷积成的输入输出shape没有变化。

所有的池化层都是最大值池化,且除了第一层(1*2*2)都是2*2*2,步长仍为1,由此可知,从16到8是降维了。

fc层则都是2048输出,后面又说4096,有点蒙蔽。

几种变化的d探索

1)当设置卷积核时间深度d分别为(1,3,5,7)时,第一个卷积并没有过早的融合时间信息,仍旧相当于是2D卷积;

2)(3,3,5,5,7)和             3)(7,5,5,3,3)

结果发现只有3*3*3的卷积核是最佳的。

为便于理解,模型代码附上:参数或许也有改变

NUM_CLASSES = 101
CROP_SIZE = 112
CHANNELS = 3
NUM_FRAMES_PER_CLIP = 16


def conv3d(name, l_input, w, b):
  return tf.nn.bias_add(
          tf.nn.conv3d(l_input, w, strides=[1, 1, 1, 1, 1], padding='SAME'),
          b
          )

def max_pool(name, l_input, k):
  return tf.nn.max_pool3d(l_input, ksize=[1, k, 2, 2, 1], strides=[1, k, 2, 2, 1], padding='SAME', name=name)

def inference_c3d(_X, _dropout, batch_size, _weights, _biases):

  # Convolution Layer
  conv1 = conv3d('conv1', _X, _weights['wc1'], _biases['bc1'])
  conv1 = tf.nn.relu(conv1, 'relu1')
  pool1 = max_pool('pool1', conv1, k=1)

  # Convolution Layer
  conv2 = conv3d('conv2', pool1, _weights['wc2'], _biases['bc2'])
  conv2 = tf.nn.relu(conv2, 'relu2')
  pool2 = max_pool('pool2', conv2, k=2)

  # Convolution Layer
  conv3 = conv3d('conv3a', pool2, _weights['wc3a'], _biases['bc3a'])
  conv3 = tf.nn.relu(conv3, 'relu3a')
  conv3 = conv3d('conv3b', conv3, _weights['wc3b'], _biases['bc3b'])
  conv3 = tf.nn.relu(conv3, 'relu3b')
  pool3 = max_pool('pool3', conv3, k=2)

  # Convolution Layer
  conv4 = conv3d('conv4a', pool3, _weights['wc4a'], _biases['bc4a'])
  conv4 = tf.nn.relu(conv4, 'relu4a')
  conv4 = conv3d('conv4b', conv4, _weights['wc4b'], _biases['bc4b'])
  conv4 = tf.nn.relu(conv4, 'relu4b')
  pool4 = max_pool('pool4', conv4, k=2)

  # Convolution Layer
  conv5 = conv3d('conv5a', pool4, _weights['wc5a'], _biases['bc5a'])
  conv5 = tf.nn.relu(conv5, 'relu5a')
  conv5 = conv3d('conv5b', conv5, _weights['wc5b'], _biases['bc5b'])
  conv5 = tf.nn.relu(conv5, 'relu5b')
  pool5 = max_pool('pool5', conv5, k=2)

  # Fully connected layer
  pool5 = tf.transpose(pool5, perm=[0,1,4,2,3])
  dense1 = tf.reshape(pool5, [batch_size, _weights['wd1'].get_shape().as_list()[0]]) # Reshape conv3 output to fit dense layer input
  dense1 = tf.matmul(dense1, _weights['wd1']) + _biases['bd1']

  dense1 = tf.nn.relu(dense1, name='fc1') # Relu activation
  dense1 = tf.nn.dropout(dense1, _dropout)

  dense2 = tf.nn.relu(tf.matmul(dense1, _weights['wd2']) + _biases['bd2'], name='fc2') # Relu activation
  dense2 = tf.nn.dropout(dense2, _dropout)

  out = tf.matmul(dense2, _weights['out']) + _biases['out']

  return out

整体上看来没啥难度,就是卷积,池化和全连接。

其中参数初始化采用的是tf.contrib.layers.xavier_initializer,在所有层中保持梯度的尺度大致相同

help可以看到具体

In uniform distribution this ends up being the range:
    `x = sqrt(6. / (in + out)); [-x, x]` and for normal distribution a standard
    deviation of `sqrt(2. / (in + out))` is used.

所有参考均已经附带链接。

另外有相关问题可以加入QQ群讨论,不设微信群

QQ群:868373192 

语音图像视频深度-学习群

或者发我邮箱:

[email protected]

发布了248 篇原创文章 · 获赞 244 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/SPESEG/article/details/105327392