圖像理解(Image Captioning)(1)CNN部分


一、 應用領域

  • 圖像搜索
    在這里插入圖片描述
  • 安全監控
    在這里插入圖片描述
  • 鑒黃
    在這里插入圖片描述

二、 原理

  • CNN(卷積神經⽹絡)
  1. 圖像特征提取
  2. 遷移學習(transfer learning)
  • LSTM(遞歸神經⽹絡)
  1. ⽂字串(sequence)的特征提取
  • DNN(深度神經⽹絡)
  1. 從圖像特征和⽂字串(sequence)
    的特征預測下⼀個單詞

通過鏈接這兩個網絡,使用CNN提取圖像特征,再使用LSTM提取文本特征,再通過多層的DNN網絡即可實現將文本特征與圖像特征的鏈接實現圖像理解

三、使用的環境與數據集

3.1. 環境

在這里插入圖片描述

3.2. 數據集

(Framing Image Description as a Ranking Task: Data, Models and Evaluation Metrics, 2013.)
• Flickr8K
• 8000 圖像, 每幅圖5個標題, 描述圖像⾥⾯的事物和事件
• 不包含著名⼈物和地點
• 分為3個集合: 6000個訓練圖像, 1000個開發圖像, 1000個測試圖像

數據示例:
在這里插入圖片描述

			終極⽬標: ⾃動⽣成圖像英⽂標題, 與⼈類⽣成的標題們越相似越好

四、網絡模型

4.1 理想⽹絡模型

在這里插入圖片描述

4.1.1 CNN網絡模型

CNN模型我們以VGG16為例(也可以選擇其他模型均可)
GG16 (Very Deep Convolutional Networks for Large-Scale Visual Recognition)

  • Pre-trained model: Oxford Visual Geometry Group贏得2014ImageNet競賽
  • ⽤於圖像分類, 將輸⼊圖像分為1000個類別
  • 模型結構如下圖所示:
  • 在這里插入圖片描述在這里插入圖片描述

Tips:
因為VGG16 CNN 原本的⽬標是分類, 基於ImageNet數據集進⾏訓練,訓練所需的時間⽐較⼤,需要4個GPU訓練3個星期左右。因此我們使用遷移學習(transfer learning),基本保留網絡原有的結構和權重,只略微調整VGG16的⽹絡輸出結構為圖像標題⽣成服務:
• VGG16 的最后⼀層是將倒數第⼆層4096維的輸出轉為1000維的輸出作為1000類別的分類概率
• 我們可以去除最后⼀層,將倒數第⼆層的4096維的輸出作為圖像標題⽣成模型的圖像特征,如下圖紅色框中所示。
在這里插入圖片描述

五、實現步驟

總體步驟:

  • 提取圖像的特征(利⽤VGG16的修改模型)
  • 初始化圖像標題為”startseq”
  • 循環如下步驟:
    • 將圖像標題轉換為整數數組,每⼀個標題的單詞對應於唯⼀⼀個整數
    • 將圖像特征和當前的圖像標題作為輸⼊, 預測標題的下⼀個單詞, 假設單詞為word1
    • 將word1添加到當前標題的結尾
    • 如果word1的值為”endseq”, 或者當前標題的⻓度達到了標題最⼤⻓度, 退出循環
    • 此刻的圖像標題就是預測的值

5.1 使⽤keras創建VGG16定義的CNN⽹絡結構

from keras.models import Sequential
from keras.layers import Dense, Flatten
from keras.layers import Conv2D
from keras.layers import MaxPooling2D


def generate_vgg16():
    """
    搭建VGG16網絡結構
    :return: VGG16網絡
    """
    input_shape = (224, 224, 3)
    model = Sequential([
        Conv2D(64, (3, 3), input_shape=input_shape, padding='same', activation='relu'),
        Conv2D(64, (3, 3), padding='same', activation='relu'),
        MaxPooling2D(pool_size=(2,2), strides=(2,2)),
        Conv2D(128, (3, 3), padding='same', activation='relu'),
        Conv2D(128, (3, 3), padding='same', activation='relu'),
        MaxPooling2D(pool_size=(2, 2), strides=(2, 2)),
        Conv2D(256, (3, 3), padding='same', activation='relu'),
        Conv2D(256, (3, 3), padding='same', activation='relu'),
        Conv2D(256, (3, 3), padding='same', activation='relu'),
        MaxPooling2D(pool_size=(2, 2), strides=(2, 2)),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        MaxPooling2D(pool_size=(2, 2), strides=(2, 2)),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        MaxPooling2D(pool_size=(2,2), strides=(2,2)),
        Flatten(),
        Dense(4096, activation='relu'),
        Dense(4096, activation='relu'),
        Dense(1000, activation='softmax')
    ])

    return model

if __name__ == '__main__':
    model = generate_vgg16()
    model.summary()

5.2 提取圖像特征

			`目標:將flicker8k的圖像⽂件轉為圖像特征, 保存為字典pickle⽂件`
  1. 從給定的VGG16⽹絡結構⽂件和⽹絡權值⽂件, 創建VGG16⽹絡
def load_vgg16_model():
    """從當前目錄下面的 vgg16_exported.json 和 vgg16_exported.h5 兩個文件中導入 VGG16 網絡並返回創建的網絡模型
    # Returns
        創建的網絡模型 model
    """
    json_file = open("vgg16_exported.json", "r")
    loaded_model_json = json_file.read()
    json_file.close()

    model=model_from_json(loaded_model_json)
    model.load_weights("vgg16_exported.h5")

    return model
  1. 修改⽹絡結構(去除最后⼀層)
model=load_vgg16_model()
# pop the last layer
model.layers.pop()
model = Model(inputs=model.inputs, outputs=model.layers[-1].output)
  1. 利⽤修改的⽹絡結構,提取flicker8k數據集中所有圖像的特征,使⽤字典存儲, key為⽂件名, value為⼀個⽹絡的輸出。

def extract_features(directory):
    features = dict()
    for fn in listdir(directory):
        fn=directory+'/'+fn
        arr=load_img_as_np_array(fn, target_size=(224, 224))

        # 改變數組的形態,增加一個維度(批處理輸入的維度)
        arr=arr.reshape((1,arr.shape[0],arr.shape[1],arr.shape[2]))

        # 預處理圖像作為VGG模型的輸入
        arr = preprocess_input(arr)

        # 計算特征
        feature =model.predict(arr, verbose=0)

        # 分離文件名和路徑以及分離文件名和后綴
        (filepath, tempfilename) = os.path.split(fn)
        (filename, extension) = os.path.splitext(tempfilename)
        id=tempfilename
        print(id)
        features[id]=feature

    return features
  1. 將字典保存為features.pkl⽂件(使⽤pickle庫)
features = extract_features(directory)
    print('提取特征的文件個數:%d' % len(features))
    print(keras.backend.image_data_format())
    #保存特征到文件
    dump(features, open('features.pkl', 'wb'))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM