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

圖像識(shí)別往往包含數(shù)以百萬(wàn)計(jì)的參數(shù),從頭訓(xùn)練需要大量打好標(biāo)簽的圖片,還需要大量的計(jì)算力(往往數(shù)百小時(shí)的GPU時(shí)間)。對(duì)此,遷移學(xué)習(xí)是一個(gè)捷徑,他可以在已經(jīng)訓(xùn)練好的相似工作模型基礎(chǔ)上,繼續(xù)訓(xùn)練新的模型。

這里我們將基于ImageNet訓(xùn)練好的模型,對(duì)適當(dāng)數(shù)量(數(shù)千張)圖像進(jìn)行訓(xùn)練,這個(gè)訓(xùn)練可能需要30分鐘左右。



準(zhǔn)備工作

安裝tensorflow-hub,這是一個(gè)類(lèi)似于tensorflow模型市場(chǎng)集散地的應(yīng)用,這個(gè)練習(xí)將使用它的一個(gè)模型作為基礎(chǔ)模型。
安裝命令:

pip3 install --upgrade tensorflow-hub

百度網(wǎng)盤(pán)下載再訓(xùn)練需要使用的花圖片集(密碼:lzjg)

下載后解壓,得到幾個(gè)文件夾,分別包含了菊花daisy、蒲公英dandelion、玫瑰rose、向日葵sunflow和郁金香tulips各種花的圖片,總計(jì)有幾千張。


讀取圖片列表create_image_lists

將菊花、蒲公英等各種文件夾下的圖片路徑都讀取出來(lái),再把每個(gè)分類(lèi)的圖片按照訓(xùn)練70%、測(cè)試20%、驗(yàn)證10%的比例拆分,組合成字典格式:

{
    dir: name, 
    trainging: [imgage_paths],
    testing: [imgage_paths], 
    validation: [imgage_paths]
}

為了將圖片按照70%20%10%進(jìn)行分類(lèi),這里使用的方法是哈?;募?/p>

  • 將文件名轉(zhuǎn)為hash值(40個(gè)數(shù)字字母組合)
  • 再把hash值轉(zhuǎn)為整數(shù)(非常大的數(shù)字)
  • 利用取余數(shù)運(yùn)算%MAX把大整數(shù)放縮到0~MAX之間
  • 0-MAX再除以MAX得到0-1隨機(jī)小數(shù),再乘以100得到百分?jǐn)?shù)
  • 判斷這個(gè)百分?jǐn)?shù)屬于哪一段,就把文件名歸到哪一段

以下是代碼及注解,很長(zhǎng),耐心看:

import argparse
import collections
from datetime import datetime
import hashlib
import random
import re
import sys

import os
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub

dir_path = os.path.dirname(os.path.realpath(__file__))
image_dir=os.path.join(dir_path,'flower_photos')  

MAX_IPC = 2 ** 27 - 1 #每分類(lèi)最大圖片數(shù)max-image-per-class

#要使用的hub模型,就是module_name
HUB_MODULE='https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/feature_vector/1'

#hub模型中要使用的量化操作節(jié)點(diǎn)名
FAKE_QUANT_OPS = ('FakeQuantWithMinMaxVars',
                  'FakeQuantWithMinMaxVarsPerChannel')


