自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用機器學習生成圖像描述

人工智能 機器學習
圖像描述是為圖像提供適當文字描述的過程。 作為人類,這似乎是一件容易的任務,即使是五歲的孩子也可以輕松完成,但是我們如何編寫一個將輸入作為圖像并生成標題作為輸出的計算機程序呢?

在深度神經網絡的最新發(fā)展之前,業(yè)內最聰明的人都無法解決這個問題,但是在深度神經網絡問世之后,考慮到我們擁有所需的數據集,這樣做是完全有可能的。

例如,網絡模型可以生成與下圖相關的以下任何標題,即“A white dog in a grassy area”,“white dog with brown spots”甚至“A dog on grass and some pink flowers ”。

[[395666]]

數據集

我們選擇的數據集為“ Flickr 8k”。 我們之所以選擇此數據,是因為它易于訪問且具有可以在普通PC上進行訓練的完美大小,也足夠訓練網絡生成適當的標題。 數據分為三組,主要是包含6k圖像的訓練集,包含1k圖像的開發(fā)集和包含1k圖像的測試集。 每個圖像包含5個標題。 示例之一如下:

使用機器學習生成圖像描述

A child in a pink dress is climbing up a set of stairs in an entryway.

A girl going into a wooden building.

A little girl climbing into a wooden playhouse.

A little girl climbing the stairs to her playhouse.

A little girl in a pink dress going into a wooden cabin.

數據清理

任何機器學習程序的第一步也是最重要的一步是清理數據并清除所有不需要的數據。在處理標題中的文本數據時,我們將執(zhí)行基本的清理步驟,例如將計算機中的所有字母都轉換為小寫字母“ Hey”和“ hey”是兩個完全不同的單詞,刪除特殊標記和標點符號,例如*, (,£,$,%等),并消除所有包含數字的單詞。

我們首先為數據集中的所有唯一內容創(chuàng)建詞匯表,即8000(圖片數量)* 5(每個圖像的標題)= 40000標題。我們發(fā)現它等于8763。但是這些詞中的大多數只出現了1到2次,我們不希望它們出現在我們的模型中,因為這不會使我們的模型對異常值具有魯棒性。因此,我們將詞匯中包含的單詞的最少出現次數設置為10個閾值,該閾值等于1652個唯一單詞。

我們要做的另一件事是在每個描述中添加兩個標記,以指示字幕的開始和結束。這兩個標記分別是“ startseq”和“ endseq”,分別表示字幕的開始和結尾。

首先,導入所有必需的庫:

  1. import numpy as np   
  2. from numpy import array   
  3. import pandas as pd   
  4. import matplotlib.pyplot as plt   
  5. import string   
  6. import os   
  7. from PIL import Image   
  8. import glob   
  9. import pickle   
  10. from time import time   
  11. from keras.preprocessing import sequence   
  12. from keras.models import Sequential   
  13. from keras.layers import LSTM, Embedding, Dense, Flatten, Reshape, concatenate, Dropout   
  14. from keras.optimizers import Adam   
  15. from keras.layers.merge import add   
  16. from keras.applications.inception_v3 import InceptionV3   
  17. from keras.preprocessing import image   
  18. from keras.models import Model   
  19. from keras import Input, layers   
  20. from keras.applications.inception_v3 import preprocess_input   
  21. from keras.preprocessing.sequence import pad_sequences   
  22. from keras.utils import to_categorical  

