Tensorflow-花分類-圖像再訓練-part-3-整理翻譯

在前面兩篇文章中Part-1Part-2,我們編寫了很多函數(shù)用于讀取文件并生成bottleneck文件并隨機批量讀取。

這一篇我們將繼續(xù)編寫相關的訓練、測試函數(shù)。


添加最終再訓練操作add_final_retrain_ops

我們需要重新訓練頂層top layer來識別新的分類,這個函數(shù)將向graph添加一些操作,隨著一些變量保存權重,然后為所有反向傳播設置梯度變化。

這個函數(shù)將為訓練和計算添加新的softmax和全連接層(密集層)。

增加和修改的代碼如下:

#添加最終再訓練操作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, '我們希望針對任意批次大小進行計算'
    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被變換,訓練用
        else:
            tf.contrib.quantize.create_eval_graph() #預測用
    tf.summary.histogram('activations', final_tensor) #for TensorBoard

    if not is_training: #對于預測,不需要添加損失函數(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輸出下面內容,都是新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í)行最終再訓練并保存run_final_retrain

從hub讀取模型,創(chuàng)建圖以及相關操作入口,添加各種操作(訓練操作、圖片解碼等),讀取bottleneck數(shù)據(jù),然后開始運作,使用變形扭曲的bottleneck數(shù)據(jù)或者緩存的,sess.run運行訓練操作。

同時注意summary信息的保存和checkpoint模型保存。

以下是增加和修改的代碼,結合之前代碼可以運行:

#保存概要和checkpoint路徑設置
CHECKPOINT_NAME = os.path.join(dir_path,'checkpoints/retrain')
summaries_dir=os.path.join(dir_path,'summaries/train')

#執(zhí)行訓練兵保存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)建圖并獲取相關的張量入口
    graph, bottleneck_tensor, resized_image_tensor, wants_quantization = (
        create_module_graph(module_spec))    
    
    with graph.as_default(): 
        #添加訓練相關的張量和操作節(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)
        
        #添加圖片解碼相關的張量入口操作
        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)
            
            #啟動訓練
            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文件夾及包含了概要信息和模型文件。



增加評價模型預測精度的操作add_evaluation_step

評價方法需要輸入新的圖片特征數(shù)據(jù)和對應的標簽,這里的函數(shù)接著上面的再訓練函數(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維度的最大值,即預測結果
            correct_prediction = tf.equal(prediction, ground_truth_tensor) #預測與標簽是否相等
        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

從存儲的訓練圖checkpoint文件讀取變量,恢復到評價圖,并利用上面的函數(shù)add_evaluation_step添加評估操作。

下面是新增和修改的代碼:


#保存概要和checkpoint路徑設置
CHECKPOINT_NAME = os.path.join(dir_path,'checkpoints/retrain')

#創(chuàng)建和恢復評價會話(沒有訓練操作),用于導出結果
#返回一個包含評價圖的會話,以及相關其他張量和操作
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(): #添加新的導出層
        (_, _, bottleneck_input,ground_truth_input, 
         final_tensor) = add_final_retrain_ops(class_count, 'final_tensor_name', 
                                               bottleneck_tensor,wants_quantization,is_training=False)
        #把訓練圖的值恢復到評價圖
        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)

輸出結果類似如下內容:

(
    <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獲取一些隨機的圖像數(shù)據(jù),就可以sess.run運行起來,把bottleneck數(shù)據(jù)作為feed_dict填充進去了。

下面是增加和修改的代碼:

#執(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)

    #隨機獲取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)

運行后會輸出一些預測數(shù)據(jù),因為在前面run_final_retrain訓練中我們只使用了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
...

本篇小結

這里介紹了retrain和eval相關的函數(shù):

  • 添加最終再訓練操作add_final_retrain_ops
  • 執(zhí)行最終再訓練并保存chekcpoint文件run_final_retrain
  • 增加評價模型預測精度的操作add_evaluation_step
  • 創(chuàng)建用于評估的會話build_eval_session
  • 執(zhí)行最終評估運算run_final_eval

探索人工智能的新邊界

如果您發(fā)現(xiàn)文章錯誤,請不吝留言指正;
如果您覺得有用,請點喜歡;
如果您覺得很有用,感謝轉發(fā)~


END

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容