Tensorflow?2.4加載處理圖片的三種方式詳解
前言
本文通過(guò)使用 cpu 版本的 tensorflow 2.4 ,介紹三種方式進(jìn)行加載和預(yù)處理圖片數(shù)據(jù)。
這里我們要確保 tensorflow 在 2.4 版本以上 ,python 在 3.8 版本以上,因?yàn)榘姹咎陀行﹥?nèi)置函數(shù)無(wú)法使用,然后要提前安裝好 pillow 和 tensorflow_datasets ,方便進(jìn)行后續(xù)的數(shù)據(jù)加載和處理工作。
由于本文不對(duì)模型進(jìn)行質(zhì)量保證,只介紹數(shù)據(jù)的加載、處理過(guò)程,所以只將模型簡(jiǎn)單訓(xùn)練即可。
數(shù)據(jù)準(zhǔn)備
首先我們先準(zhǔn)備本文的圖片數(shù)據(jù),這里我們直接使用 tensorflow 的內(nèi)置函數(shù),從網(wǎng)絡(luò)上面下載了一份花朵照片數(shù)據(jù)集,也可以直接用下面的鏈接使用迅雷下載。
數(shù)據(jù)目錄里面包含 5 個(gè)子目錄,每個(gè)子目錄對(duì)應(yīng)一個(gè)類(lèi),分別是雛菊、蒲公英、玫瑰、向日葵、郁金香,圖片總共有 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ù)讀取并處理磁盤(pán)數(shù)據(jù)
(1)使用 KERAS 內(nèi)置的函數(shù) image_dataset_from_directory 從本地進(jìn)行數(shù)據(jù)的加載,首先定義 batch_size 為 32 ,每張圖片維度大小為 (64,64,3) ,也就是長(zhǎng)、寬有 64 個(gè)像素點(diǎn),這里的長(zhǎng)、寬像素點(diǎn)數(shù)量可以自行修改,需要注意的是數(shù)字越大圖片越清晰但是后續(xù)的計(jì)算量會(huì)越大,數(shù)字越小圖片越模糊但是后續(xù)的計(jì)算量越小。
每個(gè)像素點(diǎn)是一個(gè) 3 維的 RGB 顏色向量。而每個(gè)圖片對(duì)應(yīng)的標(biāo)簽是一個(gè)花朵類(lèi)別的字符串。
我們使用 image_dataset_from_directory 選用了數(shù)據(jù)中 80% (2936 張)的圖片進(jìn)行訓(xùn)練,20% (734 張)的圖片來(lái)進(jìn)行模型效果的驗(yàn)證。
我們將這 5 種圖片類(lèi)別定義為 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)練流程是我們從磁盤(pán)加載好一份數(shù)據(jù)訓(xùn)練一模型,再去加載下一份數(shù)據(jù)去訓(xùn)練模型,然后重復(fù)這個(gè)過(guò)程,但是有時(shí)候數(shù)據(jù)集的準(zhǔn)備處理非常耗時(shí),使得我們?cè)诿看斡?xùn)練前都需要花費(fèi)大量的時(shí)間準(zhǔn)備待訓(xùn)練的數(shù)據(jù),而此時(shí) CPU 只能等待數(shù)據(jù),造成了計(jì)算資源和時(shí)間的浪費(fèi)。
(3)在從磁盤(pán)加載圖片完成后,Dataset.cache() 會(huì)將這些圖像保留在內(nèi)存中,這樣可以快速的進(jìn)行數(shù)據(jù)的獲取,如果數(shù)據(jù)量太大也可以建立緩存。
(4)我們使用 prefetch() 方法,使得我們可以讓 Dataset 在訓(xùn)練時(shí)預(yù)先準(zhǔn)備好若干個(gè)條數(shù)據(jù)樣本,每次在模型訓(xùn)練的時(shí)候都能直接拿來(lái)數(shù)據(jù)進(jìn)行計(jì)算,避免了等待耗時(shí),提高了訓(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 來(lái)將 RGB 值壓縮,因?yàn)槊總€(gè)像素點(diǎn)上代表顏色的 RGB 的三個(gè)值范圍都是在 0-255 內(nèi),所以我們要對(duì)這些值進(jìn)行歸一化操作,經(jīng)過(guò)此操作 RGB 三個(gè)值的范圍被壓縮到 0-1 之間,這樣可以加速模型的收斂
- 第二、三、四層都是使用了卷積函數(shù),卷積核大小為 3 ,輸出一個(gè) 32 維的卷積結(jié)果向量,并使用 relu 激活函數(shù)進(jìn)行非線(xiàn)性變換,并在卷積之后加入了最大池化層
- 第五層完成了將每張照片的卷積結(jié)果向量從三維重新拼接壓縮成一維
- 第六層是一個(gè)輸出為 128 的全連接層,并使用 relu 激活函數(shù)進(jìn)行非線(xiàn)性變換
- 第七層室一個(gè)輸出為 5 的全連接層,也就是輸出層,輸出該圖片分別屬于這 5 種類(lèi)別的概率分布
優(yōu)化器選擇 Adam
損失函數(shù)選擇 SparseCategoricalCrossentropy
評(píng)估指標(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
自定義方式讀取和處理磁盤(pán)數(shù)據(jù)
(1)上面的過(guò)程都是內(nèi)置的工具包直接將數(shù)據(jù)進(jìn)行處理,雖然比較方便,但是可能不夠靈活,而在這里我們可以自己手動(dòng)操作,按照自己的想法將數(shù)據(jù)進(jìn)行處理。
(2)從硬盤(pán)中讀取指定目錄中的所有的花朵圖片的絕對(duì)路徑,也就是讀取出來(lái)的只是圖片的絕對(duì)路徑字符串,如在我的計(jì)算機(jī)上第一張圖片的絕對(duì)路徑是
C:\Users\QJFY-VR\.keras\datasets\flower_photos\roses\24781114_bc83aa811e_n.jpg
然后先將這些數(shù)據(jù)進(jìn)行打亂,取 20% 為驗(yàn)證集,取 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)對(duì)訓(xùn)練集和測(cè)試集中的每條數(shù)據(jù)都進(jìn)行處理,獲得最終的圖片內(nèi)容和對(duì)應(yīng)的圖片標(biāo)簽:
每張圖片的標(biāo)簽,都是通過(guò)對(duì)每張圖片的絕對(duì)路徑中提取出來(lái)的,使用 \ 分隔符將絕對(duì)路徑分割成列表,然后取倒數(shù)第二個(gè)字符串就是其類(lèi)別標(biāo)簽,并將其轉(zhuǎn)換成 one-hot 向量
每張圖片的內(nèi)容都是通過(guò)加載絕對(duì)路徑,將加載出來(lái)的圖片內(nèi)容像素進(jìn)行指定 height、width 的大小調(diào)整進(jìn)行變化的
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)將獲得的測(cè)試集和訓(xùn)練集通過(guò) cache() 保存于內(nèi)存中,并同樣使用 prefetch() 提前加載要使用的數(shù)據(jù),使用 shuffle() 將數(shù)據(jù)進(jìn)行打散,使用 batch() 每次獲取 batch_size 個(gè)樣本。
(5)使用訓(xùn)練數(shù)據(jù)訓(xùn)練 5 個(gè) epoch ,并使用驗(yàn)證集進(jìn)行指標(biāo)評(píng)估 。由于 model 已經(jīng)被上面的數(shù)據(jù)進(jìn)行過(guò)訓(xùn)練,所以這里訓(xùn)練過(guò)程中從一開(kāi)始就能看出來(lái) 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ù)
上面的兩個(gè)方式都是從本地讀取磁盤(pán)數(shù)據(jù),除此之外我們還可以通過(guò)網(wǎng)絡(luò)來(lái)獲取數(shù)據(jù)并進(jìn)行處理,tfds 中為我們準(zhǔn)備了很多種類(lèi)的數(shù)據(jù),包括音頻、文本、圖片、視頻、翻譯等數(shù)據(jù),通過(guò)內(nèi)置函數(shù) tfds.load 從網(wǎng)絡(luò)上即可下載指定的數(shù)據(jù),這里我們從網(wǎng)絡(luò)上下載了 tf_flowers 數(shù)據(jù),其實(shí)就是我們上面用到的磁盤(pán)中的花朵磁盤(pán)數(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)
加載出來(lái)數(shù)據(jù)之后,后面處理的方式可以自行選擇,和上面的兩種大同小異。
以上就是Tensorflow 2.4加載處理圖片的三種方式詳解的詳細(xì)內(nèi)容,更多關(guān)于Tensorflow 加載處理圖片的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python啟動(dòng)應(yīng)用程序和終止應(yīng)用程序的方法
今天小編就為大家分享一篇python啟動(dòng)應(yīng)用程序和終止應(yīng)用程序的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-06-06對(duì)python中矩陣相加函數(shù)sum()的使用詳解
今天小編就為大家分享一篇對(duì)python中矩陣相加函數(shù)sum()的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01Python?數(shù)據(jù)篩選功能實(shí)現(xiàn)
這篇文章主要介紹了Python?數(shù)據(jù)篩選,無(wú)論是在數(shù)據(jù)分析還是數(shù)據(jù)挖掘的時(shí)候,數(shù)據(jù)篩選總會(huì)涉及到,這里我總結(jié)了一下python中列表,字典,數(shù)據(jù)框中一些常用的數(shù)據(jù)篩選的方法,需要的朋友可以參考下2023-04-04Python實(shí)現(xiàn)有趣的親戚關(guān)系計(jì)算器
每年的春節(jié),都會(huì)有一些自己幾乎沒(méi)印象但父母就是很熟的親戚,關(guān)系凌亂到你自己都說(shuō)不清。本文就來(lái)用Python制作一個(gè)有趣的親戚關(guān)系計(jì)算器,感興趣的可以了解一下2023-01-01pandas pd.cut()與pd.qcut()的具體實(shí)現(xiàn)
本文主要介紹了pandas pd.cut()與pd.qcut()的具體實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01Python如何創(chuàng)建裝飾器時(shí)保留函數(shù)元信息
這篇文章主要介紹了Python如何創(chuàng)建裝飾器時(shí)保留函數(shù)元信息,文中講解非常細(xì)致,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-08-08Python SqlAlchemy動(dòng)態(tài)添加數(shù)據(jù)表字段實(shí)例解析
這篇文章主要介紹了Python SqlAlchemy動(dòng)態(tài)添加數(shù)據(jù)表字段實(shí)例解析,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02