VQA入门(模型原理+模型代码)之《简单的模态融合交互》

简介

本文所介绍的VQA模型是一种最简单的VQA多模态交互模型。模型的关键点在于提取图像特征(Image_feature)和文本的特征(qst_feature),然后通过逐元素乘法将两种模态的特征融合到一起。这是一种早期的模态融合方法。

欢迎对多模态感兴趣的朋友来互相学习讨论~

原理

1.Model示意图

图画的不好,还请见谅,下面的具体模型部分会再次讲解。

Fig1:模型示意图

2.图像特征提取部分

Step1:假设训练样本的一张图像是[3,224,224]的,也就是一张图像有三个通道,图像的长和宽均为224,则训练样本为:x = [batch_size,3,224,224]。

Step2:然后经过一个预训练好的VGG19的feature部分(预训练好的vgg分为三个部分,feature部分、avgpool部分、classifier部分。如没特殊声明,后面的VGG19说的都是VGG19的feature部分)。

则经过VGG19后得到的特征为:Features = VGG19(x),其中Features的size为:[batch_size,512,7,7]。

Step3:然后再将Feature经过一些变换(这里做的是展平处理)变成[batch_size,512*7*7],然后再经过一个线性层得到image_feature,其中Image_feature的size为:[batch_size,1024]。

Fig2:图像特征提取示意图

3.文本特征提取部分

Step0:文本部分首先需要将文本映射为向量,这里采用的还是最简单的独热编码来映射。

假设有一句和图像相关的问题:“图像中的小孩穿的什么颜色衣服”。那么我们需要把这句话先编码为一个向量,需要做的是先分词(分词工具可以自行选择一些流行的即可),假设分词后的问题变成:“图像/中/的/小孩/穿/的/什么/颜色/衣服”。然后去vocab里面查询每个词出现的频率,然后为每个词赋予独热编码表示。

Step1:将独热编码的向量进行词嵌入操作。

假设上面那句话经过独热编码后变成了"X = [x_1,x_2,x_3,x_4,x_5,x_6,x_7,x_8,x_9]",其中每个x_i代表了一个词,然后x_i是一个独热编码的向量。

下面的操作就是进行词嵌入,其实非常简单,就是用一个词嵌入矩阵,将每个x_i映射为一个更好的向量。具体来说就是q_i = W_e x_i ,得到词嵌入向量。则

Step2:将词嵌入后的向量q_i按顺序依次送入到LSTM层,然后拿到LSTM层的最后一个隐层状态,作为问题的向量表示:qst_feature 。其中qst_feature的size为:[batch_size,1024]。

Fig3:文本特征提取示意图

4.模态融合

 因为我们图像特征和文本特征最后都是[batch_size,1024]的大小,所以我们可以直接将Image_feature和qst_feature进行乘法,得到融合后的特征向量。

当然这是一种早期的做法,虽然我们现在早已经不用这种粗暴的方式来做特征融合,但是刚刚入门,我觉得还是从最基础的地方来会更容易上手一些。

代码

1.图像特征提取的代码

import torch
import torch.nn as nn
from torchvision import models

class ImageEncoder(nn.Module):
    def __init__(self,embed_size):#这里的embed_size就是上面原理说的1024
        super(ImageEncoder,self).__init__()
        """
        The purpose of the class image encoder is to get the feature vector of the image
        """
        vgg19 = models.vgg19(pretrained=True).feature#加载预训练vgg19模型的feature部分
        self.cnn = vgg19
        self.fc1 = nn.Linear(512*7*7,4096)#这里为了过拟合,所以加一个线性层
        self.fc2 = nn.Linear(4096,embed_size)
        self.fl = nn.Flatten()
    def forward(self,img):
        with torch.no_grad():#这里做的目的是为了冻结住vgg19特征提取部分的参数
            features = self.cnn(img) #[batch_size,512,7,7]
        features = self.fl(features) #展平处理 [batch_size,512*7*7]
        features = self.fc1(features) #[batch_size,4096]
        img_feature = self.fc2(features) #[batch_size,embed_size=1024]
        return img_feature

2.问题特征提取的代码

class QuestionEncoder(nn.Module):
    """
    The purpose of the class QuestionEncoder is to get vector of the problem
    """
    def __init__(self,qst_vocab_size,word_embed_size,embed_size,num_layers,hidden_size):
        super(QuestionEncoder,self).__init__()
        self.embedding = nn.Embedding(qst_vocab_size,word_embed_size)
        #Uniform distributed initialization of the parameters of the word embedding layer
        nn.init.xavier_uniform_(self.embedding.weight)
        self.tanh = nn.Tanh()
        self.lstm = nn.LSTM(word_embed_size,hidden_size,num_layers)
        self.fc = nn.Linear(2*num_layers*hidden_size,embed_size)
    def forward(self,question):
        #Encoding incoming question as word vector
        qst_vec = self.embedding(question) #[batch_size,max_qst_length,word_embed_size=300]
        qst_vec = qst_vec.transpose(0,1)   #[max_qst_length,batch_size,word_embed_size]
        _,(hidden,cell) = self.lstm(qst_vec)
        qst_feature = torch.cat((hidden,cell),2)
        qst_feature = qst_feature.transpose(0,1)
        qst_feature = qst_feature.reshape(qst_feature.size()[0],-1)
        qst_feature = self.tanh(qst_feature)
        qst_feature = self.fc(qst_feature)
        return qst_feature

3.融合代码

class VqaModel(nn.Module):
    """
    The purpose of the class VqaModel is to fusion feature of v and q . Then to make classification
    """
    def __init__(self,embed_size,qst_vocab_size,ans_vocab_size,word_embed_size,num_layers,hidden_size):
        super(VqaModel,self).__init__()
        self.img_encoder = ImageEncoder(embed_size)
        self.qst_encoder = QuestionEncoder(qst_vocab_size,word_embed_size,embed_size,num_layers,hidden_size)
        self.tanh = nn.Tanh()
        self.dropout = nn.Dropout(0.3)
        self.fc1 = nn.Linear(embed_size,ans_vocab_size)
        self.fc2 = nn.Linear(ans_vocab_size,ans_vocab_size)
    def forward(self,img,qst):
        img_feature = self.img_encoder(img) #[batch_size,embed_size]
        qst_feature = self.qst_encoder(qst) #[batch_size,embed_size]
        fusion_feature = torch.mul(img_feature,qst_feature) #[batch_size,embed_size]
        fusion_feature = self.tanh(fusion_feature)
        fusion_feature = self.dropout(fusion_feature)
        fusion_feature = self.tanh(self.fc1(fusion_feature))
        fusion_feature = self.dropout(fusion_feature)
        y = self.fc2(fusion_feature)
        return y

讲在最后

这个模型应该是我们学习VQA领域想到的第一个模型,首先它是一个非常简单的将图像特征和文本特征做了个乘法。但是有一个问题,就是文本向量和图像向量之间没有交互,从而导致没有融合到更多的信息。因此我们带着这个问题,会进入下一篇论文,期待下一期继续和小伙伴们一起学习~

制作不易,如果本文对你有帮助的话,那就点个赞和关注吧~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值