我正在尝试使用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以完成我的任务。这就是为什么我不单独计算图像的嵌入。
那么我的问题如下:
我的输入数据的形状是否正确,以便在我的上下文中处理成批的视频?还是应该使用PackedSequence以外的其他东西?
在我的转发功能中,如何使用VGG和GRU单元处理一批图像序列?我不能直接将PackedSequence作为VGG的输入,所以如何进行?
这种方法似乎尊重“火炬手做事方式”吗?还是我的方法有缺陷?
答案 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作为输出。
希望您会发现它有用。