# 8.4 多GPU計算
> 注:相對于本章的前面幾節,我們實際中更可能遇到本節所討論的情況:多GPU計算。原書將MXNet的多GPU計算分成了8.4和8.5兩節,但我們將關于PyTorch的多GPU計算統一放在本節討論。
需要注意的是,這里我們談論的是單主機多GPU計算而不是分布式計算。如果對分布式計算感興趣可以參考[PyTorch官方文檔](https://pytorch.org/tutorials/intermediate/dist_tuto.html)。
本節中我們將展示如何使用多塊GPU計算,例如,使用多塊GPU訓練同一個模型。正如所期望的那樣,運行本節中的程序需要至少2塊GPU。事實上,一臺機器上安裝多塊GPU很常見,這是因為主板上通常會有多個PCIe插槽。如果正確安裝了NVIDIA驅動,我們可以通過在命令行輸入`nvidia-smi`命令來查看當前計算機上的全部GPU(或者在jupyter notebook中運行`!nvidia-smi`)。
```
nvidia-smi
```
輸出:
```
Wed May 15 23:12:38 2019
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.48 Driver Version: 390.48 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 TITAN X (Pascal) Off | 00000000:02:00.0 Off | N/A |
| 46% 76C P2 87W / 250W | 10995MiB / 12196MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 1 TITAN X (Pascal) Off | 00000000:04:00.0 Off | N/A |
| 53% 84C P2 143W / 250W | 11671MiB / 12196MiB | 4% Default |
+-------------------------------+----------------------+----------------------+
| 2 TITAN X (Pascal) Off | 00000000:83:00.0 Off | N/A |
| 62% 87C P2 190W / 250W | 12096MiB / 12196MiB | 100% Default |
+-------------------------------+----------------------+----------------------+
| 3 TITAN X (Pascal) Off | 00000000:84:00.0 Off | N/A |
| 51% 83C P2 255W / 250W | 8144MiB / 12196MiB | 58% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 44683 C python 3289MiB |
| 0 155760 C python 4345MiB |
| 0 158310 C python 2297MiB |
| 0 172338 C /home/yzs/anaconda3/bin/python 1031MiB |
| 1 139985 C python 11653MiB |
| 2 38630 C python 5547MiB |
| 2 43127 C python 5791MiB |
| 2 156710 C python3 725MiB |
| 3 14444 C python3 1891MiB |
| 3 43407 C python 5841MiB |
| 3 88478 C /home/tangss/.conda/envs/py36/bin/python 379MiB |
+-----------------------------------------------------------------------------+
```
從上面的輸出可以看到一共有四塊TITAN X GPU,每一塊總共有約12個G的顯存,此時每塊的顯存都占得差不多了......此外還可以看到GPU利用率、運行的所有程序等信息。
Pytorch在0.4.0及以后的版本中已經提供了多GPU訓練的方式,本文用一個簡單的例子講解下使用Pytorch多GPU訓練的方式以及一些注意的地方。
## 8.4.1 多GPU計算
先定義一個模型:
``` python
import torch
net = torch.nn.Linear(10, 1).cuda()
net
```
輸出:
```
Linear(in_features=10, out_features=1, bias=True)
```
要想使用PyTorch進行多GPU計算,最簡單的方法是直接用`torch.nn.DataParallel`將模型wrap一下即可:
``` python
net = torch.nn.DataParallel(net)
net
```
輸出:
```
DataParallel(
(module): Linear(in_features=10, out_features=1, bias=True)
)
```
這時,默認所有存在的GPU都會被使用。
如果我們機子中有很多GPU(例如上面顯示我們有4張顯卡,但是只有第0、3塊還剩下一點點顯存),但我們只想使用0、3號顯卡,那么我們可以用參數`device_ids`指定即可:`torch.nn.DataParallel(net, device_ids=[0, 3])`。
## 8.4.2 多GPU模型的保存與加載
我們現在來嘗試一下按照4.5節(讀取和存儲)推薦的方式進行一下模型的保存與加載。
保存模型:
``` python
torch.save(net.state_dict(), "./8.4_model.pt")
```
加載模型前我們一般要先進行一下模型定義,此時的`new_net`并沒有使用多GPU:
``` python
new_net = torch.nn.Linear(10, 1)
new_net.load_state_dict(torch.load("./8.4_model.pt"))
```
然后我們發現報錯了:
```
RuntimeError: Error(s) in loading state_dict for Linear:
Missing key(s) in state_dict: "weight", "bias".
Unexpected key(s) in state_dict: "module.weight", "module.bias".
```
事實上`DataParallel`也是一個`nn.Module`,只是這個類其中有一個module就是傳入的實際模型。因此當我們調用`DataParallel`后,模型結構變了(在外面加了一層而已,從8.4.1節兩個輸出可以對比看出來)。所以直接加載肯定會報錯的,因為模型結構對不上。
所以正確的方法是保存的時候只保存`net.module`:
``` python
torch.save(net.module.state_dict(), "./8.4_model.pt")
new_net.load_state_dict(torch.load("./8.4_model.pt")) # 加載成功
```
或者先將`new_net`用`DataParallel`包括以下再用上面報錯的方法進行模型加載:
``` python
torch.save(net.state_dict(), "./8.4_model.pt")
new_net = torch.nn.Linear(10, 1)
new_net = torch.nn.DataParallel(new_net)
new_net.load_state_dict(torch.load("./8.4_model.pt")) # 加載成功
```
注意這兩種方法的區別,推薦用第一種方法,因為可以按照普通的加載方法進行正確加載。
-----------
> 注:本節與原書基本不同,[原書傳送門](https://zh.d2l.ai/chapter_computational-performance/multiple-gpus.html)
- Home
- Introduce
- 1.深度學習簡介
- 深度學習簡介
- 2.預備知識
- 2.1環境配置
- 2.2數據操作
- 2.3自動求梯度
- 3.深度學習基礎
- 3.1 線性回歸
- 3.2 線性回歸的從零開始實現
- 3.3 線性回歸的簡潔實現
- 3.4 softmax回歸
- 3.5 圖像分類數據集(Fashion-MINST)
- 3.6 softmax回歸的從零開始實現
- 3.7 softmax回歸的簡潔實現
- 3.8 多層感知機
- 3.9 多層感知機的從零開始實現
- 3.10 多層感知機的簡潔實現
- 3.11 模型選擇、反向傳播和計算圖
- 3.12 權重衰減
- 3.13 丟棄法
- 3.14 正向傳播、反向傳播和計算圖
- 3.15 數值穩定性和模型初始化
- 3.16 實戰kaggle比賽:房價預測
- 4 深度學習計算
- 4.1 模型構造
- 4.2 模型參數的訪問、初始化和共享
- 4.3 模型參數的延后初始化
- 4.4 自定義層
- 4.5 讀取和存儲
- 4.6 GPU計算
- 5 卷積神經網絡
- 5.1 二維卷積層
- 5.2 填充和步幅
- 5.3 多輸入通道和多輸出通道
- 5.4 池化層
- 5.5 卷積神經網絡(LeNet)
- 5.6 深度卷積神經網絡(AlexNet)
- 5.7 使用重復元素的網絡(VGG)
- 5.8 網絡中的網絡(NiN)
- 5.9 含并行連結的網絡(GoogLeNet)
- 5.10 批量歸一化
- 5.11 殘差網絡(ResNet)
- 5.12 稠密連接網絡(DenseNet)
- 6 循環神經網絡
- 6.1 語言模型
- 6.2 循環神經網絡
- 6.3 語言模型數據集(周杰倫專輯歌詞)
- 6.4 循環神經網絡的從零開始實現
- 6.5 循環神經網絡的簡單實現
- 6.6 通過時間反向傳播
- 6.7 門控循環單元(GRU)
- 6.8 長短期記憶(LSTM)
- 6.9 深度循環神經網絡
- 6.10 雙向循環神經網絡
- 7 優化算法
- 7.1 優化與深度學習
- 7.2 梯度下降和隨機梯度下降
- 7.3 小批量隨機梯度下降
- 7.4 動量法
- 7.5 AdaGrad算法
- 7.6 RMSProp算法
- 7.7 AdaDelta
- 7.8 Adam算法
- 8 計算性能
- 8.1 命令式和符號式混合編程
- 8.2 異步計算
- 8.3 自動并行計算
- 8.4 多GPU計算
- 9 計算機視覺
- 9.1 圖像增廣
- 9.2 微調
- 9.3 目標檢測和邊界框
- 9.4 錨框
- 10 自然語言處理
- 10.1 詞嵌入(word2vec)
- 10.2 近似訓練
- 10.3 word2vec實現
- 10.4 子詞嵌入(fastText)
- 10.5 全局向量的詞嵌入(Glove)
- 10.6 求近義詞和類比詞
- 10.7 文本情感分類:使用循環神經網絡
- 10.8 文本情感分類:使用卷積網絡
- 10.9 編碼器--解碼器(seq2seq)
- 10.10 束搜索
- 10.11 注意力機制
- 10.12 機器翻譯