用于视频识别的CNN + RNN架构

时间:2020-08-24 19:13:25

标签: deep-learning computer-vision pytorch lstm cnn

我正在尝试使用pytorch复制in this paper中提出的ConvNet + LSTM方法。但是我正在努力寻找在模型中结合CNN和LSTM的正确方法。这是我的尝试:

class VideoRNN(nn.Module):
  def __init__(self, hidden_size, n_classes):
    super(VideoRNN, self).__init__()

    self.hidden_size = hidden_size

    vgg = models.vgg16(pretrained=True)
    embed = nn.Sequential(*list(vgg.classifier.children())[:-1])
    vgg.classifier = embed
    
    for param in vgg.parameters():
      param.requires_grad = False


    self.embedding = vgg
    self.GRU = nn.GRU(4096, hidden_size)


  def forward(self, input, hidden=None):
    embedded = self.embedding(input)
    output, hidden = self.gru(output, hidden)
    output = self.classifier(output.view(-1, 4096))

    return output, hidden

由于我的视频具有可变长度,因此我提供了PackedSequence作为输入。它是由形状为(M,B,C,H,W)的张量创建的,其中M是最大序列长度,B是批量大小。 C,H,W是每个帧的通道,高度和宽度。

我希望预先训练的CNN成为模型的一部分,因为我稍后可能会解冻某些层以微调CNN以完成我的任务。这就是为什么我不单独计算图像的嵌入。

那么我的问题如下:

  1. 我的输入数据的形状是否正确,以便在我的上下文中处理成批的视频?还是应该使用PackedSequence以外的其他东西?

  2. 在我的转发功能中,如何使用VGG和GRU单元处理一批图像序列?我不能直接将PackedSequence作为VGG的输入,所以如何进行?

  3. 这种方法似乎尊重“火炬手做事方式”吗?还是我的方法有缺陷?

1 个答案:

答案 0 :(得分:0)

我终于找到了使之工作的解决方案。这是一个简化但完整的示例,说明了我如何创建一个能够使用packedSequence作为输入的VideoRNN:

var width = element && element.getBoundingClientRect && element.getBoundingClientRect().width;

关键是class VideoRNN(nn.Module): def __init__(self, n_classes, batch_size, device): super(VideoRNN, self).__init__() self.batch = batch_size self.device = device # Loading a VGG16 vgg = models.vgg16(pretrained=True) # Removing last layer of vgg 16 embed = nn.Sequential(*list(vgg.classifier.children())[:-1]) vgg.classifier = embed # Freezing the model 3 last layers for param in vgg.parameters(): param.requires_grad = False self.embedding = vgg self.gru = nn.LSTM(4096, 2048, bidirectional=True) # Classification layer (*2 because bidirectionnal) self.classifier = nn.Sequential( nn.Linear(2048 * 2, 256), nn.ReLU(), nn.Linear(256, n_classes), ) def forward(self, input): hidden = torch.zeros(2, self.batch , 2048).to( self.device ) c_0 = torch.zeros(self.num_layer * 2, self.batch, 2048).to( self.device ) embedded = self.simple_elementwise_apply(self.embedding, input) output, hidden = self.gru(embedded, (hidden, c_0)) hidden = hidden[0].view(-1, 2048 * 2) output = self.classifier(hidden) return output def simple_elementwise_apply(self, fn, packed_sequence): return torch.nn.utils.rnn.PackedSequence( fn(packed_sequence.data), packed_sequence.batch_sizes ) 方法,该方法可以在CNN网络中馈送PackedSequence并检索由嵌入制成的新PackedSequence作为输出。

希望您会发现它有用。