8.7 Image Captioning 圖像描述

前言

圖像描述是CVNLP結合的一個典型任務,也是CVNLP橋樑,本節將介紹圖像描述模型的訓練及使用,包括經典的CNN+RNN,以及現在流行的多模態模型。

本節內容將包括:

  1. 圖像描述的概念,發展歷史,常用資料集,BLUE評價指標
  2. 基於CNN+RNN+attention機制的圖像描述模型訓練
  3. 基於Clip+GPT2的圖像描述模型訓練

<<AI人工智慧 PyTorch自學>> 8.7 Image

圖像描述簡介

Image Captioning (圖像描述)是對圖像採用文字進行描述的過程,Image Captioning又稱圖像圖像字幕生成、圖像標注、圖像說明等,目前應用在醫療診斷、智慧客服、人機交互等領域。

圖像描述是一個交叉領域,將圖片的視覺特徵和自然語言處理結合起來,實現自動化的圖片描述。

  • 2014年之前,主流方法是採用數位影像處理進行特徵提取,然後通過對特徵的描述,實現image captioning
  • 2014年,Google發表了Show and Tell: Lessons Learned from the 2015 MSCOCO Image Captioning Challenge,首次採用CNN+RNN的形式進行端到端的深度學習模型訓練,並且獲得2015 COCO 圖像描述的冠軍。
  • 20152月,Bengio領銜的團隊針對Show and Tell改進,加入了attention機制,發表了Show, Attend and Tell 該方法在文本生成模組,加入注意力機制,挖掘單詞與圖像區域的關聯關係。
  • 2019年,得益于Transformer廣泛應用,圖像描述開啟了Transformer一統天下的時代,先後有Attention on Attention for Image CaptioningImage Captioning: Transforming Objects into WordsEntangled Transformer for Image Captioning等論文採用了Transformer進行圖像描述,簡要看了論文,發現模型結構圖略顯負責,不夠優雅,這裡就不貼圖了,因為後續的超大預訓練模型將會開啟圖像描述新範式。
  • 2021年,隨著圖文、文本任務的預訓練模型(pre-training model)的成功,學者迅速將其應用於圖像描述,2021年有ClipCap2022BLIP 20231BLIPv2,目前BLIP系列已經達到較好效果,也將是本案例的重點。

簡單來說,圖像描述主流方法的發展,先經過CNN+RNN,及其變體,再到Transformer,再到VLPvisual language pre-training)模式,隨著ChatGPT等預訓練模型的成功,多模態任務也將有更多應用。

圖像描述資料集

圖像描述常用的資料集有Flickr8KFlickr30KConceptual Captions (CC)COCO2014,資料集中語料庫的高頻詞雲如下圖所示:

<<AI人工智慧 PyTorch自學>> 8.7 Image

圖片來源:《2021-07-From Show to Tell A Survey on Deep Learning-Based Image Captioning

本案例將採用COCO2014,該資料集train82783張,val40504張,test40775張,每張圖片對應有5~7句的caption。為了線下比較模型的性能,會把trainval經過karpathy分割後,train變成113287張,val變成5000張,test變成5000張,而線上測試的test不變,仍為40775張。

標注規則為:

  • 描述這個場景的所有重要部分;
  • 不描述不重要的細節。
  • 不要描述在未來或過去可能發生的事情。
  • 不描述一個人可能會說什麼。
  • 不提供專有的人名。
  • 這些句子應該至少包含8個單詞。

更多資料集介紹可參考Image Caption 2021最新整理:資料集 / 文獻 / 代碼

圖像描述評價指標

圖像描述的評價,可以參考機器翻譯的評價,都是比較兩個句子之間的相似度。

機器翻譯中常用的評價指標有,BLEU1-4, METEOR, ROUGE-L, and CIDEr等,這裡介紹最常見的BLEU1-4

BLEUIBM2002年提出的,用於機器翻譯任務的評價,發表在ACL,引用次數10000+,原文題目是“BLEU: a Method for Automatic Evaluation of Machine Translation”

