成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

PyTorch經(jīng)驗指南:技巧與陷阱

開發(fā) 開發(fā)工具 深度學(xué)習(xí)
PyTorch 的構(gòu)建者表明,PyTorch 的哲學(xué)是解決當(dāng)務(wù)之急,也就是說即時構(gòu)建和運行計算圖。本文從基本概念開始介紹了 PyTorch 的使用方法、訓(xùn)練經(jīng)驗與技巧,并展示了可能出現(xiàn)的問題與解決方案。

PyTorch 的構(gòu)建者表明,PyTorch 的哲學(xué)是解決當(dāng)務(wù)之急,也就是說即時構(gòu)建和運行計算圖。目前,PyTorch 也已經(jīng)借助這種即時運行的概念成為最受歡迎的框架之一,開發(fā)者能快速構(gòu)建模型與驗證想法,并通過神經(jīng)網(wǎng)絡(luò)交換格式 ONNX 在多個框架之間快速遷移。本文從基本概念開始介紹了 PyTorch 的使用方法、訓(xùn)練經(jīng)驗與技巧,并展示了可能出現(xiàn)的問題與解決方案。

[[238704]]

項目地址:https://github.com/Kaixhin/grokking-pytorch

PyTorch 是一種靈活的深度學(xué)習(xí)框架,它允許通過動態(tài)神經(jīng)網(wǎng)絡(luò)(例如利用動態(tài)控流——如 if 語句或 while 循環(huán)的網(wǎng)絡(luò))進(jìn)行自動微分。它還支持 GPU 加速、分布式訓(xùn)練以及各類優(yōu)化任務(wù),同時還擁有許多更簡潔的特性。以下是作者關(guān)于如何利用 PyTorch 的一些說明,里面雖然沒有包含該庫的所有細(xì)節(jié)或最優(yōu)方法,但可能會對大家有所幫助。

神經(jīng)網(wǎng)絡(luò)是計算圖的一個子類。計算圖接收輸入數(shù)據(jù),數(shù)據(jù)被路由到對數(shù)據(jù)執(zhí)行處理的節(jié)點,并可能被這些節(jié)點轉(zhuǎn)換。在深度學(xué)習(xí)中,神經(jīng)網(wǎng)絡(luò)中的神經(jīng)元(節(jié)點)通常利用參數(shù)或可微函數(shù)轉(zhuǎn)換數(shù)據(jù),這樣可以優(yōu)化參數(shù)以通過梯度下降將損失最小化。更廣泛地說,函數(shù)是隨機(jī)的,圖結(jié)構(gòu)可以是動態(tài)的。所以說,雖然神經(jīng)網(wǎng)絡(luò)可能非常適合數(shù)據(jù)流式編程,但 PyTorch 的 API 卻更關(guān)注命令式編程——一種編程更常考慮的形式。這令讀取代碼和推斷復(fù)雜程序變得簡單,而無需損耗不必要的性能;PyTorch 速度很快,且擁有大量優(yōu)化,作為終端用戶你毫無后顧之憂。

本文其余部分寫的是關(guān)于 grokking PyTorch 的內(nèi)容,都是基于 MINIST 官網(wǎng)實例,應(yīng)該要在學(xué)習(xí)完官網(wǎng)初學(xué)者教程后再查看。為便于閱讀,代碼以塊狀形式呈現(xiàn),并帶有注釋,因此不會像純模塊化代碼一樣被分割成不同的函數(shù)或文件。

Pytorch 基礎(chǔ)

PyTorch 使用一種稱之為 imperative / eager 的范式,即每一行代碼都要求構(gòu)建一個圖,以定義完整計算圖的一個部分。即使完整的計算圖還沒有構(gòu)建好,我們也可以獨立地執(zhí)行這些作為組件的小計算圖,這種動態(tài)計算圖被稱為「define-by-run」方法。

PyTorch 張量

正如 PyTorch 文檔所說,如果我們熟悉 NumPy 的多維數(shù)組,那么 Torch 張量的很多操作我們能輕易地掌握。PyTorch 提供了 CPU 張量和 GPU 張量,并且極大地加速了計算的速度。

