📜  复仇者联盟残局和深度学习 |使用 Avengers EndGames字符生成图像说明

📅  最后修改于: 2022-05-13 01:54:22.006000             🧑  作者: Mango

复仇者联盟残局和深度学习 |使用 Avengers EndGames字符生成图像说明

看,漫威迷们。复仇者们在那里拯救多元宇宙,我们也准备好尽一切努力支持他们。
在本文中,我们将使用深度学习和计算机视觉来生成复仇者联盟残局字符的字幕。我们将从基础开始,解释概念并使用预训练模型来实施项目。

概述:

图像标题生成是 AI 中的一个具有挑战性的问题,它连接计算机视觉和 NLP,其中必须为给定的照片生成文本描述。在一般意义上,对于作为输入的给定图像,我们的模型描述了图像的确切描述。它既需要来自计算机视觉领域的图像理解,即卷积神经网络,也需要来自自然语言处理领域的语言模型。
假设和测试多种方法来构建给定的预测建模问题是很重要的,并且确实有很多方法来构建为照片生成标题的问题。我们坚持我们将在本文末尾解释的一个,所以请坚持一段时间。你能拿着雷神锤吗!!!!但你可以坚持,别开玩笑了。

所以基本上我们的模型所做的是,当我们将图像传递给我们的 CNN 和 RNN 组合架构时,它将使用 NLP 生成图像的自然描述。

例子:

在深入之前,让我们先了解了解此算法所需的基本术语。

它们基本上是两种类型:

基于图像的模型:从图像中提取特征。
基于语言的模型:它将我们基于图像的模型给出的特征和对象转换为自然句子。

浓缩的特征向量由卷积神经网络形成。一般而言,这个特征向量称为嵌入,CNN 模型被称为编码器,它对给定的单词集进行编码并生成传递给解码器网络的序列。在下一步中,我们将使用来自 CNN 层的这些嵌入作为 LSTM 网络的输入, LSTM 网络是一个解码器,用于解码输入序列并生成输出。

例如:语言翻译,如法语到英语。

句子语言模型中,LSTM 是在预测句子中的下一个单词。给定图像的初始嵌入,LSTM 被训练来预测序列中最可能的下一个值。这就像向一个人展示一堆图像并要求他们记住图像的细节,然后再向他们展示与先前图像具有相似内容的新图像并要求他们回忆内容。这个“召回”和“记住”的工作是由我们的 LSTM 网络完成的,这在这里更有用。稍后当我谈到实施部分时,将向您展示它实际上是如何函数的。

在本文中,我们将使用在 ImageNet 数据集上训练的预训练卷积神经网络。图像被转换为 224 X 224 X 3 (nh x hw x nc) 的标准分辨率,这将使任何给定图像的模型的输入恒定。

从技术上讲,我们还插入StartStop来表示字幕的结束。

例子:

下图解释得更好——

测试阶段:
在测试阶段,编码器部分与训练阶段几乎相同。唯一的区别是batchnorm 层使用方差和平均值,而不是小批量统计。这可以使用encoder.eval()函数轻松实现。对于解码器部分,训练阶段和测试阶段之间存在着至关重要的区别。在测试阶段,LSTM 解码器无法观察到图像描述。为了处理这种情况,LSTM 解码器将之前生成的单词反馈给下一个输入。这可以使用 for 循环来实现。

基本上有两种字幕生成模型:

型号 1:

生成整个序列:第一种方法涉及为给定图像的对象生成整个文本描述。

Input: Photograph 
 Output: Complete textual description.

这是一个一对多的序列预测模型,它以一次性的方式生成整个输出。

  • 该模型对语言模型施加了沉重的负担,以正确的顺序生成正确的单词。
  • 图像通过特征提取模型,例如在 ImageNet 数据集上预训练的模型。
  • 一种热编码用于输出序列,它允许模型预测序列中每个单词在整个词汇表中的概率分布。
  • 所有序列都被填充到相同的长度,这意味着模型被迫在输出序列中生成多个“无字”时间步长。
  • 测试这种方法,我们发现需要一个非常大的语言模型,即使这样也很难通过模型生成 NLP 等价的持久性,例如:生成在整个序列长度上重复的相同单词作为输出。

型号 2:

从单词生成单词:这是一种不同的方法,其中 LSTM 在给定图像和一个单词作为输入的情况下生成一个单词的预测。

Input 1: Image 
 Input 2: Previously generated word or start of sequence token. 
 Output:  Next word in sequence.