它的總體思想就是準確率,假如給定標準譯文reference,模型生成的句子是candidate,句子長度為ncandidate中有m個單詞出現在referencem/n就是bleu1-gram的計算公式。

當統計不再是一個單詞,而是連續的N個單詞時,就有了n-gram的概念,片語的概念稱為n-gram,片語長度通常選擇1, 2, 3, 4

舉一個例子來看看實際的計算:

candinate: the cat sat on the mat

 

reference: the cat is on the mat

 

BLEU-1 5/6 = 0.83

 

BLEU-23/5 = 0.6

 

BLEU-31/4 = 0.25

 

BLEU-4: 0/3 = 0

Copy

分子表示candidate中預測到了的片語的次數,如BLEU-1中,5分別表示, the, cat, on, the, mat預測中了。BLEU-2中,3分別表示, the cat, on the, the mat預測中了。以此類推。

針對BLEU還有些改進計算方法,可參考BLEU詳解

BLEU的優點在於它考慮的是n-gram級別的匹配,而不是詞級別的匹配,因此可以考慮更長的匹配資訊,從而更好地評估翻譯的品質。

但是,BLEU的缺點在於無論哪種n-gram被匹配上了,都會被同等對待,這可能會導致一些問題。例如,動詞的匹配在翻譯中可能比冠詞更重要,但是在BLEU中,它們被同等地看待,這可能不太合適。

CNN+RNN 代碼實現

接下來採用CNN+RNN結構,並配合attention機制,實現圖像描述模型訓練, coco2014上可實現23.1BlEU-4

代碼來自github,論文可參考《Show, Attend and Tel

資料採用github上推薦的下載連結,coco2014,資料集劃分採用 Andrej Karpathy劃分好的json檔。

先看效果圖,這是一張測試圖片,模型可以輸出 a brown teddy bear sitting on top of a pair of shoes,能對圖中的泰迪、鞋子進行表述。

<<AI人工智慧 PyTorch自學>> 8.7 Image

資料模組

資料下載與轉換

首先下載資料,並轉換資料為pytorchdataset讀取的形式

  1. 下載圖像資料,val2014 train2014 資料夾,並將其放置到xxx/coco2014/images
  2. 下載標注數據,caption_datasets.zip,其中包含coco, flickr8k, flick30k的標籤,這裡只使用dataset_coco.json
  3. 在配套代碼00_create_input_files.py中設置以下路徑,運行後獲得相應的資料

create_input_files(dataset='coco',

                   karpathy_json_path=r'G:\deep_learning_data\coco_2014\image-caption-json\dataset_coco.json',

                   image_folder=r'G:\deep_learning_data\coco_2014\images',

                   captions_per_image=5,

                   min_word_freq=5,

                   output_folder=r'G:\deep_learning_data\coco_2014\dataset-created',

                   max_len=50)

Copy

獲得的資料是經過預處理轉換的,下面介紹對資料是如何處理的。

數據預處理

文本資料需要進行一系列的預處理,例如,將一張圖片對應的5句不等長度的描述,整理為可以batch輸入資料,這裡涉及一些NLP常見的操作,下面通過代碼進行剖析。

  1. 對描述的開頭和結尾,加入起始、停止詞 a man holds a football
  2. 將句子填充至等長,如100個詞, a man holds a football ....
  3. 創建詞映射,將詞映射為編號, [9488, 1, 20, 64, 3, 60, 57, 69, 35, 66, 14, 67, 17, 1, 68, 9489, 0,.., 0],其中94889489,0分別表示