從張量的構(gòu)建與運行就能體會,相比 TensorFLow,在 PyTorch 中聲明張量、初始化張量要簡潔地多。例如,使用 torch.Tensor(5, 3) 語句就能隨機(jī)初始化一個 5×3 的二維張量,因為 PyTorch 是一種動態(tài)圖,所以它聲明和真實賦值是同時進(jìn)行的。

在 PyTorch 中,torch.Tensor 是一種多維矩陣,其中每個元素都是單一的數(shù)據(jù)類型,且該構(gòu)造函數(shù)默認(rèn)為 torch.FloatTensor。以下是具體的張量類型:

PyTorch 張量

除了直接定義維度,一般我們還可以從 Python 列表或 NumPy 數(shù)組中創(chuàng)建張量。而且根據(jù)使用 Python 列表和元組等數(shù)據(jù)結(jié)構(gòu)的習(xí)慣,我們可以使用相似的索引方式進(jìn)行取值或賦值。PyTorch 同樣支持廣播(Broadcasting)操作,一般它會隱式地把一個數(shù)組的異常維度調(diào)整到與另一個算子相匹配的維度,以實現(xiàn)維度兼容。

自動微分模塊

TensorFlow、Caffe 和 CNTK 等大多數(shù)框架都使用靜態(tài)計算圖,開發(fā)者必須建立或定義一個神經(jīng)網(wǎng)絡(luò),并重復(fù)使用相同的結(jié)構(gòu)來執(zhí)行模型訓(xùn)練。改變網(wǎng)絡(luò)的模式就意味著我們必須從頭開始設(shè)計并定義相關(guān)的模塊。

但 PyTorch 使用的技術(shù)為自動微分(automatic differentiation)。在這種機(jī)制下,系統(tǒng)會有一個 Recorder 來記錄我們執(zhí)行的運算,然后再反向計算對應(yīng)的梯度。這種技術(shù)在構(gòu)建神經(jīng)網(wǎng)絡(luò)的過程中十分強(qiáng)大,因為我們可以通過計算前向傳播過程中參數(shù)的微分來節(jié)省時間。

從概念上來說,Autograd 會維護(hù)一個圖并記錄對變量執(zhí)行的所有運算。這會產(chǎn)生一個有向無環(huán)圖,其中葉結(jié)點為輸入向量,根結(jié)點為輸出向量。通過從根結(jié)點到葉結(jié)點追蹤圖的路徑,我們可以輕易地使用鏈?zhǔn)椒▌t自動計算梯度。

在內(nèi)部,Autograd 將這個圖表征為 Function 對象的圖,并且可以應(yīng)用 apply() 計算評估圖的結(jié)果。在計算前向傳播中,當(dāng) Autograd 在執(zhí)行請求的計算時,它還會同時構(gòu)建一個表征梯度計算的圖,且每個 Variable 的 .grad_fn 屬性就是這個圖的輸入單元。在前向傳播完成后,我們可以在后向傳播中根據(jù)這個動態(tài)圖來計算梯度。

PyTorch 還有很多基礎(chǔ)的模塊,例如控制學(xué)習(xí)過程的最優(yōu)化器、搭建深度模型的神經(jīng)網(wǎng)絡(luò)模塊和數(shù)據(jù)加載與處理等。這一節(jié)展示的張量與自動微分模塊是 PyTorch 最為核心的概念之一,讀者可查閱 PyTorch 文檔了解更詳細(xì)的內(nèi)容。

下面作者以 MNIST 為例從數(shù)據(jù)加載到模型測試具體討論了 PyTorch 的使用、思考技巧與陷阱。

PyTorch 實用指南

1. 導(dǎo)入

  1. import argparse 
  2. import torch 
  3. from torch import nn, optim 
  4. from torch.nn import functional as F 
  5. from torch.utils.data import DataLoader 
  6. from torchvision import datasets, transforms 

除了用于計算機(jī)視覺問題的 torchvision 模塊外,這些都是標(biāo)準(zhǔn)化導(dǎo)入。

