數(shù)據(jù)集:
數(shù)據(jù)集中的訓(xùn)練集使用的是coco train 2014,82783張圖片,測試集使用的是 val 2017 ,5000張圖片,對應(yīng)的caption是captions_train2014.json,和captions_val2017.json。
該文件中是以字典的形式包含其內(nèi)容信息,key值由“info”,”licenses“,”images“,”annotations“組成。
info:其中包括數(shù)據(jù)集建立的時間。下載地址,版本號等。
licenses:是數(shù)據(jù)集使用條款。
images:包括圖片的filename,height,width ,圖片對應(yīng)的網(wǎng)址,圖片對應(yīng)的caption的id。
annotation:包含image_id,對應(yīng)的caption的id,和每個圖片對應(yīng)的5句描述-
訓(xùn)練:
訓(xùn)練集使用的是coco train 2014中的全部數(shù)據(jù)。
-
測試:
測試集使用的是coco val 2017中的的數(shù)據(jù)。
-
數(shù)據(jù)預(yù)處理:
build_data.py中定義了以下幾個函數(shù):
1.def load_and_process_metadata(captions_file,image_dir):
with open(captions_file, encoding='utf-8') as f:
lines = f.readline()
d = json.loads(lines)
print(d)
f.close()
d["images"]
d["images"]中包含的內(nèi)容
[{'license':6,'file_name':'000000492110.jpg','coco_url':'http://images.cocodataset.org/val2017/000000492110.jpg', 'height': 427, 'width': 640, 'date_captured': '2013-11-24 00:43:28', 'flickr_url': 'http://farm9.staticflickr.com/8195/8139005828_fda85b4b72_z.jpg', 'id': 492110}]
d["annotations"]中包含的內(nèi)容
[{'image_id': 54592, 'id': 562033, 'caption': 'Couple of people walking up the snowy mountain with skis'},
{'image_id': 23034, 'id': 561930, 'caption': 'A man smiles watching a rider approach with two horses.'}]
captions_file:caption_train2014.json和val_2014.json文件的路徑。
image_dir:train_2014和val_2014的路徑。
函數(shù)作用:
讀取json文件將image和對應(yīng)的caption對應(yīng),將內(nèi)容封裝到 ImageMetadata中,這時的一個image_id對應(yīng)一個filename對應(yīng)五個captions
效果

描述captions
'Beef and other food on a plate next to a wine glass',
'A finished steak dinner and glass of wine are on a table.',
'some food and a fork is on a plate',
'A plate with fork and steak and a wine glass on placemat with papers in background.',
'a rare steak with a fork and a glass of wine