上述資訊,通過00_create_input_files.py獲得,資料處理後,分別獲得:

  • HDF5,包含了所有圖片,資料形狀為 N 3, 256, 256,但hdf5pytorchdataloader中無法啟用多進程,因此本案例改用保存圖片路徑的方式,在dataset中再讀取圖片
  • CATIONS*.json,包含每個描述句子添加起始詞、填充、映射後的索引,為 N_c * I 形式, N_c表示所有描述句子的梳理,I表示圖像的數量。由於coco固定了一張圖片有5個描述,因此N_c == 5.
  • CAPLENS*.json,包含每句描述的長度,N_c * I N_c表示所有描述句子的梳理,I表示圖像的數量。
  • WORDMAP*.json,所以一個字典,包含了單詞到索引的映射關係。
  • xxx_paths.pkl:包含每張圖片的路徑,用於在dataset中進行圖片讀取

原代碼採用HDF5進行圖片讀取,這樣無法採用num_worker>1,因此在這裡我將代碼改為基於圖片路徑形式進行讀取,可以充分利用cpu載入資料。詳細內容參見dataset的編寫。

模型模組

模型部分主要有encoder decoder attention三個模組。

  • encoderresnet101將圖片變為14x14x2048的特徵圖,並且經linear層變換到向量形式,便於與文本特徵拼接
  • attention模組由多個linear層構成,注意力權重最終經sigmoid函數得到0-1區間的注意力權重,並且是1x196的向量,對應著14x14的圖像區域。
  • decoder為標準的LSTM,其輸入由詞嵌入向量1x512 + attention的特徵1x2048構成
  • output模組採用LSTMhiddent feature,經過linear層輸出1x9490的分類概率向量,9490表示單詞庫中總共有9490個單詞。

模型結構如下圖所示,本圖對github原圖進行了詳細補充,對每一個資料維度及流向進行了標記:

<<AI人工智慧 PyTorch自學>> 8.7 Image

訓練與推理

在配套代碼01_train.py代碼中僅需要配置資料所在資料夾data_folder,執行 python 01_train.py即可。 epoch=14左右會得到最優BLEU-4, 22.7

關於超參數,num_worker可以設置大於1batchsize設為了256,採用的是1080ti 11GB,顯存佔用8G+,耗時大約1.5小時一個epoch

訓練代碼比較常規,只是文本任務在資料處理上有一個比較特殊的操作就是組batch時,先對文本長度進行排序,然後依次取batch送入LSTM。組batch的操作,具體如github所示:

<<AI人工智慧 PyTorch自學>> 8.7 Image

推理觀察

訓練到14epoch時可以將模型拿來試試了,將 BEST_checkpoint_coco_5_cap_per_img_5_min_word_freq.pth.tar的路徑配置到02_inference.py

  • args.img目前支援圖片以及資料夾形式的推理
  • args.model ckpt的路徑
  • args.word_map是單詞庫,模型預測出來的9490個類別需要對應到具體的單詞,用的就是這個字典。
  • out_dir是輸出圖片的資料夾

args.img = r'G:\deep_learning_data\coco_2014\images\val2014'  #img path or dir

args.model = 'BEST_checkpoint_coco_5_cap_per_img_5_min_word_freq.pth.tar'  # model checkpoint

args.word_map = r'G:\deep_learning_data\coco_2014\dataset-created\WORDMAP_coco_5_cap_per_img_5_min_word_freq.json'

out_dir = './output_img'

Copy

效果如下圖所示

訓練好的模型權重下載:連結:https://pan.baidu.com/s/1fLS0_EPqfj0x_PX3JLN1Eg 提取碼:ta3v


到這裡,快速地實現了一個效果還不錯的圖像描述模型,裡邊有一些新知識值得學習:

  1. 圖像可經過模型提取特徵,變為特徵向量與文本特徵向量融合,實現圖文多模態的處理
  2. LSTM訓練時,將句子長度排序,便可獲得batch size依次遞減的訓練樣本
  3. coco資料訓練時,一個樣本為 (一張圖片,一個句描述,句子長度),因此共5x113287=566435個訓練樣本

隨著Transformer不斷的落地應用,以及多模態模型langueage-visual模型的成功,基Transformer體系的圖像描述模型成為主流。

