T5週:スニーカーブランドの分類

本記事は🔗365日ディープラーニングトレーニング・キャンプにおける学習記録ブログです。
元の著者:K同学啊

一、序論

実験環境:

  • 言語環境:Python3.10
  • IDE:Pycharm
  • ディープラーニング環境:TensorFlow 2.10.0

1.GPU設定

import os
os.environ["TF_CPP_MIN_LOG_LEVEL"] = '2' # warningとErrorのみを表示
import os
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

import tensorflow as tf

import matplotlib.pyplot as plt
import os, PIL, pathlib
import matplotlib.pyplot as plt
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers, models
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
from PIL import Image

#----------------GPU設定---------------
gpus = tf.config.list_physical_devices("GPU")

if gpus:
    gpu0 = gpus[0]  # 複数GPUがある場合、最初のGPUのみを使用
    tf.config.experimental.set_memory_growth(gpu0, True)  # GPUメモリ使用量を必要に応じて増やす
    tf.config.set_visible_devices([gpu0], "GPU")

print(gpus)

出力結果:

[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]

2.データの読み込み

data_dir = "F:/lsydata/46-data/"

data_dir = pathlib.Path(data_dir)

3.データの確認

image_count = len(list(data_dir.glob('*/*.jpg')))

print("画像総数:",image_count)

出力結果:

画像総数: 578
roses = list(data_dir.glob('train/nike/*.jpg'))
image = PIL.Image.open(str(roses[0]))
image.show()

二、データ前処理

1.データの読み込み

batch_size = 32
img_height = 224
img_width = 224

"""
image_dataset_from_directory()についての詳細は以下の記事を参照してください:https://mtyjkh.blog.csdn.net/article/details/117018789
"""
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    "F:/lsydata/46-data/train/",
    seed=123,
    image_size=(img_height, img_width),
    batch_size=batch_size)

出力結果:

Found 502 files belonging to 2 classes.
"""
image_dataset_from_directory()についての詳細は以下の記事を参照してください:https://mtyjkh.blog.csdn.net/article/details/117018789
"""
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    "F:/lsydata/46-data/test/",
    seed=123,
    image_size=(img_height, img_width),
    batch_size=batch_size)

出力結果:

Found 76 files belonging to 2 classes.
class_names = train_ds.class_names
print(class_names)

出力結果:

['adidas', 'nike']

2.データの可視化

plt.figure(figsize=(20, 10))

for images, labels in train_ds.take(1):
    for i in range(20):
        ax = plt.subplot(5, 10, i + 1)

        plt.imshow(images[i].numpy().astype("uint8"))
        plt.title(class_names[labels[i]])
        
        plt.axis("off")

3.データの再確認

for image_batch, labels_batch in train_ds:
    print(image_batch.shape)
    print(labels_batch.shape)
    break

出力結果:

(32, 224, 224, 3)
(32,)

4.データセットの最適化

AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

三、シンプルなCNNネットワークの構築

"""
畳み込み層の計算方法が分からない場合は以下の記事を参照してください:https://blog.csdn.net/qq_38251616/article/details/114278995

layers.Dropout(0.4) は過学習を防ぎ、モデルの一般化能力を向上させます。
Dropout層に関する詳細は以下の記事を参照してください:https://mtyjkh.blog.csdn.net/article/details/115826689
"""

model = models.Sequential([
    layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 3)),
    
    layers.Conv2D(16, (3, 3), activation='relu', input_shape=(img_height, img_width, 3)), # 畳み込み層1、カーネルサイズ3*3  
    layers.AveragePooling2D((2, 2)),               # プーリング層1、2*2サンプリング
    layers.Conv2D(32, (3, 3), activation='relu'),  # 畳み込み層2、カーネルサイズ3*3
    layers.AveragePooling2D((2, 2)),               # プーリング層2、2*2サンプリング
    layers.Dropout(0.3),  
    layers.Conv2D(64, (3, 3), activation='relu'),  # 畳み込み層3、カーネルサイズ3*3
    layers.Dropout(0.3),  
    
    layers.Flatten(),                       # Flatten層、畳み込み層と全結合層を接続
    layers.Dense(128, activation='relu'),   # 全結合層、特徴量をさらに抽出
    layers.Dense(len(class_names))               # 出力層、予測結果を出力
])