这是一个一对一的序列预测模型,通过递归调用模型来生成文本描述。

  • 一个词输入要么是一个标记,它在第一次调用模型的情况下指示序列的开始,要么是从上一次调用模型时生成的词。
  • 图像通过一个特征提取模型,就像在 ImageNet 数据集上预训练的模型一样,输入词是通过词嵌入的整数编码的。
  • 输出单词是一种热编码,它允许模型预测单词在整个词汇表中的概率。
  • 递归词生成过程不断重复,直到生成序列结束标记。
  • 通过测试这种方法,我们发现模型确实生成了一些好的 n-gram 序列,但是陷入了一个循环重复相同的单词序列以进行长描述,这是一个开销,因为模型中存在内存不足的问题记住之前生成的内容。

让我们通过图像字幕的例子来获得更深层次的直觉。

我们有两种不同的技术来做到这一点——

1.用于从图像中提取特征的视觉几何群神经网络(VGG)。
2.一个循环神经网络(RNN),通过模型训练和生成字幕文本。

第1步:
使用预训练的 VGG 模型,图像被读入并调整为具有三个颜色通道的 224*224*3,然后馈入 VGG 神经网络,其中特征被提取为 Numpy 数组。由于这里使用 VGG 网络进行图像分类,因此我们不是从最后一层获取输出,而是从包含图像特征数据的全连接 (FC-2) 层获取输出。

第2步:
对于图像字幕,使用 Keras 创建一个具有 256 个神经元的 LSTM(长期短期记忆)单元。对于这个单元格,我们有四个输入:图像特征、标题、掩码和当前位置首先将标题输入和位置输入连接(合并),然后通过词嵌入层,然后图像特征和嵌入的词是还与掩码输入合并(使用连接)。它们一起通过 LSTM 单元,LSTM 单元的输出然后通过 Dropout 和 Batch Normalization 层,以防止模型过度拟合。最后,应用 Softmax 非线性,我们得到了预期的结果。

我们得到的结果是一个向量,每个条目代表字典中每个单词的可能性。概率最高的词将是我们当前的“最佳词”。与预先构建的字典一起,该向量用于“解释”下一个生成的单词,该单词可以被视为一种用于在真实标题中进行训练的基本事实。掩码在这一切中扮演着重要的角色,“记录”之前在字幕中使用的单词,以便模型知道当前单词之前的单词,并以句子的当前位置输入模型,使其不会陷入环形。

与训练类似,我们还需要获取要预测的每张图像的特征。因此,图像首先通过 VGG-16 网络架构来生成特征。对于字幕,我们使用了相同的 LSTM 模型。该模型的第一个单词输入是“#start#”标签,接下来的输入是上一次迭代的预测结果。

模型架构:

我们鼓励您查看这篇研究论文,以清楚地了解到底发生了什么。

存储块包含由三个门控制的单元“C”。蓝色显示循环连接,在时间 't-1' 的输出 'm' 通过三个门在时间 't' 反馈到内存,单元格值通过遗忘门反馈,预测单词在除了时间't'的内存输出'm'之外,时间't-1'被反馈到用于单词预测的Softmax函数中。读取其输入门'i'以及是否输出新的单元格值(输出门o)。

  • 编码器-解码器架构:通常,生成序列的模型将使用编码器将输入编码为固定形式,并使用解码器将输入逐字解码为序列。
  • 注意力:注意力网络的使用在深度学习中很普遍,而且有充分的理由。这是一种让模型只选择它认为与手头任务相关的编码部分的方法。您在此处看到的相同机制可用于编码器输出在空间或时间上具有多个点的任何模型。我们认为在图像字幕中某些像素比其他像素更重要。在对机器翻译等任务进行排序时,您认为某些单词比其他单词更重要。
  • 迁移学习:当您通过在新模型中使用现有模型的一部分来借用现有模型时,这几乎总是比从头开始训练新模型(即什么都不知道)要好,正如我们将看到的那样,我们总是可以微调这一秒- 手头特定任务的知识和使用预先训练的词嵌入是一个无效但有效的例子。我们将使用预训练的编码器,然后根据需要对其进行微调。
  • Beam Search:我们不会让您的解码器变得懒惰,只需在每个解码步骤中选择得分最高的单词,Beam Search 对于任何语言建模问题都很有用,因为它可以找到最佳序列。

我们通过代码来理解:

先决条件-

Anaconda
Pytorch
MSCOCO Dataset    

要复制本文的结果,请确保安装了先决条件。现在让我们从头开始训练一个模型,按照以下步骤操作。

数据集

git clone https://github.com/pdollar/coco.git
cd coco/PythonAPI/
make
python setup.py build
python setup.py install
cd ../../
git clone https://github.com/yunjey/pytorch-tutorial.git
cd pytorch-tutorial/tutorials/03-advanced/image_captioning/
pip install -r requirements.txt 

注意:我们建议您使用 google Colab

预训练模型——
让我们从这里下载预训练模型和词汇文件,然后我们应该使用 unzip 命令将pretrained_model.zip 解压到 ./models/vocab.pkl./data/

现在模型已经准备好了,它可以使用以下方法预测字幕:

$ python sample.py --image='/example.png'

