第八屆中國Python開發者大會PyConChina2018,由PyChina.org發起,由來自CPyUG/TopGeek等社區的30位組織者,近150位志願者在北京、上海、深圳、杭州、成都等城市舉辦。致力於推進各種Python相關的技術在互聯網、企業應用等領域的研發和應用。
代碼醫生工做室有幸接受邀請,參加了此次會議的北京站專場。在會上主要分享了《人工智能實戰案例分享-圖像處理與數值分析》。
會上分享的一些案例主要是來源於《python帶我起飛——入門、進階、商業實戰》一書與《深度學習之TensorFlow:入門、原理與進階實戰》一書。另外,還擴充了若干其它案例。在本文做爲補充,將會上分享的其它案例以詳細的圖文方式補充進來,並提供源碼。共分爲4期連載。
用slim調用PNASNet模型html
用slim微調PNASNet模型python
用對抗樣本攻擊PNASNet模型git
惡意域名檢測實例bash
案例描述網絡
有一組照片,分爲男人和女人。session
本案就是讓深度學習模型來學習這些樣本,並可以找到其中的規律,完成模型的訓練。接着可使用該模型對圖片中的人物進行識別,區分其性別是男仍是女。app
本案例中,使用了一個NASNet_A_Mobile的模型來作二次訓練。具體過程分爲4步:函數
(1)準備樣本;性能
(2)準備NASNet_A_Mobile網絡模型;學習
(3)編寫代碼進行二次訓練;
(4)使用已經訓練好的模型進行測試。
經過以下連接下載CelebA數據集:
mmlab.ie.cuhk.edu.hk/projects/Ce…
下載完以後,解壓,並手動分出一部分男人與女人的照片。
在本例中,一共用了20000張圖片用來訓練模型,其中訓練樣本由8421張男性頭像和11599張女性頭像構成(在train文件夾下),測試樣本由10張男性頭像和10張女性頭像構成(在val文件夾下)。部分樣本數據如圖5-1。
圖5-1 男女數據集樣本示例
數據樣本整理好後,統一放到data文件夾下。該數據樣本一樣也能夠在隨書的配套資源中找到。
爲了使讀者可以快速完成該實例,直觀上感覺到模型的識別能力,能夠直接使用本書配套的資源。並將其放到代碼的同級目錄下便可。
若是想體驗下從零開始手動搭建,也能夠按照下面的方法準備代碼環境及預編譯模型。
該部分的內容與3.1節徹底同樣,這裏再也不詳述。
該部分的內容與3.1節相似。在如圖3-2中的倒數第3個模型,找到 「nasnet-a_mobile_04_10_2017.tar.gz」的下載連接。將其下載並解壓。
本案例是經過4個代碼文件來實現的,具體文件及描述以下:
l 5-1 mydataset.py:處理男女圖片數據集的代碼;
l 5-2 model.py:加載預編譯模型NASNet_A_Mobile,並進行微調的代碼;
l 5-3 train.py:訓練模型的代碼;
l 5-4 test.py:測試模型的代碼。
部署時,將這4個代碼文件與slim庫、NASNet_A_Mobile模型、樣本一塊兒放到一個文件夾下便可。完整的文件結構如圖5-2。
圖5-2 分辨男女案例的文件結構
本案例中,直接將數據集的相關操做封裝到了「5-1 mydataset.py」代碼文件裏。在該文件中,實現了符合訓練與測試使用場景的數據集。在訓練模式下,會對數據進行亂序處理;在測試模式下,直接使用順序數據。兩種數據集都是按批次讀取。
這部分的知識在第4章已經有全面的介紹,這裏再也不詳述。完整代碼以下:
代碼5-1 mydataset
1 import tensorflow as tf
2 import sys
3 nets_path = r'slim' #加載環境變量
4 if nets_path not in sys.path:
5 sys.path.insert(0,nets_path)
6 else:
7 print('already add slim')
8 from nets.nasnet import nasnet #導出nasnet
9 slim = tf.contrib.slim #slim
10 image_size = nasnet.build_nasnet_mobile.default_image_size #得到圖片輸入尺寸 224
11 from preprocessing import preprocessing_factory #圖像處理
12
13 import os
14 def list_images(directory):
15 """ 16 獲取全部directory中的全部圖片和標籤 17 """
18
19 #返回path指定的文件夾包含的文件或文件夾的名字的列表
20 labels = os.listdir(directory)
21 #對標籤進行排序,以便訓練和驗證按照相同的順序進行
22 labels.sort()
23 #建立文件標籤列表
24 files_and_labels = []
25 for label in labels:
26 for f in os.listdir(os.path.join(directory, label)):
27 #轉換字符串中全部大寫字符爲小寫再判斷
28 if 'jpg' in f.lower() or 'png' in f.lower():
29 #加入列表
30 files_and_labels.append((os.path.join(directory, label, f), label))
31 #理解爲解壓 把數據路徑和標籤解壓出來
32 filenames, labels = zip(*files_and_labels)
33 #轉換爲列表 分別儲存數據路徑和對應標籤
34 filenames = list(filenames)
35 labels = list(labels)
36 #列出分類總數 好比兩類:['man', 'woman']
37 unique_labels = list(set(labels))
38
39 label_to_int = {}
40 #循環列出數據和數據下標,給每一個分類打上標籤{'woman': 2, 'man': 1,none:0}
41 for i, label in enumerate(sorted(unique_labels)):
42 label_to_int[label] = i+1
43 print(label,label_to_int[label])
44 #把每一個標籤化爲0 1 這種形式
45 labels = [label_to_int[l] for l in labels]
46 print(labels[:6],labels[-6:])
47 return filenames, labels #返回儲存數據路徑和對應轉換後的標籤
48
49 num_workers = 2 #定義並行處理數據的線程數量
50
51 #圖像批量預處理
52 image_preprocessing_fn = preprocessing_factory.get_preprocessing('nasnet_mobile', is_training=True)
53 image_eval_preprocessing_fn = preprocessing_factory.get_preprocessing('nasnet_mobile', is_training=False)
54
55 def _parse_function(filename, label): #定義圖像解碼函數
56 image_string = tf.read_file(filename)
57 image = tf.image.decode_jpeg(image_string, channels=3)
58 return image, label
59
60 def training_preprocess(image, label): #定義調整圖像大小函數
61 image = image_preprocessing_fn(image, image_size, image_size)
62 return image, label
63
64 def val_preprocess(image, label): #定義評估圖像預處理函數
65 image = image_eval_preprocessing_fn(image, image_size, image_size)
66 return image, label
67
68 #建立帶批次的數據集
69 def creat_batched_dataset(filenames, labels,batch_size,isTrain = True):
70
71 dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))
72
73 dataset = dataset.map(_parse_function, num_parallel_calls=num_workers) #對圖像解碼
74
75 if isTrain == True:
76 dataset = dataset.shuffle(buffer_size=len(filenames)) #打亂數據順序
77 dataset = dataset.map(training_preprocess, num_parallel_calls=num_workers)#調整圖像大小
78 else:
79 dataset = dataset.map(val_preprocess,num_parallel_calls=num_workers) #調整圖像大小
80
81 return dataset.batch(batch_size) #返回批次數據
82
83 #根據目錄返回數據集
84 def creat_dataset_fromdir(directory,batch_size,isTrain = True):
85 filenames, labels = list_images(directory)
86 num_classes = len(set(labels))
87 dataset = creat_batched_dataset(filenames, labels,batch_size,isTrain)
88 return dataset,num_classes 複製代碼
代碼11行,導入了preprocessing_factory函數,該函數是slim模塊中封裝好的工廠函數,用於生成模型的預處理函數。利用統一封裝好的預處理函數,對樣本進行操做(代碼60、61行),能夠提高開發效率,並可以減少出錯的可能性。
工廠函數的知識點,屬於Python基礎知識,這裏再也不詳述。有興趣的讀者能夠參考《python帶我起飛——入門、進階、商業實戰》一書的6.10節。
在微調模型的實現中,統一經過定義類MyNASNetModel來實現。在類MyNASNetModel中,大體可分爲2大動做:初始化設置、構建模型。
l 初始化設置:定義好構建模型時所須要的必要參數;
l 構建模型:針對訓練、測試、應用的三種狀況分別構建不一樣的網絡模型。在訓練過程當中,還要支持加載預編譯模型及微調模型。
實現定義類MyNASNetModel並進行初始化模型設置的代碼以下:
代碼5-2 model
1 import sys
2 nets_path = r'slim' #加載環境變量
3 if nets_path not in sys.path:
4 sys.path.insert(0,nets_path)
5 else:
6 print('already add slim')
7
8 import tensorflow as tf
9 from nets.nasnet import nasnet #導出nasnet
10 slim = tf.contrib.slim
11
12 import os
13 mydataset = __import__("5-1 mydataset")
14 creat_dataset_fromdir = mydataset.creat_dataset_fromdir
15
16 class MyNASNetModel(object):
17 """微調模型類MyNASNetModel 18 """
19 def __init__(self, model_path=''):
20 self.model_path = model_path #原始模型的路徑 複製代碼
代碼20行爲初始化MyNASNetModel類的操做。model_path指的是所要加載的原始預編譯模型。該操做只有在訓練模式下是有意義的。在測試和應用模式下,能夠爲空。
在構建模型中,不管是訓練、測試仍是應用,都須要將最基本的NASNet_A_Mobile模型載入。這裏經過定義MyNASNetModel類的MyNASNet方法來實現。具體的實現方式與3.3節的實現基本一致,不一樣的是3.3節構建的是PNASNet網絡結構,這裏構建的NASNet_A_Mobile結構。
代碼5-2 model(續)
21 def MyNASNet(self,images,is_training):
22 arg_scope = nasnet.nasnet_mobile_arg_scope() #得到模型命名空間
23 with slim.arg_scope(arg_scope):
24 #構建NASNet Mobile模型
25 logits, end_points = nasnet.build_nasnet_mobile(images,num_classes = self.num_classes+1, is_training=is_training)
26
27 global_step = tf.train.get_or_create_global_step() #定義記錄步數的張量
28
29 return logits,end_points,global_step #返回有用的張量
複製代碼
代碼25行中,往num_classes參數裏傳的值表明分類的個數,在本案例中分爲男人和女人,一共兩類(即,self.num_classes=2,該值是在後文5.2.8節中,build_model方法被賦值的)。再加上一個None類。因而傳入的值爲self.num_classes+1。
微調操做是針對訓練場景下使用的。經過定義MyNASNetModel類中的FineTuneNASNet方法來實現。微調操做主要是對預編譯模型的超參進行選擇性恢復。
由於預編譯模型NASNet_A_Mobile是在ImgNet上訓練的,有1000個分類,而本案例中識別男女的任務只有兩個分類。因此最後兩個輸出層的超參不該該被恢復(因爲分類不一樣,致使超參的個數不一樣)。在實際使用時,最後兩層的參數須要對其初始化,並單獨訓練便可。
代碼5-2 model(續)
30 def FineTuneNASNet(self,is_training): #實現微調模型的網絡操做
31 model_path = self.model_path
32
33 exclude = ['final_layer','aux_7'] #恢復超參, 除了exclude之外的所有恢復
34 variables_to_restore = slim.get_variables_to_restore(exclude=exclude)
35 if is_training == True:
36 init_fn = slim.assign_from_checkpoint_fn(model_path, variables_to_restore)
37 else:
38 init_fn = None
39
40 tuning_variables = [] #將沒有恢復的超參收集起來,用於微調訓練
41 for v in exclude:
42 tuning_variables += slim.get_variables(v)
43
44 return init_fn, tuning_variables複製代碼
代碼中,使用了exclude列表,將不須要恢復的網絡節點收集起來(代碼33行),接着將預訓練模型中的超參值賦值給剩下的節點,完成了預訓練模型的載入(代碼36行)。最後使用了tuning_variables列表,將不須要恢復的網絡節點權重收集起來(代碼40行),用於微調訓練。
在MyNASNetModel類中,還須要定義與訓練操做相關的其餘方法,具體以下:
l build_acc_base方法:用於構建評估模型的相關節點;
l load_cpk方法:用於載入及保存模型檢查點
l build_model_train方法:用於構建訓練模型中的損失函數及優化器等操做節點。
具體代碼以下:
代碼5-2 model(續)
45 def build_acc_base(self,labels):#定義評估函數
46 #返回張量中最大值的索引
47 self.prediction = tf.to_int32(tf.argmax(self.logits, 1))
48 #計算prediction、labels是否相同
49 self.correct_prediction = tf.equal(self.prediction, labels)
50 #計算平均值
51 self.accuracy = tf.reduce_mean(tf.to_float(self.correct_prediction))
52 #將前5個最高正確率的值取出來,計算平均值
53 self.accuracy_top_5 = tf.reduce_mean(tf.to_float(tf.nn.in_top_k(predictions=self.logits, targets=labels, k=5)))
54
55 def load_cpk(self,global_step,sess,begin = 0,saver= None,save_path = None): #儲存和導出模型
56 if begin == 0:
57 save_path=r'./train_nasnet' #定義檢查點路徑
58 if not os.path.exists(save_path):
59 print("there is not a model path:",save_path)
60 saver = tf.train.Saver(max_to_keep=1) #生成saver
61 return saver,save_path
62 else:
63 kpt = tf.train.latest_checkpoint(save_path) #查找最新的檢查點
64 print("load model:",kpt)
65 startepo= 0 #計步
66 if kpt!=None:
67 saver.restore(sess, kpt) #還原模型
68 ind = kpt.find("-")
69 startepo = int(kpt[ind+1:])
70 print("global_step=",global_step.eval(),startepo)
71 return startepo
72
73 def build_model_train(self,images,
74 labels,learning_rate1,learning_rate2,is_training):
75 self.logits,self.end_points,
76 self.global_step= self.MyNASNet(images,is_training=is_training)
77 self.step_init = self.global_step.initializer
78
79 self.init_fn,self.tuning_variables = self.FineTuneNASNet(
80 is_training=is_training)
81 #定義損失函數
82 tf.losses.sparse_softmax_cross_entropy(labels=labels,
83 logits=self.logits)
84 loss = tf.losses.get_total_loss()
85 #定義微調的率退化學習速率
86 learning_rate1=tf.train.exponential_decay(
87 learning_rate=learning_rate1, global_step=self.global_step,
88 decay_steps=100, decay_rate=0.5)
89 #定義聯調的率退化學習速率
90 learning_rate2=tf.train.exponential_decay(
91 learning_rate=learning_rate2, global_step=self.global_step,
92 decay_steps=100, decay_rate=0.2)
93 last_optimizer = tf.train.AdamOptimizer(learning_rate1) #優化器
94 full_optimizer = tf.train.AdamOptimizer(learning_rate2)
95 update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
96 with tf.control_dependencies(update_ops): #更新批量歸一化中的參數
97 #使loss減少方向作優化
98 self.last_train_op = last_optimizer.minimize(loss, self.global_step,var_list=self.tuning_variables)
99 self.full_train_op = full_optimizer.minimize(loss, self.global_step)
100
101 self.build_acc_base(labels) #定義評估模型相關指標
102 #寫入日誌,支持tensorBoard操做
103 tf.summary.scalar('accuracy', self.accuracy)
104 tf.summary.scalar('accuracy_top_5', self.accuracy_top_5)
105
106 #將收集的全部默認圖表併合並
107 self.merged = tf.summary.merge_all()
108 #寫入日誌文件
109 self.train_writer = tf.summary.FileWriter('./log_dir/train')
110 self.eval_writer = tf.summary.FileWriter('./log_dir/eval')
111 #定義檢查點相關變量
112 self.saver,self.save_path = self.load_cpk(self.global_step,None)複製代碼
在上面代碼中,使用了tf.losses接口來得到loss值。經過調用tf.losses.sparse_softmax_cross_entropy 函數計算具體的loss(見代碼82行)。該函數會自動將loss值添加到內部集合ops.GraphKeys.LOSSES中。而後調用tf.losses.get_total_loss函數,將ops.GraphKeys.LOSSES集合中的全部loss值獲取,並返回回來(見代碼84行)。
在代碼96行中,在反向優化時,使用了tf.control_dependencies函數對的批量歸一化操做中的均值與方差進行更新。
在MyNASNetModel類中,定義build_model方法用與構建模型的實現。在build_model方法中,經過參數mode來指定模型的具體使用場景。具體代碼以下:
代碼5-2 model(續)
113 def build_model(self,mode='train',testdata_dir='./data/val',traindata_dir='./data/train', batch_size=32,learning_rate1=0.001,learning_rate2=0.001):
114
115 if mode == 'train':
116 tf.reset_default_graph()
117 #建立訓練數據和測試數據的Dataset數據集
118 dataset,self.num_classes = creat_dataset_fromdir(traindata_dir,batch_size)
119 testdataset,_ = creat_dataset_fromdir(testdata_dir,batch_size,isTrain = False)
120
121 #建立一個可初始化的迭代器
122 iterator = tf.data.Iterator.from_structure(dataset.output_types, dataset.output_shapes)
123 #讀取數據
124 images, labels = iterator.get_next()
125
126 self.train_init_op = iterator.make_initializer(dataset)
127 self.test_init_op = iterator.make_initializer(testdataset)
128
129 self.build_model_train(images, labels,learning_rate1,learning_rate2,is_training=True)
130 self.global_init = tf.global_variables_initializer() #定義全局初始化op
131 tf.get_default_graph().finalize() #將後續的圖設爲只讀
132 elif mode == 'test':
133 tf.reset_default_graph()
134
135 #建立測試數據的Dataset數據集
136 testdataset,self.num_classes = creat_dataset_fromdir(testdata_dir,batch_size,isTrain = False)
137
138 #建立一個可初始化的迭代器
139 iterator = tf.data.Iterator.from_structure(testdataset.output_types, testdataset.output_shapes)
140 #讀取數據
141 self.images, labels = iterator.get_next()
142
143 self.test_init_op = iterator.make_initializer(testdataset)
144 self.logits,self.end_points, self.global_step= self.MyNASNet(self.images,is_training=False)
145 self.saver,self.save_path = self.load_cpk(self.global_step,None) #定義檢查點相關變量
146 #評估指標
147 self.build_acc_base(labels)
148 tf.get_default_graph().finalize() #將後續的圖設爲只讀
149 elif mode == 'eval':
150 tf.reset_default_graph()
151 #建立測試數據的Dataset數據集
152 testdataset,self.num_classes = creat_dataset_fromdir(testdata_dir,batch_size,isTrain = False)
153
154 #建立一個可初始化的迭代器
155 iterator = tf.data.Iterator.from_structure(testdataset.output_types, testdataset.output_shapes)
156 #讀取數據
157 self.images, labels = iterator.get_next()
158
159 self.logits,self.end_points, self.global_step= self.MyNASNet(self.images,is_training=False)
160 self.saver,self.save_path = self.load_cpk(self.global_step,None) #定義檢查點相關變量
161 tf.get_default_graph().finalize() #將後續的圖設爲只讀複製代碼
代碼115行,對mode進行了判斷,並按照具體的場景進行構建模型。針對訓練、測試、使用的三個場景,構建的步驟幾乎同樣,具體以下:
(1)清空張量圖(代碼11六、13三、150);
(2)生成數據集(代碼11八、13六、152);
(3)定義網絡結構(代碼12九、14四、159)。
測試與使用的場景是最類似的。在代碼中測試比使用的操做對了個評估節點的生成(代碼147)。
訓練微調模型的操做是在代碼文件「5-3 train.py」中單獨實現的。與正常的訓練方式不一樣,這裏使用了二次迭代的方式:
l 第一次迭代:微調模型,固定預編譯模型載入的權重,只訓練最後兩層;
l 第二次迭代:聯調模型,使用更小的學習率,訓練所有節點。
先將類MyNASNetModel進行實例化,在調用其build_model方法構建模型,而後使用session開始訓練。具體代碼以下:
代碼5-3 train
162 import tensorflow as tf
163 model = __import__("5-2 model")
164 MyNASNetModel = model.MyNASNetModel
165
166 batch_size = 32
167 train_dir = 'data/train'
168 val_dir = 'data/val'
169
170 learning_rate1 = 1e-1 #定義兩次迭代的學習率
171 learning_rate2 = 1e-3
172
173 mymode = MyNASNetModel(r'nasnet-a_mobile_04_10_2017\model.ckpt')#初始化模型
174 mymode.build_model('train',val_dir,train_dir,batch_size,learning_rate1 ,learning_rate2 ) #將模型定義載入圖中
175
176 num_epochs1 = 20 #微調的迭代次數
177 num_epochs2 = 200 #聯調的迭代次數
178
179 with tf.Session() as sess:
180 sess.run(mymode.global_init) #初始全局節點
181
182 step = 0
183 step = mymode.load_cpk(mymode.global_step,sess,1,mymode.saver,mymode.save_path )#載入模型
184 print(step)
185 if step == 0: #微調
186 mymode.init_fn(sess) #載入預編譯模型權重
187
188 for epoch in range(num_epochs1):
189
190 print('Starting1 epoch %d / %d' % (epoch + 1, num_epochs1)) #輸出進度
191 #用訓練集初始化迭代器
192 sess.run(mymode.train_init_op) #數據集從頭開始
193 while True:
194 try:
195 step += 1
196 #預測,合併圖,訓練
197 acc,accuracy_top_5, summary, _ = sess.run([mymode.accuracy, mymode.accuracy_top_5,mymode.merged,mymode.last_train_op])
198
199 #mymode.train_writer.add_summary(summary, step)#寫入日誌文件
200 if step % 100 == 0:
201 print(f'step: {step} train1 accuracy: {acc},{accuracy_top_5}')
202 except tf.errors.OutOfRangeError:#數據集指針在最後
203 print("train1:",epoch," ok")
204 mymode.saver.save(sess, mymode.save_path+"/mynasnet.cpkt", global_step=mymode.global_step.eval())
205 break
206
207 sess.run(mymode.step_init) #微調結束,計數器從0開始
208
209 #總體訓練
210 for epoch in range(num_epochs2):
211 print('Starting2 epoch %d / %d' % (epoch + 1, num_epochs2))
212 sess.run(mymode.train_init_op)
213 while True:
214 try:
215 step += 1
216 #預測,合併圖,訓練
217 acc, summary, _ = sess.run([mymode.accuracy, mymode.merged, mymode.full_train_op])
218
219 mymode.train_writer.add_summary(summary, step)#寫入日誌文件
220
221 if step % 100 == 0:
222 print(f'step: {step} train2 accuracy: {acc}')
223 except tf.errors.OutOfRangeError:
224 print("train2:",epoch," ok")
225 mymode.saver.save(sess, mymode.save_path+"/mynasnet.cpkt", global_step=mymode.global_step.eval())
226 break複製代碼
將以上代碼運行後,通過一段時間的訓練,能夠在本地找到「train_nasnet」文件夾,裏面放着的就是訓練生成的模型文件。
測試模型的操做是在代碼文件「5-4 test.py」中單獨實現的。這裏實現了使用測試數據集對現有模型的評估,而且使用單張圖片放到模型裏進行預測。
首先定義函數check_accuracy實現準確率的計算,接着定義函數check_sex實現男女性別的識別。具體代碼以下:
代碼5-4 test
227 import tensorflow as tf
228 model = __import__("5-2 model")
229 MyNASNetModel = model.MyNASNetModel
230
231 import sys
232 nets_path = r'slim' #加載環境變量
233 if nets_path not in sys.path:
234 sys.path.insert(0,nets_path)
235 else:
236 print('already add slim')
237
238 from nets.nasnet import nasnet #導出nasnet
239 slim = tf.contrib.slim #slim
240 image_size = nasnet.build_nasnet_mobile.default_image_size #得到圖片輸入尺寸 224
241
242 import numpy as np
243 from PIL import Image
244
245 batch_size = 32
246 test_dir = 'data/val'
247
248 def check_accuracy(sess):
249 """ 250 測試模型準確率 251 """
252 sess.run(mymode.test_init_op) #初始化測試數據集
253 num_correct, num_samples = 0, 0 #定義正確個數 和 總個數
254 i = 0
255 while True:
256 i+=1
257 print('i',i)
258 try:
259 #計算correct_prediction 獲取prediction、labels是否相同
260 correct_pred,accuracy,logits = sess.run([mymode.correct_prediction,mymode.accuracy,mymode.logits])
261 #累加correct_pred
262 num_correct += correct_pred.sum()
263 num_samples += correct_pred.shape[0]
264 print("accuracy",accuracy,logits)
265
266
267 except tf.errors.OutOfRangeError: #捕獲異常,數據用完自動跳出
268 print('over')
269 break
270
271 acc = float(num_correct) / num_samples #計算並返回準確率
272 return acc
273
274
275 def check_sex(imgdir,sess): #定義函數識別男女
276 img = Image.open(image_dir) #讀入圖片
277 if "RGB"!=img.mode : #檢查圖片格式
278 img = img.convert("RGB")
279
280 img = np.asarray(img.resize((image_size,image_size)), #圖像預處理
281 dtype=np.float32).reshape(1,image_size,image_size,3)
282 img = 2 *( img / 255.0)-1.0
283
284 prediction = sess.run(mymode.logits, {mymode.images: img})#傳入nasnet輸入端中
285 print(prediction)
286
287 pre = prediction.argmax() #返回張量中最大值的索引
288 print(pre)
289
290 if pre == 1: img_id = 'man'
291 elif pre == 2: img_id = 'woman'
292 else: img_id = 'None'
293 plt.imshow( np.asarray((img[0]+1)*255/2,np.uint8 ) )
294 plt.show()
295 print(img_id,"--",image_dir) #返回類別
296 return pre複製代碼
首先創建會話session,對模型進行測試,接着取2張圖片輸入模型,進行男女的判斷。具體代碼以下:
代碼5-4 test(續)
297 mymode = MyNASNetModel() #初始化模型
298 mymode.build_model('test',test_dir ) #將模型定義載入圖中
299
300 with tf.Session() as sess:
301 #載入模型
302 mymode.load_cpk(mymode.global_step,sess,1,mymode.saver,mymode.save_path )
303
304 #測試模型的準確性
305 val_acc = check_accuracy(sess)
306 print('Val accuracy: %f\n' % val_acc)
307
308 #單張圖片測試
309 image_dir = 'tt2t.jpg' #選取測試圖片
310 check_sex(image_dir,sess)
311
312 image_dir = test_dir + '\\woman' + '\\000001.jpg' #選取測試圖片
313 check_sex(image_dir,sess)
314
315 image_dir = test_dir + '\\man' + '\\000003.jpg' #選取測試圖片
316 check_sex(image_dir,sess)複製代碼
該程序使用的是迭代了100次數據集後的模型文件(若是要效果提升,能夠再運行久一點)。代碼運行後,輸出結果以下。
(1)顯示測試集的輸出結果:
i 1
accuracy 0.90625 [[-3.813714 1.4075054 1.1485975 ]
[-7.3948846 6.220533 -1.4093535 ]
[-1.9391974 3.048838 0.21784738]
[-3.873174 4.530942 0.43135062]
……
[-3.8561587 2.7012844 -0.3634925 ]
[-4.4860134 4.7661724 -0.67080706]
[-2.9615571 2.8164086 0.71033645]]
i 2
accuracy 0.90625 [[ -6.6900268 -2.373093 6.6710057 ]
[ -4.1005263 0.74619263 4.980012 ]
[ -5.6469827 0.39027584 1.2689826 ]
……
[ -5.8080773 0.9121424 3.4134243 ]
[ -4.242001 0.08483959 4.056322 ]]
i 3
over
Val accuracy: 0.906250
上面顯示的是測試集中man和woman文件夾中圖片的計算結果。最終模型的準確率爲90%。
(2)顯示單張圖片的運行結果:
[[-4.8022223 1.9008529 1.9379601]]
2
圖5-3 分辨男女測試圖片(a)
woman -- tt2t.jpg
[[-6.181205 -2.9042015 6.1356106]]
2
圖5-3 分辨男女測試圖片(b)
woman -- data/val\woman\000001.jpg
[[-4.896065 1.7791721 1.3118265]]
1
圖5-3 分辨男女測試圖片(c)
man -- data/val\man\000003.jpg
上面顯示了3張圖片,分別爲自選圖片、測試數據集中的女人圖片、測試數據集中的男人圖片,每張圖片下面顯示了模型識別的結果。能夠看到結果與圖片內容一致。
結尾
文內代碼能夠直接運行使用。若是不想手動搭建,還能夠下載本文的配套代碼。
【代碼獲取】:關注公衆號:xiangyuejiqiren 公衆號回覆「pycon2」
若是以爲本文有用
能夠分享給更多小夥伴