首頁 > 軟體

Tensorflow 2.4載入處理圖片的三種方式詳解

2022-11-21 14:01:37

前言

本文通過使用 cpu 版本的 tensorflow 2.4 ,介紹三種方式進行載入和預處理圖片資料。

這裡我們要確保 tensorflow 在 2.4 版本以上 ,python 在 3.8 版本以上,因為版本太低有些內建函數無法使用,然後要提前安裝好 pillow 和 tensorflow_datasets ,方便進行後續的資料載入和處理工作。

由於本文不對模型進行質量保證,只介紹資料的載入、處理過程,所以只將模型簡單訓練即可。

資料準備

首先我們先準備本文的圖片資料,這裡我們直接使用 tensorflow 的內建函數,從網路上面下載了一份花朵照片資料集,也可以直接用下面的連結使用迅雷下載。

資料目錄裡面包含 5 個子目錄,每個子目錄對應一個類,分別是雛菊、蒲公英、玫瑰、向日葵、鬱金香,圖片總共有 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')))

使用內建函數讀取並處理磁碟資料

(1)使用 KERAS 內建的函數 image_dataset_from_directory 從本地進行資料的載入,首先定義 batch_size 為 32 ,每張圖片維度大小為 (64,64,3) ,也就是長、寬有 64 個畫素點,這裡的長、寬畫素點數量可以自行修改,需要注意的是數位越大圖片越清晰但是後續的計算量會越大,數位越小圖片越模糊但是後續的計算量越小。

每個畫素點是一個 3 維的 RGB 顏色向量。而每個圖片對應的標籤是一個花朵類別的字串。

我們使用 image_dataset_from_directory 選用了資料中 80% (2936 張)的圖片進行訓練,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)常規的訓練流程是我們從磁碟載入好一份資料訓練一模型,再去載入下一份資料去訓練模型,然後重複這個過程,但是有時候資料集的準備處理非常耗時,使得我們在每次訓練前都需要花費大量的時間準備待訓練的資料,而此時 CPU 只能等待資料,造成了計算資源和時間的浪費。

(3)在從磁碟載入圖片完成後,Dataset.cache() 會將這些影象保留在記憶體中,這樣可以快速的進行資料的獲取,如果資料量太大也可以建立快取。

(4)我們使用 prefetch() 方法,使得我們可以讓 Dataset 在訓練時預先準備好若干個條資料樣本,每次在模型訓練的時候都能直接拿來資料進行計算,避免了等待耗時,提高了訓練效率。

AUTOTUNE = tf.data.AUTOTUNE
train_datas = train_datas.cache().prefetch(buffer_size=AUTOTUNE)
val_datas = val_datas.cache().prefetch(buffer_size=AUTOTUNE)

(5)這裡主要是完成模型的搭建、編譯和訓練:

  • 第一層使用縮放函數 Rescaling 來將 RGB 值壓縮,因為每個畫素點上代表顏色的 RGB 的三個值範圍都是在 0-255 內,所以我們要對這些值進行歸一化操作,經過此操作 RGB 三個值的範圍被壓縮到 0-1 之間,這樣可以加速模型的收斂
  • 第二、三、四層都是使用了折積函數,折積核大小為 3 ,輸出一個 32 維的折積結果向量,並使用 relu 啟用函數進行非線性變換,並在折積之後加入了最大池化層
  • 第五層完成了將每張照片的折積結果向量從三維重新拼接壓縮成一維
  • 第六層是一個輸出為 128 的全連線層,並使用 relu 啟用函數進行非線性變換
  • 第七層室一個輸出為 5 的全連線層,也就是輸出層,輸出該圖片分別屬於這 5 種類別的概率分佈

優化器選擇 Adam

損失函數選擇 SparseCategoricalCrossentropy

評估指標選擇 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 )

輸出結果:

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

自定義方式讀取和處理磁碟資料

(1)上面的過程都是內建的工具包直接將資料進行處理,雖然比較方便,但是可能不夠靈活,而在這裡我們可以自己手動操作,按照自己的想法將資料進行處理。

(2)從硬碟中讀取指定目錄中的所有的花朵圖片的絕對路徑,也就是讀取出來的只是圖片的絕對路徑字串,如在我的計算機上第一張圖片的絕對路徑是

C:UsersQJFY-VR.kerasdatasetsflower_photosroses24781114_bc83aa811e_n.jpg 

然後先將這些資料進行打亂,取 20% 為驗證集,取 80% 為訓練集。

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)對訓練集和測試集中的每條資料都進行處理,獲得最終的圖片內容和對應的圖片標籤:

每張圖片的標籤,都是通過對每張圖片的絕對路徑中提取出來的,使用 分隔符將絕對路徑分割成列表,然後取倒數第二個字串就是其類別標籤,並將其轉換成 one-hot 向量

每張圖片的內容都是通過載入絕對路徑,將載入出來的圖片內容畫素進行指定 height、width 的大小調整進行變化的

  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)將獲得的測試集和訓練集通過 cache() 儲存於記憶體中,並同樣使用 prefetch() 提前載入要使用的資料,使用 shuffle() 將資料進行打散,使用 batch() 每次獲取 batch_size 個樣本。

(5)使用訓練資料訓練 5 個 epoch ,並使用驗證集進行指標評估 。由於 model 已經被上面的資料進行過訓練,所以這裡訓練過程中從一開始就能看出來 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 )

結果輸出:

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

從網路上下載資料

上面的兩個方式都是從本地讀取磁碟資料,除此之外我們還可以通過網路來獲取資料並進行處理,tfds 中為我們準備了很多種類的資料,包括音訊、文字、圖片、視訊、翻譯等資料,通過內建函數 tfds.load 從網路上即可下載指定的資料,這裡我們從網路上下載了 tf_flowers 資料,其實就是我們上面用到的磁碟中的花朵磁碟資料資料。

(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)

載入出來資料之後,後面處理的方式可以自行選擇,和上面的兩種大同小異。

以上就是Tensorflow 2.4載入處理圖片的三種方式詳解的詳細內容,更多關於Tensorflow 載入處理圖片的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com