Task3:遷移學(xué)習(xí)微調(diào)訓(xùn)練

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

  1. 安裝wandb: pip install wandb
  2. 登錄 wandb:在命令行中運(yùn)行wandb login
  3. 按提示復(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()
  1. 不能把測(cè)試集圖像用于訓(xùn)練
  2. 測(cè)試集圖像可能存在錯(cuò)標(biāo)和漏標(biāo),測(cè)試集上的準(zhǔn)確率越高坞嘀,模型也不一樣越好
  3. 三種不同的遷移學(xué)習(xí)訓(xùn)練配置:只微調(diào)訓(xùn)練模型最后一層躯护、微調(diào)訓(xùn)練所有層、隨機(jī)初始化模型全部權(quán)重
  4. 更換不同的優(yōu)化器和學(xué)習(xí)率使模型收斂更快
  5. 訓(xùn)練好圖像分類模型之后丽涩,需要在測(cè)試集上評(píng)估混淆矩陣棺滞、ROC曲線、PR曲線、語(yǔ)義特征降維可視化......
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末继准,一起剝皮案震驚了整個(gè)濱河市厘擂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锰瘸,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昂灵,死亡現(xiàn)場(chǎng)離奇詭異避凝,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)眨补,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門管削,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人撑螺,你說(shuō)我怎么就攤上這事含思。” “怎么了甘晤?”我有些...
    開封第一講書人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵含潘,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我线婚,道長(zhǎng)遏弱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任塞弊,我火速辦了婚禮漱逸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘游沿。我一直安慰自己饰抒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開白布诀黍。 她就那樣靜靜地躺著袋坑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪眯勾。 梳的紋絲不亂的頭發(fā)上咒彤,一...
    開封第一講書人閱讀 52,807評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音咒精,去河邊找鬼镶柱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛模叙,可吹牛的內(nèi)容都是我干的歇拆。 我是一名探鬼主播,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼故觅!你這毒婦竟也來(lái)了厂庇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤输吏,失蹤者是張志新(化名)和其女友劉穎权旷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贯溅,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拄氯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了它浅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片译柏。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖姐霍,靈堂內(nèi)的尸體忽然破棺而出鄙麦,到底是詐尸還是另有隱情,我是刑警寧澤镊折,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布胯府,位于F島的核電站,受9級(jí)特大地震影響恨胚,放射性物質(zhì)發(fā)生泄漏盟劫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一与纽、第九天 我趴在偏房一處隱蔽的房頂上張望侣签。 院中可真熱鬧,春花似錦急迂、人聲如沸影所。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)猴娩。三九已至,卻和暖如春勺阐,著一層夾襖步出監(jiān)牢的瞬間卷中,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工渊抽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蟆豫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓懒闷,卻偏偏與公主長(zhǎng)得像十减,于是被迫代替她去往敵國(guó)和親栈幸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容