Tensorflow2.0學習(八) — tf.dataset自定義圖像數據集

這一節我們參照官方教程提供的代碼,研究如何製作自己的數據集並送入深度學習模型中訓練。我們可以看到,前幾節的內容很多是基於現成的數據集,直接導入使用即可。但在實際應用中,這顯然是不可行的。對於Tensorflow2.0,主要有兩種自定義製作我們自己數據集的方式:一種是直接由tensorflow自身提供的函數來進行製作,而另一種則是調用tensorflow的高級API  Keras的函數來製作,這兩種方式都是可行的。但是建議大家還是使用官方提供的tf.dataset方式,但在這裏二者都會進行介紹。那麼這一節會先講如何用tensorflow自身提供的方式來自定義數據集,下一節則會討論另一種方式。

這一節我們將要對一些花的數據集來進行處理,這個數據集在網上可以通過遠程鏈接進行下載。但是由於該數據集沒有分好訓練集和測試集的部分,因此在本節代碼中我們不對模型進行測試,當然這也並不是我們這一節的重點,大家只要注重數據集製作的部分即可。

這裏附上官方代碼的鏈接:https://tensorflow.google.cn/tutorials/load_data/images

一.自定義數據集的讀取

1.導入相關庫。

from __future__ import absolute_import,division,print_function,unicode_literals
import tensorflow as tf
import pathlib #讀圖片路徑
import random
import IPython.display as display #顯示圖片
import os
import matplotlib.pyplot as plt

2.這行的代碼主要是跟圖像數據後臺的緩存處理有關。

AUTOTUNE = tf.data.experimental.AUTOTUNE

3.下載數據集。fname的意思爲下載後文件的命名,而untar=True的意思爲對下載完後的文件壓縮包直接進行解壓。

data_root_orig = tf.keras.utils.get_file(origin='https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',fname='flower_photos',untar=True)

4.得到下載文件的目錄。

data_root = pathlib.Path(data_root_orig)
data_root

5.用iterdir()查看該文件夾下的文件情況。

for item in data_root.iterdir():
    print(item)

6.用glob獲取所有文件並存入列表中。這裏*的意思爲獲取所有文件,因此*/*的意思則爲獲取文件夾下的所有文件及它們的子文件。

all_images_paths = list(data_root.glob('*/*')) #獲取所有文件路徑
all_images_paths[-5:] #顯示後5個數據

7.將所有文件路徑存入列表並打亂順序。

all_images_paths = [str(path) for path in all_images_paths] #將文件路徑傳入列表
random.shuffle(all_images_paths) #打亂文件路徑順序
image_count = len(all_images_paths) #查看文件數量
image_count

8.隨機選擇3張圖片進行顯示。random_choice的意思爲隨機選擇。

for n in range(3):
    image_path = random.choice(all_images_paths) #隨機選擇
    display.display(display.Image(image_path)) #圖片顯示

9.獲取不同花朵圖片標籤的名字。這裏*/獲得的是當前目錄的文件路徑,item.name函數可自動從路徑中篩選出需要的圖片名。

label_names = sorted(item.name for item in data_root.glob('*/') if item.is_dir())
label_names

10.因爲在訓練時參數必須爲數字,因此我們需要將標籤轉爲數字表示。這裏的enumerate屬於python的語法,即是爲其建立一個索引序列並配上下標。

label_to_index = dict((name,index)for index,name in enumerate(label_names)) #轉數字
label_to_index

11.查看所有圖片路徑文件的類別。因爲圖片路徑的上一級目錄名字就是代表的它的類別,因此我們可以用parent.name直接得到。

for path in all_images_paths:
    print(pathlib.Path(path).parent.name) #上級路徑

12.存儲圖片的數字標籤到列表中。

all_images_labels = [label_to_index[pathlib.Path(path).parent.name] for path in all_images_paths]
print(all_images_labels[:10]) #顯示前10個圖片標籤

二.自定義數據集的預處理