圖片描述captions
'A blue vase filled with colorful flowers sitting on the ground.',
'A blue vase on table holding red flowers next to door.',
'A bunch of orange flowers in a blue vase on a runner on a table.',
'A blue glass vase with some flowers on a table.',
'A blue glass vase with red and yellow flowers
namedtuple("ImageMetadata",["image_id","filename",'captions']
1.讀取json文件使用json中的json.loads()方法。
2.索取json中的信息就直接使用字典中的方法就好。
2.def process_caption(caption):
tokenized_caption=[FLAGS.start_word]
tokenized_caption.extend(nltk.tokenize.word_tokenize(caption.lower()))
tokenized_caption.extend(FLAGS.end_word)
函數(shù)作用:將”start_word“和”end_word“加載到每句話中的開始和結(jié)束,作用類似于起始密碼子,終止密碼子,蛋白質(zhì)合成的起始,和終止。并把caption變成小寫,目的不讓同一個單詞在vocabulary字典中出現(xiàn)兩次節(jié)省資源。
1.使用方法是用列表中的entend方法
3.def create_vocab(captions):
counter = Counter()
for c in captions:
counter.update(c)
word_counts = [x for x in counter.items() if x[1] >= 4]
word_counts.sort(key=lambda x: x[1], reverse=True)
函數(shù)作用:統(tǒng)計caption中的所有單詞,和出現(xiàn)的頻率,并把單詞以及單詞出現(xiàn)的頻率
寫入到txt文件中。
1.使用到的方法有collections 中 Counter,Counter是一個計數(shù)器,將單詞輸入其中可
直接將單詞的出現(xiàn)頻率顯示出來。并將重復(fù)的單詞去除。并只取單詞中頻率大于4的。并從小到大排序。然后創(chuàng)建一個字典將排序好的單詞取出,將單詞從0~vocab_size給單詞賦一個id。
4.class Vocabulary(object):
def __init__(self, vocab, unk_id):
vocab:是單詞帶有對應(yīng)id的字典。
unk_id:是對應(yīng)vocab_size,也就是單詞的長度,如果單詞沒在制作的dict中就返回
一個空的字符。
word_to_id(self, word):
給定caption中的單詞,如果單詞在dict中返回對應(yīng)的word_id,不在就返回unk_id。
5. def process_dataset()
函數(shù)作用:這時的一個image仍然是對應(yīng)一個caption。將image遍歷,使每一個image對應(yīng)一個caption。然后將caption,和image讀入tfrecord中。
images = [ImageMetadata(image.image_id, image.filename, [caption])
for image in images for caption in image.captions]
random.seed(12345)
random.shuffle(images)
使用random的方法將image_caption的順序打亂。
-
tfrecord的使用方法
定義寫入tfrecord文件地writer
writer=tf.python_io.TFRecordwriter(filename) # filename:tfrecord保存的地址
文件名隊列在上述的images中已經(jīng)構(gòu)造好了
for i in range(len(images))
image=images[i]:
獲取每個image對應(yīng)的圖片地址+文件名
image_filename=image.filename
獲取每句image的描述
caption=image.captions
獲得每句caption的id
caption_id=word_to_id(caption)
-
讀入image,并解碼
with tf.gfile.FastGFile(image.filename, "rb") as f:
encoded_image = f.read()
解碼:
1. tf.decode_csv() 解碼文件文本內(nèi)容
2.tf.image.decode_jpeg(countent) 將jpeg編碼的圖像解碼為uint8張量
3.tf.image.decode_png(content) 將png編碼的圖像解碼為uint8張量
4.tf.decode_raw(value,uint8)解碼二進制內(nèi)容
構(gòu)造example:
def _int64_feature(value):
"""將int 64特性插入序列中的包裝器"""
return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
def _bytes_feature(value):
"""將字節(jié)特性插入序列示例Proto的包裝器"""
value = tf.compat.as_bytes(value)
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
def _int64_feature_list(values):
"""將int 64 FeatureList插入序列的包裝器-示例Proto"""
return tf.train.FeatureList(feature=[_int64_feature(v) for v in values])
def _bytes_feature_list(values):
"""將字節(jié)FeatureList插入序列示例Proto的包裝器"""
return tf.train.FeatureList(feature=[_bytes_feature(v) for v in values])
context = tf.train.Features(feature={
"image/image_id":_int64_feature(image.image_id),
"image/data": _bytes_feature(encoded_image),
})
feature_lists = tf.train.FeatureLists(feature_list={
"image/caption": _bytes_feature_list(caption),
"image/caption_ids": _int64_feature_list(caption_ids)
})
那么什么樣的數(shù)據(jù)需要映射為FeatureList或Feature?
我的理解是數(shù)字表示,二分類就是0或1,那么就class=0映射為tf.train.Feature(tf.train.Int64List(value=[0])), 只要這個字段包含的數(shù)據(jù)維度是固定的,就可以封裝為 Feature。
對于長度不固定的字段類型,映射為FeatureList。比如NLP樣本有一個特征是一句話,那么一句話的長度是不固定的,NLP中一般是先分詞,然后把每個詞對應(yīng)為該詞在字典中的索引,一句話就用一個一維整形數(shù)組來表示 [2, 3, 5, 20, ...],這個數(shù)組的長度是不固定的,我們就映射為
這里將caption通過上述的函數(shù)word_to_id中將caption轉(zhuǎn)化為caption_id。
sequence_example = tf.train.SequenceExample(
context=context, feature_lists=feature_lists)
將caption的feature和images的feature保存到tf.train.SequenceExample中,
將序列化后的example寫入文件
wtiter.write(example.SerializeToString())
write.close()
讀取tfrecord
-
構(gòu)造文件名讀取隊列
1.將需要讀取的文件名放入到文件名隊列中
tf.train.string_input_producer(data_file,shuffle=True)
data_file:tfrecord的文件名
shuffle=True:默認文件名隨機打亂
-
讀取
使用TFRecorder的方法讀入
_,serialized_example=reader.read(filename_queue)
-
解析example
context, sequence = tf.parse_single_sequence_example(example_serialized,
context_features={
image_feature: tf.FixedLenFeature([], dtype=tf.string)},
sequence_features={
caption_feature: tf.FixedLenSequenceFeature([], dtype=tf.int64) })
self.encoded_image = context[image_feature]
self.caption = sequence[caption_feature]
-
解碼
解碼仍然使用上述中的解碼方法
tf.image.decode_jpeg(self.encoded_image)
使用tf.cast()方法將其轉(zhuǎn)換為tf.float32,由于每張圖片的大小可能不是統(tǒng)一大小的,為了方便后面的cnn提取特征,將圖片統(tǒng)一大小。使用tf.image.resize_images(image,size=[])
在圖片處理時將圖片進行數(shù)據(jù)歸一化,優(yōu)點是
1.歸一化后加快梯度下降求最優(yōu)解的速度
2.歸一化后有可能提高精度
3.使用梯度法求最優(yōu)解時,歸一化往往非常有必要,否則模型很難收斂,甚至不能收斂
方法1
image = tf.image.convert_image_dtype(image, dtype=tf.float32) # 將圖片像素值變?yōu)閇0,1]
image = tf.subtract(image, 0.5) # 圖片像素值域由[0, 1]變換為[-0.5,0.5]
image = tf.multiply(image, 2.0) # 圖片像素值域由[0,0.5]變?yōu)閇-1,1]
方法2
def image_to_float(image)
image = tf.image.convert_image_dtype(image, dtype=tf.float32)
return (image/127.5) - 1.0
方法3
在人臉識別中用到的直接將特征值除以255的簡單縮放法
圖片處理
在對圖片處理時要進行以下操作,目的是為了防止過擬合,過擬合是指我們訓(xùn)練的模型“實在是太好了”對與訓(xùn)練的數(shù)據(jù)分類預(yù)測效果都特別好,而面對新的數(shù)據(jù)時變現(xiàn)的效果可能就沒那么好了。我們訓(xùn)練數(shù)據(jù)的目的是讓模型既不過擬合,也不是欠擬合,而是處于過擬合與欠擬合之間的一種狀態(tài)。欠擬合是指無論是對于測試集還是訓(xùn)練集的效果,表現(xiàn)得都不是很好。就比如我們復(fù)習(xí)數(shù)學(xué)吧,我們只把課本上的題會做理解,而考試面對新的題,可能只是修改個數(shù)我們就做的不太好,這種狀態(tài)稱為過擬合。而我們連書的內(nèi)容看都不看的話,啥題都不會的情況就是欠擬合。
image = tf.image.random_flip_left_right(image)
調(diào)整圖片的隨機亮度
image = tf.image.random_brightness(image, max_delta=32 / 255)
調(diào)整圖片飽和度
image = tf.image.random_saturation(image, lower=0.5, upper=1.5)
隨機調(diào)整RGB圖像的色調(diào)
image = tf.image.random_hue(image, max_delta=0.032)
在某范圍隨機調(diào)整圖片對比度
image = tf.image.random_contrast(image, lower=0.5, upper=1.5)
輸入一個張量image,把image中的每一個元素的值都壓縮在min和max之間。小于min的讓它等于min,大于max的元素值等于max
image = tf.clip_by_value(image, 0, 1.0)
- 對caption構(gòu)造input_sequence,target_sequence
images_and_captions = []
images_and_captions.append([image, self.caption])
enqueue_list = []
for image, caption in images_and_captions:
# 獲取每個句子的長度
caption_length = tf.shape(caption)[0]
# 將句子id向后移動一
input_length = tf.expand_dims(tf.subtract(caption_length, 1), 0)
# 真正句子的id
input_seq = tf.slice(caption, [0], input_length)
# 句子向有移動后的句子id目的是為了預(yù)測下一個單詞
target_seq = tf.slice(caption, [1], input_length)
indicator = tf.ones(input_length, dtype=tf.int32)
enqueue_list.append([image, input_seq, target_seq, indicator])
-
構(gòu)造批出理隊列
有兩種方法:tf.train.batch和tf.train.batch_join的區(qū)別,一般來說,單一文件多線程,那么選用tf.train.batch(需要打亂樣本,有對應(yīng)的tf.train.shuffle_batch);而對于多線程多文件的情況,一般選用tf.train.batch_join來獲取樣本(打亂樣本同樣也有對應(yīng)的tf.train.shuffle_batch_join使用)。
第一種
tf.train.batch_join(enqueue_list,
batch_size=self.batch_size,
capacity=queue_capacity,
dynamic_pad=True,
name="batch_and_pad"))
第二種
tf.train.batch(enquene_list,
batch=self.batch_size,
capacity=queue_capacity,
name="batch_and_pad")
-
構(gòu)造image_embedding
將解碼后的圖片經(jīng)過CNN的全連接層后生成[batch_size,512]的向量 -
構(gòu)造caption_embedding
將輸入的seq變成詞向量,詞向量才能在lstm中進行訓(xùn)練計算
原理就是
image.png
這里假設(shè)詞表中有“我,愛,河,南,科,技”6個字,在類比one-hot編碼的時候就形成了一個[6,6]的矩陣emdedding-map,然后我如果想取出其中的兩個單詞“河”,“南”那么就需要查emdedding-map。進行類似的矩陣相乘得到兩個詞的詞向量。
embedding_map=tf.get_variable(name="map",shape[vocab_size,512],initializer=self.initializer)
seq_embeddings = tf.nn.embedding_lookup(embedding_map, self.input_seqs)
返回的是tensor 的 shape是 [batch_size,word_size,512]
模型:
1.結(jié)構(gòu)
-
CNN
1,cnn使用的是inceptionv3模型:主要提取圖片的特征,
inceptionv3具有很少的參數(shù)量,節(jié)省計算時間加快學(xué)習(xí)速度;5x5的卷積核用兩個3x3的 卷積核代替增強表達能力,為減少計算復(fù)雜度將卷積轉(zhuǎn)化為稀疏連接以下展示cnn的結(jié)構(gòu)圖;