2. 設(shè)置

  1. parser = argparse.ArgumentParser(description='PyTorch MNIST Example'
  2. parser.add_argument('--batch-size', type=intdefault=64metavar='N'
  3.  help='input batch size for training (default: 64)'
  4. parser.add_argument('--epochs', type=intdefault=10metavar='N'
  5.  help='number of epochs to train (default: 10)'
  6. parser.add_argument('--lr', type=floatdefault=0.01, metavar='LR'
  7.  help='learning rate (default: 0.01)'
  8. parser.add_argument('--momentum', type=floatdefault=0.5, metavar='M'
  9.  help='SGD momentum (default: 0.5)'
  10. parser.add_argument('--no-cuda', action='store_true'default=False
  11.  help='disables CUDA training'
  12. parser.add_argument('--seed', type=intdefault=1metavar='S'
  13.  help='random seed (default: 1)'
  14. parser.add_argument('--save-interval', type=intdefault=10metavar='N'
  15.  help='how many batches to wait before checkpointing'
  16. parser.add_argument('--resume', action='store_true'default=False
  17.  help='resume training from checkpoint'
  18. args = parser.parse_args() 
  19.  
  20. use_cuda = torch.cuda.is_available() and not args.no_cuda 
  21. device = torch.device('cuda' if use_cuda else 'cpu') 
  22. torch.manual_seed(args.seed) 
  23. if use_cuda: 
  24.  torch.cuda.manual_seed(args.seed) 

argparse 是在 Python 中處理命令行參數(shù)的一種標(biāo)準(zhǔn)方式。

編寫與設(shè)備無關(guān)的代碼(可用時受益于 GPU 加速,不可用時會倒退回 CPU)時,選擇并保存適當(dāng)?shù)?torch.device, 不失為一種好方法,它可用于確定存儲張量的位置。關(guān)于與設(shè)備無關(guān)代碼的更多內(nèi)容請參閱官網(wǎng)文件。PyTorch 的方法是使用戶能控制設(shè)備,這對簡單示例來說有些麻煩,但是可以更容易地找出張量所在的位置——這對于 a)調(diào)試很有用,并且 b)可有效地使用手動化設(shè)備。

對于可重復(fù)實驗,有必要為使用隨機(jī)數(shù)生成的任何數(shù)據(jù)設(shè)置隨機(jī)種子(如果也使用隨機(jī)數(shù),則包括隨機(jī)或 numpy)。要注意,cuDNN 用的是非確定算法,可以通過語句 torch.backends.cudnn.enabled = False 將其禁用。

3. 數(shù)據(jù)

  1. train_data = datasets.MNIST('data', train=Truedownload=True
  2.  transform=transforms.Compose([ 
  3.  transforms.ToTensor(), 
  4.  transforms.Normalize((0.1307,), (0.3081,))])) 
  5. test_data = datasets.MNIST('data', train=Falsetransform=transforms.Compose([ 
  6.  transforms.ToTensor(), 
  7.  transforms.Normalize((0.1307,), (0.3081,))])) 
  8.  
  9. train_loader = DataLoader(train_data, batch_size=args.batch_size, 
  10.  shuffle=Truenum_workers=4pin_memory=True
  11. test_loader = DataLoader(test_data, batch_size=args.batch_size, 
  12.  num_workers=4pin_memory=True

torchvision.transforms 對于單張圖像有非常多便利的轉(zhuǎn)換工具,例如裁剪和歸一化等。

DataLoader 包含非常多的參數(shù),除了 batch_size 和 shuffle,num_workers 和 pin_memory 對于高效加載數(shù)據(jù)同樣非常重要。例如配置 num_workers > 0 將使用子進(jìn)程異步加載數(shù)據(jù),而不是使用一個主進(jìn)程塊加載數(shù)據(jù)。參數(shù) pin_memory 使用固定 RAM 以加速 RAM 到 GPU 的轉(zhuǎn)換,且在僅使用 CPU 時不會做任何運算。

4. 模型

  1. class Net(nn.Module): 
  2.  def __init__(self): 
  3.  super(Net, self).__init__() 
  4.  self.conv1 = nn.Conv2d(1, 10, kernel_size=5
  5.  self.conv2 = nn.Conv2d(10, 20, kernel_size=5
  6.  self.conv2_drop = nn.Dropout2d() 
  7.  self.fc1 = nn.Linear(320, 50) 
  8.  self.fc2 = nn.Linear(50, 10) 
  9.  
  10.  def forward(self, x): 
  11.  x = F.relu(F.max_pool2d(self.conv1(x), 2)) 
  12.  x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2)) 
  13.  xx = x.view(-1, 320) 
  14.  x = F.relu(self.fc1(x)) 
  15.  x = self.fc2(x) 
  16.  return F.log_softmax(x, dim=1
  17.  
  18. model = Net().to(device) 
  19. optimoptimiser = optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum) 
  20.  
  21. if args.resume: 
  22.  model.load_state_dict(torch.load('model.pth')) 
  23.  optimiser.load_state_dict(torch.load('optimiser.pth')) 

神經(jīng)網(wǎng)絡(luò)初始化一般包括變量、包含可訓(xùn)練參數(shù)的層級、可能獨立的可訓(xùn)練參數(shù)和不可訓(xùn)練的緩存器。隨后前向傳播將這些初始化參數(shù)與 F 中的函數(shù)結(jié)合,其中該函數(shù)為不包含參數(shù)的純函數(shù)。有些開發(fā)者喜歡使用完全函數(shù)化的網(wǎng)絡(luò)(如保持所有參數(shù)獨立,使用 F.conv2d 而不是 nn.Conv2d),或者完全由 layers 函數(shù)構(gòu)成的網(wǎng)絡(luò)(如使用 nn.ReLU 而不是 F.relu)。

在將 device 設(shè)置為 GPU 時,.to(device) 是一種將設(shè)備參數(shù)(和緩存器)發(fā)送到 GPU 的便捷方式,且在將 device 設(shè)置為 CPU 時不會做任何處理。在將網(wǎng)絡(luò)參數(shù)傳遞給優(yōu)化器之前,把它們傳遞給適當(dāng)?shù)脑O(shè)備非常重要,不然的話優(yōu)化器不能正確地追蹤參數(shù)。

神經(jīng)網(wǎng)絡(luò)(nn.Module)和優(yōu)化器(optim.Optimizer)都能保存和加載它們的內(nèi)部狀態(tài),而.load_state_dict(state_dict) 是完成這一操作的推薦方法,我們可以從以前保存的狀態(tài)字典中加載兩者的狀態(tài)并恢復(fù)訓(xùn)練。此外,保存整個對象可能會出錯。

這里沒討論的一些注意事項即前向傳播可以使用控制流,例如一個成員變量或數(shù)據(jù)本身能決定 if 語句的執(zhí)行。此外,在前向傳播的過程中打印張量也是可行的,這令 debug 更加簡單。最后,前向傳播可以使用多個參數(shù)。以下使用間斷的代碼塊展示這一點:

  1. def forward(self, x, hx, drop=False): 
  2.  hx2 = self.rnn(x, hx) 
  3.  print(hx.mean().item(), hx.var().item()) 
  4.  if hx.max.item() > 10 or self.can_drop and drop: 
  5.  return hx 
  6.  else: 
  7.  return hx2 

5. 訓(xùn)練

  1. model.train() 
  2. train_losses = [] 
  3.  
  4. for i, (data, target) in enumerate(train_loader): 
  5.  data, target = data.to(device), target.to(device) 
  6.  optimiser.zero_grad() 
  7.  output = model(data) 
  8.  loss = F.nll_loss(output, target) 
  9.  loss.backward() 
  10.  train_losses.append(loss.item()) 
  11.  optimiser.step() 
  12.  
  13.  if i % 10 == 0: 
  14.  print(i, loss.item()) 
  15.  torch.save(model.state_dict(), 'model.pth') 
  16.  torch.save(optimiser.state_dict(), 'optimiser.pth') 
  17.  torch.save(train_losses, 'train_losses.pth') 

網(wǎng)絡(luò)模塊默認(rèn)設(shè)置為訓(xùn)練模式,這影響了某些模塊的工作方式,最明顯的是 dropout 和批歸一化。最好用.train() 對其進(jìn)行手動設(shè)置,這樣可以把訓(xùn)練標(biāo)記向下傳播到所有子模塊。

在使用 loss.backward() 收集一系列新的梯度以及用 optimiser.step() 做反向傳播之前,有必要手動地將由 optimiser.zero_grad() 優(yōu)化的參數(shù)梯度歸零。默認(rèn)情況下,PyTorch 會累加梯度,在單次迭代中沒有足夠資源來計算所有需要的梯度時,這種做法非常便利。

PyTorch 使用一種基于 tape 的自動化梯度(autograd)系統(tǒng),它收集按順序在張量上執(zhí)行的運算,然后反向重放它們來執(zhí)行反向模式微分。這正是為什么 PyTorch 如此靈活并允許執(zhí)行任意計算圖的原因。如果沒有張量需要做梯度更新(當(dāng)你需要為該過程構(gòu)建一個張量時,你必須設(shè)置 requires_grad=True),則不需要保存任何圖。然而,網(wǎng)絡(luò)傾向于包含需要梯度更新的參數(shù),因此任何網(wǎng)絡(luò)輸出過程中執(zhí)行的計算都將保存在圖中。因此如果想保存在該過程中得到的數(shù)據(jù),你將需要手動禁止梯度更新,或者,更常見的做法是將其保存為一個 Python 數(shù)(通過一個 Python 標(biāo)量上的.item())或者 NumPy 數(shù)組。更多關(guān)于 autograd 的細(xì)節(jié)詳見官網(wǎng)文件。

截取計算圖的一種方式是使用.detach(),當(dāng)通過沿時間的截斷反向傳播訓(xùn)練 RNN 時,數(shù)據(jù)流傳遞到一個隱藏狀態(tài)可能會應(yīng)用這個函數(shù)。當(dāng)對損失函數(shù)求微分(其中一個成分是另一個網(wǎng)絡(luò)的輸出)時,也會很方便。但另一個網(wǎng)絡(luò)不應(yīng)該用「loss - examples」的模式進(jìn)行優(yōu)化,包括在 GAN 訓(xùn)練中從生成器的輸出訓(xùn)練判別器,或使用價值函數(shù)作為基線(例如 A2C)訓(xùn)練 actor-critic 算法的策略。另一種在 GAN 訓(xùn)練(從判別器訓(xùn)練生成器)中能高效阻止梯度計算的方法是在整個網(wǎng)絡(luò)參數(shù)上建立循環(huán),并設(shè)置 param.requires_grad=False,這在微調(diào)中也很常用。

除了在控制臺/日志文件里記錄結(jié)果以外,檢查模型參數(shù)(以及優(yōu)化器狀態(tài))也是很重要的。你還可以使用 torch.save() 來保存一般的 Python 對象,但其它標(biāo)準(zhǔn)選擇還包括內(nèi)建的 pickle。

6. 測試

  1. model.eval() 
  2. test_loss, correct = 0, 0 
  3.  
  4. with torch.no_grad(): 
  5.  for data, target in test_loader: 
  6.  data, target = data.to(device), target.to(device) 
  7.  output = model(data) 
  8.  test_loss += F.nll_loss(output, target, size_average=False).item() 
  9.  pred = output.argmax(1, keepdim=True
  10.  correct += pred.eq(target.view_as(pred)).sum().item() 
  11.  
  12. test_loss /= len(test_data) 
  13. acc = correct / len(test_data) 
  14. print(acc, test_loss) 

為了早點響應(yīng).train(),應(yīng)利用.eval() 將網(wǎng)絡(luò)明確地設(shè)置為評估模式。

正如前文所述,計算圖通常會在使用網(wǎng)絡(luò)時生成。通過 with torch.no_grad() 使用 no_grad 上下文管理器,可以防止這種情況發(fā)生。

7. 其它

內(nèi)存有問題?可以查看官網(wǎng)文件獲取幫助。

CUDA 出錯?它們很難調(diào)試,而且通常是一個邏輯問題,會在 CPU 上產(chǎn)生更易理解的錯誤信息。如果你計劃使用 GPU,那最好能夠在 CPU 和 GPU 之間輕松切換。更普遍的開發(fā)技巧是設(shè)置代碼,以便在啟動合適的項目(例如準(zhǔn)備一個較小/合成的數(shù)據(jù)集、運行一個 train + test epoch 等)之前快速運行所有邏輯來檢查它。如果這是一個 CUDA 錯誤,或者你沒法切換到 CPU,設(shè)置 CUDA_LAUNCH_BLOCKING=1 將使 CUDA 內(nèi)核同步啟動,從而提供更詳細(xì)的錯誤信息。

torch.multiprocessing,甚至只是一次運行多個 PyTorch 腳本的注意事項。因為 PyTorch 使用多線程 BLAS 庫來加速 CPU 上的線性代數(shù)計算,所以它通常需要使用多個內(nèi)核。如果你想一次運行多個任務(wù),在具有多進(jìn)程或多個腳本的情況下,通過將環(huán)境變量 OMP_NUM_THREADS 設(shè)置為 1 或另一個較小的數(shù)字來手動減少線程,這樣做減少了 CPU thrashing 的可能性。官網(wǎng)文件還有一些其它注意事項,尤其是關(guān)于多進(jìn)程。

【本文是51CTO專欄機(jī)構(gòu)“機(jī)器之心”的原創(chuàng)譯文,微信公眾號“機(jī)器之心( id: almosthuman2014)”】

戳這里,看該作者更多好文

責(zé)任編輯:趙寧寧 來源: 51CTO專欄
相關(guān)推薦

2017-03-22 09:44:04

DevOps轉(zhuǎn)型陷阱實踐

2024-09-24 13:11:18

2025-04-27 09:45:58

JavaScript深拷貝淺拷貝

2024-04-10 08:24:29

2022-12-09 11:21:07

2021-08-01 00:08:06

JsonGo標(biāo)準(zhǔn)庫

2011-07-15 17:35:19

JavaScript

2011-07-13 16:36:11

C++

2009-11-17 11:24:00

PHP應(yīng)用技巧

2020-07-27 08:05:56

C++語言后端

2010-06-12 17:37:18

UML實踐指南

2021-01-27 10:46:07

Pytorch深度學(xué)習(xí)模型訓(xùn)練

2011-07-11 10:24:09

PHP

2009-10-28 17:04:20

linux快速啟動

2011-07-07 18:39:22

SEO

2009-12-31 10:21:53

Silverlight

2011-04-07 09:57:34

2013-01-16 08:56:53

iOS故障排除指南

2021-03-07 09:05:45

Pytorch機(jī)器學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 日韩欧美专区 | 欧美视频三区 | 日本国产高清 | 狠狠色综合欧美激情 | 一区二区免费视频 | 久久国产精品久久久久 | 欧洲av在线 | 国产精品免费av | 国产一区二区三区在线 | 在线不卡视频 | 午夜精品久久 | 亚洲一区三区在线观看 | 欧美一区永久视频免费观看 | 日本亚洲精品成人欧美一区 | 精品国产视频在线观看 | 国产日韩欧美在线播放 | 视频第一区 | 国产中文字幕在线 | 四虎在线观看 | 在线观看视频亚洲 | 久久久久国产精品一区二区 | 久久成人免费视频 | 国产精品国产成人国产三级 | 国产成人精品免费视频 | 农夫在线精品视频免费观看 | 一级毛片免费完整视频 | 成人无遮挡毛片免费看 | 日韩一级电影免费观看 | 国内精品久久久久久久影视简单 | 日韩精品中文字幕在线 | 蜜桃视频一区二区三区 | 国产精品免费在线 | 成人免费一区二区 | 国产情侣啪啪 | 日韩免费1区二区电影 | 欧美一区二区三区免费在线观看 | 欧美视频在线看 | 欧美成人a∨高清免费观看 欧美日韩中 | 日本成人综合 | 中文字幕第100页 | 成人av在线播放 |