Tensorflow-Inception-圖像識(shí)別案例-整理翻譯

人類大腦可以輕而易舉的識(shí)別圖像中的獅子和豹子竣灌,識(shí)別各種符號(hào)和文字,識(shí)別人臉腐魂,等等帐偎,但這些對(duì)于計(jì)算機(jī)來說就很難。因?yàn)槲覀兊拇竽X尤其擅長(zhǎng)圖像識(shí)別蛔屹。

題外削樊,其實(shí)也并非完全如此,對(duì)于陌生的內(nèi)容兔毒,我們并不能做的太好漫贞,比如你可能看過太多的日文字幕,但再看到屏幕上的日文符號(hào)的時(shí)候育叁,你還記得它是否在《名偵探柯南》中出現(xiàn)過嗎迅脐?同樣,我們對(duì)于華人明星的臉幾乎從不會(huì)搞混誰是誰豪嗽,但對(duì)于歐美明不太知名的明星恐怕就經(jīng)常分不清哪個(gè)是哪個(gè)谴蔑。人類也經(jīng)常被各種視覺錯(cuò)覺所欺騙,比如經(jīng)常去看的3D電影龟梦,一塊幕布竟然被我們看出了立體感隐锭,不覺得奇怪嗎?這里面一定隱藏著什么一些未被重視的算法计贰。

在過去的幾年钦睡,計(jì)算機(jī)科學(xué)家在圖像識(shí)別上取得了重大突破,尤其是CNN卷積神經(jīng)網(wǎng)絡(luò)的使用躁倒,計(jì)算機(jī)已經(jīng)能夠解決很多有難度的圖像識(shí)別任務(wù)荞怒,甚至某些領(lǐng)域比人做的還好。

計(jì)算機(jī)視覺算法已經(jīng)攻克了學(xué)院派的ImageNet測(cè)試標(biāo)準(zhǔn)秧秉,成功的模型不斷進(jìn)步: QuocNet, AlexNet, Inception (GoogLeNet), BN-Inception-v2褐桌,Google谷歌內(nèi)部和外部的科學(xué)家正在探討下一代圖像識(shí)別模型,Inception-v3福贞。

Inception-v3是基于2012年以來ImageNet圖片挑戰(zhàn)賽數(shù)據(jù)訓(xùn)練得到的撩嚼,這個(gè)挑戰(zhàn)賽是計(jì)算機(jī)視覺的標(biāo)桿性的比賽,需要識(shí)別1000種分類挖帘,比如斑馬完丽、斑點(diǎn)狗和洗碗機(jī)等,比如下面是AlexNet模型識(shí)別的一些分類:


螨蟲拇舀,貨船逻族,踏板摩托,美洲豹骄崩;粉色條表示了最大可能的分類聘鳞,都獲得了正確的結(jié)果

為了對(duì)比模型,我們檢查模型預(yù)測(cè)失敗率最高的5個(gè)預(yù)測(cè)要拂,AlexNet在2012年top5錯(cuò)誤率是15.3%,Inception是6.67%抠璃,Inception-v2是4.9,Inception-v3是3.46%脱惰。而人類的top-5錯(cuò)誤率是5.1%搏嗡。

本篇教程將介紹如何使用Inception-v3識(shí)別1000種分類,也會(huì)介紹如何從這個(gè)模型種提取更高特征拉一,以便于用其他識(shí)別任務(wù)采盒。


準(zhǔn)備工作

首先從百度云盤下載相關(guān)文件(密碼:q3kf)

其中包含了saved_model和imgs兩個(gè)文件夾

  • saved_model,這里是谷歌Inception項(xiàng)目基于眾多圖片訓(xùn)練好的模型蔚润,以及分類名稱對(duì)照表數(shù)據(jù)(label_map_proto.pbtxt磅氨,nameid2name.txt)。這里是已保存的模型嫡纠,而不是checkpoint文件烦租。
  • imgs,只是一張將被識(shí)別的熊貓圖片。

這次我將tensorflow升級(jí)到了1.7除盏,推薦通過下面命令行升級(jí)

pip3 install --upgrade pip
pip3 install --upgrade tensorflow

代碼結(jié)構(gòu)

import os
import re #regular expressions正則表達(dá)式操作模塊
import numpy as np
import tensorflow as tf