1.定義圖片預處理函數和圖片讀入函數,第一個decode_jpeg爲將讀入圖片的參數映射爲圖片,然後將圖片大小統一併歸一化。

def preprocess_img(image):
    image = tf.image.decode_jpeg(image,channels=3) #映射爲圖片
    image = tf.image.resize(image,[192,192]) #修改大小
    image /= 255.0 #歸一化
    return image

def load_and_preprocess_image(path):
    image = tf.io.read_file(path) #這裏注意的是這裏讀到的是許多圖片參數
    return preprocess_img(image)

2.顯示其中一張圖片。

image_path = all_images_paths[0]
label = all_images_labels[0]
plt.imshow(load_and_preprocess_image(image_path))
plt.grid(False)
plt.title(label_names[label].title())

3.構建一個tf.dataset,將圖片數據傳入其中。最簡單的方法就是使用from_tensor_slices方法。將圖片路徑字符串數組切片,得到一個字符串數據集。然後將我們剛纔定義的圖片讀取和預處理函數傳入map函數中,即通過在路徑數據集上映射preprocess_image來動態加載和格式化圖片。

path_ds = tf.data.Dataset.from_tensor_slices(all_images_paths) #路徑字符串集合
image_ds = path_ds.map(load_and_preprocess_image, num_parallel_calls=AUTOTUNE) #通過路徑加載圖片數據集

到了這一步我們就把我們的所有圖片數據集加載到tf.dataset中了。

4.將標籤數據也傳入其中。cast的意思即是將什麼數據轉爲什麼類型,這裏我們將其轉爲整型int64。

label_ds = tf.data.Dataset.from_tensor_slices(tf.cast(all_images_labels,tf.int64)) #讀入標籤

5.將圖片數據和標籤打包組合在一起。

image_label_ds = tf.data.Dataset.zip((image_ds,label_ds)) #圖片和標籤整合

6.我們還可以通過一些函數對圖片集進行打亂、重複、分批操作。

Batch_size = 32
ds = image_label_ds.shuffle(buffer_size=image_count) #打亂數據
ds = ds.repeat() #數據重複
ds = ds.batch(Batch_size) #分割batch
ds = ds.prefetch(buffer_size=AUTOTUNE) #使數據集在後臺取得 batch

到了這一步我們的圖片標籤都已經制作好了,下一步進行模型搭建訓練。

三.模型搭建

1.這裏我們將使用一個的名爲MobileNetV2模型作爲backbone進行訓練。192爲我們剛纔修改後圖片的尺寸,include_top意爲是否保留頂層的全連接層,這裏我們選擇False,因爲我們只需要它的特徵輸出部分。之後我們將這個模型設置爲還未訓練的形式。

mobile_net = tf.keras.applications.MobileNetV2(input_shape=(192,192,3),include_top=False) 
mobile_net.trainable=False

2.整體模型搭建。

model = tf.keras.Sequential([
    mobile_net,
    tf.keras.layers.GlobalAveragePooling2D(), #平均池化
    tf.keras.layers.Dense(len(label_names),activation='softmax') #分類
])

3.模型參數設置。

model.compile(optimizer=tf.keras.optimizers.Adam(),
              loss='sparse_categorical_crossentropy',
              metrics=["accuracy"])

4.打印模型概要。

model.summary()

5.查看模型需要訓練完所有圖片的次數是多少,我們將圖片數量/batch_size即可得到。這裏要注意的是epochs和step_per_epoch的區別,前者是整體全部圖片訓練的次數,後者則是要訓練完一次epoch所需要的step。

steps_per_epoch=tf.math.ceil(len(all_images_paths)/Batch_size).numpy()
steps_per_epoch

我們發現要訓練115個step所有的batch才能訓練完。爲了節約時間,我們這裏只選擇step=3。

model.fit(ds, epochs=1, steps_per_epoch=3,verbose=2)

 

以上就是本節的內容,下次內容會講述另一種製作數據集的方式。謝謝大家的觀看和支持!

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章