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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

PyTorch学习记录——PyTorch进阶训练技巧

發(fā)布時間:2024/5/14 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PyTorch学习记录——PyTorch进阶训练技巧 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

PyTorch學(xué)習記錄——PyTorch進階訓(xùn)練技巧

  • 1.自定義損失函數(shù)
    • 1.1 以函數(shù)的方式定義損失函數(shù)
    • 1.2 以類的方式定義損失函數(shù)
    • 1.3 比較與思考
  • 2.動態(tài)調(diào)整學(xué)習率
    • 2.1 官方提供的scheduler API
    • 2.2 自定義scheduler
    • 2.3 問題
  • 3.模型微調(diào)
    • 3.1 模型微調(diào)流程
    • 3.2 Pytorch中已有模型結(jié)構(gòu)及預(yù)訓(xùn)練參數(shù)的復(fù)用
    • 3.3 Pytorch中模型微調(diào)的實現(xiàn)
      • 3.3.1 固定微調(diào)部分,訓(xùn)練差異部分
      • 3.3.2 不同學(xué)習率訓(xùn)練不同部分
    • 3.4 timm庫
    • 補充知識
      • filter的基礎(chǔ)用法
  • 4.半精度訓(xùn)練
  • 5.使用argparse進行調(diào)參
  • 參考資料

1.自定義損失函數(shù)

自定義損失函數(shù)的方法主要包括兩種,即以函數(shù)的方式定義和以類的方式定義。

1.1 以函數(shù)的方式定義損失函數(shù)

以函數(shù)的方式定義與定義python函數(shù)沒有什么區(qū)別,通過將參與損失計算的張量(即Tensor)作為函數(shù)的形參進行定義,例如

def my_loss(output: torch.Tensor, target: torch.Tensor):loss = torch.mean((output - target) ** 2)return loss

在上述定義中,我們使用了MSELoss損失函數(shù)。同時可以看到,在損失函數(shù)編寫過程中,可以直接使用我們熟悉的Python中的運算符,包括加減乘除等等,但牽涉到矩陣運算,如矩陣乘法則需要使用Pytorch提供的張量計算接口torch.matmul。采用這樣的方式定義損失函數(shù)實際上就僅需要把計算過程定義清楚即可,或者說是把計算圖或數(shù)據(jù)流定義清楚。

1.2 以類的方式定義損失函數(shù)

以類的方式定義損失函數(shù)需要讓我們定義的類繼承nn.Module類。采用這樣的方式定義損失函數(shù)類,可以讓我們把定義的損失函數(shù)作為一個神經(jīng)網(wǎng)絡(luò)層來對待。Pytorch現(xiàn)有的損失函數(shù)也大都采用這種類的方式進行定義的。事實上,在Pytorch中,Loss函數(shù)部分繼承自_loss, 部分繼承自_WeightedLoss, 而_WeightedLoss繼承自_loss, _loss繼承自 nn.Module。例如,通過查看Pytorch中CrossEntropyLoss的代碼,我們可以看到上述關(guān)系,如下。

class CrossEntropyLoss(_WeightedLoss):...class _WeightedLoss(_Loss):...class _Loss(Module):...

1.3 比較與思考

教程中有說到,相比于以函數(shù)的方式定義的損失函數(shù),類的方式定義更為常用。

雖然以函數(shù)定義的方式很簡單,但是以類方式定義更加常用,…

然而,從教程中給出的例子,比如DiceLoss損失函數(shù)的定義

class DiceLoss(nn.Module):def __init__(self,weight=None,size_average=True):super(DiceLoss,self).__init__()def forward(self,inputs,targets,smooth=1):inputs = F.sigmoid(inputs) inputs = inputs.view(-1)targets = targets.view(-1)intersection = (inputs * targets).sum() dice = (2.*intersection + smooth)/(inputs.sum() + targets.sum() + smooth) return 1 - dice

