您好,登錄后才能下訂單哦!
這篇文章主要介紹Pytorch如何讓GPU加速,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
前言
深度學習涉及很多向量或多矩陣運算,如矩陣相乘、矩陣相加、矩陣-向量乘法等。深層模型的算法,如BP,Auto-Encoder,CNN等,都可以寫成矩陣運算的形式,無須寫成循環運算。然而,在單核CPU上執行時,矩陣運算會被展開成循環的形式,本質上還是串行執行。GPU(Graphic Process Units,圖形處理器)的眾核體系結構包含幾千個流處理器,可將矩陣運算并行化執行,大幅縮短計算時間。隨著NVIDIA、AMD等公司不斷推進其GPU的大規模并行架構,面向通用計算的GPU已成為加速可并行應用程序的重要手段。得益于GPU眾核(many-core)體系結構,程序在GPU系統上的運行速度相較于單核CPU往往提升幾十倍乃至上千倍。
目前,GPU已經發展到了較為成熟的階段。利用GPU來訓練深度神經網絡,可以充分發揮其數以千計計算核心的能力,在使用海量訓練數據的場景下,所耗費的時間大幅縮短,占用的服務器也更少。如果對適當的深度神經網絡進行合理優化,一塊GPU卡相當于數十甚至上百臺CPU服務器的計算能力,因此GPU已經成為業界在深度學習模型訓練方面的首選解決方案。
如何使用GPU?現在很多深度學習工具都支持GPU運算,使用時只要簡單配置即可。Pytorch支持GPU,可以通過to(device)函數來將數據從內存中轉移到GPU顯存,如果有多個GPU還可以定位到哪個或哪些GPU。Pytorch一般把GPU作用于張量(Tensor)或模型(包括torch.nn下面的一些網絡模型以及自己創建的模型)等數據結構上。
單GPU加速
使用GPU之前,需要確保GPU是可以使用,可通過torch.cuda.is_available()的返回值來進行判斷。返回True則具有能夠使用的GPU。
通過torch.cuda.device_count()可以獲得能夠使用的GPU數量。
如何查看平臺GPU的配置信息?在命令行輸入命令nvidia-smi即可 (適合于Linux或Windows環境)。圖5-13是GPU配置信息樣例,從中可以看出共有2個GPU。
圖 GPU配置信息
把數據從內存轉移到GPU,一般針對張量(我們需要的數據)和模型。 對張量(類型為FloatTensor或者是LongTensor等),一律直接使用方法.to(device)或.cuda()即可。
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") #或device = torch.device("cuda:0") device1 = torch.device("cuda:1") for batch_idx, (img, label) in enumerate(train_loader): img=img.to(device) label=label.to(device)
對于模型來說,也是同樣的方式,使用.to(device)或.cuda來將網絡放到GPU顯存。
#實例化網絡 model = Net() model.to(device) #使用序號為0的GPU #或model.to(device1) #使用序號為1的GPU
多GPU加速
這里我們介紹單主機多GPUs的情況,單機多GPUs主要采用的DataParallel函數,而不是DistributedParallel,后者一般用于多主機多GPUs,當然也可用于單機多GPU。
使用多卡訓練的方式有很多,當然前提是我們的設備中存在兩個及以上的GPU。
使用時直接用model傳入torch.nn.DataParallel函數即可,如下代碼:
#對模型
net = torch.nn.DataParallel(model)
這時,默認所有存在的顯卡都會被使用。
如果你的電腦有很多顯卡,但只想利用其中一部分,如只使用編號為0、1、3、4的四個GPU,那么可以采用以下方式:
#假設有4個GPU,其id設置如下 device_ids =[0,1,2,3] #對數據 input_data=input_data.to(device=device_ids[0]) #對于模型 net = torch.nn.DataParallel(model) net.to(device)
或者
os.environ["CUDA_VISIBLE_DEVICES"] = ','.join(map(str, [0,1,2,3]))
net = torch.nn.DataParallel(model)
其中CUDA_VISIBLE_DEVICES 表示當前可以被Pytorch程序檢測到的GPU。
下面為單機多GPU的實現代碼。
背景說明
這里使用波士頓房價數據為例,共506個樣本,13個特征。數據劃分成訓練集和測試集,然后用data.DataLoader轉換為可批加載的方式。采用nn.DataParallel并發機制,環境有2個GPU。當然,數據量很小,按理不宜用nn.DataParallel,這里只是為了說明使用方法。
加載數據
boston = load_boston() X,y = (boston.data, boston.target) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0) #組合訓練數據及標簽 myset = list(zip(X_train,y_train))
把數據轉換為批處理加載方式批次大小為128,打亂數據
from torch.utils import data device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") dtype = torch.FloatTensor train_loader = data.DataLoader(myset,batch_size=128,shuffle=True)
定義網絡
class Net1(nn.Module): """ 使用sequential構建網絡,Sequential()函數的功能是將網絡的層組合到一起 """ def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim): super(Net1, self).__init__() self.layer1 = torch.nn.Sequential(nn.Linear(in_dim, n_hidden_1)) self.layer2 = torch.nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2)) self.layer3 = torch.nn.Sequential(nn.Linear(n_hidden_2, out_dim)) def forward(self, x): x1 = F.relu(self.layer1(x)) x1 = F.relu(self.layer2(x1)) x2 = self.layer3(x1) #顯示每個GPU分配的數據大小 print("\tIn Model: input size", x.size(),"output size", x2.size()) return x2
把模型轉換為多GPU并發處理格式
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") #實例化網絡 model = Net1(13, 16, 32, 1) if torch.cuda.device_count() > 1: print("Let's use", torch.cuda.device_count(), "GPUs") # dim = 0 [64, xxx] -> [32, ...], [32, ...] on 2GPUs model = nn.DataParallel(model) model.to(device)
運行結果
Let's use 2 GPUs DataParallel( (module): Net1( (layer1): Sequential( (0): Linear(in_features=13, out_features=16, bias=True) ) (layer2): Sequential( (0): Linear(in_features=16, out_features=32, bias=True) ) (layer3): Sequential( (0): Linear(in_features=32, out_features=1, bias=True) ) ) )
選擇優化器及損失函數
optimizer_orig = torch.optim.Adam(model.parameters(), lr=0.01)
loss_func = torch.nn.MSELoss()
模型訓練,并可視化損失值
from torch.utils.tensorboard import SummaryWriter writer = SummaryWriter(log_dir='logs') for epoch in range(100): model.train() for data,label in train_loader: input = data.type(dtype).to(device) label = label.type(dtype).to(device) output = model(input) loss = loss_func(output, label) # 反向傳播 optimizer_orig.zero_grad() loss.backward() optimizer_orig.step() print("Outside: input size", input.size() ,"output_size", output.size()) writer.add_scalar('train_loss_paral',loss, epoch)
運行的部分結果
In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1]) In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1]) Outside: input size torch.Size([128, 13]) output_size torch.Size([128, 1]) In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1]) In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1]) Outside: input size torch.Size([128, 13]) output_size torch.Size([128, 1])
從運行結果可以看出,一個批次數據(batch-size=128)拆分成兩份,每份大小為64,分別放在不同的GPU上。此時用GPU監控也可發現,兩個GPU都同時在使用。
8. 通過web查看損失值的變化情況
圖 并發運行訓練損失值變化情況
圖形中出現較大振幅,是由于采用批次處理,而且數據沒有做任何預處理,對數據進行規范化應該更平滑一些,大家可以嘗試一下。
單機多GPU也可使用DistributedParallel,它多用于分布式訓練,但也可以用在單機多GPU的訓練,配置比使用nn.DataParallel稍微麻煩一點,但是訓練速度和效果更好一點。具體配置為:
#初始化使用nccl后端 torch.distributed.init_process_group(backend="nccl") #模型并行化 model=torch.nn.parallel.DistributedDataParallel(model)
單機運行時使用下面方法啟動
python -m torch.distributed.launch main.py
使用GPU注意事項
使用GPU可以提升我們訓練的速度,如果使用不當,可能影響使用效率,具體使用時要注意以下幾點:
GPU的數量盡量為偶數,奇數的GPU有可能會出現異常中斷的情況;
GPU很快,但數據量較小時,效果可能沒有單GPU好,甚至還不如CPU;
如果內存不夠大,使用多GPU訓練的時候可通過設置pin_memory為False,當然使用精度稍微低一點的數據類型有時也效果。
以上是Pytorch如何讓GPU加速的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。