Dogs vs. Cats(猫狗大战)项目
数据预处理
import numpy as np
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 数据集路径(注意 Windows 路径需用双反斜杠或原始字符串)
train_dir = r"D:\python训练营\dogs-vs-cats\train"
# 数据增强与归一化
train_datagen = ImageDataGenerator(
rescale=1./255,
validation_split=0.2, # 80% 训练,20% 验证
rotation_range=20,
zoom_range=0.2,
horizontal_flip=True
)
# 加载数据
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(224, 224), # 调整图像尺寸(根据数据集选择)
batch_size=32,
class_mode='binary', # 二分类(猫 vs 狗)
subset='training'
)
val_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(224, 224),
batch_size=32,
class_mode='binary',
subset='validation'
)
构建并训练 CNN 模型
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
# 定义 CNN 模型
model = Sequential([
Conv2D(32, (3,3), activation='relu', input_shape=(224,224,3)),
MaxPooling2D((2,2)),
Conv2D(64, (3,3), activation='relu'),
MaxPooling2D((2,2)),
Conv2D(128, (3,3), activation='relu'),
MaxPooling2D((2,2)),
Flatten(),
Dense(512, activation='relu'),
Dense(1, activation='sigmoid') # 二分类输出
])
# 编译模型
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy']
)
# 训练模型
history = model.fit(
train_generator,
epochs=10,
validation_data=val_generator
)
Grad-CAM 可视化
实现 Grad-CAM
import cv2
import matplotlib.pyplot as plt
from tensorflow.keras.models import Model
def grad_cam(model, img_array, layer_name, eps=1e-8):
# 获取模型和特定卷积层
grad_model = Model(
inputs=[model.inputs],
outputs=[model.get_layer(layer_name).output, model.output]
)
# 计算梯度
with tf.GradientTape() as tape:
conv_outputs, predictions = grad_model(img_array)
loss = predictions[:, 0] # 适用于二分类
# 计算梯度
grads = tape.gradient(loss, conv_outputs)
pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))
# 生成热力图
conv_outputs = conv_outputs[0]
heatmap = conv_outputs @ pooled_grads[..., tf.newaxis]
heatmap = tf.squeeze(heatmap)
heatmap = tf.maximum(heatmap, 0) / (tf.math.reduce_max(heatmap) + eps)
return heatmap.numpy()
def overlay_heatmap(img, heatmap, alpha=0.5):
# 调整热力图颜色
heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
heatmap = np.uint8(255 * heatmap)
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
superimposed_img = cv2.addWeighted(img, alpha, heatmap, 1-alpha, 0)
return superimposed_img
加载测试图像并生成热力图
# 加载单张图像
img_path = 'dataset/test/dog.1234.jpg' # 替换为你的测试图像路径
img = tf.keras.preprocessing.image.load_img(img_path, target_size=(224, 224))
img_array = tf.keras.preprocessing.image.img_to_array(img)
img_array = np.expand_dims(img_array, axis=0) / 255.0 # 归一化
# 选择最后一个卷积层(根据模型结构)
layer_name = 'conv2d_2' # 替换为你的模型中最后一个卷积层名称
# 生成热力图
heatmap = grad_cam(model, img_array, layer_name)
# 可视化
plt.figure(figsize=(10, 6))
plt.subplot(1, 2, 1)
plt.imshow(img_array[0])
plt.title('Original Image')
plt.subplot(1, 2, 2)
plt.imshow(heatmap, cmap='jet')
plt.title('Grad-CAM Heatmap')
plt.show()
# 叠加热力图到原图
img = cv2.imread(img_path)
img = cv2.resize(img, (224, 224))
superimposed_img = overlay_heatmap(img, heatmap)
plt.imshow(cv2.cvtColor(superimposed_img, cv2.COLOR_BGR2RGB))
plt.title('Grad-CAM Overlay')
plt.axis('off')
plt.show()
需要注意的主要有两点:
(1)确保路径与代码中一致
(2)注意内存,可采取减小 batch_size 或使用更小的输入尺寸(如 (128, 128))。