下面介紹一款親民的模型,CLIPCap,親民指它在10801天就可以訓練,並且仍舊使用了強大的Transformer模型,論文idea值得學習。

CLIPCap 代碼實現

接下來,借助強大的多模態模型的特徵提取能力實現圖像描述。

這裡採用CLIP對圖像的理解能力,獲取圖像編碼特徵embedding向量,再經過一個生成器模型,實現圖像描述。這個工作就是202111月發表的ClipCap

ClipCap提出一種輕量化的方法,可以結合 CLIPimage encoder GPT-2 ,實現圖像描述。

ClipCap有三個部分,分別是image encoder mapping network gpt2。其中image encodergpt2都是在超大規模資料集上預訓練過的,可以直接用。

在學習ClipCap前,先來瞭解什麼是CLIP,什麼是GPT2

CLIP簡介

CLIP(Contrastive Language-Image Pre-training),基於對比學習的文圖預訓練模型,該模型可實現zero-shot的圖像分類、檢測等下游任務,也可以作為圖像檢索、圖像生成、圖像描述任務的backbone,是圖文多模態模型領域中劃時代意義的一個作品。

CLIP20212月由openAI發表,並開源了模型,模型由4的圖文資料,採用對比學習方式進行訓練得到,由於對比學習與超大規模的資料集加持,使CLIP模型很好的理解了自然圖像,在眾多資料集上表現出了優異的zero-shot性能,同時在表徵學習(representation learning)中也很好。

CLIP模型由text encoderimage encoder組成,分別對文本和圖像進行特徵提取,獲得特徵向量,隨後進行對比學習,即圖像1與文本1是一對資料,I1向量要與T1越接近越好,I1與其它的T向量越不接近越好,對於一個batch的資料來說,可以構成一個方陣,對角線上是正樣本,非對角線是負樣本。

 

 

 

<<AI人工智慧 PyTorch自學>> 8.7 Image

訓練偽代碼如下:

# 分別提取圖像特徵和文本特徵

I_f = image_encoder(I) #[n, d_i]

T_f = text_encoder(T) #[n, d_t]

 

# 對兩個特徵進行線性投射,得到相同維度的特徵,並進行l2歸一化

I_e = l2_normalize(np.dot(I_f, W_i), axis=1)

T_e = l2_normalize(np.dot(T_f, W_t), axis=1)

 

# 計算縮放的余弦相似度:[n, n]

logits = np.dot(I_e, T_e.T) * np.exp(t)

 

# 對稱的對比學習損失:等價於N個類別的cross_entropy_loss

labels = np.arange(n) # 對角線元素的labels

loss_i = cross_entropy_loss(logits, labels, axis=0)

loss_t = cross_entropy_loss(logits, labels, axis=1)

loss = (loss_i + loss_t)/2

Copy

text encoder採用的是標準的text transformer

image encoder則有多個模型,主要是ResNet系列,包含5個不同大小的模型:ResNet50ResNet101RN50x4RN50x16RNx64(後面三個模型是按照EfficientNet縮放規則對ResNet分別增大4x16x64x得到),ViT系列,3個不同大小的模型:ViT-B/32ViT-B/16ViT-L/14。所有的模型都訓練32epochs,採用AdamW優化器,而且訓練過程採用了一個較大的batch size32768。由於資料量較大,最大的ResNet模型RN50x64需要在592V100卡上訓練18天,而最大ViT模型ViT-L/14需要在256V100卡上訓練12天,都需要幾千個V100天。

模型訓練好之後,神奇之處在於其可以zero-shot的進行圖像分類,這個方式很具有創新性。具體步驟是

  1. 人為設定一批候選類別的文本描述,例如:A photo of {label} 然後label分別填入候選類別的單詞,假設有N個類別,則得到N個句子
  2. 送入text encoder,得到N個文本特徵向量
  3. 圖像送入image encoder,得到圖像特徵向量
  4. 圖像特徵向量與N個文本特徵向量進行比較,找到最近的那個特徵向量,即可得到類別輸出

 