確實又難以體現(xiàn)出其相比函數(shù)方法的優(yōu)越之處。考慮到類這種面向?qū)ο蟮脑O(shè)計方式,上述采用類的方式設(shè)計損失函數(shù)可能存在如下兩個方面的優(yōu)勢:

  • 當損失函數(shù)計算過程中出現(xiàn)一些類似滑動平均等需要動態(tài)緩存一些數(shù)的時候,采用類的方式可以直接將這樣的數(shù)存放在實體對象中;

  • 采用類的方式可以通過繼承的方式梳理清楚不同損失函數(shù)的關(guān)系,并有可能能復(fù)用一些父類損失函數(shù)的特性和方法。

2.動態(tài)調(diào)整學(xué)習率

無論是在深度學(xué)習任務(wù)中還是深度強化學(xué)習任務(wù)中,學(xué)習率對于神經(jīng)網(wǎng)絡(luò)的訓(xùn)練非常重要。因為本質(zhì)上講,兩者都是通過數(shù)據(jù)驅(qū)動的手段,通過梯度下降類算法,對神經(jīng)網(wǎng)絡(luò)的參數(shù)進行尋優(yōu)。對于一個任務(wù),在起始時,我們可能設(shè)定了一個比較好的學(xué)習率。這使得我們的算法在訓(xùn)練初期收斂的效率和效果都較好。但隨著訓(xùn)練的進行,特別是當網(wǎng)絡(luò)參數(shù)非常靠近我們期待的位置時(神經(jīng)網(wǎng)絡(luò)參數(shù)空間中的理想點),我們初期設(shè)置的學(xué)習率可能就會顯得偏大,導(dǎo)致梯度下降過程步長過長,從而使得神經(jīng)網(wǎng)絡(luò)參數(shù)在理想點附近震蕩。

為解決上述問題,一種方式是通過手動調(diào)整學(xué)習率,來適應(yīng)神經(jīng)網(wǎng)絡(luò)訓(xùn)練不同的時期,以及神經(jīng)網(wǎng)絡(luò)所達到的不同性能。但這樣的方式就要求我們要能夠自行設(shè)計出一套學(xué)習率變化的算法,這無疑為我們程序訓(xùn)練的編寫又增加了復(fù)雜度。另一種方式下,我們可以使用Pytorch中的scheduler進行動態(tài)的學(xué)習率調(diào)整。

Pytorch的scheduler可以提供兩種使用方式的支持:官方提供的scheduler API和自定義的scheduler。

2.1 官方提供的scheduler API

官方提供的scheduler API主要放在torch.optim.lr_scheduler中,具體包括

scheduler API說明參數(shù)
lr_scheduler.LambdaLR學(xué)習率lr為一個初始值乘以一個函數(shù),當last_epoch=-1時,lr取值為初始值* optimizer (Optimizer) – Wrapped optimizer.
* lr_lambda (function or list) – A function which computes a multiplicative factor given an integer parameter epoch, or a list of such functions, one for each group in optimizer.param_groups.

* last_epoch (int) – The index of last epoch. Default: -1.

* verbose (bool) – If True, prints a message to stdout for each update. Default: False.
lr_scheduler.MultiplicativeLR學(xué)習率lr為一個初始值乘以一個函數(shù),當last_epoch=-1時,lr取值為初始值* optimizer (Optimizer) – Wrapped optimizer.

* lr_lambda (function or list) – A function which computes a multiplicative factor given an integer parameter epoch, or a list of such functions, one for each group in optimizer.param_groups.

* last_epoch (int) – The index of last epoch. Default: -1.

* verbose (bool) – If True, prints a message to stdout for each update. Default: False.
lr_scheduler.StepLR每step_size個epoch,學(xué)習率lr變?yōu)槠洚斍爸党艘詆amma,當last_epoch=-1時,lr取值為初始值* optimizer (Optimizer) – Wrapped optimizer.

* step_size (int) – Period of learning rate decay.

* gamma (float) – Multiplicative factor of learning rate decay. Default: 0.1.

* last_epoch (int) – The index of last epoch. Default: -1.

* verbose (bool) – If True, prints a message to stdout for each update. Default: False.
lr_scheduler.MultiStepLR當epoch數(shù)達到milestones數(shù)量時,學(xué)習率lr變?yōu)槠洚斍爸党艘詆amma,當last_epoch=-1時,lr取值為初始值* optimizer (Optimizer) – Wrapped optimizer.

