多輸出模型
使用函式式API構建多輸出模型完成多標籤分類任務。
資料集下載連結:https://pan.baidu.com/s/1JtKt7KCR2lEqAirjIXzvgg 提取碼:2kbc
1.讀取資料並構建資料集
詳細的API介紹在Tensorflow學習筆記5.0中均有提及,這裡只簡單講述方法流程並展示程式碼。
1.1圖片資料讀取
首先匯入需要的模組(執行環境為jupyternotebook)。
1 import tensorflow as tf 2 import numpy as np 3 import pathlib 4 import matplotlib.pyplot as plt 5 import random 6 %matplotlib inline
建立地址為資料所在位置的根目錄,所建立的data_root為一個WindowsPath型別的變數。。
1 data_dir = 'E:/BaiduNetdiskDownload/多輸出模型資料集(同時預測物品和顏色)/multi-output-classification/dataset' 2 data_root = pathlib.Path(data_dir)
讀取該目錄下所有的jpg/jpeg檔案,圖片儲存位置為dataset/(標籤資料夾)/*,所以使用.glob('*/*')來獲取所有的圖片檔案。
1 all_image_path = list(data_root.glob('*/*')) 2 image_count = len(all_image_path) #共計2525張圖片
1.2標籤讀取
在讀取完圖片之後,我們還要讀取圖片對應的標籤資訊。
我們所進行的是一個衣服分類任務,每件衣服都有顏色和型別兩個標籤,我們需要提取出每張圖片對應的標籤。
圖片儲存在名字為“顏色_型別”的資料夾下,對應了這些圖片的顏色和型別,所以我們對資料夾名字進行處理即可。
首先我們獲取所有含有標籤資訊的資料夾名稱。
1 label_names = sorted(item.name for item in data_root.glob('*') if item.is_dir())
label_names中包含了所有的標籤名稱——['black_jeans', 'black_shoes', 'blue_dress', 'blue_jeans', 'blue_shirt', 'red_dress', 'red_shirt']。總共七種類別,為三種顏色類別和四種衣服型別的組合。
下一步獎顏色和型別標籤分別提取出來,使用.split('_')對字串進行分割,得到每個複合標籤對應的兩個基本標籤。
1 color_label = set(name.split('_')[0] for name in label_names) 2 item_label = set(name.split('_')[1] for name in label_names)
然後我們通過這兩個存有標籤的集合構建從標籤字串對映到數字編號的字典。
1 color_to_indx = dict((name, indx) for indx, name in enumerate(color_label)) 2 item_to_indx = dict((name, indx) for indx, name in enumerate(item_label))
現在我們僅僅是獲得了字典,而沒有獲得與圖片對應的基本標籤,下一步我們著手製作這些標籤,一個圖片應該對應兩個標籤。
首先獲取每個圖片與之對應的複合類別標籤(顏色_型別標籤)。
使用.parent.name方法獲得WindowsPath物件的父資料夾名字,即圖片的標籤。
1 all_image_label = list(pathlib.Path(path).parent.name for path in all_image_path)
然後通過兩個字典構建出每個圖片的兩個數字標籤。
1 color_label = list(color_to_indx[label.split('_')[0]] for label in all_image_label) 2 item_label = list(item_to_indx[label.split('_')[1]] for label in all_image_label)
1.3資料集的構建
在獲取完標籤和影像地址後,我們利用這些資訊來製作一個標準的資料集。
首先定義一個影像處理函式,用於讀取並解碼影像,同時歸一化為統一的尺寸。
1 def load_pregrosess_image(path): 2 image = tf.io.read_file(path) 3 image = tf.image.decode_jpeg(image, channels = 3) 4 image = tf.image.resize(image, [224, 224]) 5 image = tf.cast(image, tf.float32) 6 image = image / 255 7 #image = image * 2 - 1 8 return image
使用tf.data中提供的方法對圖片地址進行切片操作,變成一個dateset型別的資料,然後使用.map方法利用剛剛定義的函式將地址處理為影像。
1 train_image_ds = tf.data.Dataset.from_tensor_slices(all_image_path) 2 image_data = train_image_ds.map(load_pregrosess_image)
同樣的把兩個標籤也切片封裝為dataset型別的檔案,最後再把圖片和標籤合併變成完整的資料集。
1 label_data = tf.data.Dataset.from_tensor_slices((color_label, item_label)) 2 dataset = tf.data.Dataset.zip((image_data, label_data))
隨後按照8:2分為訓練集和驗證集即可。
1 BATCHSIZE = 8 2 train_count = int(image_count * 0.8) 3 test_count = image_count - train_count 4 5 train_dataset = dataset.take(train_count) 6 test_dataset = dataset.skip(train_count) 7 8 train_dataset = train_dataset.shuffle(train_count).repeat().batch(BATCHSIZE) 9 test_dataset = test_dataset.repeat().batch(BATCHSIZE)
至此資料集構建完畢,下一步將搭建模型並進行訓練。
2.多輸出模型
由於我們要預測圖片的兩個屬性,顏色和衣服型別,同樣的我們也需要兩個輸出,然而線性模型顯然無法滿足我們的需求。所以我們使用函式式API構建非線性模型來完成目標。
2.1構建模型
我們的模型結構為一個卷積神經網路和兩個分類器,如圖所示。(3D畫圖隨手一畫很醜見諒(。﹏。*))
由卷積神經網路提取特徵,然後通過兩個分類器輸出圖片在兩個不同標籤上的分類結果。
我們採用預訓練的Mobile-Net作為卷積部分並凍結其可訓練引數,使用函式式API搭建模型,注意這裡有兩個輸出層,在keras.Model方法中用列表形式作為輸入,同時給兩個輸出層新增name引數進行命名便於區分和後續呼叫。
函式式API在Tensorflow學習筆記No.2中有詳細介紹這裡也不再做贅述,預訓練網路的使用在Tensorflow學習筆記No.8中有相關介紹。
1 input = tf.keras.Input(shape = (224, 224, 3)) 2 3 mobile_net = tf.keras.applications.MobileNetV2(weights = 'imagenet', input_shape = (224, 224, 3), include_top = False) 4 mobile_net.trianable = False 5 6 x = mobile_net(input) 7 x = tf.keras.layers.GlobalAveragePooling2D()(x) 8 x1 = tf.keras.layers.Dense(1024, activation = 'relu')(x) 9 x2 = tf.keras.layers.Dense(1024, activation = 'relu')(x) 10 output_color = tf.keras.layers.Dense(3, activation = 'softmax', name = 'output_color')(x1) 11 output_item = tf.keras.layers.Dense(4, activation = 'softmax', name = 'output_item')(x2) 12 13 model = tf.keras.Model(inputs = input, outputs = [output_color, output_item])
將全連線層和softmax組合在一起作為分類器,按照上圖所示方式進行連線即可。
得到的模型如下圖所示,使用model.summary()進行檢視:
2.2模型訓練
不熟悉model.complie()和model.fit()方法的小夥伴可以翻看Tensorflow學習筆記No.1進行學習這裡也不在贅述(主要是因為懶)。
注意,因為有兩個分類器,所以對每個分類器要單獨規定一個損失函式,使用字典的方式按照{輸出層名稱:損失函式,......}的格式指定分類器,前面對卷積命名也是方便此步驟的進行。
steps_per_epoch和validation_steps代表了訓練集和驗證集每一個epoch需要訓練多少步,也就是資料總數/BATCH_SIZE。
注意學習率設定為0.0001等較小的學習率,使用較大的學習率會導致loss異常增大。
1 model.compile(optimizer = tf.keras.optimizers.Adam(learning_rate=0.0001), 2 loss = {'output_color':'sparse_categorical_crossentropy', 3 'output_item':'sparse_categorical_crossentropy'}, 4 metrics = ['acc'] 5 ) 6 7 history = model.fit(train_dataset, 8 steps_per_epoch = train_count//BATCHSIZE, 9 epochs = 5, 10 validation_data = test_dataset, 11 validation_steps = test_count//BATCHSIZE, 12 )
由於使用了預訓練模型,只需要5個epochs便可以達到90%以上的準確率,得到如下所示結果(僅供參考)。
到這裡多輸出模型的例項就結束了,前段時間由於事情較多斷更了一段時間,後續會繼續更新Tensorflow的學習筆記。由於本人正在參加AI演算法競賽(入門菜雞),後續可能會分享一些與競賽有關的內容,撒悠娜拉 Bey~ o(* ̄▽ ̄*)ブ。