1. 安裝配置環(huán)境
pip install numpy pandas matplotlib seaborn plotly requests tqdm opencv-python pillow wandb -i https://pypi.tuna.tsinghua.edu.cn/simple
pip3 install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113
#下載中文字體
wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/dataset/SimHei.ttf --no-check-certificate
#創(chuàng)建目錄
import os
# 存放結(jié)果文件
os.mkdir('output')
# 存放訓(xùn)練得到的模型權(quán)重
os.mkdir('checkpoints')
# 存放生成的圖表
os.mkdir('圖表')
2. 準(zhǔn)備圖像分類數(shù)據(jù)集
wget https://zihao-openmmlab.obs.cn-east-3.myhuaweicloud.com/20220716-mmclassification/dataset/fruit30/fruit30_split.zip
#解壓
unzip fruit30_split.zip >> /dev/null
# 刪除壓縮包
!rm fruit30_split.zip
3. 使用遷移學(xué)習(xí)微調(diào)二跋,訓(xùn)練出圖像分類模型
在自己的圖像分類數(shù)據(jù)集上寇钉,使用ImageNet預(yù)訓(xùn)練圖像分類模型初始化命贴,改動(dòng)分類層,遷移學(xué)習(xí)微調(diào)訓(xùn)練
#導(dǎo)入工具包
import time
import os
import numpy as np
from tqdm import tqdm
import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F
import matplotlib.pyplot as plt
%matplotlib inline
# 忽略煩人的紅色提示
import warnings
warnings.filterwarnings("ignore")
# 有 GPU 就用 GPU萧豆,沒有就用 CPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print('device', device)
###圖像預(yù)處理
from torchvision import transforms
# 訓(xùn)練集圖像預(yù)處理:縮放裁剪、圖像增強(qiáng)昏名、轉(zhuǎn) Tensor涮雷、歸一化
train_transform = transforms.Compose([transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
# (不需要圖像增強(qiáng))測(cè)試集圖像預(yù)處理-RCTN:縮放、裁剪轻局、轉(zhuǎn) Tensor洪鸭、歸一化
test_transform = transforms.Compose([transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
#載入圖像分類數(shù)據(jù)集
# 數(shù)據(jù)集文件夾路徑
dataset_dir = 'fruit30_split'
train_path = os.path.join(dataset_dir, 'train')
test_path = os.path.join(dataset_dir, 'val')
print('訓(xùn)練集路徑', train_path)
print('測(cè)試集路徑', test_path)
from torchvision import datasets
#datasets中的ImageFolder是直接傳入數(shù)據(jù)集的路徑和預(yù)處理的方式就可以構(gòu)建出訓(xùn)練集和測(cè)試集
# 載入訓(xùn)練集
train_dataset = datasets.ImageFolder(train_path, train_transform)
# 載入測(cè)試集
test_dataset = datasets.ImageFolder(test_path, test_transform)
print('訓(xùn)練集圖像數(shù)量', len(train_dataset))
#訓(xùn)練集圖像數(shù)量 4375
print('類別個(gè)數(shù)', len(train_dataset.classes))
#類別個(gè)數(shù) 30
print('各類別名稱', train_dataset.classes)
#類別名稱 ['哈密瓜', '圣女果', '山竹', '楊梅', '柚子', '
#檸檬', '桂圓', '梨', '椰子', '榴蓮', '火龍果', '獼猴桃', '
#石榴', '砂糖橘', '胡蘿卜', '臍橙', '芒果', '苦瓜', '蘋果-
#紅', '蘋果-青', '草莓', '荔枝', '菠蘿', '葡萄-白', '葡萄-
#紅', '西瓜', '西紅柿', '車?yán)遄?, '香蕉', '黃瓜']
print('測(cè)試集圖像數(shù)量', len(test_dataset))
print('類別個(gè)數(shù)', len(test_dataset.classes))
print('各類別名稱', test_dataset.classes)
#類別和索引號(hào)一一對(duì)應(yīng)
# 各類別名稱
class_names = train_dataset.classes
n_class = len(class_names)
class_names
# 映射關(guān)系:類別 到 索引號(hào)
train_dataset.class_to_idx
#{'哈密瓜': 0, '圣女果': 1, '山竹': 2, '楊梅': 3, '柚子': 4, '檸檬': 5, '桂圓': 6, #'梨': 7, '椰子': 8, '榴蓮': 9, '火
#龍果': 10, '獼猴桃': 11, '石榴': 12, '砂糖橘': 13, '胡蘿卜
#': 14, '臍橙': 15, '芒果': 16, '苦瓜': 17, '蘋果-紅': 18, '蘋果-青': 19, '草莓': #20, '荔枝': 21, '菠蘿': 22, '葡萄-
#白': 23, '葡萄-紅': 24, '西瓜': 25, '西紅柿': 26, '車?yán)遄?: 27, '香蕉': 28, '黃瓜': 29}
# 映射關(guān)系:索引號(hào) 到 類別
idx_to_labels = {y:x for x,y in train_dataset.class_to_idx.items()}
idx_to_labels
# 保存為本地的 npy 文件
np.save('idx_to_labels.npy', idx_to_labels)
np.save('labels_to_idx.npy', train_dataset.class_to_idx)
#定義數(shù)據(jù)加載器DataLoader
from torch.utils.data import DataLoader
BATCH_SIZE = 32
# 訓(xùn)練集的數(shù)據(jù)加載器
train_loader = DataLoader(train_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
num_workers=4
)
# 測(cè)試集的數(shù)據(jù)加載器
test_loader = DataLoader(test_dataset,
batch_size=BATCH_SIZE,
shuffle=False,
num_workers=4
)
#查看一個(gè)batch的圖像和標(biāo)注
# DataLoader 是 python生成器,每次調(diào)用返回一個(gè) batch 的數(shù)據(jù)
images, labels = next(iter(train_loader))
images.shape
labels
#可視化一個(gè)batch的圖像和標(biāo)注
# 將數(shù)據(jù)集中的Tensor張量轉(zhuǎn)為numpy的array數(shù)據(jù)類型
images = images.numpy()
images[5].shape
plt.hist(images[5].flatten(), bins=50)
plt.savefig('hist.pdf')
plt.show()
# batch 中經(jīng)過(guò)預(yù)處理的圖像
idx = 2
plt.imshow(images[idx].transpose((1,2,0))) # 轉(zhuǎn)為(224, 224, 3)
plt.title('label:'+str(labels[idx].item()))
plt.savefig('label.pdf')
label = labels[idx].item()
label
pred_classname = idx_to_labels[label]
pred_classname
#火龍果
# 原始圖像
idx = 2
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
plt.imshow(np.clip(images[idx].transpose((1,2,0)) * std + mean, 0, 1))
plt.title('label:'+ pred_classname)
plt.savefig('label_org.pdf')
plt.show()
#導(dǎo)入訓(xùn)練需使用的工具包
from torchvision import models
import torch.optim as optim
###遷移學(xué)習(xí)訓(xùn)練方法
#1. 只微調(diào)訓(xùn)練模型最后一層(全連接分類層)
model = models.resnet18(pretrained=True) # 載入預(yù)訓(xùn)練模型
# 修改全連接層仑扑,使得全連接層的輸出與當(dāng)前數(shù)據(jù)集類別數(shù)對(duì)應(yīng)
# 新建的層默認(rèn) requires_grad=True
model.fc = nn.Linear(model.fc.in_features, n_class)
#n_class
model.fc
#只微調(diào)訓(xùn)練最后一層全連接層的參數(shù)览爵,凍結(jié)其他層
optimizer=optim.Adam(model.fc.parameters())
#2. 微調(diào)訓(xùn)練所有層
model = models.resnet18(pretrained=True) # 載入預(yù)訓(xùn)練模型
model.fc = nn.Linear(model.fc.in_features, n_class)
optimizer = optim.Adam(model.parameters())
#3. 隨機(jī)初始化模型全部權(quán)重,重新訓(xùn)練所有層
model = models.resnet18(pretrained=False) # 只載入模型結(jié)構(gòu)镇饮,不載入預(yù)訓(xùn)練權(quán)重參數(shù)
model.fc = nn.Linear(model.fc.in_features, n_class)
optimizer = optim.Adam(model.parameters())
#訓(xùn)練配置
model = model.to(device)
# 交叉熵?fù)p失函數(shù)
criterion = nn.CrossEntropyLoss()
# 訓(xùn)練輪次 Epoch
EPOCHS = 20
#模擬一個(gè)batch的訓(xùn)練
# 獲得一個(gè) batch 的數(shù)據(jù)和標(biāo)注
images, labels = next(iter(train_loader))
images = images.to(device)
labels = labels.to(device)
# 輸入模型拾枣,執(zhí)行前向預(yù)測(cè)
outputs = model(images)
# 獲得當(dāng)前 batch 所有圖像的預(yù)測(cè)類別 logit 分?jǐn)?shù)
outputs.shape
# 由 logit,計(jì)算當(dāng)前 batch 中盒让,每個(gè)樣本的平均交叉熵?fù)p失函數(shù)值
loss = criterion(outputs, labels)
# 反向傳播“三部曲”
optimizer.zero_grad() # 清除梯度
loss.backward() # 反向傳播
optimizer.step() # 優(yōu)化更新
# 獲得當(dāng)前 batch 所有圖像的預(yù)測(cè)類別
_, preds = torch.max(outputs, 1)
preds
labels
#完整訓(xùn)練過(guò)程
# 遍歷每個(gè) EPOCH
for epoch in tqdm(range(EPOCHS)):
model.train()
for images, labels in train_loader: # 獲得一個(gè) batch 的數(shù)據(jù)和標(biāo)注
images = images.to(device)
labels = labels.to(device)
outputs = model(images)
loss = criterion(outputs, labels) # 計(jì)算當(dāng)前 batch 中梅肤,每個(gè)樣本的平均交叉熵?fù)p失函數(shù)值
optimizer.zero_grad()
loss.backward()
optimizer.step()
#在測(cè)試集上初步測(cè)試
model.eval()
with torch.no_grad():
correct = 0
total = 0
for images, labels in tqdm(test_loader):
images = images.to(device)
labels = labels.to(device)
outputs = model(images)
_, preds = torch.max(outputs, 1)
total += labels.size(0)
correct += (preds == labels).sum()
print('測(cè)試集上的準(zhǔn)確率為 {:.3f} %'.format(100 * correct / total))
#測(cè)試集上的準(zhǔn)確率為 87.755 %
#保存模型
torch.save(model, 'checkpoints/fruit30_pytorch_20220814.pth')
4. 微調(diào)訓(xùn)練過(guò)程(升級(jí)版)
#導(dǎo)入工具包
#圖像預(yù)處理
#載入圖像分類數(shù)據(jù)集
#類別和索引號(hào)映射字典
#定義數(shù)據(jù)加載器DataLoader
#導(dǎo)入訓(xùn)練時(shí)所需要的工具包
from torchvision import models
import torch.optim as optim
from torch.optim import lr_scheduler #增加了學(xué)習(xí)率
#選擇三種遷移學(xué)習(xí)訓(xùn)練方式
##### 選擇一:只微調(diào)訓(xùn)練模型最后一層(全連接分類層)
model = models.resnet18(pretrained=True) # 載入預(yù)訓(xùn)練模型
# 修改全連接層,使得全連接層的輸出與當(dāng)前數(shù)據(jù)集類別數(shù)對(duì)應(yīng)
# 新建的層默認(rèn) requires_grad=True
model.fc = nn.Linear(model.fc.in_features, n_class)
model.fc
# 只微調(diào)訓(xùn)練最后一層全連接層的參數(shù)邑茄,其它層凍結(jié)
optimizer = optim.Adam(model.fc.parameters())
##### 選擇二:微調(diào)訓(xùn)練所有層
# model = models.resnet18(pretrained=True) # 載入預(yù)訓(xùn)練模型
# model.fc = nn.Linear(model.fc.in_features, n_class)
# optimizer = optim.Adam(model.parameters())
##### 選擇三:隨機(jī)初始化模型全部權(quán)重姨蝴,從頭訓(xùn)練所有層
# model = models.resnet18(pretrained=False) # 只載入模型結(jié)構(gòu),不載入預(yù)訓(xùn)練權(quán)重參數(shù)
# model.fc = nn.Linear(model.fc.in_features, n_class)
# optimizer = optim.Adam(model.parameters())
#訓(xùn)練配置
model=model.to(device)
# 交叉熵?fù)p失函數(shù)
criterion = nn.CrossEntropyLoss()
# 訓(xùn)練輪次 Epoch
EPOCHS = 30
# 學(xué)習(xí)率降低策略
lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.5)
#每隔5個(gè)epoch 讓學(xué)習(xí)率降低為原來(lái)的*0.5
#定義函數(shù)(在訓(xùn)練集上訓(xùn)練)
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import accuracy_score
from sklearn.metrics import f1_score
from sklearn.metrics import roc_auc_score
#運(yùn)行一個(gè) batch 的訓(xùn)練肺缕,返回當(dāng)前 batch 的訓(xùn)練日志
def train_one_batch(images, labels):
'''
運(yùn)行一個(gè) batch 的訓(xùn)練左医,返回當(dāng)前 batch 的訓(xùn)練日志
'''
# 獲得一個(gè) batch 的數(shù)據(jù)和標(biāo)注
images = images.to(device)
labels = labels.to(device)
outputs = model(images) # 輸入模型,執(zhí)行前向預(yù)測(cè)
loss = criterion(outputs, labels) # 計(jì)算當(dāng)前 batch 中同木,每個(gè)樣本的平均交叉熵?fù)p失函數(shù)值
# 優(yōu)化更新權(quán)重
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 獲取當(dāng)前 batch 的標(biāo)簽類別和預(yù)測(cè)類別
_, preds = torch.max(outputs, 1) # 獲得當(dāng)前 batch 所有圖像的預(yù)測(cè)類別
preds = preds.cpu().numpy()
loss = loss.detach().cpu().numpy()
outputs = outputs.detach().cpu().numpy()
labels = labels.detach().cpu().numpy()
log_train = {}
log_train['epoch'] = epoch
log_train['batch'] = batch_idx
# 計(jì)算分類評(píng)估指標(biāo)
log_train['train_loss'] = loss
log_train['train_accuracy'] = accuracy_score(labels, preds)
# 可以計(jì)算訓(xùn)練集上的指標(biāo)
# log_train['train_precision'] = precision_score(labels, preds, average='macro')
# log_train['train_recall'] = recall_score(labels, preds, average='macro')
# log_train['train_f1-score'] = f1_score(labels, preds, average='macro')
return log_train
#定義一個(gè)函數(shù)(在整個(gè)測(cè)試集上評(píng)估)
def evaluate_testset():
'''
在整個(gè)測(cè)試集上評(píng)估浮梢,返回分類評(píng)估指標(biāo)日志
'''
loss_list = []
labels_list = []
preds_list = []
with torch.no_grad():
for images, labels in test_loader: # 生成一個(gè) batch 的數(shù)據(jù)和標(biāo)注
images = images.to(device)
labels = labels.to(device)
outputs = model(images) # 輸入模型,執(zhí)行前向預(yù)測(cè)
# 獲取整個(gè)測(cè)試集的標(biāo)簽類別和預(yù)測(cè)類別
_, preds = torch.max(outputs, 1) # 獲得當(dāng)前 batch 所有圖像的預(yù)測(cè)類別
preds = preds.cpu().numpy()
loss = criterion(outputs, labels) # 由 logit彤路,計(jì)算當(dāng)前 batch 中秕硝,每個(gè)樣本的平均交叉熵?fù)p失函數(shù)值
loss = loss.detach().cpu().numpy()
outputs = outputs.detach().cpu().numpy()
labels = labels.detach().cpu().numpy()
loss_list.append(loss)
labels_list.extend(labels)
preds_list.extend(preds)
log_test = {}
log_test['epoch'] = epoch
# 計(jì)算分類評(píng)估指標(biāo)
log_test['test_loss'] = np.mean(loss) #測(cè)試集上的loss
log_test['test_accuracy'] = accuracy_score(labels_list, preds_list)
log_test['test_precision'] = precision_score(labels_list, preds_list, average='macro')
log_test['test_recall'] = recall_score(labels_list, preds_list, average='macro')
log_test['test_f1-score'] = f1_score(labels_list, preds_list, average='macro')
return log_test
#訓(xùn)練開始之前,需要記錄訓(xùn)練過(guò)程日志
epoch = 0
batch_idx = 0
best_test_accuracy = 0
# 訓(xùn)練日志-訓(xùn)練集
df_train_log = pd.DataFrame()
log_train = {}
log_train['epoch'] = 0
log_train['batch'] = 0
images, labels = next(iter(train_loader))
log_train.update(train_one_batch(images, labels))
df_train_log = df_train_log.append(log_train, ignore_index=True)
df_train_log
# epoch batch train_loss train_accuracy
0 0 0 3.6047866 0.0625
# 訓(xùn)練日志-測(cè)試集 整個(gè)測(cè)試集
df_test_log = pd.DataFrame()
log_test = {}
log_test['epoch'] = 0
log_test.update(evaluate_testset())
df_test_log = df_test_log.append(log_test, ignore_index=True)
df_test_log
# epoch test_loss test_accuracy test_precision test_recall test_f1-score
0 0.0 3.275232 0.037106 0.013615 0.036673 0.015244
登陸wandb
- 安裝wandb: pip install wandb
- 登錄 wandb:在命令行中運(yùn)行wandb login
- 按提示復(fù)制粘貼API Key至命令行中
#創(chuàng)建wandb可視化項(xiàng)目
import wandb
#project是大項(xiàng)目 洲尊,name是小項(xiàng)目 起名是用時(shí)間來(lái)取名的
wandb.init(project='fruit30', name=time.strftime('%m%d%H%M%S'))
#進(jìn)行訓(xùn)練
for epoch in range(1, EPOCHS+1):
print(f'Epoch {epoch}/{EPOCHS}')
## 訓(xùn)練階段
model.train()
for images, labels in tqdm(train_loader): # 獲得一個(gè) batch 的數(shù)據(jù)和標(biāo)注
batch_idx += 1
log_train = train_one_batch(images, labels)
df_train_log = df_train_log.append(log_train, ignore_index=True)
wandb.log(log_train)
lr_scheduler.step() #學(xué)習(xí)率更新
## 測(cè)試階段
model.eval()
log_test = evaluate_testset()
df_test_log = df_test_log.append(log_test, ignore_index=True)
wandb.log(log_test)
# 保存最新的最佳模型文件
# 在測(cè)試集上的準(zhǔn)確率有更好的远豺,就會(huì)更新
if log_test['test_accuracy'] > best_test_accuracy:
# 刪除舊的最佳模型文件(如有)
old_best_checkpoint_path = 'checkpoints/best-{:.3f}.pth'.format(best_test_accuracy)
if os.path.exists(old_best_checkpoint_path):
os.remove(old_best_checkpoint_path)
# 保存新的最佳模型文件
new_best_checkpoint_path = 'checkpoints/best-{:.3f}.pth'.format(log_test['test_accuracy'])
torch.save(model, new_best_checkpoint_path)
print('保存新的最佳模型', 'checkpoints/best-{:.3f}.pth'.format(best_test_accuracy))
best_test_accuracy = log_test['test_accuracy']
df_train_log.to_csv('訓(xùn)練日志-訓(xùn)練集.csv', index=False)
df_test_log.to_csv('訓(xùn)練日志-測(cè)試集.csv', index=False)
#在測(cè)試集上評(píng)價(jià)
# 載入最佳模型作為當(dāng)前模型
model = torch.load('checkpoints/best-{:.3f}.pth'.format(best_test_accuracy))
model.eval()
print(evaluate_testset()) # 在整個(gè)測(cè)試集上做評(píng)估
#{'epoch': 30, 'test_loss': 0.23493767, 'test_accuracy': 0.8794063079777366, 'test_precision': 0.8843936613935047, 'test_recall': 0.8781298367986428, 'test_f1-score': 0.8781021317064345}
5. 可視化訓(xùn)練日志
#導(dǎo)入工具包
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
#導(dǎo)入訓(xùn)練日志表格
df_train = pd.read_csv('訓(xùn)練日志-訓(xùn)練集.csv')
df_test = pd.read_csv('訓(xùn)練日志-測(cè)試集.csv')
df_train
df_test
#訓(xùn)練集損失函數(shù)
plt.figure(figsize=(16, 8))
x = df_train['batch']
y = df_train['train_loss']
plt.plot(x, y, label='訓(xùn)練集')
plt.tick_params(labelsize=20)
plt.xlabel('batch', fontsize=20)
plt.ylabel('loss', fontsize=20)
plt.title('訓(xùn)練集損失函數(shù)', fontsize=25)
plt.savefig('圖表/訓(xùn)練集損失函數(shù).pdf', dpi=120, bbox_inches='tight')
plt.show()
#訓(xùn)練集準(zhǔn)確率
plt.figure(figsize=(16, 8))
x = df_train['batch']
y = df_train['train_accuracy']
plt.plot(x, y, label='訓(xùn)練集')
plt.tick_params(labelsize=20)
plt.xlabel('batch', fontsize=20)
plt.ylabel('loss', fontsize=20)
plt.title('訓(xùn)練集準(zhǔn)確率', fontsize=25)
plt.savefig('圖表/訓(xùn)練集準(zhǔn)確率.pdf', dpi=120, bbox_inches='tight')
plt.show()
#測(cè)試集損失函數(shù)
plt.figure(figsize=(16, 8))
x = df_test['epoch']
y = df_test['test_loss']
plt.plot(x, y, label='測(cè)試集')
plt.tick_params(labelsize=20)
plt.xlabel('epoch', fontsize=20)
plt.ylabel('loss', fontsize=20)
plt.title('測(cè)試集損失函數(shù)', fontsize=25)
plt.savefig('圖表/測(cè)試集損失函數(shù).pdf', dpi=120, bbox_inches='tight')
plt.show()
#測(cè)試集評(píng)估指標(biāo)
from matplotlib import colors as mcolors
import random
random.seed(124)
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', 'tab:gray', 'tab:olive', 'tab:cyan', 'black', 'indianred', 'brown', 'firebrick', 'maroon', 'darkred', 'red', 'sienna', 'chocolate', 'yellow', 'olivedrab', 'yellowgreen', 'darkolivegreen', 'forestgreen', 'limegreen', 'darkgreen', 'green', 'lime', 'seagreen', 'mediumseagreen', 'darkslategray', 'darkslategrey', 'teal', 'darkcyan', 'dodgerblue', 'navy', 'darkblue', 'mediumblue', 'blue', 'slateblue', 'darkslateblue', 'mediumslateblue', 'mediumpurple', 'rebeccapurple', 'blueviolet', 'indigo', 'darkorchid', 'darkviolet', 'mediumorchid', 'purple', 'darkmagenta', 'fuchsia', 'magenta', 'orchid', 'mediumvioletred', 'deeppink', 'hotpink']
markers = [".",",","o","v","^","<",">","1","2","3","4","8","s","p","P","*","h","H","+","x","X","D","d","|","_",0,1,2,3,4,5,6,7,8,9,10,11]
linestyle = ['--', '-.', '-']
def get_line_arg():
'''
隨機(jī)產(chǎn)生一種繪圖線型
'''
line_arg = {}
line_arg['color'] = random.choice(colors)
# line_arg['marker'] = random.choice(markers)
line_arg['linestyle'] = random.choice(linestyle)
line_arg['linewidth'] = random.randint(1, 4)
# line_arg['markersize'] = random.randint(3, 5)
return line_arg
metrics = ['test_accuracy', 'test_precision', 'test_recall', 'test_f1-score']
plt.figure(figsize=(16, 8))
x = df_test['epoch']
for y in metrics:
plt.plot(x, df_test[y], label=y, **get_line_arg())
plt.tick_params(labelsize=20)
plt.ylim([0, 1])
plt.xlabel('epoch', fontsize=20)
plt.ylabel(y, fontsize=20)
plt.title('測(cè)試集分類評(píng)估指標(biāo)', fontsize=25)
plt.savefig('圖表/測(cè)試集分類評(píng)估指標(biāo).pdf', dpi=120, bbox_inches='tight')
plt.legend(fontsize=20)
plt.show()
- 不能把測(cè)試集圖像用于訓(xùn)練
- 測(cè)試集圖像可能存在錯(cuò)標(biāo)和漏標(biāo),測(cè)試集上的準(zhǔn)確率越高坞嘀,模型也不一樣越好
- 三種不同的遷移學(xué)習(xí)訓(xùn)練配置:只微調(diào)訓(xùn)練模型最后一層躯护、微調(diào)訓(xùn)練所有層、隨機(jī)初始化模型全部權(quán)重
- 更換不同的優(yōu)化器和學(xué)習(xí)率使模型收斂更快
- 訓(xùn)練好圖像分類模型之后丽涩,需要在測(cè)試集上評(píng)估混淆矩陣棺滞、ROC曲線、PR曲線、語(yǔ)義特征降維可視化......