自分用メモ 画像認識の練習

# --- 必要なモジュールインポート ---
import os
import pandas as pd
import numpy as np
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import layers, models
from tensorflow.keras.applications import EfficientNetV2B0
# --- 1. ラベルファイルと画像ディレクトリの設定 ---
data_dir = "./cifar10_subset"
labels_path = os.path.join(data_dir, "labels.tsv")
images_dir = os.path.join(data_dir, "images")
# --- 2. ラベル読み込み ---
labels_df = pd.read_csv(labels_path, sep="\t")
print(labels_df)
labels_df["label"] = labels_df["label"].astype(str)
print(labels_df)
# --- 3. ImageDataGenerator 準備 ---
datagen = ImageDataGenerator(
#    rescale=1./255
    validation_split=0.1,
    # rotation_range=15,         # 回転 ±15度
    # width_shift_range=0.1,     # 横方向 10%ずらす
    # height_shift_range=0.1,    # 縦方向 10%ずらす
    # zoom_range=0.1,            # 拡大縮小10%
    # horizontal_flip=True,      # 左右反転
)
# --- 4. Generator作成 ---
IMG_SIZE = 224
BATCH_SIZE = 32

train_generator = datagen.flow_from_dataframe(
    dataframe=labels_df,
    directory=images_dir,
    x_col="filename",
    y_col="label",
    target_size=(IMG_SIZE, IMG_SIZE),
    class_mode="categorical",
    batch_size=BATCH_SIZE,
    shuffle=True,
    subset="training",
    seed=42
)

val_generator = datagen.flow_from_dataframe(
    dataframe=labels_df,
    directory=images_dir,
    x_col="filename",
    y_col="label",
    target_size=(IMG_SIZE, IMG_SIZE),
    class_mode="categorical",
    batch_size=BATCH_SIZE,
    shuffle=True,
    subset="validation",
    seed=42
)
# --- 5. モデル構築 ---
base_model = EfficientNetV2B0(
    include_top=False,
    weights="imagenet",
    input_shape=(IMG_SIZE, IMG_SIZE, 3)
)
base_model.trainable = False

inputs = layers.Input(shape=(IMG_SIZE, IMG_SIZE, 3))
x = base_model(inputs, training=False)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(10, activation="softmax")(x)

model = models.Model(inputs, outputs)

model.compile(
    optimizer=tf.keras.optimizers.Adam(1e-2),
    loss="categorical_crossentropy",
    metrics=["accuracy"]
)
from tensorflow.keras.callbacks import ReduceLROnPlateau

# 学習率スケジューラの定義
lr_scheduler = ReduceLROnPlateau(
    monitor='val_loss',
    factor=0.5,
    patience=3,
    verbose=1,
    min_lr=1e-6
)
import tensorflow as tf
print("TensorFlow version:", tf.__version__)
print("Num GPUs Available:", len(tf.config.list_physical_devices('GPU')))

# 実際に使われているデバイスの確認
tf.debugging.set_log_device_placement(True)
# --- 6. モデル学習 ---
history = model.fit(
    train_generator,
    validation_data=val_generator,
    epochs=10,
    workers=8,
    callbacks=[lr_scheduler],
    # use_multiprocessing=True,
)
# --- 7. モデルFine-tuning(オプション) ---
base_model.trainable = True
# block6a以降だけ学習対象
set_trainable = False
for layer in base_model.layers:
    if 'block6a' in layer.name:
        set_trainable = True
    layer.trainable = set_trainable
    
model.compile(
    optimizer=tf.keras.optimizers.Adam(1e-4),
    loss="categorical_crossentropy",
    metrics=["accuracy"]
)
history_fine = model.fit(
    train_generator,
    validation_data=val_generator,
    epochs=30,
    workers=8,
    callbacks=[lr_scheduler],
    # use_multiprocessing=True,
)
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()

# 画像リサイズ(ここは一気にやってもいいけど、メモリ注意)
x_test_resized = tf.image.resize(x_test, (224, 224))

# スケーリング(0〜1化)
# x_test_resized = x_test_resized / 255.0

# 正解ラベルを one-hotに(今のモデルが 'categorical_crossentropy' だから)
from tensorflow.keras.utils import to_categorical
y_test_categorical = to_categorical(y_test, num_classes=10)

test_loss, test_acc = model.evaluate(x_test_resized, y_test_categorical, batch_size=32)
print("Test loss:", test_loss)
print("Test accuracy:", test_acc)
from tensorflow.keras.models import Model, load_model
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import cifar10

# モデルとデータの準備
#model = load_model("model/cifar10_model.h5")  # モデルパスは適宜修正
(_, _), (x_test, _) = cifar10.load_data()

# EfficientNetV2のベースモデルを取得
effnet = model.get_layer("efficientnetv2-b0")

# 可視化したい層の名前(代表的なブロック)
layer_names = [
    "stem_conv",                        # 入力
    "block1a_project_activation",       # 低レベル特徴抽出(色・線)
    "block3a_expand_activation",        # 中レベル特徴
    "block4a_activation",              # 中~高レベル
    "block6a_activation",              # 高レベル特徴
    "top_activation",                  # 分類前最終活性
]


# 中間層モデル作成
intermediate_model = Model(
    inputs=effnet.input,
    outputs=[effnet.get_layer(name).output for name in layer_names]
)

# 画像準備(CIFAR-10の1枚をリサイズ)
img = x_test[0]
img_resized = tf.image.resize(img, (224, 224))
img_resized = np.expand_dims(img_resized, axis=0)

# 中間層出力を取得
feature_maps = intermediate_model.predict(img_resized)

# 入力画像表示
plt.figure(figsize=(2, 2))
plt.imshow(img)
plt.title("Input image")
plt.axis("off")
plt.show()

# 各層の出力を可視化(チャンネル先頭8個のみ)
for layer_name, fmap in zip(layer_names, feature_maps):
    fig, axs = plt.subplots(1, 10, figsize=(15, 3))
    fig.suptitle(layer_name)
    for i in range(10):
        axs[i].imshow(fmap[0, :, :, i], cmap='viridis')
        axs[i].axis('off')
    plt.show()