2.模型輸入的image尺寸為299x299X3 ,batch_size=32 數(shù)據(jù)類型為float32
shape:[batch_size, height, width, channels]
4.使用batch_normalization.(簡稱BN)
BN是一種解決深度神經(jīng)網(wǎng)絡(luò)層數(shù)太多,而沒有辦法有效向前傳遞的問題,因為每一層的輸出值都會有不同的均值,和方差,所以輸出的數(shù)據(jù)分布也不一樣。
優(yōu)點:
1.他不僅加快模型的收斂速度,而且更重要的是在一定程度上緩解了深度網(wǎng)絡(luò)中的“梯度彌散”(就是在靠近輸出層的hidden layer梯度越大,參數(shù)更新快,但是靠近輸入層的hidden layer梯度小,參數(shù)更新慢,幾乎和初始狀態(tài)一樣,隨機分布。梯度爆炸與之相反)總體來說就是梯度相當(dāng)不穩(wěn)定。
2.控制過擬合可以減少或不用dropout
3.降低網(wǎng)絡(luò)對初始化權(quán)重不敏感
4.允許使用較大的學(xué)習(xí)率
所以使用BN可以使得模型訓(xùn)練更加容易和穩(wěn)定。BN從字面意思來說就是每一批數(shù)據(jù)進行歸一化,這里分批在前面的數(shù)據(jù)準備里已經(jīng)進行了分批處理。BN可以在網(wǎng)絡(luò)中任意一層進行歸一化處理,V3-inception使用到的優(yōu)化器是SGD。
沒有使用BN的時候每層的值迅速全部變?yōu)榱?,也就是說所有的神經(jīng)元都已經(jīng)死了,而有BN,relu過后,每層的值都能有一個比較好的分布效果。
QQ截圖20190604122213.png
數(shù)據(jù)如果在梯度很小的區(qū)域,那么學(xué)習(xí)率就會很慢甚至長時間停滯,但是減均值除方差后,數(shù)據(jù)就被移到中心區(qū)域,如右圖所示,對于大多數(shù)激活函數(shù)來說,這個區(qū)域的梯度都是很大的。這個用來解決梯度消失。但是如果每一層都是這樣做的話,數(shù)據(jù)的分布總是隨著變化敏感的區(qū)域,相當(dāng)于不用考慮數(shù)據(jù)分布變化了這樣訓(xùn)練起來更有效率。但是減均值除方差得到的分布是正態(tài)分布,但是并不是正態(tài)分布就是最好或者最能體現(xiàn)我們訓(xùn)練樣本的特征分布。因為數(shù)據(jù)本身很多情況下是不對稱的,或者激活函數(shù)未必是對方差為1的數(shù)據(jù)最好的效果,就比如sigmoid激活函數(shù),在-1到1之間的梯度變化不大。這樣的話對于非線性變化的作用就不能很好的提現(xiàn),換言之就是,均方誤差操作后可能會削弱網(wǎng)絡(luò)的性能,所以再加一步利用優(yōu)化變一下方差大小和均值位置,使得新的分布更切合數(shù)據(jù)的真實分布,保證模型的非線性表達能力。
卷積層
作用:通過在原始圖像上平移來提取特征
tf.nn.conv2(input,fitter,strides,padding)
input:是傳入四個維度的圖片或者上一層卷積得到的tensor
fitter:卷積核相當(dāng)于權(quán)重有初始值有形狀,
strides:步長大小,決定卷積核每次移動的步長,決定了卷積后的圖片大小。
padding:可設(shè)置為‘’SAME“,"VALID"當(dāng)padding=SAME時下一層的圖片長寬計算new_widh=w/s(向上取整)。padding=VALID時new_width=(w-f+1)/s。w為圖片的長寬,f是卷積核大小,s是步長
激活函數(shù)
作用:增加非線性分割能力,對輸入的數(shù)據(jù)原始空間進行扭曲。
- relu
1,有效的解決了梯度小時問題
2,計算速比較快
SGD:(批梯度下降)的求解速度遠快于sigmoid和tanh
sigmoid:采用sigmoid缺點:計算量相對大,而采用relu激活函數(shù),整個過程的計算量節(jié)省很多,在深層神經(jīng)網(wǎng)絡(luò)中,sigmoid函數(shù)反向傳播時很容易出現(xiàn)梯度消失的情況
池化層
作用:減小學(xué)習(xí)參數(shù),降低網(wǎng)絡(luò)的復(fù)雜度
池化層分為最大池化和平均池化,一般最常用最大池化,最大池化是在卷積核大小的feature_map上取最大值,因為這個最大值可以反映了這個feature周圍的特征。
內(nèi)部的池化窗口和卷積核類似,以及步長,padding
Incpetion V3中將5×5的卷積替換成了兩個3×3的卷積
而且在這個module中還是用了卷積的分解,將一個7×7的卷積拆分成了一個1×7的卷積和一個7×1的卷積,不僅能夠大大節(jié)省參數(shù)降低模型的過擬合,還能比一個7×7的卷積多一個非線性的變換。另外inceptionv3將卷積網(wǎng)絡(luò)進行了拆分,其結(jié)果比對稱的拆分為幾個相同的小卷積核效果更明顯,可以處理更多,更豐富的空間特征,增加特征多樣性。
-
LSTM
對于LSTM神經(jīng)網(wǎng)絡(luò)無論是從什么角度描述,中間做的一堆事情,還是找什么樣的特征是最適合做這樣的一個分類任務(wù),最終連接softmax是用于分類。時序t就是每個單詞輸入的先后順序,它結(jié)合上一時刻的輸出同時乘以權(quán)重當(dāng)做這一時刻的輸入20181205233257613.png
定義RNN的基本單元
lstm_cell=tf.contrib.rnn.BasicLSTMCell(num_units=512,state_is_tuple=True)
為了防止過擬合,在LSTM中也添加了dropout層,分別使input,和output的值控制在0.7
lstm_cell=tf.contrib.rnn.DropoutWrapper(lstm_cell,input_keep_prob=0.7,
output_keep_prob=0.7)
定義圖中的隱狀態(tài):hi,可以把隱狀態(tài)視作記憶體,它捕捉了之前時間點上的信息。記憶體在RNN迭代的過程也在不斷地更新內(nèi)部的記憶,就像人的大腦一樣,不斷地記住新的東西,又在忘記舊的
獲得lstm全零狀態(tài)
zero_state=lstm_cell.zero_state(batch_size=batch_size,dtype=tf.float32)
更新lstm狀態(tài),這里將經(jīng)過CNN后提取得到的特征向量輸入到lstm_cell
_,initial_state=lstm_cell(self.image_embeddings,zero_state)
定義RNN循環(huán),在這里將句子的特征向量self.seq_embeddings輸入到RNN中.sequence_length:圖片對應(yīng)的caption的句子長度。
initial_state:更新后的initial_state。
lstm_outputs, _ = tf.nn.dynamic_rnn(cell=lstm_cell, inputs=self.seq_embeddings,
sequence_length=sequence_length,
initial_state=initial_state,
dtype=tf.float32,
scope=lstm_scope)
在lstm最后添加一個全連接層作為最終的輸出
num_outputs:定義輸出的維度
weights_initializer:設(shè)置權(quán)重參數(shù),
該函數(shù)默認使用relu的激活函數(shù)
logits = tf.contrib.layers.fully_connected(
inputs=lstm_outputs,
num_outputs=10000,
activation_fn=None,
weights_initializer=self.initializer,
scope=logits_scope)
2.原理
-
構(gòu)造損失函數(shù)
損失函數(shù)使用softmax的交叉熵損失函數(shù),target是logits經(jīng)過向右移動一后得到的caption的id,target經(jīng)過tf.cast(tf.reshape(self.seq_target,[-1]),dtype=tf.float32)后才能傳到交叉熵中計算logits對于target的偏離程度
方法1
losses=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=targets)
weights:是一個數(shù)值全為1的shape=[batch_size*word_size]的一維數(shù)組
因為每個批次的數(shù)據(jù)都會產(chǎn)生不同的loss值,將每個批次得到的損失值除以批次大小,得到每個批次的平均損失
batch_loss=tf.div(tf.reduce_sum(tf.multiply(losses,weights)),tf.reduce_sum(weights),name="batch_loss")
tf.losses.add_loss(batch_loss)
total_loss=tf.losses.get_total_loss()
方法2
正確的答案,這里將[batch_size,num_steps]二維數(shù)組轉(zhuǎn)換為一維數(shù)組損失的權(quán)重。在這里所有的權(quán)重都為1,也就是說不同batch和不同時刻的重要程度是一樣的。
loss=tf.contrib.legacy_seq2seq.sequence_loss_by_example(
[logits],[tf.reshape(self.targets,[-1][tf.ones([batch_size*num_steps],dtype=tf.float32)] )
計算得到每個batch的平均損失
total_cost=tf.reduce_sum(loss)/batch_size
3.實驗
-
訓(xùn)練
-
超參數(shù)
1.learning_rate
指數(shù)衰減法:
如果staircase=True,代表每decay_step步更新一次learning_rate,如果staircase=False,那就每次迭代都會更新學(xué)習(xí)率。學(xué)習(xí)率計算方法
image
-
最初設(shè)置learning_rate=2.0
tf.train.exponential_decay(learning_rate,global_step,decay_steps=decay_step,decay_rate=0.5 , staircase=True)
1,global_step:用于衰減計算的全局步數(shù)。喂入一次batch_size 計為一次global_step
2,decay_step:衰減速度(num_examples_per_epoch/batch_size)*num_epochs_per_decay
num_example_per_epoch:所有的image_caption的數(shù)量
batch_size:batch_size一般設(shè)置為2的n次冪,這里設(shè)置為32
num_epochs_per_decay設(shè)置的是8
3,decay_rate:衰減系數(shù)
多項式學(xué)習(xí)率衰減
polynomial_decay(learning_rate, global_step, decay_steps,end_learning_rate=0.0001, power=1.0,cycle=False, name=None):
在對抗神經(jīng)網(wǎng)絡(luò)中使用的一種學(xué)習(xí)率衰減方法,特點是確定結(jié)束的學(xué)習(xí)率,學(xué)習(xí)率更新公式是:
decayed_learning_rate = (learning_rate - end_learning_rate) *(1 - global_step / decay_steps) ^ (power) + end_learning_rate
對于神經(jīng)網(wǎng)絡(luò)中三個參數(shù)的概念:
epoch: 訓(xùn)練時,所有訓(xùn)練數(shù)據(jù)都訓(xùn)練一次,即所有數(shù)據(jù)的個數(shù)
batch:使用訓(xùn)練集中的一小部分樣本對模型進行一次反向傳播的參數(shù)更新,這一小部分樣本稱為“一批數(shù)據(jù)”。
batch_size: 在訓(xùn)練集中選擇一組樣本用來更新權(quán)值。一個batch_size包含的樣本數(shù)目,通常設(shè)為2的n次冪,常用的包括32,64,128,256,網(wǎng)絡(luò)較小的時候使用256,較大時使用32,或者16.
實例:
數(shù)據(jù)集中有50000張訓(xùn)練的圖片數(shù)量,現(xiàn)在選擇batch_size=256對模型進行訓(xùn)練。
每個epoch要訓(xùn)練的圖片數(shù)量:50000
訓(xùn)練集具有的batch數(shù)50000/256=196(向上取整)
每個epoch需要完成的batch數(shù)196
每個epoch中發(fā)生的模型權(quán)重更新次數(shù):196
不同次的epoch訓(xùn)練雖然用的都是訓(xùn)練集的五萬張圖片,但是對模型的權(quán)重跟新值卻是不同的,因為不同次的模型處于的loss在空間上的不同位置,模型的訓(xùn)練次數(shù)越靠后,越接近谷底,loss也就越小。
優(yōu)化函數(shù)
優(yōu)化函數(shù)使用的是隨機梯度下降SGD:SGD是每一次迭代計算mini-batch的梯度,然后對參數(shù)進行更新,計算梯度的方法是求偏導(dǎo),對于訓(xùn)練數(shù)據(jù)集,我們首先將其分成n個batch,每個batch包含m個樣本。我們每次更新都利用一個batch的數(shù)據(jù),而非整個訓(xùn)練集、
優(yōu)點:
當(dāng)訓(xùn)練數(shù)據(jù)太多時,將訓(xùn)練集分成一個一個批次,可以減少機器的壓力,并且可以更快地收斂
-
測試
-
運行結(jié)果
p是概率,因為生成的圖片描述不是只有三句,所以三句話的概率和不為零,只是挑選了三句概率最大的打印出來。

-
結(jié)果分析
效果由于在訓(xùn)練時loss值沒有下降到最小,所以效果不是太好,圖中是兩個長頸鹿站在草地上,但是在后面兩句將長頸鹿預(yù)測成大象。
參考鏈接:
1.在構(gòu)建讀取隊列時可以開啟多線程:https://zhuanlan.zhihu.com/p/47760620和https://zhuanlan.zhihu.com/p/40588218
2.在lstm的構(gòu)建和理解:https://www.cnblogs.com/hypnus-ly/p/8407905.html
3.caption的詞向量方面:https://www.bilibili.com/video/av35575799/?p=7
4.cnn模型https://blog.csdn.net/loveliuzz/article/details/79135583