def create_image_lists():   
    result = collections.OrderedDict() #有序字典,匹配順序到labels
    sub_dirs = sorted(x[0] for x in tf.gfile.Walk(image_dir)) #獲得花類(lèi)型文件夾列表,第一個(gè)是根目錄    
    
    is_root_dir = True
    for sub_dir in sub_dirs:        
        if is_root_dir: #跳過(guò)根目錄
            is_root_dir = False
            continue
            
        extensions = ['jpg', 'jpeg', 'JPG', 'JPEG']
        file_list = []
        dir_name = os.path.basename(sub_dir) #得到花分類(lèi)的名字daisy,rose...
        if dir_name == image_dir:
            continue
        for extension in extensions:
            file_glob = os.path.join(image_dir, dir_name, '*.' + extension) #獲取所有圖片路徑
            file_list.extend(tf.gfile.Glob(file_glob)) #將所有圖片路徑加入到file_list  
        label_name = re.sub(r'[^a-z0-9]+', ' ', dir_name.lower()) #清理花分類(lèi)名稱(chēng)字符,這里沒(méi)意義
        
        training_images = [] #用于訓(xùn)練的圖片路徑
        testing_images = [] #用于測(cè)試的圖片路徑
        validation_images = [] #用于驗(yàn)證的圖片路徑
        for file_name in file_list:
            base_name = os.path.basename(file_name) #得到文件名7166550328_de0d73cfa9.jpg...
            hash_name = re.sub(r'_nohash_.*$', '', file_name) #得到圖片全路徑
            hash_name_hashed = hashlib.sha1(tf.compat.as_bytes(hash_name)).hexdigest() #轉(zhuǎn)40位hash
            hash_int=int(hash_name_hashed, 16) #轉(zhuǎn)超長(zhǎng)的整數(shù)
            hash_per=hash_int%(MAX_IPC + 1)*(100.0 / MAX_IPC) #放縮到0~100

            if hash_per < 10: #驗(yàn)證集10%
                validation_images.append(base_name)
            elif hash_per < 30: #測(cè)試集20%
                testing_images.append(base_name)
            else: #訓(xùn)練集70%
                training_images.append(base_name)
                
        result[label_name] = {
            'dir': dir_name,
            'training': training_images,
            'testing': testing_images,
            'validation': validation_images,
        }
    return result

#入口函數(shù)
def main(_):    
    create_image_lists();

#模塊或應(yīng)用
if __name__ == '__main__':
    tf.app.run()

最終輸出的result格式:

([
    ('daisy', { 
        'dir': 'daisy', 
        'training': ['14167534527_781ceb1b7a_n.jpg',...], 
        'testing': ['20773528301_008fcbc5a1_n.jpg',...],
        'validation': ['721595842_bacd80a6ac.jpg',...]
    }), 
    ('dandelion', { 
        'dir': 'dandelion', 
        'training': ['14167534527_781ceb1b7a_n.jpg',...], 
        'testing': ['20773528301_008fcbc5a1_n.jpg',...],
        'validation': ['721595842_bacd80a6ac.jpg',...]
    }), 
    ...
])


獲取圖片全路徑的函數(shù)get_image_path

首先利用上面的create_image_lists方法生成圖片列表,然后可以在下面函數(shù)中直接使用它。

get_image_path函數(shù)主要是從image_lists中恢復(fù)出某個(gè)圖片路徑。

增加和修改的代碼

#所有圖片列表對(duì)象
image_lists=create_image_lists()

#獲取一個(gè)圖片路徑,label_name花類(lèi)名同dir_name,category是training/testingvalidation,index是圖片索引,set_dir可替換flower_photos文件夾名
def get_image_path(label_name,category,index,set_dir=image_dir): 
    label_lists = image_lists[dir_name]
    category_list = label_lists[category]        
    mod_index = index % len(category_list) #避免超出長(zhǎng)度范圍
    base_name = category_list[mod_index]
    sub_dir = label_lists['dir']
    full_path = os.path.join(image_dir, sub_dir, base_name)
    
    return full_path

#入口函數(shù)
def main(_):       
    get_image_path('daisy','training',66)

如果把上面返回的full_path打印出來(lái),大概是

/Users/zhyuzh/desktop/.../flower_photos/daisy/267148092_4bb874af58.jpg


生成瓶頸文件路徑的函數(shù)get_bottleneck_path

Bottleneck瓶頸文件是對(duì)原始眾多圖片數(shù)據(jù)進(jìn)行整理后的數(shù)據(jù)文件,能夠更加方便的被tensorflow調(diào)用來(lái)訓(xùn)練、檢驗(yàn)或預(yù)測(cè)使用。具體創(chuàng)建方法在下面會(huì)詳解,這里只是先生成一個(gè)存放瓶頸文件的目錄。

以下是修改和增加的代碼

bottleneck_dir=os.path.join(dir_path,'bottlenecks')  