#準(zhǔn)備目錄
dir_path = os.path.dirname(os.path.realpath(__file__))
model_dir=os.path.join(dir_path,'saved_model')  
image_path=os.path.join(dir_path, 'imgs/panda.jpg')
proto_path=os.path.join(dir_path, 'saved_model/label_map_proto.pbtxt')
name_path=os.path.join(dir_path, 'saved_model/nameid2name.txt')
model_path=os.path.join(model_dir, 'classify_image_graph_def.pb')

#我們的主要代碼將添加在這里

#入口函數(shù)
def main(_):    
    #在這里運(yùn)行測(cè)試


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

加載分類名稱對(duì)照表函數(shù)

首先看一下兩個(gè)文件的內(nèi)容:

分類類別編號(hào)(target_class即nodeid)和名稱編號(hào)( target_class_string即nameid)的對(duì)應(yīng)關(guān)系label_map_proto.pbtxt:

# -*- protobuffer -*-
# LabelMap from ImageNet 2012 full data set UID to int32 target class.
entry {
  target_class: 449
  target_class_string: "n01440764"
}
entry {
  target_class: 450
  target_class_string: "n01443537"
}

名稱編號(hào)(n開頭)和名稱的對(duì)應(yīng)關(guān)系nameid2name.txt:

n00004475   organism, being
n00005787   benthos
n00006024   heterotroph
n00006484   cell
n00007846   person, individual, someone, somebody, mortal, soul

我們向代碼添加獲取分類的函數(shù)get_class,并喂它創(chuàng)建兩個(gè)方法:

  • load叉橱,用來讀取兩個(gè)文件,逐行讀取痴颊,然后拆分赏迟,重組成為兩個(gè)字典{nodeid:nameid}和{nameid:name},再把兩個(gè)字典合并成為{nodeid:name}
  • get_name_by_nodeid,根據(jù)上面的字典蠢棱,通過nodeid獲取name锌杀。
    并在init里面自動(dòng)使用load()方法讀取。

在main里面運(yùn)行并測(cè)試,增加和修改的部分代碼如下:

#用來把分類節(jié)點(diǎn)nodeid轉(zhuǎn)為物體名稱字符串的函數(shù)
class get_class():
    def __init__(self):
        self.class_list=self.load() #載入泻仙,生成{nodeid:name}字典
       
    #從文本載入名稱id映射數(shù)據(jù)
    def load(self):
        #讀取nameid和name的對(duì)應(yīng)關(guān)系
        nameid2name = {} #字典{nid:name}
        lines1 = tf.gfile.GFile(name_path).readlines()
        p = re.compile(r'[n\d]*[ \S,]*') #定義正則匹配方式
        for line in lines1:
            #findall將n00004475  organism, being分解成['n00004475','organism, being']
            parsed_items = p.findall(line) 
            nid = parsed_items[0]
            name = parsed_items[2]
            nameid2name[nid] = name
            
        #讀取nodeid和nameid的對(duì)應(yīng)關(guān)系  
        nodeid2nameid = {}
        lines2 = tf.gfile.GFile(proto_path).readlines()
        for line in lines2:
            #參考數(shù)據(jù)格式entry {
            #  target_class: 449
            #  target_class_string: "n01440764"
            #}
            if line.startswith('  target_class:'):
                target_class = int(line.split(': ')[1])
            if line.startswith('  target_class_string:'):
                target_class_string = line.split(': ')[1]
                nodeid2nameid[target_class] = target_class_string[1:-2]
                
        #合并成nodeid和name的對(duì)應(yīng)關(guān)系
        nodeid2name = {}
        for key, val in nodeid2nameid.items():
            if val not in nameid2name:
                tf.logging.fatal('對(duì)應(yīng)失敗: %s', val)
            name = nameid2name[val]
            nodeid2name[key] = name
                
        print(nodeid2name) #這里打印結(jié)果糕再!
        return nodeid2name
    
    #根據(jù)nodeid獲取分類名
    def get_name_by_nodeid(self, nodeid):
        if nodeid not in self.class_list:
            return ''
        return self.class_list[nodeid]                

#入口函數(shù)
def main(_):    
    getclass = get_class()

運(yùn)行將會(huì)打印出結(jié)果,編號(hào)對(duì)應(yīng)了名稱。

