日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

pytorch 模型微调

發布時間:2023/12/18 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 pytorch 模型微调 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 新數據集和原始數據集合類似,那么直接可以微調一個最后的FC層或者重新指定一個新的分類器
  • 新數據集比較小和原始數據集合差異性比較大,那么可以使用從模型的中部開始訓練,只對最后幾層進行fine-tuning
  • 新數據集比較小和原始數據集合差異性比較大,如果上面方法還是不行的化那么最好是重新訓練,只將預訓練的模型作為一個新模型初始化的數據
  • 新數據集的大小一定要與原始數據集相同,比如CNN中輸入的圖片大小一定要相同,才不會報錯
  • 如果數據集大小不同的話,可以在最后的fc層之前添加卷積或者pool層,使得最后的輸出與fc層一致,但這樣會導致準確度大幅下降,所以不建議這樣做
  • 對于不同的層可以設置不同的學習率,一般情況下建議,對于使用的原始數據做初始化的層設置的學習率要小于(一般可設置小于10倍)初始化的學習率,這樣保證對于已經初始化的數據不會扭曲的過快,而使用初始化學習率的新層可以快速的收斂。
  • %matplotlib inline import torch,os,torchvision import torch.nn as nn import torch.nn.functional as F import pandas as pd import numpy as np import matplotlib.pyplot as plt from torch.utils.data import DataLoader, Dataset from torchvision import datasets, models, transforms from PIL import Image from sklearn.model_selection import StratifiedShuffleSplit torch.__version__

    這里面我們使用官方訓練好的resnet50來參加kaggle上面的 dog breed 狗的種類識別來做一個簡單微調實例。

    首先我們需要下載官方的數據解壓,只要保持數據的目錄結構即可,這里指定一下目錄的位置,并且看下內容

    DATA_ROOT = '/home/huangshaobo/dataset/dog' all_labels_df = pd.read_csv(os.path.join(DATA_ROOT,'labels.csv')) all_labels_df.head()


    獲取狗的分類,根據分類進行編號。這里定義了兩個字典,分別以名字和id作為對應,方便后面處理:

    breeds = all_labels_df.breed.unique() breed2idx = dict((breed,idx) for idx,breed in enumerate(breeds)) idx2breed = dict((idx,breed) for idx,breed in enumerate(breeds)) len(breeds)


    添加到列表中:

    all_labels_df['label_idx'] = [breed2idx[b] for b in all_labels_df.breed] all_labels_df.head()


    由于我們的數據集不是官方指定的格式,我們自己定義一個數據集:

    class DogDataset(Dataset):def __init__(self, labels_df, img_path, transform=None):self.labels_df = labels_dfself.img_path = img_pathself.transform = transformdef __len__(self):return self.labels_df.shape[0]def __getitem__(self, idx):image_name = os.path.join(self.img_path, self.labels_df.id[idx]) + '.jpg'img = Image.open(image_name)label = self.labels_df.label_idx[idx]if self.transform:img = self.transform(img)return img, label # 定義一些超參數: IMG_SIZE = 224 # resnet50的輸入是224的所以需要將圖片統一大小 BATCH_SIZE= 256 #這個批次大小需要占用4.6-5g的顯存,如果不夠的化可以改下批次,如果內存超過10G可以改為512 IMG_MEAN = [0.485, 0.456, 0.406] IMG_STD = [0.229, 0.224, 0.225] CUDA=torch.cuda.is_available() DEVICE = torch.device("cuda" if CUDA else "cpu")# 定義訓練和驗證數據的圖片變換規則: train_transforms = transforms.Compose([transforms.Resize(IMG_SIZE),transforms.RandomResizedCrop(IMG_SIZE),transforms.RandomHorizontalFlip(),transforms.RandomRotation(30),transforms.ToTensor(),transforms.Normalize(IMG_MEAN, IMG_STD) ])val_transforms = transforms.Compose([transforms.Resize(IMG_SIZE),transforms.CenterCrop(IMG_SIZE),transforms.ToTensor(),transforms.Normalize(IMG_MEAN, IMG_STD) ])

    我們這里只分割10%的數據作為訓練時的驗證數據:

    dataset_names = ['train', 'valid'] stratified_split = StratifiedShuffleSplit(n_splits=1, test_size=0.1, random_state=0) train_split_idx, val_split_idx = next(iter(stratified_split.split(all_labels_df.id, all_labels_df.breed))) train_df = all_labels_df.iloc[train_split_idx].reset_index() val_df = all_labels_df.iloc[val_split_idx].reset_index() print(len(train_df)) print(len(val_df))


    使用官方的dataloader載入數據:

    image_transforms = {'train':train_transforms, 'valid':val_transforms}train_dataset = DogDataset(train_df, os.path.join(DATA_ROOT,'train'), transform=image_transforms['train']) val_dataset = DogDataset(val_df, os.path.join(DATA_ROOT,'train'), transform=image_transforms['valid']) image_dataset = {'train':train_dataset, 'valid':val_dataset}image_dataloader = {x:DataLoader(image_dataset[x],batch_size=BATCH_SIZE,shuffle=True,num_workers=0) for x in dataset_names} dataset_sizes = {x:len(image_dataset[x]) for x in dataset_names} # 開始配置網絡,由于ImageNet是識別1000個物體,我們的狗的分類一共只有120, # 所以需要對模型的最后一層全連接層進行微調,將輸出從1000改為120:model_ft = models.resnet50(pretrained=True) # 這里自動下載官方的預訓練模型,并且 # 將所有的參數層進行凍結 for param in model_ft.parameters():param.requires_grad = False # 這里打印下全連接層的信息 print(model_ft.fc) num_fc_ftr = model_ft.fc.in_features #獲取到fc層的輸入 model_ft.fc = nn.Linear(num_fc_ftr, len(breeds)) # 定義一個新的FC層 model_ft=model_ft.to(DEVICE)# 放到設備中 print(model_ft) # 最后再打印一下新的模型 # 設置訓練參數:criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam([{'params':model_ft.fc.parameters()} ], lr=0.001)#指定 新加的fc層的學習率

    定義訓練函數:

    def train(model,device, train_loader, epoch):model.train()for batch_idx, data in enumerate(train_loader):x,y= datax=x.to(device)y=y.to(device)optimizer.zero_grad()y_hat= model(x)loss = criterion(y_hat, y)loss.backward()optimizer.step()print ('Train Epoch: {}\t Loss: {:.6f}'.format(epoch,loss.item()))

    定義測試函數:

    def test(model, device, test_loader):model.eval()test_loss = 0correct = 0with torch.no_grad():for i,data in enumerate(test_loader): x,y= datax=x.to(device)y=y.to(device)optimizer.zero_grad()y_hat = model(x)test_loss += criterion(y_hat, y).item() # sum up batch losspred = y_hat.max(1, keepdim=True)[1] # get the index of the max log-probabilitycorrect += pred.eq(y.view_as(pred)).sum().item()test_loss /= len(test_loader.dataset)print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(test_loss, correct, len(val_dataset),100. * correct / len(val_dataset)))

    訓練9次,看看效果:

    for epoch in range(1, 10):%time train(model=model_ft,device=DEVICE, train_loader=image_dataloader["train"],epoch=epoch)test(model=model_ft, device=DEVICE, test_loader=image_dataloader["valid"])


    我們看到只訓練了9次就達到了80%的準確率,效果還是可以的。

    但是每次訓練都需要將一張圖片在全部網絡中進行計算,而且計算的結果每次都是一樣的,這樣浪費了很多計算的資源。 下面我們就將這些不進行反向傳播或者說不更新網絡權重參數層的計算結果保存下來, 這樣我們以后使用的時候就可以直接將這些結果輸入到FC層或者以這些結果構建新的網絡層, 省去了計算的時間,并且這樣如果只訓練全連接層,CPU就可以完成了。

    PyTorch論壇中說到可以使用自己手動實現模型中的forward參數,這樣看起來是很簡便的,但是這樣處理起來很麻煩,不建議這樣使用。

    這里我們就要采用PyTorch比較高級的API,hook來處理了,我們要先定義一個hook函數

    in_list= [] # 這里存放所有的輸出 def hook(module, input, output):#input是一個tuple代表順序代表每一個輸入項,我們這里只有一項,所以直接獲取#需要全部的參數信息可以使用這個打印#for val in input:# print("input val:",val)for i in range(input[0].size(0)):in_list.append(input[0][i].cpu().numpy()) # 在相應的層注冊hook函數,保證函數能夠正常工作,我們這里直接hook 全連接層前面的pool層,獲取pool層的輸入數據,這樣會獲得更多的特征:model_ft.avgpool.register_forward_hook(hook) # 開始獲取輸出,這里我們因為不需要反向傳播,所以直接可以使用no_grad嵌套:%%time with torch.no_grad():for batch_idx, data in enumerate(image_dataloader["train"]):x,y= datax=x.to(DEVICE)y=y.to(DEVICE)y_hat = model_ft(x)

    總結

    以上是生活随笔為你收集整理的pytorch 模型微调的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。