前提
機械学習初心者です。
vgg16の転移学習で二値分類を行っています。
ほぼコピペですが学習・検証まで行えました。
なんとかコンフュージョンマトリクスの作成までこぎつけました。
学習・検証のために画像をnumpy.ndarray型に変換しているのだとは思いますが、これは可逆的なものなのでしょうか?
実現したいこと
・検証に使用しTP・TN・FP・FNに振り分けられたそれぞれの画像を再度jpgの形式で保存したいです。できればフォルダごとに分けたいです。
該当のソースコード
Python
1import tensorflow as tf 2from tensorflow.keras.preprocessing import image_dataset_from_directory 3from sklearn.model_selection import train_test_split 4import matplotlib.pyplot as plt 5import numpy as np 6 7 8# 画像ディレクトリ 9IMG_DIR = "/content/drive/My Drive/images4" 10# バッチサイズ 11BATCH_SIZE = 32 12# VGG16を使用するため以下のサイズに設定 13IMAGE_SIZE = (224, 224) 14IMAGE_SHAPE = IMAGE_SIZE + (3, ) 15 16# 訓練、検証、テストの比率 17TRAIN_SIZE = 0.9 18VALIDATION_SIZE = 0.1 19 20# 実行毎に同一の結果が得られるようシード値を固定 21RANDOM_STATE = 123 22 23# 学習率 24LEARNING_RATE = 3e-5 25 26# エポック数 27INITIAL_EPOCHS = 10 28 29# ------------------------------------------------------------ 30# 1.画像とラベル取得と訓練・検証・テスト分割 31# ------------------------------------------------------------ 32# (1) 画像読み込み 33image_dataset = image_dataset_from_directory(IMG_DIR, 34 shuffle=False, 35 batch_size=BATCH_SIZE, 36 image_size=IMAGE_SIZE 37 ) 38 39# (2) 画像データセットをX:画像とY:クラス名で各々配列化 40image_class_names = image_dataset.class_names 41img_X = [] 42img_Y = [] 43for img_ds_batch in list(image_dataset.as_numpy_iterator()): 44 img_X.extend(img_ds_batch[0]) 45 img_Y.extend(img_ds_batch[1]) 46 47img_X = np.asarray(img_X) 48img_Y = np.asarray(img_Y) 49 50# (3) 画像データの標準化 51img_X = tf.keras.applications.vgg16.preprocess_input(img_X) 52 53# (4) データセットを訓練・検証・テストに分割 54# データセットを[train, (validation + test)]に分割 55img_X_train, img_X_valid, img_Y_train, img_Y_valid = train_test_split( 56 img_X, img_Y, 57 train_size=TRAIN_SIZE, 58 random_state=RANDOM_STATE, 59 stratify=img_Y) 60 61# ------------------------------------------------------------ 62# 2.モデル構築と学習 63# ------------------------------------------------------------ 64# (1) 転移学習のベースモデルとしてVGG16を宣言 65base_model = tf.keras.applications.vgg16.VGG16(include_top=False, 66 input_shape=IMAGE_SHAPE, 67 weights='imagenet') 68 69# (2) 畳み込みベースの凍結 70base_model.trainable = False 71 72# (3) モデル構築 73# Flatten(=平坦化層)追加 74x = tf.keras.layers.Flatten()(base_model.output) 75# FC1層追加 76x = tf.keras.layers.Dense(4096, activation='relu')(x) 77# FC2層追加 78x = tf.keras.layers.Dense(4096, activation='relu')(x) 79# 入力画像の形状 80transfer_learning_inputs = base_model.inputs 81# predictions層の追加 82# 今回分類するクラス数を指定 83image_class_num = len(image_class_names) 84transfer_learning_prediction = tf.keras.layers.Dense( 85 image_class_num, activation='softmax')(x) 86# 転移学習モデル構築 87transfer_learning_model = tf.keras.Model(inputs=transfer_learning_inputs, 88 outputs=transfer_learning_prediction) 89 90# (4) モデルのコンパイル 91transfer_learning_model.compile(optimizer= 92 tf.keras.optimizers.Adam(learning_rate=LEARNING_RATE), 93 loss='sparse_categorical_crossentropy', 94 metrics=['accuracy']) 95 96# (5) モデルの学習 97history = transfer_learning_model.fit(img_X_train, img_Y_train, 98 epochs=INITIAL_EPOCHS, 99 batch_size=BATCH_SIZE, 100 validation_data=(img_X_valid, img_Y_valid)) 101 102 103# (6) 最終的なValidationデータの評価 104from sklearn.metrics import confusion_matrix 105import itertools 106 107print(transfer_learning_model.evaluate(img_X_valid, img_Y_valid, verbose=0)) 108 109def plot_confusion_matrix(cm, classes, 110 normalize=False, 111 title='Confusion matrix', 112 cmap=plt.cm.Blues): 113 """ 114 This function prints and plots the confusion matrix. 115 Normalization can be applied by setting `normalize=True`. 116 """ 117 if normalize: 118 cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] 119 print("Normalized confusion matrix") 120 else: 121 print('Confusion matrix, without normalization') 122 123 print(cm) 124 125 plt.imshow(cm, interpolation='nearest', cmap=cmap) 126 plt.title(title) 127 plt.colorbar() 128 tick_marks = np.arange(len(classes)) 129 plt.xticks(tick_marks, classes, rotation=45) 130 plt.yticks(tick_marks, classes) 131 132 fmt = '.2f' if normalize else 'd' 133 thresh = cm.max() / 2. 134 for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): 135 plt.text(j, i, format(cm[i, j], fmt), 136 horizontalalignment="center", 137 color="white" if cm[i, j] > thresh else "black") 138 139 plt.tight_layout() 140 plt.ylabel('True label') 141 plt.xlabel('Predicted label') 142 143 144pred_y = transfer_learning_model.predict(img_X_valid) 145pred_y_classes = np.argmax(pred_y,axis = 1) 146confusion_mtx = confusion_matrix(img_Y_valid,pred_y_classes) 147plot_confusion_matrix(confusion_mtx, classes = range(2)) 148
ここに問題に対して試したことを記載してください。
補足情報(FW/ツールのバージョンなど)
google colab上でtensorflow・keras
ここにより詳細な情報を記載してください。
> 画像をnumpy.ndarray型に変換しているのだとは思いますが、これは可逆的なものなのでしょうか?
> 再度jpgの形式で保存したい
の「可逆的」の意味が、pythonで画像ファイルを読み込んだnumpy配列を画像ファイルに保存したら、元の画像ファイルと同じものが保存できるか?
という意味ならば、画像ファイルがjpgの場合は元の画像ファイルと同じものは保存できないので、「可逆的」ではありません
たとえば、下記を例にします
Aがもともとの画像ファイル、αがkerasでの学習に使われたデータです
jpg画像A
↓ pythonで読み込む
numpy配列α
↓ jpg画像ファイルに保存
jpg画像B
↓ pythonで読み込む
numpy配列β
「可逆的」の意味が、上記例でもし
・AとBが全く同じになる
または
・αとβが全く同じになる
という意味なら、画像ファイルがjpgの場合はどちらもムリなので、「可逆的」ではありません
> 検証に使用しTP・TN・FP・FNに振り分けられたそれぞれの画像を再度jpgの形式で保存したいです。できればフォルダごとに分けたいです。
質問内容が、もし
・AIの分類結果に基づき、もともとの「画像ファイル」を、分類ラベル別のディレクトリに「ファイルのコピー」をする
と、
・AIの分類結果に基づき、もともとの「画像ファイルを読み込んだデータ」を、分類ラベル別のディレクトリに「画像ファイルとして保存」する
が、結果同じになるのか?
というものなら、画像ファイルがjpgの場合は同じにはなりません
質問の意味を勘違いしてたら、ごめんなさい
上記コメントに私が書いた
> 画像ファイルがjpgの場合は元の画像ファイルと同じものは保存できない
は、
import numpy as np
import cv2
aaa = cv2.imread("元のjpg画像ファイルのパス")
cv2.imwrite("bbb.jpg", aaa, [cv2.IMWRITE_JPEG_QUALITY, 100])
bbb = cv2.imread("bbb.jpg")
abdiff = aaa.astype("float") - bbb.astype("float")
print(np.max(abdiff))
print(np.min(abdiff))
を実行したら分かります
numpy配列「aaa」と「bbb」は、コードの最後の二行の表示結果から同じではないことが分かります
それはすなわち、「元のjpg画像ファイル」と「bbb.jpg」が同じではないということです
もしかすると、「元のjpg画像ファイル」によっては(画素値変化が画像全体で非常に滑らかで少ない等)、numpy配列「aaa」と「bbb」が同じになる場合もあるかもしれませんが、それは非常に稀なケースです
一般的な画像で上記コードを実行したら、numpy配列「aaa」と「bbb」は同じにはなりません
ありがとうございます。
全く同じ画像にならないということがおぼろげながら理解できました。
下記のコードでなんとか保存ができました。
しかし色などがおかしくなってしまっています。
極力もとの画像に近づけることはできないでしょうか。
from PIL import Image
im = Image.fromarray(((img_X_valid[1])*255).astype(np.uint8))
im.save("TP.jpeg")
ご教授頂けると幸いです。
コメントに私が書いた
> 画像ファイルがjpgの場合は元の画像ファイルと同じものは保存できない
は、画素値を数値として比較したら分かるけど、画像を見比べてもすぐにはなかなか分からないくらいのレベルの話なので、
> 色などがおかしくなってしまっています。
は、原因が違います
> # (3) 画像データの標準化
img_X = tf.keras.applications.vgg16.preprocess_input(img_X)
で、
https://snowman-88888.hatenablog.com/entry/2017/04/01/043624
の「特徴」に書かれてるように、RGBからBGRに変更するとか、各色の平均値(?)「103.939, 116.779, 123.68」を引くとかしてるので、その逆をしないといけません
https://tensorflow.classcat.com/2022/07/02/keras-2-examples-generative-neural-style-transfer/
の「画像前処理 / deprocessing ユティリティ」の「def deprocess_image(x):」を参考にしてみてください
勉強になりました。
tf.keras.applications.vgg16.preprocess_input のところでVGG16に適した形に変換されているということですね。
戻すのなかなか大変なプロセスのように感じました。
参考にします。
別のアプローチになりますが、
検証用の画像にどのpred_y_classesが割り当てられたか特定することできますか?
例えばpred_y_classesをすべて表示させて、〇番目が0とか…
もとのファイル名をわかりやすく1.jpg 2.jpg 3.jpg....
という感じにすれば特定できるのではないかと考えました。
https://qiita.com/haru1977/items/7aaf1eaeb0747fe613be
に書かれてるようにすれば、
> # (4) データセットを訓練・検証・テストに分割
# データセットを[train, (validation + test)]に分割
img_X_train, img_X_valid, img_Y_train, img_Y_valid = train_test_split(...
で分割する前の「img_X」内での順番を知ることはできると思いますが、それを利用するには、
> # (1) 画像読み込み
image_dataset = image_dataset_from_directory(IMG_DIR,...
と
> # (2) 画像データセットをX:画像とY:クラス名で各々配列化
image_class_names = image_dataset.class_names
で作成された「img_X」に、もともとの各画像ファイルがどのような順番で格納されてるのか、を把握しておく必要があります
「image_dataset_from_directory()」に「shuffle=False」を付けて実行してるので、おそらくファイル名順等の規則的な順番だろうとは思いますが、よく知りません
仮にファイル名順で格納されてるとしても、「30.jpg」と「5.jpg」のどちらが先になるのか、みたいな話もありますし
【追記】
https://stackoverflow.com/questions/62166588/how-to-obtain-filenames-during-prediction-while-using-tf-keras-preprocessing-ima
に、「image_dataset_from_directory()」で読み込んだ画像ファイルのパス(の並び)を取得する方法が書かれてました
https://qiita.com/haru1977/items/7aaf1eaeb0747fe613be
に書かれてる方法で、画像ファイルのパス(の並び)も「train_test_split()」で一緒に分割させることができるかも
ありがとうございます。
参考になりました。
画像の並びを確認して評価に使用することを試みます。

回答2件
あなたの回答
tips
プレビュー