<<AI人工智慧 PyTorch自學>> 8.7 Image

 

使用CLIP進行zero-shot分類,另外一個比較重要的地方是文本描述的生成,上面的例子我們採用A photo of {label},但其實也有其它選擇,比如我們直接用類別標籤,這其實屬於最近NLP領域比較火的一個研究:prompt learning或者prompt engineering,具體可以見這篇綜述論文:Pre-train, Prompt, and Predict: A Systematic Survey of Prompting Methods in Natural Language Processing,這裡就不再進行闡述。

感興趣可參考官方的ImageNet分類的Prompt engineering,採用80個不同的prompt來進行集成,發現在ImageNet資料集上能帶來3.5%的提升,具體見CLIP公開的notebook

到這裡大體瞭解CLIP中有一個對自然圖像理解能力很強的image encoder,可以獲得很好的圖像特徵向量,接下來需要一個能接收embedding向量,輸出文本描述的強大模型,GPT當之無愧作為首選。

GPT2簡介

GPT2(Generative Pre-trained 2),是由OpenAI開發的生成式自然語言模型,鑒於chatGPT的火爆,這裡不過多介紹GPT1,2,3,3.5,4的差別。

在這裡需要瞭解gpt2是一個生成式模型,根據輸入的文本資訊,可以生成一系列文本,如輸入一個問題句子,gpt將句子變為text embedding,輸入到模型中,然後一個一個單詞的輸出,最終輸出一句回答。其中,人類輸入的問題句子,可以看成是prefix embeddinggpt根據首碼資訊,依次生成內容。

Prefix embeddings是指在GPT模型中,為每一個輸入詞添加一個首碼,然後將添加首碼後的詞轉化為向量表示。這個首碼是指輸入詞前面的所有詞,它可以為模型提供更多的上下文資訊,説明模型更好地理解輸入文本的含義。

舉個例子,假設輸入文本是我喜歡吃蘋果,對於蘋果這個詞,它的首碼是我喜歡吃,添加首碼後的詞就是我喜歡吃蘋果。這個添加首碼後的詞可以被轉化為向量表示,然後作為GPT模型的輸入。

CLIPCap中,正式利用了gpt2強大的文本生成能力進行圖像描述,但圖像資訊如何輸入到gpt呢?接下來就看看CLIPCap的創新。

CLIP Captioning

202111月,ClipCap提出一種輕量化的方法,可以結合 CLIPimage encoder GPT-2 ,實現圖像描述。

ClipCap有三個部分,分別是image encoder mapping network gpt2。其中image encodergpt2都是在超大規模資料集上預訓練過的,可以直接用。

由於CLIPGPT2不好訓練,所以設計一個mapping network,圖像embedding特徵向文本embedding特徵的轉換,從而巧妙的銜接了CLIPGPT2,並且可以僅訓練mapping nework,這一點與當前BLIP v2中的QFormer是一樣的。

<<AI人工智慧 PyTorch自學>> 8.7 Image

結合上圖,來看看模型到底是如何實現圖像描述的。

第一步,一張圖片及其對應的描述文本,會被輸入到CLIP中,得到image embedding向量:512維,文本則通過gpt2的字典轉換為tokensgpt2字典有50257個詞。

第二步:圖像特徵經過maping network,獲得40x768的特徵,可以理解為將圖像翻譯為了40768的特徵向量

第三步:文本tokens經過word2emb獲得 text embedding向量40x768維度,這裡的40表示句子最長有40個單詞,如果補足40,填充即可。

第四步:圖像與文本特徵拼接,輸入到gpt2進行訓練,gpt2輸出8050257維的分類概率向量,其中取後40個向量進行輸出分類的單詞,最終形成句子。

上述為訓練過程,其中CLIPGPT2是可以凍結的,詳情可看代碼。

在推理的時候,GPT2 word2emb的這一分支是沒有的,gpt2僅拿到圖像的40x768向量進行推理,逐步生成每一個單詞,最終形成句子。