{449: 'tench, Tinca tinca', 450: 'goldfish, Carassius auratus', 442: 'great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias', 443: 'tiger shark,...

這個(gè)操作其實(shí)沒什么意義玉转,但是如果沒有這個(gè)450到'goldfish, Carassius auratus'(金魚)的轉(zhuǎn)換突想,那么稍后預(yù)測(cè)出我們的圖片是565,我們也沒法知道這是什么鬼。


讀取已保存的模型

我們使用tf.gfile來讀取保存的pd文件model_path=os.path.join(model_dir, 'classify_image_graph_def.pb'),把內(nèi)容恢復(fù)到tf.GraphDeftensorflow的計(jì)算圖中猾担。

下面是增加和修改部分的代碼袭灯,運(yùn)行后沒有輸出結(jié)果。

#從保存的模型讀取graph
def create_graph():
    with tf.gfile.FastGFile(model_path, 'rb') as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        _ = tf.import_graph_def(graph_def, name='')

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

對(duì)圖片進(jìn)行預(yù)測(cè)的函數(shù)

簽名create_graph載入已保存模型創(chuàng)建了圖绑嘹,我們只要從graph中找出最終輸出的張量softmax稽荧,然后利用feed_dict重新喂食我們的圖片,就能run出預(yù)測(cè)結(jié)果工腋。
當(dāng)然別忘了用我們辛苦編寫的get_class來把預(yù)測(cè)的nodeid改為可以讀懂的名稱再打印出來姨丈。

增加和修改部分的代碼如下:

#執(zhí)行預(yù)測(cè)
def predict_image():
    image_data = tf.gfile.FastGFile(image_path, 'rb').read() #讀取圖片
    create_graph() #創(chuàng)建計(jì)算圖

    with tf.Session() as sess:
        softmax_tensor = sess.graph.get_tensor_by_name('softmax:0') #從計(jì)算圖中提取張量
        predictions = sess.run(softmax_tensor,{'DecodeJpeg/contents:0': image_data}) #輸入feed_dict進(jìn)行運(yùn)算
        predictions = np.squeeze(predictions) #去掉冗余的1維形狀,比如把張量形狀從(1,3,1)變?yōu)?3)

        #輸出打印
        getclass = get_class()
        top5 = predictions.argsort()[-5:][::-1]
        
        print('\n預(yù)測(cè)結(jié)果是:')
        for node_id in top5:
            name_string = getclass.get_name_by_nodeid(node_id)
            score = predictions[node_id]
            print('%s (score = %.5f)' % (name_string, score))
        

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

這次運(yùn)行就能預(yù)測(cè)大熊貓(giant panda)了擅腰!輸出類似下面的結(jié)果,0.89107表示這個(gè)圖片有89.107%的可能是大熊貓:

預(yù)測(cè)結(jié)果是:
giant panda, panda, panda bear, coon bear, Ailuropoda  (score = 0.89107)
indri, indris, Indri indri, Indri brevicaudatus (score = 0.00779)
lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens (score = 0.00296)
custard apple (score = 0.00147)
earthstar (score = 0.00117)

結(jié)語

使用谷歌Inception項(xiàng)目訓(xùn)練好的模型來預(yù)測(cè)圖片蟋恬,其實(shí)關(guān)鍵代碼很簡(jiǎn)單,就是載入模型趁冈,重新生成計(jì)算圖歼争,進(jìn)行預(yù)測(cè)。但大篇幅的代碼都是get_class來轉(zhuǎn)換文字的箱歧。
下面是全部代碼:

import os
import re #regular expressions正則表達(dá)式操作模塊
import numpy as np
import tensorflow as tf

#準(zhǔn)備目錄
dir_path = os.path.dirname(os.path.realpath(__file__))
model_dir=os.path.join(dir_path,'saved_model')  
image_path=os.path.join(dir_path, 'imgs/panda.jpg')
proto_path=os.path.join(dir_path, 'saved_model/label_map_proto.pbtxt')
name_path=os.path.join(dir_path, 'saved_model/nameid2name.txt')
model_path=os.path.join(model_dir, 'classify_image_graph_def.pb')

#用來把分類節(jié)點(diǎn)nodeid轉(zhuǎn)為物體名稱字符串的函數(shù)
class get_class():
    def __init__(self):
        self.class_list=self.load() #載入矾飞,生成{nodeid:name}字典
       
    #從文本載入名稱id映射數(shù)據(jù)
    def load(self):
        #讀取nameid和name的對(duì)應(yīng)關(guān)系
        nameid2name = {} #字典{nid:name}
        lines1 = tf.gfile.GFile(name_path).readlines()
        p = re.compile(r'[n\d]*[ \S,]*') #定義正則匹配方式
        for line in lines1:
            #findall將n00004475  organism, being分解成['n00004475','organism, being']
            parsed_items = p.findall(line) 
            nid = parsed_items[0]
            name = parsed_items[2]
            nameid2name[nid] = name
            
        #讀取nodeid和nameid的對(duì)應(yīng)關(guān)系  
        nodeid2nameid = {}
        lines2 = tf.gfile.GFile(proto_path).readlines()
        for line in lines2:
            #參考數(shù)據(jù)格式entry {
            #  target_class: 449
            #  target_class_string: "n01440764"
            #}
            if line.startswith('  target_class:'):
                target_class = int(line.split(': ')[1])
            if line.startswith('  target_class_string:'):
                target_class_string = line.split(': ')[1]
                nodeid2nameid[target_class] = target_class_string[1:-2]
                
        #合并成nodeid和name的對(duì)應(yīng)關(guān)系
        nodeid2name = {}
        for key, val in nodeid2nameid.items():
            if val not in nameid2name:
                tf.logging.fatal('對(duì)應(yīng)失敗: %s', val)
            name = nameid2name[val]
            nodeid2name[key] = name
                
        return nodeid2name
    
    #根據(jù)nodeid獲取分類名
    def get_name_by_nodeid(self, nodeid):
        if nodeid not in self.class_list:
            return ''
        return self.class_list[nodeid]                

#從保存的模型讀取graph
def create_graph():
    with tf.gfile.FastGFile(model_path, 'rb') as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        _ = tf.import_graph_def(graph_def, name='')
        
#執(zhí)行預(yù)測(cè)
def predict_image():
    image_data = tf.gfile.FastGFile(image_path, 'rb').read() #讀取圖片
    create_graph() #創(chuàng)建計(jì)算圖

    with tf.Session() as sess:
        softmax_tensor = sess.graph.get_tensor_by_name('softmax:0') #從計(jì)算圖中提取張量
        predictions = sess.run(softmax_tensor,{'DecodeJpeg/contents:0': image_data}) #輸入feed_dict進(jìn)行運(yùn)算
        predictions = np.squeeze(predictions) #去掉冗余的1維形狀,比如把張量形狀從(1,3,1)變?yōu)?3)

        #輸出打印
        getclass = get_class()
        top5 = predictions.argsort()[-5:][::-1]
        
        print('\n預(yù)測(cè)結(jié)果是:')
        for node_id in top5:
            name_string = getclass.get_name_by_nodeid(node_id)
            score = predictions[node_id]
            print('%s (score = %.5f)' % (name_string, score))
        
#入口函數(shù)
def main(_):    
    predict_image()

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

探索人工智能的新邊界

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


END

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蝉衣,隨后出現(xiàn)的幾起案子括尸,更是在濱河造成了極大的恐慌,老刑警劉巖病毡,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件濒翻,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡啦膜,警方通過查閱死者的電腦和手機(jī)有送,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來僧家,“玉大人雀摘,你說我怎么就攤上這事“斯埃” “怎么了阵赠?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵涯塔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我清蚀,道長(zhǎng)匕荸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任轧铁,我火速辦了婚禮每聪,結(jié)果婚禮上旦棉,老公的妹妹穿的比我還像新娘齿风。我一直安慰自己,他們只是感情好绑洛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布救斑。 她就那樣靜靜地躺著,像睡著了一般真屯。 火紅的嫁衣襯著肌膚如雪脸候。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天绑蔫,我揣著相機(jī)與錄音运沦,去河邊找鬼。 笑死配深,一個(gè)胖子當(dāng)著我的面吹牛携添,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播篓叶,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼烈掠,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了缸托?” 一聲冷哼從身側(cè)響起左敌,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俐镐,沒想到半個(gè)月后矫限,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡佩抹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年叼风,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匹摇。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咬扇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出廊勃,到底是詐尸還是另有隱情懈贺,我是刑警寧澤经窖,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站梭灿,受9級(jí)特大地震影響画侣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜堡妒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一配乱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧皮迟,春花似錦搬泥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至爆阶,卻和暖如春燥透,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辨图。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工班套, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人故河。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓吱韭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親忧勿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子杉女,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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