* milestones (list) – List of epoch indices. Must be increasing.

* gamma (float) – Multiplicative factor of learning rate decay. / * Default: 0.1.

* last_epoch (int) – The index of last epoch. Default: -1.

* verbose (bool) – If True, prints a message to stdout for each update. Default: False.
lr_scheduler.ExponentialLR每個epoch,學(xué)習率lr變?yōu)槠洚斍爸党艘詆amma,當last_epoch=-1時,lr取值為初始值* optimizer (Optimizer) – Wrapped optimizer.

* gamma (float) – Multiplicative factor of learning rate decay.

* last_epoch (int) – The index of last epoch. Default: -1.

* verbose (bool) – If True, prints a message to stdout for each update. Default: False.
lr_scheduler.CosineAnnealingLR采用cos衰減的方式調(diào)整學(xué)習率,當last_epoch=-1時,lr取值為初始值* optimizer (Optimizer) – Wrapped optimizer.

* T_max (int) – Maximum number of iterations.

* eta_min (float) – Minimum learning rate. Default: 0.

* last_epoch (int) – The index of last epoch. Default: -1.

* verbose (bool) – If True, prints a message to stdout for each update. Default: False.
lr_scheduler.ReduceLROnPlateau當某項指標不再下降時削減學(xué)習率* ptimizer (Optimizer) – Wrapped optimizer.

* mode (str) – One of min, max. In min mode, lr will be reduced when the quantity monitored has stopped decreasing; in max mode it will be reduced when the quantity monitored has stopped increasing. Default: ‘min’.

* factor (float) – Factor by which the learning rate will be reduced. new_lr = lr * factor. Default: 0.1.

* patience (int) – Number of epochs with no improvement after which learning rate will be reduced. For example, if patience = 2, then we will ignore the first 2 epochs with no improvement, and will only decrease the LR after the 3rd epoch if the loss still hasn’t improved then. Default: 10.

* threshold (float) – Threshold for measuring the new optimum, to only focus on significant changes. Default: 1e-4.

* threshold_mode (str) – One of rel, abs. In rel mode, dynamic_threshold = best * ( 1 + threshold ) in ‘max’ mode or best * ( 1 - threshold ) in min mode. In abs mode, dynamic_threshold = best + threshold in max mode or best - threshold in min mode. Default: ‘rel’.

* cooldown (int) – Number of epochs to wait before resuming normal operation after lr has been reduced. Default: 0.

min_lr (float or list) – A scalar or a list of scalars. A lower bound on the learning rate of all param groups or each group respectively. Default: 0.

* eps (float) – Minimal decay applied to lr. If the difference between new and old lr is smaller than eps, the update is ignored. Default: 1e-8.

* verbose (bool) – If True, prints a message to stdout for each update. Default: False.
lr_scheduler.CyclicLR以某種循環(huán)策略調(diào)整學(xué)習率詳見https://pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.CyclicLR.html#torch.optim.lr_scheduler.CyclicLR
lr_scheduler.OneCycleLR以某種單次循環(huán)策略調(diào)整學(xué)習率詳見https://pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.OneCycleLR.html#torch.optim.lr_scheduler.OneCycleLR
lr_scheduler.CosineAnnealingWarmRestarts采用cos衰減的方式調(diào)整學(xué)習率,當last_epoch=-1時,lr取值為初始值

在訓(xùn)練中,上述scheduler API通過實例化創(chuàng)建scheduler實例,再通過在optimizer優(yōu)化一步(即調(diào)用step()方法)后,調(diào)用step()方法進行學(xué)習率調(diào)整,如下:

# 選擇優(yōu)化器 optimizer = torch.optim.Adam(...) # 選擇一種或多種動態(tài)調(diào)整學(xué)習率方法 scheduler = torch.optim.lr_scheduler.... # 進行訓(xùn)練 for epoch in range(100):train(...)validate(...)optimizer.step()# 在優(yōu)化器參數(shù)更新之后再動態(tài)調(diào)整學(xué)習率scheduler.step() ...

