动手学深度学习(二十七)——微调(fine turning)
生活随笔
收集整理的這篇文章主要介紹了
动手学深度学习(二十七)——微调(fine turning)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
文章目錄
- 一、微調(diào)(fine tuning)
- 1. 微調(diào)的四個步驟:
- 2. 微調(diào)的訓練過程
- 3. 常用的微調(diào)技術
- 4. 總結
- 二、動手實現(xiàn)和測試微調(diào)
- 1. 數(shù)據(jù)準備
- 2. 模型微調(diào)
- 3. 對比不使用微調(diào)和不同的微調(diào)參數(shù)
- 4. 凍結層進行微調(diào)
一、微調(diào)(fine tuning)
1. 微調(diào)的四個步驟:
2. 微調(diào)的訓練過程
- 更小的學習率(大stride在初始模型中已走過了,相當于已經(jīng)有一個比較好的模型了)
- 更少的迭代次數(shù)
3.源數(shù)據(jù)集遠復雜于目標數(shù)據(jù),通常得到的微調(diào)效果更好
3. 常用的微調(diào)技術
- 源數(shù)據(jù)可能也有目標數(shù)據(jù)中的部分標號
- 可以使用預訓練好的模型分類器中對應標號對應的向量作初始化值
- 神經(jīng)網(wǎng)絡通常學習有層次的特征表示(底層描述的特征更加通用,而高層的特征和數(shù)據(jù)集相關性更強)
- 可以固定相對底部的層,不參與參數(shù)更新(應用了更強的正則化)
4. 總結
二、動手實現(xiàn)和測試微調(diào)
%matplotlib inline import os import torch import torchvision from torch import nn from d2l import torch as d2l1. 數(shù)據(jù)準備
# 下載熱狗數(shù)據(jù)集 d2l.DATA_HUB['hotdog'] = (d2l.DATA_URL+'hotdog.zip','fba480ffa8aa7e0febbb511d181409f899b9baa5') data_dir = d2l.download_extract('hotdog') # 加載數(shù)據(jù) train_imgs = torchvision.datasets.ImageFolder(os.path.join(data_dir, 'train')) test_imgs = torchvision.datasets.ImageFolder(os.path.join(data_dir, 'test')) # 查看數(shù)據(jù) '''展示了8張熱狗數(shù)據(jù)和非熱狗的數(shù)據(jù),圖像的大小和橫縱比例都不盡相同''' hotdogs = [train_imgs[i][0] for i in range(8)] # hotdogs not_hotdogs = [train_imgs[-i-1][0] for i in range(8)] # not hotdogs d2l.show_images(hotdogs + not_hotdogs, 2, 8, scale=1.4); # 數(shù)據(jù)增廣使數(shù)據(jù)規(guī)整變多 ''' 在訓練期間,我們首先從圖像中裁切隨機大小和隨機長寬比的區(qū)域,然后將該區(qū)域縮放為 224x224 輸入圖像。 在測試過程中,我們將圖像的高度和寬度都縮放到 256 像素,然后裁剪中央 224 x 224 區(qū)域作為輸入。 此外,對于三個 RGB(紅、綠和藍)顏色通道,我們標準化每個通道。 具體而言,通道的平均值將從該通道的每個值中減去,然后將結果除以該通道的標準差。 ''' # 在Imagenet上使用的Normalize直接搬過來,參數(shù)第一個是mean,第二個是std;image = (image-mean)/std;這里是三通道 normalize = torchvision.transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]) train_augs = torchvision.transforms.Compose([torchvision.transforms.RandomResizedCrop(224),torchvision.transforms.RandomHorizontalFlip(),torchvision.transforms.ToTensor(),normalize, ])test_augs = torchvision.transforms.Compose([torchvision.transforms.Resize(256),torchvision.transforms.CenterCrop(224),torchvision.transforms.ToTensor(), normalize])2. 模型微調(diào)
定義和初始化模型
# 定義和初始化模型 ''' 使用ImageNet數(shù)據(jù)集預訓練的ResNet-18作為源模型; 指pretrained =True,以保存模型參數(shù) ''' pretrained_net = torchvision.models.resnet18(pretrained=True)Check原始模型參數(shù)
# 源模型包含多個要素圖層和一個輸出圖層,對除了輸出圖層之外的層進行微調(diào) '''查看源模型的輸出圖層參數(shù)''' pretrained_net.fc Linear(in_features=512, out_features=1000, bias=True) # 初始化微調(diào)圖層 finetune_net = torchvision.models.resnet18(pretrained=True) finetune_net.fc = nn.Linear(finetune_net.fc.in_features, 2) nn.init.xavier_uniform_(finetune_net.fc.weight);定義訓練函數(shù),便于更多參數(shù)的調(diào)整
# 如果 `param_group=True`,輸出層中的模型參數(shù)將使用十倍的學習率 def train_fine_tuning(net, learning_rate, batch_size=128, num_epochs=5,param_group=True):train_iter = torch.utils.data.DataLoader(torchvision.datasets.ImageFolder(os.path.join(data_dir, 'train'),transform=train_augs),batch_size=batch_size, shuffle=True)test_iter = torch.utils.data.DataLoader(torchvision.datasets.ImageFolder(os.path.join(data_dir, 'test'),transform=test_augs),batch_size=batch_size)devices = d2l.try_all_gpus()loss = nn.CrossEntropyLoss(reduction="none")if param_group:'''將所有層的參數(shù)都拿出來進行訓練,最后一層的學習率是前面層的10倍'''params_1x = [param for name, param in net.named_parameters()if name not in ["fc.weight", "fc.bias"]]trainer = torch.optim.SGD([{'params': params_1x}, {'params': net.fc.parameters(),'lr': learning_rate * 10}], lr=learning_rate,weight_decay=0.001)else:'''全部參數(shù)一樣地訓練'''trainer = torch.optim.SGD(net.parameters(), lr=learning_rate,weight_decay=0.001)d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs,devices) # 使用較小的學習率,通過微調(diào)預訓練獲得的模型參數(shù) train_fine_tuning(finetune_net, 5e-5) loss 0.181, train acc 0.932, test acc 0.935 228.9 examples/sec on [device(type='cuda', index=0)]3. 對比不使用微調(diào)和不同的微調(diào)參數(shù)
如果不使用微調(diào),直接從零開始訓練:不使用微調(diào)的結果精度遠遠低于微調(diào)的結果
# 對比不使用微調(diào) scratch_net = torchvision.models.resnet18() scratch_net.fc = nn.Linear(scratch_net.fc.in_features, 2) train_fine_tuning(scratch_net, 5e-4, param_group=False) loss 0.384, train acc 0.831, test acc 0.814 229.5 examples/sec on [device(type='cuda', index=0)]調(diào)整fine turning 的學習率發(fā)現(xiàn):學習率變太高會降低訓練的精度
# 調(diào)高fine turning 的學習率 finetune_net = torchvision.models.resnet18(pretrained=True) finetune_net.fc = nn.Linear(finetune_net.fc.in_features, 2) nn.init.xavier_uniform_(finetune_net.fc.weight); train_fine_tuning(finetune_net, 4e-5) loss 0.203, train acc 0.921, test acc 0.930 229.4 examples/sec on [device(type='cuda', index=0)]4. 凍結層進行微調(diào)
凍結一部分的層進行訓練:凍結層訓練可以減少訓練的時間,但是具體要凍結哪些層需要調(diào)整,我這里使用的方法也不確定是否正確,因為使用requires_grad沒有使用成功,就找了個笨方法
# 如果不更新輸出層之前的層的參數(shù)(凍結一些層) # 我這里沒有使用requires_grad = False,沒有仔細探究是否真的凍結住了。是否需要將不計算梯度放到train函數(shù)之中 def train_fine_tuning_freeze(net, learning_rate, batch_size=128, num_epochs=5):train_iter = torch.utils.data.DataLoader(torchvision.datasets.ImageFolder(os.path.join(data_dir, 'train'),transform=train_augs),batch_size=batch_size, shuffle=True)test_iter = torch.utils.data.DataLoader(torchvision.datasets.ImageFolder(os.path.join(data_dir, 'test'),transform=test_augs),batch_size=batch_size)devices = d2l.try_all_gpus()loss = nn.CrossEntropyLoss(reduction="none")'''凍結一些層(只更新最后層的參數(shù))'''trainer = torch.optim.SGD(net.fc.parameters(), lr=learning_rate,weight_decay=0.001)d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs,devices)finetune_net = torchvision.models.resnet18(pretrained=True) finetune_net.fc = nn.Linear(finetune_net.fc.in_features, 2) nn.init.xavier_uniform_(finetune_net.fc.weight); train_fine_tuning_freeze(finetune_net, 5e-5,num_epochs=10) loss 0.299, train acc 0.878, test acc 0.887 231.1 examples/sec on [device(type='cuda', index=0)]如果有什么存在疑惑的地方可以在評論區(qū)提出,大家一起討論!
總結
以上是生活随笔為你收集整理的动手学深度学习(二十七)——微调(fine turning)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在C++中删除文件
- 下一篇: 深度学习笔记 —— 微调