讓我們定義一些輔助函數:

  1. load descriptions   
  2. def load_doc(filename):   
  3. file = open(filename, 'r')   
  4. text = file.read()   
  5. file.close()   
  6. return text   
  7.   
  8.   
  9. def load_descriptions(doc):   
  10. mapping = dict()   
  11. for line in doc.split('\n'):   
  12. tokens = line.split()   
  13. if len(line) < 2:   
  14. continue   
  15. image_id, image_desc = tokens[0], tokens[1:]   
  16. image_id = image_id.split('.')[0]   
  17. image_desc = ' '.join(image_desc)   
  18. if image_id not in mapping:   
  19. mapping[image_id] = list()   
  20. mapping[image_id].append(image_desc)   
  21. return mapping   
  22.   
  23. def clean_descriptions(descriptions):   
  24. table = str.maketrans('''', string.punctuation)   
  25. for key, desc_list in descriptions.items():   
  26. for i in range(len(desc_list)):   
  27. desc = desc_list[i]   
  28. desc = desc.split()   
  29. desc = [word.lower() for word in desc]   
  30. desc = [w.translate(tablefor w in desc]   
  31. desc = [word for word in desc if len(word)>1]   
  32. desc = [word for word in desc if word.isalpha()]   
  33. desc_list[i] = ' '.join(desc)   
  34.   
  35. return descriptions   
  36.   
  37. # save descriptions to file, one per line   
  38. def save_descriptions(descriptions, filename):   
  39. lines = list()   
  40. for key, desc_list in descriptions.items():   
  41. for desc in desc_list:   
  42. lines.append(key + ' ' + desc)   
  43. data = '\n'.join(lines)   
  44. file = open(filename, 'w')   
  45. file.write(data)   
  46. file.close()   
  47.   
  48.   
  49. load clean descriptions into memory   
  50. def load_clean_descriptions(filename, dataset):   
  51. doc = load_doc(filename)   
  52. descriptions = dict()   
  53. for line in doc.split('\n'):   
  54. tokens = line.split()   
  55. image_id, image_desc = tokens[0], tokens[1:]   
  56. if image_id in dataset:   
  57. if image_id not in descriptions:   
  58. descriptions[image_id] = list()   
  59. desc = 'startseq ' + ' '.join(image_desc) + ' endseq'   
  60. descriptions[image_id].append(desc)   
  61. return descriptions   
  62.   
  63. def load_set(filename):   
  64. doc = load_doc(filename)   
  65. dataset = list()   
  66. for line in doc.split('\n'):   
  67. if len(line) < 1:   
  68. continue   
  69. identifier = line.split('.')[0]   
  70. dataset.append(identifier)   
  71. return set(dataset)   
  72.   
  73. load training dataset   
  74.   
  75.   
  76. filename = "dataset/Flickr8k_text/Flickr8k.token.txt"   
  77. doc = load_doc(filename)   
  78. descriptions = load_descriptions(doc)   
  79. descriptions = clean_descriptions(descriptions)   
  80. save_descriptions(descriptions, 'descriptions.txt')   
  81. filename = 'dataset/Flickr8k_text/Flickr_8k.trainImages.txt'   
  82. train = load_set(filename)   
  83. train_descriptions = load_clean_descriptions('descriptions.txt', train)  

讓我們一一解釋:

load_doc:獲取文件的路徑并返回該文件內的內容

load_descriptions:獲取包含描述的文件的內容,并生成一個字典,其中以圖像id為鍵,以描述為值列表

clean_descriptions:通過將所有字母都轉換為小寫字母,忽略數字和標點符號以及僅包含一個字符的單詞來清理描述

save_descriptions:將描述字典作為文本文件保存到內存中

load_set:從文本文件加載圖像的所有唯一標識符

load_clean_descriptions:使用上面提取的唯一標識符加載所有已清理的描述

數據預處理

接下來,我們對圖像和字幕進行一些數據預處理。 圖像基本上是我們的特征向量,即我們對網絡的輸入。 因此,我們需要先將它們轉換為固定大小的向量,然后再將其傳遞到神經網絡中。 為此,我們使用了由Google Research [3]創(chuàng)建的Inception V3模型(卷積神經網絡)進行遷移學習。 該模型在'ImageNet'數據集[4]上進行了訓練,可以對1000張圖像進行圖像分類,但是我們的目標不是進行分類,因此我們刪除了最后一個softmax層,并為每張圖像提取了2048個固定矢量,如圖所示 以下:

使用機器學習生成圖像描述

標題文字是我們模型的輸出,即我們必須預測的內容。 但是預測并不會一次全部發(fā)生,而是會逐字預測字幕。 為此,我們需要將每個單詞編碼為固定大小的向量(將在下一部分中完成)。 為此,我們首先需要創(chuàng)建兩個字典,即“單詞到索引”將每個單詞映射到一個索引(在我們的情況下為1到1652),以及“索引到單詞”將字典將每個索引 映射到其對應的單詞字典。 我們要做的最后一件事是計算在數據集中具有最大長度的描述的長度,以便我們可以填充所有其他內容以保持固定長度。 在我們的情況下,該長度等于34。

字詞嵌入

如前所述,我們將每個單詞映射到固定大小的向量(即200)中,我們將使用預訓練的GLOVE模型。 最后,我們?yōu)樵~匯表中的所有1652個單詞創(chuàng)建一個嵌入矩陣,其中為詞匯表中的每個單詞包含一個固定大小的向量。

  1. Create a list of all the training captions   
  2. all_train_captions = []   
  3. for key, val in train_descriptions.items():   
  4. for cap in val:   
  5. all_train_captions.append(cap)   
  6.   
  7.   
  8. # Consider only words which occur at least 10 times in the corpus   
  9. word_count_threshold = 10   
  10. word_counts = {}   
  11. nsents = 0   
  12. for sent in all_train_captions:   
  13. nsents += 1   
  14. for w in sent.split(' '):   
  15. word_counts[w] = word_counts.get(w, 0) + 1   
  16.   
  17. vocab = [w for w in word_counts if word_counts[w] >= word_count_threshold]   
  18. print('Preprocessed words {} -> {}'.format(len(word_counts), len(vocab)))   
  19.   
  20.   
  21. ixtoword = {}   
  22. wordtoix = {}   
  23.   
  24. ix = 1   
  25. for w in vocab:   
  26. wordtoix[w] = ix   
  27. ixtoword[ix] = w   
  28. ix += 1   
  29.   
  30. vocab_size = len(ixtoword) + 1 # one for appended 0's   
  31.   
  32. Load Glove vectors   
  33. glove_dir = 'glove.6B'   
  34. embeddings_index = {}   
  35. f = open(os.path.join(glove_dir, 'glove.6B.200d.txt'), encoding="utf-8")   
  36.   
  37. for line in f:   
  38. values = line.split()   
  39. word = values[0]   
  40. coefs = np.asarray(values[1:], dtype='float32')   
  41. embeddings_index[word] = coefs   
  42. f.close()   
  43.   
  44. embedding_dim = 200   
  45.   
  46. # Get 200-dim dense vector for each of the words in out vocabulary   
  47. embedding_matrix = np.zeros((vocab_size, embedding_dim))   
  48.   
  49. for word, i in wordtoix.items():   
  50. embedding_vector = embeddings_index.get(word)   
  51. if embedding_vector is not None:   
  52. embedding_matrix[i] = embedding_vector  
  53.   

讓我們接收下這段代碼:

第1至5行:將所有訓練圖像的所有描述提取到一個列表中

第9-18行:僅選擇詞匯中出現次數超過10次的單詞

第21–30行:創(chuàng)建一個要索引的單詞和一個對單詞詞典的索引。

第33–42行:將Glove Embeddings加載到字典中,以單詞作為鍵,將vector嵌入為值

第44–52行:使用上面加載的嵌入為詞匯表中的單詞創(chuàng)建嵌入矩陣

數據準備

這是該項目最重要的方面之一。 對于圖像,我們需要使用Inception V3模型將它們轉換為固定大小的矢量,如前所述。

  1. # Below path contains all the images   
  2. all_images_path = 'dataset/Flickr8k_Dataset/Flicker8k_Dataset/'   
  3. Create a list of all image names in the directory   
  4. all_images = glob.glob(all_images_path + '*.jpg')   
  5.   
  6. Create a list of all the training and testing images with their full path names   
  7. def create_list_of_images(file_path):   
  8. images_names = set(open(file_path, 'r').read().strip().split('\n'))   
  9. images = []   
  10.   
  11. for image in all_images:   
  12. if image[len(all_images_path):] in image_names:   
  13. images.append(image)   
  14.   
  15. return images   
  16.   
  17.   
  18. train_images_path = 'dataset/Flickr8k_text/Flickr_8k.trainImages.txt'   
  19. test_images_path = 'dataset/Flickr8k_text/Flickr_8k.testImages.txt'   
  20.   
  21. train_images = create_list_of_images(train_images_path)   
  22. test_images = create_list_of_images(test_images_path)   
  23.   
  24. #preprocessing the images   
  25. def preprocess(image_path):   
  26. img = image.load_img(image_path, target_size=(299, 299))   
  27. x = image.img_to_array(img)   
  28. x = np.expand_dims(x, axis=0)   
  29. x = preprocess_input(x)   
  30. return x   
  31.   
  32. Load the inception v3 model   
  33. model = InceptionV3(weights='imagenet')   
  34.   
  35. Create a new model, by removing the last layer (output layer) from the inception v3   
  36. model_new = Model(model.input, model.layers[-2].output)   
  37.   
  38. # Encoding a given image into a vector of size (2048, )   
  39. def encode(image):   
  40. image = preprocess(image)   
  41. fea_vec = model_new.predict(image)   
  42. fea_vec = np.reshape(fea_vec, fea_vec.shape[1])   
  43. return fea_vec   
  44.   
  45.   
  46. encoding_train = {}   
  47. for img in train_images:   
  48. encoding_train[img[len(all_images_path):]] = encode(img)   
  49.   
  50.   
  51. encoding_test = {}   
  52. for img in test_images:   
  53. encoding_test[img[len(all_images_path):]] = encode(img)   
  54.   
  55. # Save the bottleneck features to disk   
  56. with open("encoded_files/encoded_train_images.pkl""wb"as encoded_pickle:   
  57. pickle.dump(encoding_train, encoded_pickle)   
  58.   
  59. with open("encoded_files/encoded_test_images.pkl""wb"as encoded_pickle:   
  60. pickle.dump(encoding_test, encoded_pickle)   
  61.   
  62.   
  63. train_features = load(open("encoded_files/encoded_train_images.pkl""rb"))  
  1. 第1-22行:將訓練和測試圖像的路徑加載到單獨的列表中
  2. 第25–53行:循環(huán)訓練和測試集中的每個圖像,將它們加載為固定大小,對其進行預處理,使用InceptionV3模型提取特征,最后對其進行重塑。
  3. 第56–63行:將提取的特征保存到磁盤

現在,我們不會一次預測所有的標題文字,因為我們不只是將圖像提供給計算機,并要求它為其生成文字。 我們要做的就是給它圖像的特征向量,以及標題的第一個單詞,并讓它預測第二個單詞。 然后我們給它給出前兩個單詞,并讓它預測第三個單詞。 讓我們考慮數據集部分中給出的圖像和標題“一個女孩正在進入木結構建筑”。 在這種情況下,在添加令牌“ startseq”和“ endseq”之后,以下分別是我們的輸入(Xi)和輸出(Yi)。

使用機器學習生成圖像描述

此后,我們將使用我們創(chuàng)建的“索引”字典來更改輸入和輸出中的每個詞以映射索引。 在進行批處理時,我們希望所有序列的長度均等,這就是為什么要在每個序列后附加0直到它們成為最大長度(如上所述計算為34)的原因。 正如人們所看到的那樣,這是大量的數據,將其立即加載到內存中是根本不可行的,為此,我們將使用一個數據生成器將其加載到小塊中降低是用的內存。

  1. # data generator, intended to be used in a call to model.fit_generator()   
  2. def data_generator(descriptions, photos, wordtoix, max_length, num_photos_per_batch):   
  3. X1, X2, y = list(), list(), list()   
  4. n=0   
  5. # loop for ever over images   
  6. while 1:   
  7. for key, desc_list in descriptions.items():   
  8. n+=1   
  9. # retrieve the photo feature   
  10. photo = photos[key+'.jpg']   
  11. for desc in desc_list:   
  12. # encode the sequence   
  13. seq = [wordtoix[word] for word in desc.split(' ') if word in wordtoix]   
  14. # split one sequence into multiple X, y pairs   
  15. for i in range(1, len(seq)):   
  16. # split into input and output pair   
  17. in_seq, out_seq = seq[:i], seq[i]   
  18. # pad input sequence   
  19. in_seq = pad_sequences([in_seq], maxlen=max_length)[0]   
  20. # encode output sequence   
  21. out_seq = to_categorical([out_seq], num_classes=vocab_size)[0]   
  22. # store   
  23. X1.append(photo)   
  24. X2.append(in_seq)   
  25. y.append(out_seq)   
  26. # yield the batch data   
  27. if n==num_photos_per_batch:   
  28. yield [[array(X1), array(X2)], array(y)]   
  29. X1, X2, y = list(), list(), list()   
  30. n=0  

上面的代碼遍歷所有圖像和描述,并生成表中的數據項。 yield將使函數再次從同一行運行,因此,讓我們分批加載數據

模型架構和訓練

如前所述,我們的模型在每個點都有兩個輸入,一個輸入特征圖像矢量,另一個輸入部分文字。 我們首先將0.5的Dropout應用于圖像矢量,然后將其與256個神經元層連接。 對于部分文字,我們首先將其連接到嵌入層,并使用如上所述經過GLOVE訓練的嵌入矩陣的權重。 然后,我們應用Dropout 0.5和LSTM(長期短期記憶)。 最后,我們將這兩種方法結合在一起,并將它們連接到256個神經元層,最后是一個softmax層,該層預測我們詞匯中每個單詞的概率。 可以使用下圖概括高級體系結構:

 

使用機器學習生成圖像描述

 

以下是訓練期間選擇的超參數:損失被選擇為“categorical-loss entropy”,優(yōu)化器為“Adam”。 該模型總共訓練了30輪,但對于前20輪,批次大小和學習率分別為0.001和3,而接下來的10輪分別為0.0001和6。

  1. inputs1 = Input(shape=(2048,))   
  2. fe1 = Dropout(0.5)(inputs1)   
  3. fe2 = Dense(256, activation='relu')(fe1)   
  4. inputs2 = Input(shape=(max_length1,))   
  5. se1 = Embedding(vocab_size, embedding_dim, mask_zero=True)(inputs2)   
  6. se2 = Dropout(0.5)(se1)   
  7. se3 = LSTM(256)(se2)   
  8. decoder1 = add([fe2, se3])   
  9. decoder2 = Dense(256, activation='relu')(decoder1)   
  10. outputs = Dense(vocab_size, activation='softmax')(decoder2)   
  11. model = Model(inputs=[inputs1, inputs2], outputs=outputs)   
  12.   
  13. model.layers[2].set_weights([embedding_matrix])   
  14. model.layers[2].trainable = False   
  15.   
  16. model.compile(loss='categorical_crossentropy', optimizer='adam')   
  17.   
  18. epochs = 20   
  19. number_pics_per_batch = 3   
  20. steps = len(train_descriptions)//number_pics_per_batch   
  21.   
  22. generator = data_generator(train_descriptions, train_features, wordtoix, max_length1, number_pics_per_batch)   
  23. history = model.fit_generator(generator, epochs=20, steps_per_epoch=steps, verbose=1)   
  24.   
  25.   
  26. model.optimizer.lr = 0.0001   
  27. epochs = 10   
  28. number_pics_per_batch = 6   
  29. steps = len(train_descriptions)//number_pics_per_batch   
  30.   
  31. generator = data_generator(train_descriptions, train_features, wordtoix, max_length1, number_pics_per_batch)   
  32. history1 = model.fit_generator(generator, epochs=10, steps_per_epoch=steps, verbose=1)   
  33. model.save('saved_model/model_' + str(30) + '.h5')  

讓我們來解釋一下代碼:

第1-11行:定義模型架構

第13–14行:將嵌入層的權重設置為上面創(chuàng)建的嵌入矩陣,并且還設置trainable = False,因此該層將不再受任何訓練

第16–33行:如上所述,使用超參數在兩個單獨的間隔中訓練模型

推理

下面顯示了前20輪的訓練損失,然后是接下來的10輪的訓練損失:

使用機器學習生成圖像描述

為了進行推斷,我們編寫了一個函數,該函數根據我們的模型(即貪心)將下一個單詞預測為具有最大概率的單詞

  1. def greedySearch(photo):   
  2. in_text = 'startseq'   
  3. for i in range(max_length1):   
  4. sequence = [wordtoix[w] for w in in_text.split() if w in wordtoix]   
  5. sequence = pad_sequences([sequence], maxlen=max_length1)   
  6. yhat = model.predict([photo,sequence], verbose=0)   
  7. yhat = np.argmax(yhat)   
  8. word = ixtoword[yhat]   
  9. in_text += ' ' + word   
  10. if word == 'endseq':   
  11. break   
  12. final = in_text.split()   
  13. final = final[1:-1]   
  14. final = ' '.join(final)   
  15. return final   
  16.   
  17. z=1   
  18. pic = list(encoding_test.keys())[999]   
  19. image = encoding_test[pic].reshape((1,2048))   
  20. x=plt.imread(images+pic)   
  21. plt.imshow(x)   
  22. plt.show()   
  23. print("Greedy:",greedySearch(image))  
使用機器學習生成圖像描述

效果還不錯

 

責任編輯:華軒 來源: 今日頭條
相關推薦

2018-01-15 15:58:17

機器學習色彩還原k-means算法

2022-06-05 21:16:08

機器學習Python

2022-05-19 10:27:34

機器學習人工智能

2017-05-03 19:08:10

機器學習

2022-06-09 09:14:31

機器學習PythonJava

2024-09-09 11:45:15

ONNX部署模型

2017-09-01 18:17:40

2023-11-22 13:10:01

2022-08-15 15:16:20

機器學習圖片深度學習

2023-02-03 11:40:49

機器學習分析情感

2022-07-13 09:00:00

機器學習eBay數據

2017-07-07 14:41:13

機器學習神經網絡JavaScript

2019-09-30 10:12:21

機器學習數據映射

2017-08-25 14:29:43

機器學習Java

2021-11-02 09:40:50

TensorFlow機器學習人工智能

2017-09-09 06:04:22

深度學習人物圖像神經網絡

2010-07-02 08:53:06

MIS SQL Ser

2019-12-03 10:22:50

AWSAI亞馬遜

2009-09-29 16:48:42

Hibernate J

2009-11-09 12:30:23

WCF生成代理
點贊
收藏

51CTO技術棧公眾號