在前面兩篇文章中Part-1,Part-2,我們編寫了很多函數(shù)用于讀取文件并生成bottleneck文件并隨機(jī)批量讀取褐啡。
這一篇我們將繼續(xù)編寫相關(guān)的訓(xùn)練罩锐、測試函數(shù)奉狈。
添加最終再訓(xùn)練操作add_final_retrain_ops
我們需要重新訓(xùn)練頂層top layer來識別新的分類,這個函數(shù)將向graph添加一些操作涩惑,隨著一些變量保存權(quán)重仁期,然后為所有反向傳播設(shè)置梯度變化。
這個函數(shù)將為訓(xùn)練和計算添加新的softmax和全連接層(密集層)竭恬。
增加和修改的代碼如下:
#添加最終再訓(xùn)練操作ops跛蛋,一個softmax層一個dense層
#注意這里的quantize_layer為真假值,但必須與create_module_graph(module_spec)得到的wants_quantization一致痊硕,否則出錯
def add_final_retrain_ops(class_count,final_tensor_name,
bottleneck_tensor,quantize_layer,is_training):
batch_size, bottleneck_tensor_size = bottleneck_tensor.get_shape().as_list()
assert batch_size is None, '我們希望針對任意批次大小進(jìn)行計算'
with tf.name_scope('input'):
bottleneck_input = tf.placeholder_with_default(
bottleneck_tensor,
shape=[batch_size, bottleneck_tensor_size],
name='BottleneckInputPlaceholder')
ground_truth_input = tf.placeholder(tf.int64, [batch_size], name='GroundTruthInput')
#組織下面的操作使他們在Tensorboard中可見
layer_name = 'final_retrain_ops'
with tf.name_scope(layer_name):
with tf.name_scope('weights'):
initial_value = tf.truncated_normal( #正態(tài)截取赊级,上下不超過0.001*2
[bottleneck_tensor_size, class_count], stddev=0.001)
layer_weights = tf.Variable(initial_value, name='final_weights')
variable_summaries(layer_weights)
with tf.name_scope('biases'):
layer_biases = tf.Variable(tf.zeros([class_count]), name='final_biases')
variable_summaries(layer_biases)
with tf.name_scope('Wx_plus_b'):
logits = tf.matmul(bottleneck_input, layer_weights) + layer_biases
tf.summary.histogram('pre_activations', logits)
final_tensor = tf.nn.softmax(logits, name=final_tensor_name)
if quantize_layer:
if is_training:
tf.contrib.quantize.create_training_graph() #自動重寫graph量子化,僅新增的layer被變換岔绸,訓(xùn)練用
else:
tf.contrib.quantize.create_eval_graph() #預(yù)測用
tf.summary.histogram('activations', final_tensor) #for TensorBoard
if not is_training: #對于預(yù)測理逊,不需要添加損失函數(shù)或優(yōu)化器橡伞,所以返回兩個None
return None, None, bottleneck_input, ground_truth_input, final_tensor
with tf.name_scope('cross_entropy'): #平均交叉熵作為損失函數(shù)
cross_entropy_mean = tf.losses.sparse_softmax_cross_entropy(labels=ground_truth_input, logits=logits)
tf.summary.scalar('cross_entropy', cross_entropy_mean)
with tf.name_scope('train'):
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1) #梯度漸變優(yōu)化函數(shù)
train_step = optimizer.minimize(cross_entropy_mean)
return (train_step, cross_entropy_mean, bottleneck_input, ground_truth_input,final_tensor)
#入口函數(shù)
def main(_):
tf.logging.set_verbosity(tf.logging.WARN)
module_spec = hub.load_module_spec(HUB_MODULE)
graph, bottleneck_tensor, resized_image_tensor, wants_quantization = (
create_module_graph(module_spec))
with graph.as_default():
result = add_final_retrain_ops(5, 'final_tensor_name',
bottleneck_tensor,wants_quantization, is_training=True)
打印result輸出下面內(nèi)容,都是新graph中的各種操節(jié)點或張量:
(
<tf.Operation 'train/GradientDescent' type=NoOp>, #train_step
<tf.Tensor 'cross_entropy/sparse_softmax_cross_entropy_loss/value:0' shape=() dtype=float32>,#cross_entropy_mean
<tf.Tensor 'input/BottleneckInputPlaceholder:0' shape=(?, 1280) dtype=float32>, #bottleneck_input
<tf.Tensor 'input/GroundTruthInput:0' shape=(?,) dtype=int64>, #ground_truth_input
<tf.Tensor 'final_tensor_name:0' shape=(?, 5) dtype=float32> #final_tensor
)
執(zhí)行最終再訓(xùn)練并保存run_final_retrain
從hub讀取模型,創(chuàng)建圖以及相關(guān)操作入口晋被,添加各種操作(訓(xùn)練操作骑歹、圖片解碼等),讀取bottleneck數(shù)據(jù)墨微,然后開始運作道媚,使用變形扭曲的bottleneck數(shù)據(jù)或者緩存的,sess.run運行訓(xùn)練操作翘县。
同時注意summary信息的保存和checkpoint模型保存最域。
以下是增加和修改的代碼,結(jié)合之前代碼可以運行:
#保存概要和checkpoint路徑設(shè)置
CHECKPOINT_NAME = os.path.join(dir_path,'checkpoints/retrain')
summaries_dir=os.path.join(dir_path,'summaries/train')
#執(zhí)行訓(xùn)練兵保存checkpoint的函數(shù)
def run_final_retrain(do_distort=True):
tf.logging.set_verbosity(tf.logging.WARN)
module_spec = hub.load_module_spec(HUB_MODULE)
#創(chuàng)建圖并獲取相關(guān)的張量入口
graph, bottleneck_tensor, resized_image_tensor, wants_quantization = (
create_module_graph(module_spec))
with graph.as_default():
#添加訓(xùn)練相關(guān)的張量和操作節(jié)點入口
(train_step, cross_entropy, bottleneck_input,ground_truth_input,
final_tensor) = add_final_retrain_ops(5, 'final_tensor_name',
bottleneck_tensor,wants_quantization,True)
with tf.Session(graph=graph) as sess:
init = tf.global_variables_initializer()
sess.run(init)
#添加圖片解碼相關(guān)的張量入口操作
jpeg_data_tensor, decoded_image_tensor = add_jpeg_decoding(module_spec)
#讀取圖片的bottleneck數(shù)據(jù)
if do_distort:
distorted_jpeg_data_tensor,distorted_image_tensor=add_input_distortions(module_spec,True,50,50,50)
else:
cache_bottlenecks(sess,
jpeg_data_tensor,decoded_image_tensor,
resized_image_tensor,bottleneck_tensor)
#記錄概要信息與保存
train_saver = tf.train.Saver()
merged = tf.summary.merge_all()
train_writer = tf.summary.FileWriter(summaries_dir,sess.graph)
#開始運作锈麸!
for i in range(5):
#獲取圖片bottleneck數(shù)據(jù)
if do_distort:
(train_bottlenecks,train_ground_truth) = get_random_distorted_bottlenecks(
sess,100, 'training',
distorted_jpeg_data_tensor,distorted_image_tensor,
resized_image_tensor, bottleneck_tensor)
else:
(train_bottlenecks,train_ground_truth, _) = get_random_cached_bottlenecks(
sess, 100, 'training',
jpeg_data_tensor,decoded_image_tensor,
resized_image_tensor, bottleneck_tensor)
#啟動訓(xùn)練
train_summary, _ = sess.run([merged, train_step],feed_dict={bottleneck_input: train_bottlenecks,ground_truth_input: train_ground_truth})
train_writer.add_summary(train_summary, i)
#保存模型
train_saver.save(sess, CHECKPOINT_NAME)
#入口函數(shù)
def main(_):
run_final_retrain()
運行可能需要幾分鐘時間镀脂,成功后將會生成checkpoints文件夾和summaries文件夾及包含了概要信息和模型文件。
增加評價模型預(yù)測精度的操作add_evaluation_step
評價方法需要輸入新的圖片特征數(shù)據(jù)和對應(yīng)的標(biāo)簽忘伞,這里的函數(shù)接著上面的再訓(xùn)練函數(shù)得到的final_tensor, ground_truth_input薄翅,作為新的輸入口,實現(xiàn)評價功能氓奈。
增加和修改的代碼如下:
#插入評價精確度的操作翘魄,返回元組(evaluation step, prediction)
def add_evaluation_step(result_tensor, ground_truth_tensor):
with tf.name_scope('accuracy'):
with tf.name_scope('correct_prediction'):
prediction = tf.argmax(result_tensor, 1) #獲取axis=1維度的最大值,即預(yù)測結(jié)果
correct_prediction = tf.equal(prediction, ground_truth_tensor) #預(yù)測與標(biāo)簽是否相等
with tf.name_scope('accuracy'):
evaluation_step = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) #跨維度計算平均數(shù)
tf.summary.scalar('accuracy', evaluation_step)
return evaluation_step, prediction
#入口函數(shù)
def main(_):
tf.logging.set_verbosity(tf.logging.WARN)
module_spec = hub.load_module_spec(HUB_MODULE)
graph, bottleneck_tensor, resized_image_tensor, wants_quantization = (
create_module_graph(module_spec))
with graph.as_default():
(train_step, cross_entropy, bottleneck_input,ground_truth_input,
final_tensor) = add_final_retrain_ops(5,'final_tensor_name',bottleneck_tensor,
wants_quantization,is_training=True)
with tf.Session(graph=graph) as sess:
result=add_evaluation_step(final_tensor, ground_truth_input)
打印result的輸出是兩個張量:
(
<tf.Tensor 'accuracy/accuracy/Mean:0' shape=() dtype=float32>, #evaluation_step
<tf.Tensor 'accuracy/correct_prediction/ArgMax:0' shape=(?,) dtype=int64> #prediction
)
創(chuàng)建用于評估的會話build_eval_session
從存儲的訓(xùn)練圖checkpoint文件讀取變量舀奶,恢復(fù)到評價圖暑竟,并利用上面的函數(shù)add_evaluation_step添加評估操作。
下面是新增和修改的代碼:
#保存概要和checkpoint路徑設(shè)置
CHECKPOINT_NAME = os.path.join(dir_path,'checkpoints/retrain')
#創(chuàng)建和恢復(fù)評價會話(沒有訓(xùn)練操作)育勺,用于導(dǎo)出結(jié)果
#返回一個包含評價圖的會話但荤,以及相關(guān)其他張量和操作
def build_eval_session(module_spec, class_count):
eval_graph, bottleneck_tensor, resized_input_tensor, wants_quantization = (
create_module_graph(module_spec))
eval_sess = tf.Session(graph=eval_graph)
with eval_graph.as_default(): #添加新的導(dǎo)出層
(_, _, bottleneck_input,ground_truth_input,
final_tensor) = add_final_retrain_ops(class_count, 'final_tensor_name',
bottleneck_tensor,wants_quantization,is_training=False)
#把訓(xùn)練圖的值恢復(fù)到評價圖
tf.train.Saver().restore(eval_sess, CHECKPOINT_NAME)
# 添加評估操作
evaluation_step, prediction = add_evaluation_step(final_tensor,
ground_truth_input)
return (eval_sess, resized_input_tensor, bottleneck_input, ground_truth_input,
evaluation_step, prediction)
#入口函數(shù)
def main(_):
tf.logging.set_verbosity(tf.logging.WARN)
module_spec = hub.load_module_spec(HUB_MODULE)
graph, bottleneck_tensor, resized_image_tensor, wants_quantization = (
create_module_graph(module_spec))
with graph.as_default():
result=build_eval_session(module_spec, 5)
print(result)
輸出結(jié)果類似如下內(nèi)容:
(
<tensorflow.python.client.session.Session object at 0x120babdd8>, #sess
<tf.Tensor 'Placeholder:0' shape=(?, 224, 224, 3) dtype=float32>, #resized_input_tensor
<tf.Tensor 'input/BottleneckInputPlaceholder:0' shape=(?, 1280) dtype=float32>, #bottleneck_input
<tf.Tensor 'input/GroundTruthInput:0' shape=(?,) dtype=int64>, #ground_truth_input
<tf.Tensor 'accuracy/accuracy/Mean:0' shape=() dtype=float32>, #evaluation_step
<tf.Tensor 'accuracy/correct_prediction/ArgMax:0' shape=(?,) dtype=int64> #prediction
)
執(zhí)行最終評估運算run_final_eval
首先我們需要創(chuàng)建用于評估的會話build_eval_session,然后利用get_random_cached_bottlenecks獲取一些隨機(jī)的圖像數(shù)據(jù)涧至,就可以sess.run運行起來腹躁,把bottleneck數(shù)據(jù)作為feed_dict填充進(jìn)去了。
下面是增加和修改的代碼:
#執(zhí)行最終評估運算
def run_final_eval(sess, module_spec, class_count,
jpeg_data_tensor, decoded_image_tensor,
resized_image_tensor, bottleneck_tensor):
#創(chuàng)建評估會話
(sess, _, bottleneck_input, ground_truth_input, evaluation_step,
prediction) = build_eval_session(module_spec, class_count)
#隨機(jī)獲取bottleneck
test_bottlenecks, test_ground_truth, test_filenames = (
get_random_cached_bottlenecks(sess, BATCH_SIZE,'testing',
jpeg_data_tensor,decoded_image_tensor,
resized_image_tensor,bottleneck_tensor))
#運行評估南蓬!
test_accuracy, predictions = sess.run(
[evaluation_step, prediction],
feed_dict={bottleneck_input: test_bottlenecks,#feed_dict
ground_truth_input: test_ground_truth})
print('Final test accuracy = %.1f%% (N=%d)' %(test_accuracy * 100, len(test_bottlenecks)))
print('=== MISCLASSIFIED TEST IMAGES ===')
for i, test_filename in enumerate(test_filenames):
if predictions[i] != test_ground_truth[i]:
print('%70s %s' % (test_filename,list(image_lists.keys())[predictions[i]]))
#入口函數(shù)
def main(_):
tf.logging.set_verbosity(tf.logging.WARN)
module_spec = hub.load_module_spec(HUB_MODULE)
graph, bottleneck_tensor, resized_image_tensor, wants_quantization = (
create_module_graph(module_spec))
with tf.Session(graph=graph) as sess:
init = tf.global_variables_initializer()
sess.run(init)
jpeg_data_tensor, decoded_image_tensor = add_jpeg_decoding(module_spec)
run_final_eval(sess, module_spec, 5,
jpeg_data_tensor, decoded_image_tensor,
resized_image_tensor,bottleneck_tensor)
運行后會輸出一些預(yù)測數(shù)據(jù)纺非,因為在前面run_final_retrain訓(xùn)練中我們只使用了5range,所以精度非常的低:
Final test accuracy = 32.0% (N=100)
=== MISCLASSIFIED TEST IMAGES ===
/Users/zhyuzh/desktop/MyProjects/tfTemp/Retrain/flower_photos/dandelion/142390525_5d81a3659d_m.jpg daisy
/Users/zhyuzh/desktop/MyProjects/tfTemp/Retrain/flower_photos/tulips/13472393854_b2530f7029_n.jpg rose
...
本篇小結(jié)
這里介紹了retrain和eval相關(guān)的函數(shù):
- 添加最終再訓(xùn)練操作add_final_retrain_ops
- 執(zhí)行最終再訓(xùn)練并保存chekcpoint文件run_final_retrain
- 增加評價模型預(yù)測精度的操作add_evaluation_step
- 創(chuàng)建用于評估的會話build_eval_session
- 執(zhí)行最終評估運算run_final_eval
探索人工智能的新邊界
如果您發(fā)現(xiàn)文章錯誤蓖康,請不吝留言指正铐炫;
如果您覺得有用,請點喜歡蒜焊;
如果您覺得很有用倒信,感謝轉(zhuǎn)發(fā)~
END