2.2 自定義scheduler

自定義scheduler的方法是通過構(gòu)建自定義函數(shù)adjust_learning_rate,來改變optimizer的param_group中l(wèi)r的值實現(xiàn)的,例如:

def adjust_learning_rate(optimizer, epoch):lr = args.lr * (0.1 ** (epoch // 30))for param_group in optimizer.param_groups:param_group['lr'] = lr

基于此定義的scheduler,我們便可以在訓(xùn)練時進行使用,如下:

# 選擇優(yōu)化器 optimizer = torch.optim.Adam(...) # 進行訓(xùn)練 for epoch in range(100):train(...)validate(...)optimizer.step()# 調(diào)用自定義函數(shù)調(diào)整學(xué)習率adjust_learning_rate(optimizer, epoch)...

2.3 問題

在使用自定義學(xué)習率調(diào)整函數(shù)時,自定義學(xué)習率調(diào)整函數(shù)是否也要放在optimizer.step()語句之后?

3.模型微調(diào)

當前,模型參數(shù)的規(guī)模持續(xù)膨脹,能夠達到的能力水平,甚至跨任務(wù)的泛化水平也在不斷提高,但這些模型往往均是通過在大數(shù)據(jù)集上訓(xùn)練的。因此,當前在很多深度學(xué)習任務(wù)求解上的做法是基于一個在很大的數(shù)據(jù)集上訓(xùn)練的模型進行進一步調(diào)整實現(xiàn)的。這其實就是模型微調(diào)——基于預(yù)訓(xùn)練模型在當前任務(wù)上進行進一步訓(xùn)練。也正是基于這樣的思想,近年來預(yù)訓(xùn)練大模型開始成為熱點。從BERT到GPT-3,到大模型的出現(xiàn)一方面促進了AI模型泛化能力的提升,另一方面也削減了下游任務(wù)(具體任務(wù))的訓(xùn)練成本,催生了“大模型預(yù)訓(xùn)練+微調(diào)”的應(yīng)用研發(fā)范式。

Pytorch提供了許多預(yù)訓(xùn)練好的網(wǎng)絡(luò)模型(VGG,ResNet系列,mobilenet系列…),這些模型都是PyTorch官方在相應(yīng)的大型數(shù)據(jù)集訓(xùn)練好的。在面對具體下游任務(wù)時,我們可以從中選擇與我們?nèi)蝿?wù)接近的模型,換成我們的數(shù)據(jù)進行精調(diào),也就是我們經(jīng)常見到的finetune。

3.1 模型微調(diào)流程

