您好,登錄后才能下訂單哦!
目錄:
介紹
動機
先決條件
數據采集
了解數據
數據清理
加載訓練集
數據預處理- 圖像
數據預處理- 字幕
使用生成器函數準備數據
Word嵌入
模型架構
推理
評估
結論和未來的工作
參考
1.簡介
你在下面的圖片中看到了什么?
你能寫一個標題嗎?
你們當中有些人可能會說“一只白色的狗趴在草地上”,有些人可能會說“有一只帶有褐色斑點的白狗”,還有一些人可能會說“狗在草地上還有一些粉紅色的花朵”。
絕對所有這些標題都與此圖像相關,也可能還有其他一些標題。但我想說的是,對于我們人類來說,看一眼照片就能夠用適當的語言來描述它,這很容易。即使是5歲的孩子也可以輕松地做到這一點。
但是,你能編寫一個計算機程序,將圖像作為輸入并產生相關的標題作為輸出嗎?
簡單的架構
在深度神經網絡發展之前,即使是計算機視覺領域最先進的研究人員,這個問題也是很難想象的。但隨著深度學習的出現,如果您擁有所需的數據集,則可以非常輕松地解決此問題。
Andrej Karapathy在斯坦福大學的博士論文中對這個問題進行了很好的研究[1],他現在也是特斯拉的AI主任。
這篇文章的目的是解釋(盡可能簡單的話)深度學習如何用于解決為給定圖像生成標題的問題,因此名稱為Image Captioning。
為了更好地了解這個問題,我強烈建議使用Microsoft創建的這個系統,稱為Caption Bot。只需轉到此鏈接并嘗試上傳您想要的任何圖片;這個系統會為它生成一個標題。(https://www.captionbot.ai/)
2.動機
我們必須首先了解這個問題對現實世界場景的重要性。在這些應用程序中,它的問題的解決方案可能非常有用。
自動駕駛汽車- 自動駕駛是最大的挑戰之一,如果我們可以適當地描述汽車周圍的場景,它可以提升自動駕駛系統。
對盲人的幫助- 我們可以為盲人創造一種產品,引導他們在沒有其他人支持的情況下在公路上行駛。我們可以通過首先將場景轉換為文本然后將文本轉換為語音來實現此目的。兩者現在都是深度學習的著名應用。
在今天閉路電視攝像機無處不在,但在觀看這個世界的同時,如果我們還可以生成相關字幕,那么一旦某些惡意活動發生,我們就可以立即發出警報。這可能有助于減少一些犯罪和/或事故。
自動字幕可以幫助使Google圖片搜索與Google搜索一樣好用,因為每個圖片都可以先轉換為標題,然后根據標題執行搜索。
3.先決條件
本文假設您熟悉基本的深度學習概念,如多層感知器、卷積神經網絡、遞歸神經網絡、遷移學習、梯度下降、過度擬合、概率、文本處理、Python語法和數據結構、Keras庫等。
4.數據收集
有很多開源數據集可用于此問題,如Flickr 8k(包含8k圖像),Flickr 30k(包含30k圖像),MS COCO(包含180k圖像)等。
但是為了本案例研究的目的,我使用了Flickr 8k數據集(https://forms.illinois.edu/sec/1713398)在不是非常高端的PC /筆記本電腦的系統上,訓練具有大量圖像的模型可能是不可行的。
該數據集包含8000個圖像,每個圖像有5個字幕(正如我們在“簡介”部分中已經看到的那樣,圖像可以有多個字幕,所有字幕都是同時相關的)。
這些圖像分叉如下:
訓練集- 6000圖像
Dev Set - 1000張圖片
測試集- 1000張圖像
5.了解數據
如果您從我提供的鏈接下載了數據,那么,與圖像一起,您還將獲得一些與圖像相關的文本文件。其中一個文件是“Flickr8k.token.txt”,其中包含每個圖像的名稱及其5個標題。我們可以按如下方式閱讀此文件:
文本文件如下:
因此,每行包含<圖像名稱> #i <caption>,其中0≤i≤4
即圖像名稱,標題號(0到4)和實際標題。
現在,我們創建一個名為“描述”的字典,其中包含圖像的名稱(不帶.jpg擴展名)作為鍵,以及相應圖像的5個標題列表作為值。
例如,參考上面的截圖,字典將如下所示:
6.數據清理
當我們處理文本時,我們通常會執行一些基本的清理工作,例如低層包裝所有單詞(否則“hello”和“Hello”將被視為兩個單獨的單詞),刪除特殊標記(如'%','$','#'等),消除包含數字的單詞(如'hey199'等)。
以下代碼執行以下基本清理步驟:
在數據集中8000*5(即40000)圖像字幕(語料庫)中創建所有獨特單詞的詞匯表:
這意味著我們在所有40000個圖像標題中都有8763個獨特的單詞。我們將所有這些標題及其圖像名稱寫在一個新文件中,即“descript.txt”并將其保存在磁盤上。
但是,如果我們仔細考慮一下,其中的很多這些詞只會出現很少次,比如1、2或3次。由于我們正在創建一個預測模型,我們不希望我們的詞匯表中包含所有單詞,而是更容易出現更常見的單詞。這有助于模型對異常值變得更加穩健并減少錯誤。
因此,我們只考慮在整個語料庫中出現至少10次的那些詞。代碼如下:
所以現在我們的詞匯表中只有1651個獨特的單詞
7.加載訓練集
文本文件“Flickr_8k.trainImages.txt”包含屬于訓練集的圖像的名稱。所以我們將這些名稱加載到列表“train”中。
因此,我們將名為“train”的列表中的6000個訓練圖像分開。
現在我們從Python詞典“train_descriptions”中的“descriptions.txt”(保存在硬盤上)加載這些圖像的描述。
但是,當我們加載它們時,我們將在每個標題中添加兩個標記,如下所示(稍后解釋):
'startseq' - >這是一個開始序列標記,將在每個標題的開頭添加。
'endseq' - >這是一個結束序列標記,將在每個標題的末尾添加。
8.數據預處理- 圖像
圖像只是我們模型的輸入(X)。 您可能已經知道,模型的任何輸入都必須以向量的形式給出。
我們需要將每個圖像轉換為固定大小的矢量,然后將其作為輸入饋送到神經網絡。 為此,我們使用Google Research創建的InceptionV3模型(卷積神經網絡)選擇遷移學習。
該模型在Imagenet數據集上進行訓練,以對1000種不同類別的圖像進行圖像分類。 但是,我們的目的不是對圖像進行分類,而是為每個圖像獲取固定長度的信息矢量。 此過程稱為自動特征工程。
我們只是從模型中刪除最后一個softmax圖層,并為每個圖像提取2048長度向量(瓶頸特征),如下所示:
特征向量提取(特征工程)
代碼如下:
現在我們將每個圖像傳遞給該模型以獲得相應的2048長度特征向量,如下所示:
我們將所有瓶頸訓練功能保存在Python字典中,并使用Pickle文件將其保存在磁盤上,即“encoded_train_images.pkl”,其鍵是圖像名稱,值是對應的2048長度特征向量。
注意:如果您沒有高端PC /筆記本電腦,此過程可能需要一到兩個小時。
類似地,我們編碼所有測試圖像并將它們保存在文件“encoded_test_images.pkl”中。
9.數據預處理- 字幕
我們必須注意,字幕是我們想要預測的。因此,在訓練期間,標題將是模型正在學習預測的目標變量(Y)。
但對整個標題的預測是不可能同時發生的,我們將逐字預測字幕。因此,我們需要將每個單詞編碼為固定大小的向量。然而,這部分將在后面看到模型設計時看到,但是現在我們將創建兩個Python詞典,即“wordtoix”(發音為- word to index)和“ixtoword”(發音為- index to word)。
簡單地說,我們將用整數(索引)表示詞匯表中的每個唯一單詞。如上所示,我們在語料庫中有1652個唯一的單詞,因此每個單詞將由1到1652之間的整數索引表示。
這兩個Python字典可以使用如下:
wordtoix ['abc'] - >返回單詞'abc'的索引
ixtoword [k] - >返回索引為'k'的單詞
使用的代碼如下:
還有一個我們需要計算的參數,即標題的最大長度,我們這樣做如下:
所以任何標題的最大長度是34。
10.使用生成器函數準備數據
這是本案例研究中最重要的步驟之一。在這里,我們將了解如何以便于作為深度學習模型的輸入的方式準備數據。
從現在開始,我將嘗試通過以下示例解釋剩余的步驟:
考慮我們有3個圖像及其3個相應的標題如下:
Caption_1 - >黑貓坐在草地上
Caption_2 - >白貓正在路上行走
Caption_3 - >黑貓正走在草地上散步
現在,假設我們將使用前兩個圖像及其標題來訓練模型,我們將使用第三個圖像來測試我們的模型。
現在我們要回答的問題是:我們如何將其構建為監督學習問題?數據矩陣是什么樣的?我們有多少數據點?等
首先,我們需要將兩個圖像轉換為它們對應的2048長度特征向量,如上所述。設“Image_1”和“Image_2”分別為前兩個圖像的特征向量
其次,讓我們通過在兩者中添加兩個標記“startseq”和“endseq”來構建前兩個(列車)字幕的詞匯表:(假設我們已經執行了基本的清理步驟)
Caption_1 - >“startseq黑貓坐在草地上endseq”
Caption_2 - >“startseq白貓正在路上行走”
vocab = {black,cat,endseq,grass,is,on,road,sat,startseq,the,walking,white}
讓我們給出詞匯表中每個單詞的索引:
黑色-1,貓-2,endseq -3,草-4,是-5,在-6,道路-7,坐-8,startseq -9,-10,行走-11,白色-12
現在讓我們嘗試將其構建為監督學習問題,其中我們有一組數據點D = {Xi,Yi},其中Xi是數據點'i'的特征向量,Yi是對應的目標變量。
讓我們拍攝第一張圖像矢量Image_1及其相應的標題“startseq,黑貓坐在草地上”。回想一下,Image vector是輸入,標題是我們需要預測的。但我們預測標題的方式如下:
我們第一次提供圖像矢量和第一個單詞作為輸入,并嘗試預測第二個單詞,即:
輸入= Image_1 +'startseq';輸出='the'
然后我們提供圖像矢量和前兩個單詞作為輸入并嘗試預測第三個單詞,即:
輸入= Image_1 +'startseq';輸出='貓'
等等…
因此,我們可以總結一個圖像的數據矩陣及其相應的標題如下:
對應于一個圖像及其標題的數據點
必須注意的是,一個圖像+標題不是單個數據點,而是多個數據點,具體取決于標題的長度。
同樣,如果我們同時考慮圖像及其標題,我們的數據矩陣將如下所示:
圖像和標題的數據矩陣
我們現在必須明白,在每個數據點中,不僅僅是作為系統輸入的圖像,還有一個部分字幕,它有助于預測序列中的下一個字。
由于我們正在處理序列,我們將使用循環神經網絡來讀取這些部分字幕(稍后將詳細介紹)。
但是,我們已經討論過,我們不會傳遞標題的實際英文文本,而是我們將傳遞索引序列,其中每個索引代表一個唯一的單詞。
由于我們已經為每個單詞創建了一個索引,現在讓我們用它們的索引替換單詞,并理解數據矩陣將是什么樣子:
用索引替換單詞后的數據矩陣
由于我們將進行批處理(稍后解釋),我們需要確保每個序列的長度相等。因此,我們需要在每個序列的末尾追加0。但是我們應該在每個序列中添加多少個零?
這就是我們計算標題最大長度為34的原因(如果你還記得)。因此,我們將附加許多零,這將導致每個序列的長度為34。
數據矩陣將如下所示:
在每個序列上附加零,使它們全長相同34
需要數據生成器:
我希望這能讓您更好地了解我們如何為此問題準備數據集。然而,這有一個很大的問題。在上面的例子中,我只考慮了2個圖像和標題,這些圖像和標題導致了15個數據點。
但是,在我們的實際訓練數據集中,我們有6000張圖像,每張圖像有5個字幕。這使得總共30000個圖像和標題。即使假設平均每個字幕只有5個字長,也會導致總計30000 * 5,即150000個數據點。
我們再做一些計算:
每個數據點的長度是多少?
數據點的長度=圖像矢量的長度+部分字幕的長度。
圖像特征向量的長度= 2048(已經討論過)
但部分字幕的長度是多少?
嗯,你可能認為它是34,但這是錯的。
每個單詞(或索引)將通過一種單詞嵌入技術映射(嵌入)到更高維度的空間。
之后,在模型構建階段,我們將看到每個單詞/索引使用預先訓練的GLOVE單詞嵌入模型映射到200長的向量。
現在每個序列包含34個索引,其中每個索引是長度為200的向量。因此,一個數據點的長度為:
2048 +(34 * 256)= 8848。
從最小的方面來看,我們至少可以獲得150,000個數據點。因此,數據矩陣的大小是:
150,000 * 10752 = 1327200000塊。
現在,即使我們假設一個塊占用2個字節,然后,為了存儲該數據矩陣,我們將需要接近3 GB的主存儲器。 (回想一下,我們假設字幕的平均長度為5個字,可能更多)。
這是非常大的要求,即使我們能夠設法將這么多數據加載到RAM中,它也會使系統變得非常慢。
出于這個原因,我們在深度學習中使用了很多數據生成器。數據生成器是一種在Python中本機實現的功能。Keras API提供的ImageDataGenerator類只不過是Python中生成器函數的實現。
那么使用生成器函數如何解決這個問題呢?
如果您了解深度學習的基礎知識,那么您必須知道要在特定數據集上訓練模型,我們需要使用某些版本的隨機梯度下降(SGD),如Adam,Rmsprop,Adagrad等。
對于SGD,我們不計算整個數據集的損失來更新梯度。而是在每次迭代中,我們計算一批數據點(通常為64,128,256等)上的損失以更新梯度。
這意味著我們不需要立即將整個數據集存儲在內存中。即使我們在內存中有當前的一批點,但它足以達到我們的目的。
Python中的生成器函數完全用于此目的。它就像一個迭代器,從最后一次調用它的位置恢復功能。
數據生成器的代碼如下:
11.字嵌入
如上所述,我們將把每個單詞(索引)映射到一個200長的向量,為此,我們將使用預先訓練好的GLOVE模型:
現在,對于我們詞匯表中的所有1652個獨特單詞,創建了一個嵌入矩陣,該矩陣將在訓練之前加載到模型中。
12.模型架構
由于輸入由兩部分組成,即圖像矢量和部分字幕,因此我們無法使用Keras庫提供的Sequential API。 出于這個原因,我們使用Functional API,它允許我們創建合并模型。
首先讓我們看一下包含高級子模塊的簡要架構:
高水平的架構
我們將模型定義如下:
讓我們看看模型摘要:
模型中的參數摘要
下圖有助于可視化網絡結構并更好地理解兩個輸入流:
帶有注釋的架構圖
右側的黑色文本是為您提供的注釋,用于將您對數據準備的理解映射到模型體系結構。
LSTM(長短期記憶)層只是一個專門的回歸神經網絡來處理序列輸入(在我們的例子中是部分字幕)。
如果您已按照上一節進行操作,我認為閱讀這些注釋可幫助您以直接的方式理解模型體系結構。
回想一下,我們已經從預先訓練的GLOVE模型中創建了一個嵌入矩陣,我們需要在開始訓練之前將其包含在模型中:
請注意,由于我們使用的是預先訓練好的嵌入層,因此我們需要在訓練模型之前將其凍結(trainable = False),以便在反向傳播期間不會更新它。
最后,我們使用adam優化器編譯模型
訓練期間的超參數:
然后將該模型訓練30個時期,初始學習率為0.001,每批3個圖片(批量)。然而,在20個時期之后,學習率降低到0.0001并且模型被訓練為每批6張圖片。
這通常是有道理的,因為在訓練的后期階段,模型正趨向收斂,我們必須降低學習率,以便我們朝著最小值邁出更小的步伐。隨著時間的推移增加批量大小有助于您的梯度更新更強大。
時間:我在www.paperspace.com上使用了GPU + Gradient Notebook,因此我花了大約一個小時訓練模型。但是,如果您在沒有GPU的PC上進行訓練,則可能需要8到16個小時,具體取決于您的系統配置。
13.推理
所以到目前為止我們已經看到了如何準備數據和構建模型。在本系列的最后一步中,我們將了解如何通過傳入新圖像來測試(推斷)我們的模型,即如何為新測試圖像生成標題。
回想一下,在我們看到如何準備數據的示例中,我們只使用了前兩個圖像及其標題。現在讓我們使用第三個圖像,并嘗試了解我們希望如何生成標題。
第三個圖像矢量和標題如下:
Image_3 - >黑貓正在草地上行走
此示例中的詞匯還包括:
vocab = {black,cat,endseq,grass,is,on,road,sat,startseq,the,walking,white},具有以下索引:
黑色-1,貓-2,endseq -3,草-4,是-5,在-6,道路-7,坐-8,startseq -9,-10,行走-11,白色-12
我們將迭代生成標題,一次一個字如下:
迭代1:
我們提供圖像矢量Image_3以及'startseq'作為模型的部分標題。 (您現在應該理解'startseq'的重要性,它在推理期間用作任何圖像的初始部分標題)。
我們現在期望我們的模型預測第一個單詞“the”。
但等等,該模型生成一個12長的向量(在示例中,而在原始示例中為1652長向量),這是詞匯表中所有單詞的概率分布。出于這個原因,我們貪婪地選擇具有最大概率的單詞,給定特征向量和部分標題。
如果模型訓練得很好,我們必須期望單詞“the”的概率最大:
推論1
這稱為最大似然估計(MLE),即我們根據給定輸入的模型選擇最可能的單詞。有時這種方法也被稱為貪婪搜索,因為我們貪婪地選擇具有最大概率的單詞。
迭代2:
這一次讓我們假設模型已經預測了前一次迭代中的“the”。所以現在我們將模型的輸入作為圖像矢量Image_3和部分標題“startseq the”。現在我們期望模型在給定圖像特征向量和部分字幕的情況下產生“黑色”一詞的最高概率。
推論2
通過這種方式,我們繼續迭代以生成序列中的下一個單詞。但這里的一個重要問題是我們什么時候停止?
因此,當滿足以下兩個條件之一時,我們就會停止:
我們遇到'endseq',這意味著模型認為這是標題的結尾。 (您現在應該了解'endseq'標記的重要性)
我們達到模型生成的單詞數的最大閾值。
如果滿足上述任何條件,我們將打破循環并將生成的標題報告為給定圖像的模型輸出。推理代碼如下:
14.評估
為了理解模型有多好,讓我們嘗試在測試數據集的圖像上生成標題(即模型在訓練期間沒有看到的圖像)。
輸出- 1
注意:我們必須了解模型如何精確識別顏色。
輸出- 2
輸出- 3
輸出- 4
輸出- 5
當然,如果我只向你展示合適的字幕,那我就是在騙你。世界上沒有任何模型是完美的,這種模式也會犯錯誤。讓我們看一些例子,其中標題不是很相關,有時甚至是不相關的。
輸出 - 6
可能是襯衫的顏色與背景中的顏色混合在一起
輸出- 7
為什么模特將著名的拉斐爾·納達爾歸為女性?可能是因為長發。
輸出- 8
這次模型得到的語法不正確
輸出- 9
很明顯,該模型盡力了解情景,但標題仍然不是很好。
輸出- 10
再一個例子,模型失敗,標題無關緊要。
總而言之,我必須說,我的初始化模型,沒有任何嚴格的超參數調整,在生成圖像標題方面做得不錯。
很重要的一點:
我們必須明白,用于測試的圖像必須在語義上與用于訓練模型的圖像相關。例如,如果我們在貓、狗等的圖像上訓練我們的模型,我們就不能在飛機、瀑布等圖像上進行測試。這是一個例子,火車和測試裝置的分布會有很大不同,在這種情況下,世界上沒有機器學習模型可以提供良好的性能。
15.結論和未來的工作
請參閱我的GitHub鏈接,以訪問Jupyter Notebook中編寫的完整代碼。
(https://github.com/hlamba28/Automatic-Image-Captioning.git)
請注意,由于模型的隨機性,您生成的標題(如果您嘗試復制代碼)可能與我的情況下生成的標題不完全相似。
當然,這只是第一個解決方案,可以進行大量修改以改善此解決方案,如:
使用更大的數據集。
改變模型架構,例如包括一個注意模塊。
進行更多超參數調整(學習率、批量大小、層數、單位數、輟學率等)。
使用交叉驗證集來了解過度擬合。
在推理期間使用Beam Search而不是Greedy Search。
使用BLEU評分來評估和衡量模型的性能。
以適當的面向對象的方式編寫代碼,以便其他人更容易復制:-)
16.參考文獻
https://cs.stanford.edu/people/karpathy/cvpr2015.pdf
https://arxiv.org/abs/1411.4555
https://arxiv.org/abs/1703.09137
https://arxiv.org/abs/1708.02043
https://machinelearningmastery.com/develop-a-deep-learning-caption-generation-model-in-python/
https://www.youtube.com/watch?v=yk6XDFm3J2c
https://www.appliedaicourse.com/
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。