#獲取一個(gè)瓶頸文件路徑的函數(shù)
def get_bottleneck_path(label_name, category,index):
    module_name = (HUB_MODULE.replace('://', '~')  # URL scheme.
                   .replace('/', '~')  # URL and Unix paths.
                    .replace(':', '~').replace('\\', '~'))  # Windows paths.
    return get_image_path(label_name, category,index,bottleneck_dir) + '_' + 'module_name' + '.txt' #為了簡(jiǎn)化路徑,我們臨時(shí)使用字符串module_name而不是變量

#入口函數(shù)
def main(_):       
    bnpath=get_bottleneck_path('daisy','training',66)
    print(bnpath)

從hub.ModuleSpec生成圖和模型的函數(shù)create_module_graph

因?yàn)槲覀儾⒉皇峭耆珡念^開(kāi)始訓(xùn)練模型,而是在hub的某個(gè)模型的基礎(chǔ)上進(jìn)行再訓(xùn)練,所以首先我們要從hub上拉取模型信息,并從中恢復(fù)出原計(jì)算圖graph的一些張量參數(shù)以便于使用。

#要使用的hub模型
HUB_MODULE='https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/feature_vector/1'

#hub模型中要使用的量化操作節(jié)點(diǎn)名
FAKE_QUANT_OPS = ('FakeQuantWithMinMaxVars',
                  'FakeQuantWithMinMaxVarsPerChannel')

#創(chuàng)建從一個(gè)hub.ModuleSpec生成計(jì)算圖并從Hub載入模型的函數(shù)
#module_spec需要使用的hub.ModuleSpec,bottleneck_tensor模型輸出的額bottleneck_tensor值
#resized_input_tensor模型期望的輸入的圖像數(shù)據(jù)的尺寸,wants_quantization是否要量化
def create_module_graph(module_spec):
    height, width = hub.get_expected_image_size(module_spec)
    with tf.Graph().as_default() as graph:
        resized_input_tensor = tf.placeholder(tf.float32, [None, height, width, 3])
        m = hub.Module(module_spec)
        bottleneck_tensor = m(resized_input_tensor)
        wants_quantization = any(node.op in FAKE_QUANT_OPS
                                 for node in graph.as_graph_def().node) #any任何一個(gè)為真即為真
    return graph, bottleneck_tensor, resized_input_tensor, wants_quantization


#入口函數(shù)
def main(_):       
    module_spec = hub.load_module_spec(HUB_MODULE)
    result=create_module_graph(module_spec)
    print(result)

輸出結(jié)果如下,包含了graph, bottleneck_tensor, resized_input_tensor, wants_quantization四個(gè)字段:

(
  <tensorflow.python.framework.ops.Graph object at 0x11b3da668>, 
  <tf.Tensor 'module_apply_default/hub_output/feature_vector/SpatialSqueeze:0'   shape=(?, 1280) dtype=float32>, 
  <tf.Tensor 'Placeholder:0' shape=(?, 224, 224, 3) dtype=float32>, 
  False
)

提取圖片瓶頸值的函數(shù)run_bottleneck_on_image

上面的代碼我們從hub獲得了模型,并提取到了graph計(jì)算圖,這個(gè)函數(shù)將使用計(jì)算圖中的兩個(gè)張量進(jìn)行運(yùn)算,先對(duì)圖片進(jìn)行調(diào)整尺寸轉(zhuǎn)為張量,然后提取它的瓶頸張量值。

以下是增加的代碼,暫時(shí)不運(yùn)行它,稍后和下面的函數(shù)一起測(cè)試:

#對(duì)一張圖片執(zhí)行推斷,提取瓶頸總結(jié)層summary layer
#sess當(dāng)前session,image_data字符串格式j(luò)peg數(shù)據(jù),image_data_tensor圖的輸入數(shù)據(jù)層
#decoded_image_tensor圖像改變尺寸和處理后的輸出,resized_input_tensor識(shí)別圖的輸入節(jié)點(diǎn)
#bottleneck_tesnor最終softmax之前的層
#返回瓶頸值數(shù)組numpy array
def run_bottleneck_on_image(sess, image_data, image_data_tensor,
                            decoded_image_tensor, resized_input_tensor,
                            bottleneck_tensor):
    resized_input_values = sess.run(decoded_image_tensor, #解碼JPEG,調(diào)整大小,放縮像素值
                                    {image_data_tensor: image_data}) #feed_dict
    bottleneck_values = sess.run(bottleneck_tensor, #使用識(shí)別網(wǎng)絡(luò)運(yùn)行它
                                 {resized_input_tensor: resized_input_values}) #feed_dict
    bottleneck_values = np.squeeze(bottleneck_values) #去掉冗余的數(shù)組嵌套,簡(jiǎn)化形狀
    return bottleneck_values