模型精調(diào)分為如下幾步:

  • 在源數(shù)據(jù)集上預(yù)訓(xùn)練一個神經(jīng)網(wǎng)絡(luò)模型,即源模型。這一步實際上預(yù)訓(xùn)練模型制作方為我們準備好了,即我們在Pytorch中拿到的就已經(jīng)是預(yù)訓(xùn)練好的模型了。

  • 創(chuàng)建新的神經(jīng)網(wǎng)絡(luò)模型,即目標模型。將源模型中除了最終的輸出層外所有部分的模型和相應(yīng)的參數(shù)復(fù)制到目標模型中。這一步是通過模型結(jié)構(gòu)和參數(shù)的拷貝,將源模型(預(yù)訓(xùn)練模型)預(yù)訓(xùn)練中的經(jīng)驗賦予目標模型。但由于目標模型與源模型面對的任務(wù)不同,因此,目標模型中最后的輸出層保留獨立。我認為,這里不僅限于輸出層,擴充一些。只要是針對當前任務(wù)特有的層都可以保留相對于源模型的獨立性。

  • 為目標模型添加一個與目標模型任務(wù)想匹配的輸出層,并隨機初始化該層的模型參數(shù)。

  • 在目標數(shù)據(jù)集上訓(xùn)練目標模型。對于輸出層(即目標模型特有的部分),我們將從頭訓(xùn)練,而其余層的參數(shù)都是基于源模型的參數(shù)微調(diào)得到的。

  • 在上述流程下,我們可以實現(xiàn)對模型的精調(diào)。下面,需要考慮如下幾個方面的細節(jié):

    • Pytorch中已有模型結(jié)構(gòu)及預(yù)訓(xùn)練參數(shù)的復(fù)用
    • Pytorch中模型微調(diào)的實現(xiàn)

    3.2 Pytorch中已有模型結(jié)構(gòu)及預(yù)訓(xùn)練參數(shù)的復(fù)用

    Pytorch中提供了許多預(yù)訓(xùn)練好的網(wǎng)絡(luò)模型,包括它們的網(wǎng)絡(luò)結(jié)構(gòu)和預(yù)訓(xùn)練模型權(quán)重,均可通過torchvision獲取,各個預(yù)訓(xùn)練網(wǎng)絡(luò)模型實例的創(chuàng)建如下:

    import torchvision.models as models resnet18 = models.resnet18() alexnet = models.alexnet() vgg16 = models.vgg16() squeezenet = models.squeezenet1_0() densenet = models.densenet161() inception = models.inception_v3() googlenet = models.googlenet() shufflenet = models.shufflenet_v2_x1_0() mobilenet_v2 = models.mobilenet_v2() mobilenet_v3_large = models.mobilenet_v3_large() mobilenet_v3_small = models.mobilenet_v3_small() resnext50_32x4d = models.resnext50_32x4d() wide_resnet50_2 = models.wide_resnet50_2() mnasnet = models.mnasnet1_0()

    上述預(yù)訓(xùn)練模型實例創(chuàng)建中調(diào)用的初始化函數(shù)都包含有一個pretrained參數(shù),該參數(shù)默認為False。故采用上述代碼,我們僅獲得了預(yù)訓(xùn)練網(wǎng)絡(luò)模型的結(jié)構(gòu),而參數(shù)是隨機初始化的。為載入預(yù)訓(xùn)練好的模型參數(shù),需將pretrained參數(shù)設(shè)置為True,如下:

    import torchvision.models as models resnet18 = models.resnet18(pretrained=True)

    注意:

    • 程序運行時會首先檢查默認路徑(在Linux和Mac的是用戶根目錄下的.cache文件夾。在Windows下是C:\Users\<username>\.cache\torch\hub\checkpoint)中是否有已經(jīng)下載的模型權(quán)重,一旦權(quán)重被下載,下次加載就不需要下載了。

    • 我們也可以將自己的權(quán)重下載下來放到同文件夾下,然后再將參數(shù)加載網(wǎng)絡(luò),例如:

      import torchvision.models as models import torch model = models.resnet18(pretrained=False) model.load_state_dict(torch.load('/models/resnet18-f37072fd.pth'))

    3.3 Pytorch中模型微調(diào)的實現(xiàn)

    在上述模型微調(diào)流程中,我們僅對與當前任務(wù)密切相關(guān)且與預(yù)訓(xùn)練模型有差異的部分進行完整訓(xùn)練,而對與預(yù)訓(xùn)練模型一致的部分進行微調(diào)。微調(diào)方式分為兩種:

    • 方法1:先不訓(xùn)練微調(diào)部分,集中訓(xùn)練差異部分,而后在以較小的學(xué)習率整體微調(diào)訓(xùn)練

    • 方法2:采用不同的學(xué)習率訓(xùn)練微調(diào)部分和差異部分

    3.3.1 固定微調(diào)部分,訓(xùn)練差異部分

    在默認情況下,模型參數(shù)的屬性.requires_grad = True。如果我們正在提取特征并且只想為新初始化的層計算梯度,其他參數(shù)不進行改變,那我們就需要將設(shè)置requires_grad = False來凍結(jié)部分層,例如:

    import torchvision.models as models# 載入預(yù)訓(xùn)練模型 model = models.resnet18(pretrained=True)# 凍結(jié)預(yù)訓(xùn)練模型部分梯度 for param in model.parameters():param.requires_grad = False# 修改模型 num_ftrs = model.fc.in_features model.fc = nn.Linear(in_features=num_ftrs, out_features=4, bias=True)

    上述設(shè)計下,訓(xùn)練過程中梯度僅會回傳至fc層,而不會影響預(yù)訓(xùn)練模型部分。

    3.3.2 不同學(xué)習率訓(xùn)練不同部分

    具體而言,得益于Pytorch的靈活性,我們可以采用不同的學(xué)習率對不同的模型層進行訓(xùn)練,以實現(xiàn)采用較大的學(xué)習率進行完整訓(xùn)練,采用較小的學(xué)習率進行微調(diào)訓(xùn)練。現(xiàn)假設(shè)我們僅對上述resnet18的最后一層進行調(diào)整,以實現(xiàn)一個二分類任務(wù)。

    首先,我們對原有的resnet18的網(wǎng)絡(luò)結(jié)構(gòu)和模型參數(shù)進行“繼承”

    import torchvision.models as models import torch import torch.nn as nn import torch.optim as optimmodel = models.resnet18(pretrained=False) model.load_state_dict(torch.load('/models/resnet18-f37072fd.pth'))

    修改最后的輸出層

    model.fc = nn.Linear(512, 2)

    然后,分割出特征提取部分模型參數(shù)(預(yù)訓(xùn)練模型參數(shù))和輸出層模型參數(shù)

    output_params = list(map(id, model.fc.parameters())) feature_params = list(filter(lambda p: id(p) not in output_params, model.parameters()))

    接著,我們通過在優(yōu)化器中指定不同部分的模型采用不同的學(xué)習率進行訓(xùn)練,即可實現(xiàn)基于預(yù)訓(xùn)練模型的精調(diào),如下:

    lr = 0.001 optimizer = opim.SGD([{'params': feature_params},{'params': model.fc.parameters(), 'lr': lr * 10}], lr=lr, weight_decay=0.001)

    3.4 timm庫

    上述預(yù)訓(xùn)練模型微調(diào)中,我們主要使用的是torchvision庫。除了該庫以外,還有一個常見的預(yù)訓(xùn)練模型庫,叫做timm,這個庫是由來自加拿大溫哥華Ross Wightman創(chuàng)建的。里面提供了許多計算機視覺的SOTA模型,可以當作是torchvision的擴充版本,并且里面的模型在準確度上也較高。

    在得到我們想要使用的預(yù)訓(xùn)練模型后,我們可以通過timm.create_model()的方法來進行模型的創(chuàng)建,我們可以通過傳入?yún)?shù)pretrained=True,來使用預(yù)訓(xùn)練模型。同樣的,我們也可以使用跟torchvision里面的模型一樣的方法查看模型的參數(shù),類型。關(guān)于預(yù)訓(xùn)練模型的修改,似乎僅能通過timm.create_model()方法接口在創(chuàng)建和載入模型時進行修改,但尚不確定。如果后續(xù)使用,可參考官網(wǎng)或者Github鏈接。

    import timm import torchmodel = timm.create_model('resnet34',pretrained=True) # 修改模型(將1000類改為10類輸出) model = timm.create_model('resnet34',num_classes=10,pretrained=True) # 改變輸入通道數(shù) model = timm.create_model('resnet34',num_classes=10,pretrained=True,in_chans=1)

    補充知識

    filter的基礎(chǔ)用法

    filter是一個過濾器,其作用是從列表(或其他序列類型)中篩選出滿足條件的子列表。對于列表(或其他序列類型),如果希望從中篩選出滿足某個約束條件的子列表,我們一般的做法是使用一個for循環(huán)遍歷每個元素然后執(zhí)行相同約束條件判斷,將滿足條件的放入新的子列表中。例如,從列表中找出所有偶數(shù)子列表,并按對應(yīng)的先后順序放入子列表中:

    a = [1, 2, 3, 4, 5] b = [] for i in a:if i % 2 == 0:b.append(i)

    那么如果使用filter的話,使用filter函數(shù)使得代碼變得更簡潔:

    a = [1, 2, 3, 4, 5] def check(i): return i % 2 == 0 b = list(filter(check, a))

    4.半精度訓(xùn)練

    GPU的性能主要分為兩部分:算力顯存前者決定了顯卡計算的速度,后者則決定了顯卡可以同時放入多少數(shù)據(jù)用于計算。在可以使用的顯存數(shù)量一定的情況下,每次訓(xùn)練能夠加載的數(shù)據(jù)更多(也就是batch size更大),則也可以提高訓(xùn)練效率。另外,有時候數(shù)據(jù)本身也比較大(比如3D圖像、視頻等),顯存較小的情況下可能甚至batch size為1的情況都無法實現(xiàn)。因此,合理使用顯存也就顯得十分重要。

    PyTorch默認的浮點數(shù)存儲方式用的是torch.float32,小數(shù)點后位數(shù)更多固然能保證數(shù)據(jù)的精確性,但絕大多數(shù)場景其實并不需要這么精確,只保留一半的信息也不會影響結(jié)果,也就是使用torch.float16格式。由于數(shù)位減了一半,因此被稱為“半精度”,半精度能夠減少顯存占用,使得顯卡可以同時加載更多數(shù)據(jù)進行計算。

    在PyTorch中使用autocast配置半精度訓(xùn)練,同時需要在下面三處加以設(shè)置:

    • import autocast

      from torch.cuda.amp import autocast
    • 模型設(shè)置

      在模型定義中,使用python的裝飾器方法,用autocast裝飾模型中的forward函數(shù)。

      @autocast() def forward(self, x):...return x
    • 訓(xùn)練過程

      在訓(xùn)練過程中,只需在將數(shù)據(jù)輸入模型及其之后的部分放入“with autocast():“即可

      for x in train_loader:x = x.cuda()with autocast():output = model(x)...

    半精度訓(xùn)練主要適用于數(shù)據(jù)本身的size比較大(比如說3D圖像、視頻等)。當數(shù)據(jù)本身的size并不大時(比如手寫數(shù)字MNIST數(shù)據(jù)集的圖片尺寸只有28*28),使用半精度訓(xùn)練則可能不會帶來顯著的提升。

    5.使用argparse進行調(diào)參

    argparse是python的命令行解析的標準模塊,可以讓我們直接在命令行中就可以向程序中傳入?yún)?shù),通過argparse將命令行傳入的其他參數(shù)進行解析、保存和使用。在使用argparse后,我們在命令行輸入的參數(shù)就可以以這種形式python file.py --lr 1e-4 --batch_size 32來完成對常見超參數(shù)的設(shè)置。

    總的來說,我們可以將argparse的使用歸納為以下三個步驟:

  • 創(chuàng)建ArgumentParser()對象
  • import argparse# 創(chuàng)建ArgumentParser()對象 parser = argparse.ArgumentParser()
  • 調(diào)用add_argument()方法添加參數(shù)
  • # 添加參數(shù): # action = `store_true` 會將output參數(shù)記錄為True # type 規(guī)定了參數(shù)的格式, default 規(guī)定了默認值 # required=True表示該參數(shù)為必選參數(shù),要求必須從命令行給出參數(shù)值 parser.add_argument('-o', '--output', action='store_true', help="shows output") parser.add_argument('--lr', type=float, default=3e-5, help='select the learning rate, default=1e-3') parser.add_argument('--batch_size', type=int, required=True, help='input batch size')
  • 使用parse_args()解析參數(shù)
  • # 使用parse_args()解析函數(shù) args = parser.parse_args() if args.output:print("This is some output")print(f"learning rate:{args.lr} ")

    總的來說,argparse確實能夠便捷化和靈活化命令行參數(shù)傳遞和解析,但即便將其封裝在方法里,如果存在多處獲取,獲取過程還是要反復(fù)調(diào)用該方法/函數(shù)。因此,如果是多處調(diào)用的配置,可以采用argparse和配置文件相結(jié)合的方式進行參數(shù)配置,動態(tài)性較強的通過argparse進行配置,而靜態(tài)性較強的則可以采用配置文件的形式進行配置。

    參考資料

    深入淺出PyTorch:第六章 PyTorch進階訓(xùn)練技巧

    總結(jié)

    以上是生活随笔為你收集整理的PyTorch学习记录——PyTorch进阶训练技巧的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。