9.23 深度学习微调
- 深度學習中最重要的一個技術
標注一個數據集很貴
- ImageNet 標注了一千多萬張圖片,但是實際使用的只有 120 萬張圖片,類別數是 1000 ,它算是一個比較大的數據集
- Fashion-MNIST 一共有 6 萬張圖片,類別數是 10 , 算是一個比較小的數據集
- 通常自己的數據集規模通常在這兩者之間,大概在 5 萬張圖片左右,類別數大概是 100 左右,平均下來每一類物體大概有 500 張圖片左右
適合 ImageNet 的復雜模型可能會在自己的數據集上過擬合,另外由于訓練樣本有限,訓練模型的準確性可能無法滿足實際要求,解決以上問題有兩種解決方案:
1、收集更多的數據。數據集越大越好,但是收集和標記數據可能需要大量的時間和金錢。
2、應用遷移學習(transfer leanring)。將從源數據集學到的知識遷移到目標數據集,通常來說希望在大數據集上訓練好的模型能夠提取到更通用的圖像特征,有助于識別邊緣、紋理、形狀和對象組合,從而幫助提升在自己數據集上的精度,核心思想是假設模型對整個物體識別有一定的基礎的情況下,不需要自己提供太大的數據集就能夠獲得很好的識別精度,這也是人工智能所追求的目標
網絡架構
一個神經網絡一般可以分為兩塊,一部分做特征提取,一部分做線性分類
- 假設將一張圖像輸入到模型中,可以認為最下面的一部分是在進行特征提取(特征抽取就是將原始像素變成容易線性分割的特征,深度學習的突破性進展就在于特征提取是可以學習的,而不用人工思考如何提供特征)
- 最后一部分就是一個全連接層和 softmax 來進行分類(可以認為是一個簡單的線性分類器:Softmax 回歸)
微調
- 假設在源數據集(一個比較大的數據集)上已經訓練好了一個模型,模型中特征提取的部分對源數據集是有效的,那么它對目標數據集也應該是有效的,這樣做是優于隨機生成提取特征的
- 最后一部分是不能直接使用的,因為標號發生了改變,所以最后一部分難以進行重用
- 微調的核心思想是:在一個比較大的源數據集上訓練好的模型中用于特征提取的部分,在目標數據集上提取特征時進行重用
微調中的權重初始化
微調包括四個步驟:
- 因為損失 Loss 是從后往前進行傳遞的,所以最后的分類部分訓練比較快,進行隨機初始化也不會有太大的影響;而前面的特征提取的部分本身已經具備很好的特征提取效果,只是根據源數據集和目標數據集的差異進行微調,可能在最開始訓練的時候就已經比較接近最終的結果,所以不用做過多的訓練和變動
訓練
是一個目標數據集上的正常訓練任務,但使用更強的正則化(如果不使用預訓練模型,直接在自己的數據集上正常訓練,在時間足夠的情況下也是可以從隨機初始化訓練到完全 fitting 自己的數據集,但是可能會導致 Overfitting ,這是沒有必要的,不如對預訓練模型進行微調)
- 使用更小的學習率(已經比較接近最優解了,因此不需要太大的學習率)
- 使用更少的數據迭代
源數據集遠遠復雜于目標數據集,通常微調的效果更好
- 源數據集的類別數、圖片數量、樣本個數通常是目標數據集的 10 倍或者 100 倍,才能達到很好的微調效果,否則微調的效果不如直接在目標數據集上進行重新訓練
重用分類器權重
- 源數據集中可能也有目標數據中的標號
- 可以使用預訓練好的模型分類器中對應標號對應的向量來做初始化
固定一些層
神經網絡通常學習有層次的特征表示
- 低層次的特征更加通用(越低層次學習的是一些底層的細節)
- 高層次的特征則更跟數據集相關(越高層次則更加語義化)
- 可以認為越到后面和標號的關聯度越大,約到前面則越低層,所以底層的特征更加通用,高層的特征和數據的關聯度更大
可以固定底部一些層的參數,不參與更新(不做優化,在微調的時候不改變底層類別的權重,因為這些參數不再發生變化,所以模型的復雜度變低了,可以認為是更強的正則的效果)
- 更強的正則
通常來說,假設數據集很小,直接訓練很容易過擬合的情況下,可以固定底部的一些參數不參與更新
總結
1、微調通過使用在大數據上得到的預訓練好的模型來初始化目標數據集上的模型權重來完成提升精度
2、預訓練模型質量很重要
3、微調通常速度更快,精度更高(可以借助在大數據集上所獲得的先驗知識)
4、建議盡量從微調開始訓練,不要直接從目標數據集上從零開始進行訓練
- 未來從原始數據集上進行訓練的會越來越少,主要是學術界或者大公司在很大的數據集上進行重新訓練
- 對于個人或者實際應用來講,通常是使用微調
5、遷移學習將從源數據集中學到的知識“遷移”到目標數據集,微調遷移學習的常見技巧
6、除輸出層外,目標模型從源模型中復制所有模型設計及其參數,并根據目標數據集對這些參數進行微調,但是目標模型的輸出層需要從頭開始訓練
7、通常微調參數使用較小的學習率,而從頭開始訓練輸出層可以使用更大的學習率
代碼:
%matplotlib inline import os import torch import torchvision from torch import nn from d2l import torch as d2ld2l.DATA_HUB['hotdog'] = (d2l.DATA_URL + 'hotdog.zip','fba480ffa8aa7e0febbb511d181409f899b9baa5') data_dir = d2l.download_extract('hotdog')train_imgs = torchvision.datasets.ImageFolder(os.path.join(data_dir,'train')) test_imgs = torchvision.datasets.ImageFolder(os.path.join(data_dir,'test'))# 圖片的大小和縱橫比各有不同 hotdogs = [train_imgs[i][0] for i in range(8)] print(train_imgs[0]) # 圖片和標簽,合為一個元組 print(train_imgs[0][0]) # 元組第一個元素為圖片 not_hotdogs = [train_imgs[-i - 1][0] for i in range(8)] d2l.show_images(hotdogs + not_hotdogs, 2, 8, scale=1.4) # 定義和初始化模型 pretrained_net = torchvision.models.resnet18(pretrained=True) # 把模型和在ImageNet上定義好的參數拿過來 pretrained_net.fc # full connection全連接層,最后一層,查看最后一層的輸入和輸出結構 finetune_net = torchvision.models.resnet18(pretrained=True) finetune_net.fc = nn.Linear(finetune_net.fc.in_features,2) # 最后一層修改為輸出類別數為2 nn.init.xavier_uniform_(finetune_net.fc.weight) # 只對最后一層的weight做隨即初始化 # 微調座位 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:# 除了最后一層的learning rate外,用的是默認的learning rate# 最后一層的learning rate用的是十倍的learning rateparams_lx = [param for name, param in net.named_parameters()if name not in ["fc.weight","fc.bias"] ]trainer = torch.optim.SGD([{'params': params_lx}, {'params': net.fc.parameters(), 'lr': learning_rate * 10}],lr=learning_rate, weight_decay=0.001)else: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) # 使用較小的學習率 train_fine_tuning(finetune_net,6e-6) # 為了進行比較,所有模型參數初始化為隨機值 scratch_net = torchvision.models.resnet18() # 這里沒有pretrained=True,沒有拿預訓練的參數 scratch_net.fc = nn.Linear(scratch_net.fc.in_features,2) train_fine_tuning(scratch_net,5e-4,param_group=False) # param_group=False使得所有層的參數都為默認的學習率總結
以上是生活随笔為你收集整理的9.23 深度学习微调的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 红警3命令与征服注册激活启动cdkey联
- 下一篇: 李沐动手学深度学习V2-BERT微调和代