創(chuàng)建瓶頸文件的函數(shù)create_bottleneck_file

首先我們創(chuàng)建ensure_dir_exists函數(shù),確保文件夾存在,不存在的話(huà)就創(chuàng)建它。

然后在create_bottleneck_file函數(shù)中我們先用上面創(chuàng)建的get_bottleneck_path方法獲取存儲(chǔ)文件路徑bottleneck_path,同樣獲取圖片路徑image_path并讀取圖片數(shù)據(jù)image_data,使用上面創(chuàng)建的run_bottleneck_on_image函數(shù)把圖片數(shù)據(jù)利用session和graph內(nèi)的張量,轉(zhuǎn)為瓶頸值并保存到文件中。

以下是新增代碼,仍然不能運(yùn)行,因?yàn)閰?shù)jpeg_data_tensor, decoded_image_tensor還無(wú)法獲得,稍后我們會(huì)一起測(cè)試:

#確保目錄路徑存在,不存在就創(chuàng)建
def ensure_dir_exists(dir_name):
    if not os.path.exists(dir_name):
        os.makedirs(dir_name)

#創(chuàng)建一個(gè)瓶頸文件
def create_bottleneck_file(sess,label_name,category, index, jpeg_data_tensor,
                           decoded_image_tensor, resized_input_tensor,
                           bottleneck_tensor):
    sub_dir=os.path.join(dir_path,'bottlenecks/'+label_name)  
    ensure_dir_exists(sub_dir) #創(chuàng)建文件夾
    
    bottleneck_path=get_bottleneck_path(label_name, category,index) #存儲(chǔ)瓶頸文件的路徑
    tf.logging.info('正在創(chuàng)建bottleneck文件:' + bottleneck_path)
    image_path = get_image_path(label_name,category,index) #獲取圖片文件全路徑
    image_data = tf.gfile.FastGFile(image_path, 'rb').read() #獲取文件原數(shù)據(jù)
    try:
        bottleneck_values = run_bottleneck_on_image( #從圖片生成瓶頸值
            sess,image_data, jpeg_data_tensor, decoded_image_tensor,
            resized_input_tensor, bottleneck_tensor)
    except Exception as e:
        raise RuntimeError('處理文件出錯(cuò) %s (%s)' % (image_path,str(e)))
    bottleneck_string = ','.join(str(x) for x in bottleneck_values)
    with open(bottleneck_path, 'w') as bottleneck_file:
        bottleneck_file.write(bottleneck_string) #將獲得的bottleneck值用逗號(hào)連接成字符串寫(xiě)入文件

向計(jì)算圖添加圖片解碼操作的函數(shù)add_jpeg_decoding

jpg_data_tensor是一個(gè)placeholder,decoded_image_tensor是調(diào)整過(guò)大小的圖像數(shù)據(jù)張量格式。

下面是新增和修改的代碼,可以結(jié)合上面兩個(gè)函數(shù)一起測(cè)試運(yùn)行:

#添加操作,執(zhí)行jpeg解碼和調(diào)整大小 ,返回兩個(gè)張量jpeg_data_tensor,decoded_image_tensor    
def add_jpeg_decoding(module_spec):
    input_height, input_width = hub.get_expected_image_size(module_spec)
    input_depth = hub.get_num_image_channels(module_spec)
    jpeg_data = tf.placeholder(tf.string, name='DecodeJPGInput')
    decoded_image = tf.image.decode_jpeg(jpeg_data, channels=input_depth)
    #將全范圍的unit8轉(zhuǎn)為0~1范圍的float32
    decoded_image_as_float = tf.image.convert_image_dtype(decoded_image,tf.float32)
    decoded_image_4d = tf.expand_dims(decoded_image_as_float, 0) #擴(kuò)充形狀的維度
    resize_shape = tf.stack([input_height, input_width]) #通過(guò)合并提升維度
    resize_shape_as_int = tf.cast(resize_shape, dtype=tf.int32)
    resized_image = tf.image.resize_bilinear(decoded_image_4d,
                                             resize_shape_as_int)  #放縮圖像尺寸
    return jpeg_data, resized_image


