Tensorflow?2.4加載處理圖片的三種方式詳解
前言
本文通過使用 cpu 版本的 tensorflow 2.4 ,介紹三種方式進行加載和預(yù)處理圖片數(shù)據(jù)。
這里我們要確保 tensorflow 在 2.4 版本以上 ,python 在 3.8 版本以上,因為版本太低有些內(nèi)置函數(shù)無法使用,然后要提前安裝好 pillow 和 tensorflow_datasets ,方便進行后續(xù)的數(shù)據(jù)加載和處理工作。
由于本文不對模型進行質(zhì)量保證,只介紹數(shù)據(jù)的加載、處理過程,所以只將模型簡單訓(xùn)練即可。
數(shù)據(jù)準(zhǔn)備
首先我們先準(zhǔn)備本文的圖片數(shù)據(jù),這里我們直接使用 tensorflow 的內(nèi)置函數(shù),從網(wǎng)絡(luò)上面下載了一份花朵照片數(shù)據(jù)集,也可以直接用下面的鏈接使用迅雷下載。
數(shù)據(jù)目錄里面包含 5 個子目錄,每個子目錄對應(yīng)一個類,分別是雛菊、蒲公英、玫瑰、向日葵、郁金香,圖片總共有 3670 張。
import pathlib import numpy as np import os import PIL import PIL.Image import tensorflow as tf import tensorflow_datasets as tfds dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz" data_dir = tf.keras.utils.get_file(origin=dataset_url, fname='flower_photos', untar=True) data_dir = pathlib.Path(data_dir) image_count = len(list(data_dir.glob('*/*.jpg')))
使用內(nèi)置函數(shù)讀取并處理磁盤數(shù)據(jù)
(1)使用 KERAS 內(nèi)置的函數(shù) image_dataset_from_directory 從本地進行數(shù)據(jù)的加載,首先定義 batch_size 為 32 ,每張圖片維度大小為 (64,64,3) ,也就是長、寬有 64 個像素點,這里的長、寬像素點數(shù)量可以自行修改,需要注意的是數(shù)字越大圖片越清晰但是后續(xù)的計算量會越大,數(shù)字越小圖片越模糊但是后續(xù)的計算量越小。
每個像素點是一個 3 維的 RGB 顏色向量。而每個圖片對應(yīng)的標(biāo)簽是一個花朵類別的字符串。
我們使用 image_dataset_from_directory 選用了數(shù)據(jù)中 80% (2936 張)的圖片進行訓(xùn)練,20% (734 張)的圖片來進行模型效果的驗證。
我們將這 5 種圖片類別定義為 daisy、 dandelion、roses、 sunflowers、 tulips 保存于 class_names 。
batch_size = 32 height = 64 width = 64 train_datas = tf.keras.preprocessing.image_dataset_from_directory( data_dir, validation_split=0.2, subset="training", seed=0, image_size=(height, width), batch_size=batch_size) val_datas = tf.keras.preprocessing.image_dataset_from_directory( data_dir, validation_split=0.2, subset="validation", seed=0, image_size=(height, width), batch_size=batch_size) class_names = train_datas.class_names
(2)常規(guī)的訓(xùn)練流程是我們從磁盤加載好一份數(shù)據(jù)訓(xùn)練一模型,再去加載下一份數(shù)據(jù)去訓(xùn)練模型,然后重復(fù)這個過程,但是有時候數(shù)據(jù)集的準(zhǔn)備處理非常耗時,使得我們在每次訓(xùn)練前都需要花費大量的時間準(zhǔn)備待訓(xùn)練的數(shù)據(jù),而此時 CPU 只能等待數(shù)據(jù),造成了計算資源和時間的浪費。
(3)在從磁盤加載圖片完成后,Dataset.cache() 會將這些圖像保留在內(nèi)存中,這樣可以快速的進行數(shù)據(jù)的獲取,如果數(shù)據(jù)量太大也可以建立緩存。
(4)我們使用 prefetch() 方法,使得我們可以讓 Dataset 在訓(xùn)練時預(yù)先準(zhǔn)備好若干個條數(shù)據(jù)樣本,每次在模型訓(xùn)練的時候都能直接拿來數(shù)據(jù)進行計算,避免了等待耗時,提高了訓(xùn)練效率。
AUTOTUNE = tf.data.AUTOTUNE train_datas = train_datas.cache().prefetch(buffer_size=AUTOTUNE) val_datas = val_datas.cache().prefetch(buffer_size=AUTOTUNE)
(5)這里主要是完成模型的搭建、編譯和訓(xùn)練:
- 第一層使用縮放函數(shù) Rescaling 來將 RGB 值壓縮,因為每個像素點上代表顏色的 RGB 的三個值范圍都是在 0-255 內(nèi),所以我們要對這些值進行歸一化操作,經(jīng)過此操作 RGB 三個值的范圍被壓縮到 0-1 之間,這樣可以加速模型的收斂
- 第二、三、四層都是使用了卷積函數(shù),卷積核大小為 3 ,輸出一個 32 維的卷積結(jié)果向量,并使用 relu 激活函數(shù)進行非線性變換,并在卷積之后加入了最大池化層
- 第五層完成了將每張照片的卷積結(jié)果向量從三維重新拼接壓縮成一維
- 第六層是一個輸出為 128 的全連接層,并使用 relu 激活函數(shù)進行非線性變換
- 第七層室一個輸出為 5 的全連接層,也就是輸出層,輸出該圖片分別屬于這 5 種類別的概率分布
優(yōu)化器選擇 Adam
損失函數(shù)選擇 SparseCategoricalCrossentropy
評估指標(biāo)選擇 Accuracy
model = tf.keras.Sequential([ tf.keras.layers.experimental.preprocessing.Rescaling(1./255), tf.keras.layers.Conv2D(32, 3, activation='relu'), tf.keras.layers.MaxPooling2D(), tf.keras.layers.Conv2D(32, 3, activation='relu'), tf.keras.layers.MaxPooling2D(), tf.keras.layers.Conv2D(32, 3, activation='relu'), tf.keras.layers.MaxPooling2D(), tf.keras.layers.Flatten(), tf.keras.layers.Dense(128, activation='relu'), tf.keras.layers.Dense(5) ]) model.compile( optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy']) model.fit( train_datas, validation_data=val_datas, epochs=5 )
輸出結(jié)果:
Epoch 1/5
92/92 [==============================] - 10s 101ms/step - loss: 1.5019 - accuracy: 0.3167 - val_loss: 1.1529 - val_accuracy: 0.5177
Epoch 2/5
92/92 [==============================] - 6s 67ms/step - loss: 1.1289 - accuracy: 0.5244 - val_loss: 1.0833 - val_accuracy: 0.5736
...
Epoch 5/5
92/92 [==============================] - 6s 65ms/step - loss: 0.8412 - accuracy: 0.6795 - val_loss: 1.0528 - val_accuracy: 0.6172
自定義方式讀取和處理磁盤數(shù)據(jù)
(1)上面的過程都是內(nèi)置的工具包直接將數(shù)據(jù)進行處理,雖然比較方便,但是可能不夠靈活,而在這里我們可以自己手動操作,按照自己的想法將數(shù)據(jù)進行處理。
(2)從硬盤中讀取指定目錄中的所有的花朵圖片的絕對路徑,也就是讀取出來的只是圖片的絕對路徑字符串,如在我的計算機上第一張圖片的絕對路徑是
C:\Users\QJFY-VR\.keras\datasets\flower_photos\roses\24781114_bc83aa811e_n.jpg
然后先將這些數(shù)據(jù)進行打亂,取 20% 為驗證集,取 80% 為訓(xùn)練集。
datas = tf.data.Dataset.list_files(str(data_dir/'*/*'), shuffle=False) datas = datas.shuffle(image_count, reshuffle_each_iteration=False) val_size = int(image_count * 0.2) train_datas = datas.skip(val_size) val_datas = datas.take(val_size)
(3)對訓(xùn)練集和測試集中的每條數(shù)據(jù)都進行處理,獲得最終的圖片內(nèi)容和對應(yīng)的圖片標(biāo)簽:
每張圖片的標(biāo)簽,都是通過對每張圖片的絕對路徑中提取出來的,使用 \ 分隔符將絕對路徑分割成列表,然后取倒數(shù)第二個字符串就是其類別標(biāo)簽,并將其轉(zhuǎn)換成 one-hot 向量
每張圖片的內(nèi)容都是通過加載絕對路徑,將加載出來的圖片內(nèi)容像素進行指定 height、width 的大小調(diào)整進行變化的
def get_label(file_path): parts = tf.strings.split(file_path, os.path.sep) return tf.argmax(parts[-2] == class_names) def decode_img(img): return tf.image.resize(tf.io.decode_jpeg(img, channels=3), [height, width]) def process_path(file_abs_path): label = get_label(file_abs_path) img = decode_img(tf.io.read_file(file_abs_path)) return img, label train_datas = train_datas.map(process_path, num_parallel_calls=AUTOTUNE) val_datas = val_datas.map(process_path, num_parallel_calls=AUTOTUNE)
(4)將獲得的測試集和訓(xùn)練集通過 cache() 保存于內(nèi)存中,并同樣使用 prefetch() 提前加載要使用的數(shù)據(jù),使用 shuffle() 將數(shù)據(jù)進行打散,使用 batch() 每次獲取 batch_size 個樣本。
(5)使用訓(xùn)練數(shù)據(jù)訓(xùn)練 5 個 epoch ,并使用驗證集進行指標(biāo)評估 。由于 model 已經(jīng)被上面的數(shù)據(jù)進行過訓(xùn)練,所以這里訓(xùn)練過程中從一開始就能看出來 val_accuracy較高。
def configure_for_performance(ds): ds = ds.cache().prefetch(buffer_size=AUTOTUNE) ds = ds.shuffle(buffer_size=1000).batch(batch_size) return ds train_datas = configure_for_performance(train_datas) val_datas = configure_for_performance(val_datas) model.fit( train_datas, validation_data=val_datas, epochs=5 )
結(jié)果輸出:
Epoch 1/5
92/92 [==============================] - 11s 118ms/step - loss: 0.1068 - accuracy: 0.9680 - val_loss: 0.1332 - val_accuracy: 0.9537
Epoch 2/5
92/92 [==============================] - 10s 113ms/step - loss: 0.0893 - accuracy: 0.9721 - val_loss: 0.0996 - val_accuracy: 0.9673
...
Epoch 5/5
92/92 [==============================] - 10s 112ms/step - loss: 0.0328 - accuracy: 0.9939 - val_loss: 0.1553 - val_accuracy: 0.9550
從網(wǎng)絡(luò)上下載數(shù)據(jù)
上面的兩個方式都是從本地讀取磁盤數(shù)據(jù),除此之外我們還可以通過網(wǎng)絡(luò)來獲取數(shù)據(jù)并進行處理,tfds 中為我們準(zhǔn)備了很多種類的數(shù)據(jù),包括音頻、文本、圖片、視頻、翻譯等數(shù)據(jù),通過內(nèi)置函數(shù) tfds.load 從網(wǎng)絡(luò)上即可下載指定的數(shù)據(jù),這里我們從網(wǎng)絡(luò)上下載了 tf_flowers 數(shù)據(jù),其實就是我們上面用到的磁盤中的花朵磁盤數(shù)據(jù)數(shù)據(jù)。
(train_datas, val_datas, test_datas), metadata = tfds.load( 'tf_flowers', split=['train[:70%]', 'train[70%:90%]', 'train[90%:]'], with_info=True, as_supervised=True) train_datas = configure_for_performance(train_datas) val_datas = configure_for_performance(val_datas) test_datas = configure_for_performance(test_datas)
加載出來數(shù)據(jù)之后,后面處理的方式可以自行選擇,和上面的兩種大同小異。
以上就是Tensorflow 2.4加載處理圖片的三種方式詳解的詳細內(nèi)容,更多關(guān)于Tensorflow 加載處理圖片的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python啟動應(yīng)用程序和終止應(yīng)用程序的方法
今天小編就為大家分享一篇python啟動應(yīng)用程序和終止應(yīng)用程序的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-06-06Python?數(shù)據(jù)篩選功能實現(xiàn)
這篇文章主要介紹了Python?數(shù)據(jù)篩選,無論是在數(shù)據(jù)分析還是數(shù)據(jù)挖掘的時候,數(shù)據(jù)篩選總會涉及到,這里我總結(jié)了一下python中列表,字典,數(shù)據(jù)框中一些常用的數(shù)據(jù)篩選的方法,需要的朋友可以參考下2023-04-04Python實現(xiàn)有趣的親戚關(guān)系計算器
每年的春節(jié),都會有一些自己幾乎沒印象但父母就是很熟的親戚,關(guān)系凌亂到你自己都說不清。本文就來用Python制作一個有趣的親戚關(guān)系計算器,感興趣的可以了解一下2023-01-01pandas pd.cut()與pd.qcut()的具體實現(xiàn)
本文主要介紹了pandas pd.cut()與pd.qcut()的具體實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01Python如何創(chuàng)建裝飾器時保留函數(shù)元信息
這篇文章主要介紹了Python如何創(chuàng)建裝飾器時保留函數(shù)元信息,文中講解非常細致,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-08-08Python SqlAlchemy動態(tài)添加數(shù)據(jù)表字段實例解析
這篇文章主要介紹了Python SqlAlchemy動態(tài)添加數(shù)據(jù)表字段實例解析,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下2018-02-02