Dogs vs. Cats Redux: Kernels Edition | Kaggle
任務:給定貓狗圖像數據集 進行二分類。
Cats or Dogs - using CNN with Transfer Learning | Kaggle(參考)
Cats or Dogs | Kaggle (我的kaggle)
本文介紹了使用ResNet50預訓練模型進行貓狗圖像分類的完整流程。
數據預處理、模型構建、訓練評估和預測輸出,展示了遷移學習在圖像分類任務中的高效應用。
首先從Kaggle數據集解壓圖片并處理數據,將文件名轉換為獨熱標簽(貓[0,1],狗[1,0])。
然后構建ResNet50模型,移除原始分類層并改為二分類softmax輸出,使用ImageNet預訓練權重初始化。
模型在訓練集上訓練20個epoch后,在驗證集上準確率達到98%以上。
1. zip 圖片提取與 文件名標簽提取
從zip文件提取出 train 地址列表和 test 地址列表
import zipfile
import oswith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip', 'r') as z:z.extractall('.') # 將ZIP文件中的所有內容解壓到當前目錄train_image_list = z.namelist() # 獲取名稱列表train_image_list = os.listdir("./train/") # 進一步解壓with zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip', 'r') as z:z.extractall('.')test_image_list = z.namelist()test_image_list = os.listdir("./test/")print(train_image_list[0],test_image_list[0]) # 文件名 train格式 類別+數字 test只有數字
把train文件夾地址和圖像文件名列表,拼湊出完整的地址;
cv2讀取出圖片;文件名提取出標簽 二分類概率 貓為[0,1] 狗為[1,0]
from random import shuffle
from tqdm import tqdm
import cv2
import numpy as np
import pandas as pdRANDOM_STATE = 2018
IMG_SIZE = 224
def process_data(data_image_list, DATA_FOLDER, isTrain):data_df = []for img in tqdm(data_image_list):if(isTrain):label = [1,0] if img.split('.')[0] == 'cat' else [0,1] # 根據文件名 轉換獨熱標簽else:label = img.split('.')[0]path = os.path.join(DATA_FOLDER,img) # 拼接為完整路徑img = cv2.imread(path,cv2.IMREAD_COLOR) # 讀取img = cv2.resize(img, (IMG_SIZE,IMG_SIZE)) # 設定大小data_df.append([np.array(img),np.array(label)]) # 拼在一起返回shuffle(data_df) # 打亂return data_dftrain = process_data(train_image_list, './train/', True)
test = process_data(test_image_list, './test/', False)
2. EDA 圖片探索 訓練集圖片展示
展示 5*5 張訓練集圖片和測試集圖片
def show_images(data, isTest=False):f, ax = plt.subplots(5,5, figsize=(15,15))for i,data in enumerate(data[:25]):img_data,img_num = data[0],data[1]label = np.argmax(img_num) # 獨熱向量 [0,1] 為狗 轉換為文字標簽if label == 1: str_label='Dog'elif label == 0: str_label='Cat'if(isTest):str_label="None"ax[i//5, i%5].imshow(img_data)ax[i//5, i%5].axis('off')ax[i//5, i%5].set_title("Label: {}".format(str_label))plt.show()show_images(train)
show_images(test,True)
3.?建立模型?ResNet
?殘差神經網絡ResNet預訓練參數 遷移學習
移除原始ResNet50最后的1000類分類層,改為softmax 激活函數二分類
使用在ImageNet上預訓練的權重(好的初始化快速收斂)允許訓練微調
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Densemodel = Sequential()
model.add(ResNet50(include_top=False, # 移除原始ResNet50最后的1000類分類層pooling='max', # 在卷積特征上添加全局最大池化,將特征圖轉換為向量weights='imagenet' # 使用在ImageNet上預訓練的權重
))
model.add(Dense(2, activation='softmax')) # softmax 激活函數二分類model.layers[0].trainable = True # 允許訓練微調
model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()
4. 準備數據并訓練
X = np.array([data[0] for data in train]).reshape(-1,IMG_SIZE,IMG_SIZE,3)
y = np.array([data[1] for data in train])
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.25, random_state=RANDOM_STATE)
train_model = model.fit(X_train, y_train, batch_size=64, epochs=20, verbose=1, validation_data=(X_val, y_val))
verbose=1 訓練進度展示
5. 預測+評估
模型評估:model.evaluate 評估分數; 驗證集真實和預測 分類報告
score = model.evaluate(X_val, y_val, verbose=0) # 評估分數
print('Validation loss:', score[0])
print('Validation accuracy:', score[1])predicted_classes = model.predict_classes(X_val) # 預測
y_true = np.argmax(y_val,axis=1) # 實際from sklearn.metrics import classification_report # 分類報告
print(classification_report(y_true, predicted_classes, target_names=["Cat", "Dog"]))
這三個指標均達到 98%以上
還可以 可視化部分驗證集結果(人眼看是否差不多分類正確)
f, ax = plt.subplots(5, 5, figsize=(15, 15))for i, (img_data, _) in enumerate(test[:25]):prediction = model.predict(img_data.reshape(-1, IMG_SIZE, IMG_SIZE, 3))[0]label = 'Dog' if np.argmax(prediction) == 1 else 'Cat'ax[i//5, i%5].imshow(img_data)ax[i//5, i%5].axis('off')ax[i//5, i%5].set_title(f"Predicted: {label}")plt.show()
預測并保存結果
pred_list = []
img_list = []
for img in tqdm(test):data = img[0].reshape(-1,IMG_SIZE,IMG_SIZE,3)pred_list.append(model.predict([data])[0][1])img_list.append(img_idx[1])submission = pd.DataFrame({'id':img_list , 'label':pred_list})
submission.to_csv("submission.csv", index=False)