#入口函數(shù)
def main(_):
    module_spec = hub.load_module_spec(HUB_MODULE)
    graph, bottleneck_tensor, resized_input_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)
        create_bottleneck_file(sess,'daisy','training', 65, jpeg_data_tensor,
                               decoded_image_tensor, resized_input_tensor,
                               bottleneck_tensor)

在main函數(shù)里面我們先是利用hub.load_module_spec載入了模型,然后使用create_module_graph創(chuàng)建了圖,已經(jīng)從圖中提取的bottleneck_tensor和resized_inpt_tensor。

然后我們利用graph創(chuàng)建了session,初始化了變量,又使用add_jpeg_decoding方法創(chuàng)建了兩個(gè)張量jpeg_data_tensor和decoded_image_tensor。

最后我們使用create_bottleneck_file方法,在/bottlenecks/daisy/目錄下創(chuàng)建了一個(gè)文件,并把我們得到的圖片bottleneck數(shù)據(jù)寫(xiě)入其中。

這個(gè)文件的都是很多的浮點(diǎn)小數(shù),這些數(shù)字在另外的角度上反映了像素之間的關(guān)系,而tensorflow能夠從中更加容易的找到規(guī)律:

1.1014792,1.7321489,0.284751,0.7904396,0.0,0.11441692,0.0,0.30288044,0.07657591,0.353643,0.0,1.2191151,0.3042915,1.0002377,0.18627474,0.4791365,0.0,0.058162533,1.0755428,0.047679365,0.0,1.5222605,0.51027495,0.109168105,0.3694405,0.014923426,0.0032605443,2.3457944,0.5158326...

階段小結(jié)

這階段我們主要編寫(xiě)了幾個(gè)函數(shù),實(shí)現(xiàn)了圖像文件的列表生成、bottleneck文件的創(chuàng)建的內(nèi)容:

  1. 讀取圖片列表create_image_lists
  2. 獲取圖片全路徑的函數(shù)get_image_path
  3. 生成瓶頸文件路徑的函數(shù)get_bottleneck_path
  4. 從hub.ModuleSpec生成圖和模型的函數(shù)create_module_graph
  5. 提取圖片瓶頸值的函數(shù)run_bottleneck_on_image
  6. 確保路徑文件夾存在的函數(shù)ensure_dir_exists
  7. 創(chuàng)建瓶頸文件的函數(shù)create_bottleneck_file
  8. 向計(jì)算圖添加圖片解碼操作的函數(shù)add_jpeg_decoding

以下是此階段的全部代碼:

import argparse
import collections
from datetime import datetime
import hashlib
import random
import re
import sys

import os
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub

dir_path = os.path.dirname(os.path.realpath(__file__))
image_dir=os.path.join(dir_path,'flower_photos')  
bottleneck_dir=os.path.join(dir_path,'bottlenecks')  

MAX_IPC = 2 ** 27 - 1 #每分類(lèi)最大圖片數(shù)max-image-per-class

#要使用的hub模型,就是module_name
HUB_MODULE='https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/feature_vector/1'

#hub模型中要使用的量化操作節(jié)點(diǎn)名
FAKE_QUANT_OPS = ('FakeQuantWithMinMaxVars',
                  'FakeQuantWithMinMaxVarsPerChannel')