model.summary()  # ネットワーク構造を出力

出力結果:

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 rescaling (Rescaling)       (None, 224, 224, 3)       0         
                                                                 
 conv2d (Conv2D)             (None, 222, 222, 16)      448       
                                                                 
 average_pooling2d (AverageP  (None, 111, 111, 16)     0         
 ooling2D)                                                       
                                                                 
 conv2d_1 (Conv2D)           (None, 109, 109, 32)      4640      
                                                                 
 average_pooling2d_1 (Averag  (None, 54, 54, 32)       0         
 ePooling2D)                                                     
                                                                 
 dropout (Dropout)           (None, 54, 54, 32)        0         
                                                                 
 conv2d_2 (Conv2D)           (None, 52, 52, 64)        18496     
                                                                 
 dropout_1 (Dropout)         (None, 52, 52, 64)        0         
                                                                 
 flatten (Flatten)           (None, 173056)            0         
                                                                 
 dense (Dense)               (None, 128)               22151296  
                                                                 
 dense_1 (Dense)             (None, 2)                 258       
                                                                 
=================================================================
Total params: 22,175,138
Trainable params: 22,175,138
Non-trainable params: 0
_________________________________________________________________

四、モデル訓練

1.動的学習率の設定

# 初期学習率を設定
initial_learning_rate = 0.1

lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
        initial_learning_rate, 
        decay_steps=10,      # ヒント!!!これはepochではなくstepsを示します
        decay_rate=0.92,     # 学習率が一度減少すると、decay_rate倍になります
        staircase=True)

# 指数減衰学習率をオプティマイザに適用
optimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)

model.compile(optimizer=optimizer,
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

2.早停止とモデルの保存

epochs = 50

# 最良モデルパラメータを保存
checkpointer = ModelCheckpoint('best_model.h5',
                                monitor='val_accuracy',
                                verbose=1,
                                save_best_only=True,
                                save_weights_only=True)

# 早停止を設定
earlystopper = EarlyStopping(monitor='val_accuracy', 
                             min_delta=0.001,
                             patience=20, 
                             verbose=1)

3.モデル訓練の実行

history = model.fit(train_ds,
                    validation_data=val_ds,
                    epochs=epochs,
                    callbacks=[checkpointer, earlystopper])

出力結果:

Epoch 1/20
16/16 [==============================] - ETA: 0s - loss: 24878.3555 - accuracy: 0.4980
Epoch 1: val_accuracy improved from -inf to 0.50000, saving model to best_model.h5
16/16 [==============================] - 7s 351ms/step - loss: 24878.3555 - accuracy: 0.4980 - val_loss: 0.6937 - val_accuracy: 0.5000
Epoch 2/20
16/16 [==============================] - ETA: 0s - loss: 0.6977 - accuracy: 0.4980
Epoch 2: val_accuracy did not improve from 0.50000
16/16 [==============================] - 5s 289ms/step - loss: 0.6977 - accuracy: 0.4980 - val_loss: 0.6942 - val_accuracy: 0.5000
...

五、モデル評価

1.損失関数と精度のグラフ

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(len(loss))

plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

2.特定画像での予測

# 最も良いモデル重みを読み込む
model.load_weights('best_model.h5')

# img = Image.open("./45-data/Monkeypox/M06_01_04.jpg")  # 予測したい画像を選択
img = Image.open("./46-data/test/nike/1.jpg")  # 予測したい画像を選択
image = tf.image.resize(img, [img_height, img_width])

img_array = tf.expand_dims(image, 0) #/255.0  # 正規化処理を忘れずに(学習データと同じ処理を適用)

predictions = model.predict(img_array) # 使用する学習済みモデルを指定
print("予測結果:",class_names[np.argmax(predictions)])

出力結果:

予測結果: nike

タグ: TensorFlow CNN 画像分類 機械学習 深層学習

9月5日 09:42 投稿