让我们开始表演吧!

导入所有库并确保笔记本位于存储库的根文件夹中:

import torch
import matplotlib.pyplot as plt
import numpy as np 
import argparse
import pickle 
import os
from torchvision import transforms 
from PIL import Image
  
# this file is located in pytorch tutorial/image 
# captioning which we pull from git remember
from build_vocab import Vocabulary   
from model import EncoderCNN, DecoderRNN

无法更改硬编码模型:

# Model path 
  
# make sure path must correct 
ENCODER_PATH = 'content/encoder-5-3000.pkl' 
DECODER_PATH = 'content/decoder-5-3000.pkl'
VOCAB_PATH =   'content/vocab.pkl'
  
# CONSTANTS because of architecture what we are using
EMBED_SIZE = 256
HIDDEN_SIZE = 512
NUM_LAYERS = 1

为 load_image 添加此配置代码:

# Device configuration snippet
device = torch.cuda.device(0) # 0 represent default device
  
  
# Function to Load and Resize the image
def load_image(image_path, transform=None): 
  image = Image.open(image_path)
  image = image.resize([224, 224], Image.LANCZOS)
  if transform is not None:
    image = transform(image).unsqueeze(0)
  return image

现在,让我们编写一个 PyTorch函数,它使用预训练的数据文件来预测输出:

def PretrainedResNet(image_path, encoder_path=ENCODER_PATH, 
                     decoder_path=DECODER_PATH,
                     vocab_path=VOCAB_PATH,
                     embed_size=EMBED_SIZE,
                     hidden_size=HIDDEN_SIZE,
                     num_layers=NUM_LAYERS):
  
    # Image preprocessing
    transform = transforms.Compose([
                transforms.ToTensor(), 
                transforms.Normalize((0.485, 0.456, 0.406), 
                                     (0.229, 0.224, 0.225))])
        
    # Load vocabulary wrapper
    with open(vocab_path, 'rb') as f:
        vocab = pickle.load(f)
  
    # Build models
  
    # eval mode (batchnorm uses moving mean/variance)
    encoder = EncoderCNN(embed_size).eval()  
    decoder = DecoderRNN(embed_size, hidden_size,
                          len(vocab), num_layers)
  
    encoder = encoder.to(device)
    decoder = decoder.to(device)
  
    # Load the trained model parameters
    encoder.load_state_dict(torch.load(encoder_path))
    decoder.load_state_dict(torch.load(decoder_path))
  
    # Prepare an image
    image = load_image(image_path, transform)
    image_tensor = image.to(device)
      
    # Generate a caption from the image
    feature = encoder(image_tensor)
    sampled_ids = decoder.sample(feature)
  
    # (1, max_seq_length) -> (max_seq_length)
    sampled_ids = sampled_ids[0].cpu().numpy()         
      
    # Convert word_ids to words
    sampled_caption = []
    for word_id in sampled_ids:
        word = vocab.idx2word[word_id]
        sampled_caption.append(word)
        if word == '':
            break
    sentence = ' '.join(sampled_caption)[8:-5].title() 
  
    # Print out the image and the generated caption
    image = Image.open(image_path)
    return sentence, image

让我们开始为 Avenger's EndGame 中的一些场景制作字幕,看看它的概括性如何,别忘了欣赏。

要预测标签,请使用以下代码:

plt.figure(figsize=(24,24))
predicted_label, image = PretrainedResNet(image_path='IMAGE_PATH')
plt.imshow(image)
print(predicted_label)

我们有绿巨人,现在我们有深度学习。 😀

测试图像:Thor-Mark I

我们来看看这张图片

现在你觉得这张照片怎么样?在不向下滚动的情况下记住一个标题。

plt.figure(figsize=(17,19))
predicted_label, img = PretrainedResNet(image_path='./image/AVENGERENDGAME1.png')
plt.imshow(img)
print(predicted_label)

输出:

Thor 


测试图像:Tony-Mark II

现在你觉得这张照片怎么样?在不向下滚动的情况下记住一个标题。

plt.figure(figsize=(22,22))
predicted_label, img = PretrainedResNet(image_path='./image/AVENGERENDGAME2.png')
plt.imshow(img)
print(predicted_label)

输出:

(tony and doctor strange)


测试图像:Hulk-Mark III

现在你觉得这张照片怎么样?在不向下滚动的情况下记住一个标题。

plt.figure(figsize=(42,49))
predicted_label, img = PretrainedResNet(image_path='./image/AVENGERENDGAME3.png')
plt.imshow(img)
print(predicted_label)

输出:

(thanos and Hulk)

注意:我们在此处使用图像名称AVENGERENDGAME*.png ,其中 * 从 1、2、3 不等,以此类推,但您可以放置自己的图像并记住,一张可能会得到不同的标题,而另一张可能会得到不同的标题。