#獲取全部文件列表
def create_image_lists(): 
  
    result = collections.OrderedDict() #有序字典,匹配順序到labels
    sub_dirs = sorted(x[0] for x in tf.gfile.Walk(image_dir)) #獲得花類(lèi)型文件夾列表,第一個(gè)是根目錄
    
    
    is_root_dir = True
    for sub_dir in sub_dirs:        
        if is_root_dir: #跳過(guò)根目錄
            is_root_dir = False
            continue
            
        extensions = ['jpg', 'jpeg', 'JPG', 'JPEG']
        file_list = []
        dir_name = os.path.basename(sub_dir) #得到花分類(lèi)的名字daisy,rose...
        if dir_name == image_dir:
            continue
        for extension in extensions:
            file_glob = os.path.join(image_dir, dir_name, '*.' + extension) #獲取所有圖片路徑
            file_list.extend(tf.gfile.Glob(file_glob)) #將所有圖片路徑加入到file_list  
        label_name = re.sub(r'[^a-z0-9]+', ' ', dir_name.lower()) #清理花分類(lèi)名稱(chēng)字符,這里沒(méi)意義
        
        training_images = [] #用于訓(xùn)練的圖片路徑
        testing_images = [] #用于測(cè)試的圖片路徑
        validation_images = [] #用于驗(yàn)證的圖片路徑
        for file_name in file_list:
            base_name = os.path.basename(file_name) #得到文件名7166550328_de0d73cfa9.jpg...
            hash_name = re.sub(r'_nohash_.*$', '', file_name) #得到圖片全路徑
            hash_name_hashed = hashlib.sha1(tf.compat.as_bytes(hash_name)).hexdigest() #轉(zhuǎn)40位hash
            hash_int=int(hash_name_hashed, 16) #轉(zhuǎn)超長(zhǎng)的整數(shù)
            hash_per=hash_int%(MAX_IPC + 1)*(100.0 / MAX_IPC) #放縮到0~100

            if hash_per < 10: #驗(yàn)證集10%
                validation_images.append(base_name)
            elif hash_per < 30: #測(cè)試集20%
                testing_images.append(base_name)
            else: #訓(xùn)練集70%
                training_images.append(base_name)
                
        result[label_name] = {
            'dir': dir_name,
            'training': training_images,
            'testing': testing_images,
            'validation': validation_images,
        }
    return result

#所有圖片列表對(duì)象
image_lists=create_image_lists()

#獲取一個(gè)圖片路徑,label_name花類(lèi)名同dir_name,category是training/testingvalidation,index是圖片索引,set_dir可替換flower_photos文件夾名
def get_image_path(label_name,category,index,set_dir=image_dir): 
    label_lists = image_lists[label_name]
    category_list = label_lists[category]        
    mod_index = index % len(category_list) #避免超出長(zhǎng)度范圍
    base_name = category_list[mod_index]
    sub_dir = label_lists['dir']
    full_path = os.path.join(set_dir, sub_dir, base_name)
    
    return full_path

#獲取一個(gè)瓶頸文件路徑的函數(shù)
def get_bottleneck_path(label_name, category,index):
    module_name = (HUB_MODULE.replace('://', '~')  # URL scheme.
                   .replace('/', '~')  # URL and Unix paths.
                    .replace(':', '~').replace('\\', '~'))  # Windows paths.
    return get_image_path(label_name, category,index,bottleneck_dir) + '_' + 'module_name' + '.txt'

#創(chuàng)建從一個(gè)hub.ModuleSpec生成計(jì)算圖并從Hub載入模型的函數(shù)
#module_spec需要使用的hub.ModuleSpec,bottleneck_tensor模型輸出的額bottleneck_tensor值
#resized_input_tensor模型期望的輸入的圖像數(shù)據(jù)的尺寸,wants_quantization是否要量化
def create_module_graph(module_spec):
    height, width = hub.get_expected_image_size(module_spec)
    with tf.Graph().as_default() as graph:
        resized_input_tensor = tf.placeholder(tf.float32, [None, height, width, 3])
        m = hub.Module(module_spec)
        bottleneck_tensor = m(resized_input_tensor)
        wants_quantization = any(node.op in FAKE_QUANT_OPS
                                 for node in graph.as_graph_def().node) #any任何一個(gè)為真即為真
    return graph, bottleneck_tensor, resized_input_tensor, wants_quantization