CLIP Captioning 訓練代碼實現

第一步,資料集下載及準備

首先準備資料集,這裡採用coco 2014,需要下載的檔有

  1. 預處理過的標籤文件:train_caption.json
  2. 原始影像檔夾:train2014val2014

組織為以下目錄形式

  • ROOT_PROJECT / data / annotations / train_caption.json
  • ROOT_PROJECT / data / train2014
  • ROOT_PROJECT / data / val2014

第二步,CLIP模型特徵提取,運行配套代碼00_parse_coco.py

python 00_parse_coco.py --clip_model_type ViT-B/32

Copy

由於不涉及CLIP的訓練,因此CLIP對每一張圖片的輸出是固定的,所以可以把訓練集中的566757個樣本對進行特徵提取及文本tokens的映射。

執行以下代碼,預計需要3小時完成56萬多張樣本對的處理。

結果將保存在

  • ROOT_PROJECDT / data / oscar_split_ViT-B_32_train.pkl
  • ROOT_PROJECDT / data / oscar_split_ViT-B_32_train_tokens.pkl

第三步,模型訓練,運行配套代碼01-train.py

python 01-train.py --data ./data/coco/oscar_split_ViT-B_32_train.pkl --out_dir ./coco_train/

Copy

到這裡就可以開始訓練了,在1080ti上訓練10epoch,耗時16小時,模型將保存在 ROOT_PROJECDT / coco_train 資料夾下

提供一個預訓練權重,模型權重下載連結提取碼:mqri

CLIP Captioning 推理代碼實現

推理示例,運行配套代碼02-inference.py,需要配置下面三個路徑即可。

ckpt_path = r'coco_prefix-009-2023-0411.pt' 

path_img = r'G:\deep_learning_data\coco_2014\images\val2014'

out_dir = './inference_output'

Copy

推理代碼中,配置好模型路徑、測試圖片/資料夾路徑,輸出路徑,運行即可得到結果

推理僅需要0.2s即可獲得一例輸出,速度還是可以接受的。

下圖為val2014中的一些推理結果示意圖

<<AI人工智慧 PyTorch自學>> 8.7 Image

到這裡Clip Cap就結束了,簡單回顧一下Clip Cap整體內容。

  1. 借力:Clip Cap 站在了兩個巨人的肩膀上,分別是CLIPGPT2
  2. 磨合:為了讓兩個模組可以更好的融合使用,提出mapping network模組將CLIP的輸出轉換為GPT2能接收的特徵向量形式, 40x76840"單詞"的特徵向量形式。
  3. 親民:在1080ti上一天時間就可以訓練coco資料集,並且還能用上大模型,這個motivation不得不說很巧妙

如果想將Clip Cap運用于中文,也推薦大家閱讀ClipCap-Chinese

小結

Image Captioning 是一個CV+NLP的典型應用,是從一幅圖輸出一句話的過程,並且具有較高的商業價值,如字幕生成、圖像標注、圖像說明等。

本文介紹了圖像描述的概念,發展歷史,常用資料集,BLUE評價指標,並通過代碼實現兩種主流的圖像描述演算法。

CNN+RNN架構

  1. CNN負責提取特徵圖,並變為特徵向量1x512作為h0輸入到RNN
  2. RNN逐步輸出單詞

Clip Cap

  1. 借助大模型——CLIPGPT2,效果比CNN+RNN好很多,這也是基於Transformer的深度學習模型廣泛應用的原因之一
  2. 巧妙的將圖像特徵與NLP模型嫁接起來,後續更為強大的BLIP v2同樣採用了此操作

關於圖像描述、文圖、圖文等多模態任務,十分推薦大家學習以下內容

https://github.com/salesforce/BLIP

https://github.com/salesforce/LAVIS

 

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 HCHUNGW 的頭像
    HCHUNGW

    HCHUNGW的部落格

    HCHUNGW 發表在 痞客邦 留言(0) 人氣()