Tensorflow-花分類-圖像再訓(xùn)練-part-3-整理翻譯

在前面兩篇文章中Part-1Part-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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市泳梆,隨后出現(xiàn)的幾起案子鳖悠,更是在濱河造成了極大的恐慌榜掌,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乘综,死亡現(xiàn)場離奇詭異憎账,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)卡辰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進(jìn)店門胞皱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人九妈,你說我怎么就攤上這事反砌。” “怎么了萌朱?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵宴树,是天一觀的道長。 經(jīng)常有香客問我晶疼,道長酒贬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任翠霍,我火速辦了婚禮锭吨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘壶运。我一直安慰自己耐齐,他們只是感情好浪秘,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布蒋情。 她就那樣靜靜地躺著,像睡著了一般耸携。 火紅的嫁衣襯著肌膚如雪棵癣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天夺衍,我揣著相機(jī)與錄音狈谊,去河邊找鬼。 笑死沟沙,一個胖子當(dāng)著我的面吹牛河劝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播矛紫,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼赎瞎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了颊咬?” 一聲冷哼從身側(cè)響起务甥,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤牡辽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后敞临,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體态辛,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年挺尿,在試婚紗的時候發(fā)現(xiàn)自己被綠了奏黑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡编矾,死狀恐怖攀涵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情洽沟,我是刑警寧澤以故,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站裆操,受9級特大地震影響怒详,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜踪区,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一昆烁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缎岗,春花似錦静尼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至眷细,卻和暖如春拦盹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背溪椎。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工普舆, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人校读。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓沼侣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親歉秫。 傳聞我的和親對象是個殘疾皇子蛾洛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容