#對(duì)一張圖片執(zhí)行推斷,提取瓶頸總結(jié)層summary layer
#sess當(dāng)前session,image_data字符串格式j(luò)peg數(shù)據(jù),image_data_tensor圖的輸入數(shù)據(jù)層
#decoded_image_tensor圖像改變尺寸和處理后的輸出,resized_input_tensor識(shí)別圖的輸入節(jié)點(diǎn)
#bottleneck_tesnor最終softmax之前的層
#返回瓶頸值數(shù)組numpy array
def run_bottleneck_on_image(sess,image_data, image_data_tensor,
                            decoded_image_tensor, resized_input_tensor,
                            bottleneck_tensor):
    resized_input_values = sess.run(decoded_image_tensor, #解碼JPEG,調(diào)整大小,放縮像素值
                                    {image_data_tensor: image_data}) #feed_dict
    bottleneck_values = sess.run(bottleneck_tensor, #使用識(shí)別網(wǎng)絡(luò)運(yùn)行它
                                 {resized_input_tensor: resized_input_values}) #feed_dict
    bottleneck_values = np.squeeze(bottleneck_values) #去掉冗余的數(shù)組嵌套,簡(jiǎn)化形狀
    return bottleneck_values


#確保目錄路徑存在,不存在就創(chuàng)建
def ensure_dir_exists(dir_name):
    if not os.path.exists(dir_name):
        os.makedirs(dir_name)

#創(chuàng)建一個(gè)瓶頸文件
def create_bottleneck_file(sess,label_name,category, index, jpeg_data_tensor,
                           decoded_image_tensor, resized_input_tensor,
                           bottleneck_tensor):
    sub_dir=os.path.join(dir_path,'bottlenecks/'+label_name)  
    ensure_dir_exists(sub_dir) #創(chuàng)建文件夾
    
    bottleneck_path=get_bottleneck_path(label_name, category,index) #存儲(chǔ)瓶頸文件的路徑
    tf.logging.info('正在創(chuàng)建bottleneck文件:' + bottleneck_path)
    image_path = get_image_path(label_name,category,index) #獲取圖片文件全路徑
    image_data = tf.gfile.FastGFile(image_path, 'rb').read() #獲取文件原數(shù)據(jù)
    try:
        bottleneck_values = run_bottleneck_on_image( #從圖片生成瓶頸值
            sess,image_data, jpeg_data_tensor, decoded_image_tensor,
            resized_input_tensor, bottleneck_tensor)
    except Exception as e:
        raise RuntimeError('處理文件出錯(cuò) %s (%s)' % (image_path,str(e)))
    bottleneck_string = ','.join(str(x) for x in bottleneck_values)
    with open(bottleneck_path, 'w') as bottleneck_file:
        bottleneck_file.write(bottleneck_string) #將獲得的bottleneck值用逗號(hào)連接成字符串寫(xiě)入文件
        
#添加操作,執(zhí)行jpeg解碼和調(diào)整大小 ,返回兩個(gè)張量jpeg_data_tensor,decoded_image_tensor    
def add_jpeg_decoding(module_spec):
    input_height, input_width = hub.get_expected_image_size(module_spec)
    input_depth = hub.get_num_image_channels(module_spec)
    jpeg_data = tf.placeholder(tf.string, name='DecodeJPGInput')
    decoded_image = tf.image.decode_jpeg(jpeg_data, channels=input_depth)
    #將全范圍的unit8轉(zhuǎn)為0~1范圍的float32
    decoded_image_as_float = tf.image.convert_image_dtype(decoded_image,tf.float32)
    decoded_image_4d = tf.expand_dims(decoded_image_as_float, 0) #擴(kuò)充形狀的維度
    resize_shape = tf.stack([input_height, input_width])
    resize_shape_as_int = tf.cast(resize_shape, dtype=tf.int32)
    resized_image = tf.image.resize_bilinear(decoded_image_4d,
                                             resize_shape_as_int)
    return jpeg_data, resized_image


#入口函數(shù)
def main(_):
    module_spec = hub.load_module_spec(HUB_MODULE)
    graph, bottleneck_tensor, resized_input_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)
        create_bottleneck_file(sess,'daisy','training', 65, jpeg_data_tensor,
                               decoded_image_tensor, resized_input_tensor,
                               bottleneck_tensor)   
    

#模塊或應(yīng)用
if __name__ == '__main__':
    tf.app.run()

探索人工智能的新邊界

如果您發(fā)現(xiàn)文章錯(cuò)誤,請(qǐng)不吝留言指正;
如果您覺(jué)得有用,請(qǐng)點(diǎn)喜歡;
如果您覺(jué)得很有用,感謝轉(zhuǎn)發(fā)~


END

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

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容