7 个有用的 PyTorch 技巧
原文:https://www.reddit.com/r/MachineLearning/comments/n9fti7/d_a_few_helpful_pytorch_tips_examples_included/
原文標題:a_few_helpful_pytorch_tips_examples_included
譯文作者:kbsc13
聯系方式:
Github:https://github.com/ccc013/AI_algorithm_notes
知乎專欄:機器學習與計算機視覺,AI 論文筆記
微信公眾號:AI 算法筆記
前言
這是在國外的論壇 reddit 的機器學習版塊,有人總結了大概 7 個有用的 PyTorch 技巧,并且還附帶了 colab 的代碼例子和視頻,代碼和視頻鏈接分別如下:
代碼:https://colab.research.google.com/drive/15vGzXs_ueoKL0jYpC4gr9BCTfWt935DC?usp=sharing
視頻:https://youtu.be/BoC8SGaT3GE
視頻也同步上傳到我的 b 站上,鏈接如下:
https://www.bilibili.com/video/BV1YK4y1A7KM/
另外代碼和視頻可以在我的公眾號后臺回復"12"獲取。
1. 直接在目標設備上創建 Tensors
第一個技巧就是使用 device 參數直接在目標設備上創建張量,這里分別演示了兩種做法的運行時間,
第一種是先在 cpu 上創建 tensors,然后用.cuda() 移動到 GPU 上,代碼如下所示:
start_time = time.time()for _ in range(100):# Creating on the CPU, then transfering to the GPUcpu_tensor = torch.ones((1000, 64, 64))gpu_tensor = cpu_tensor.cuda()print('Total time: {:.3f}s'.format(time.time() - start_time))第二種則是直接在目標設備上創建張量,代碼如下所示:
start_time = time.time()for _ in range(100):# Creating on GPU directlycpu_tensor = torch.ones((1000, 64, 64), device='cuda')print('Total time: {:.3f}s'.format(time.time() - start_time))兩種方法的運行時間如下所示:
可以看到直接在目標設備創建 Tensors 的速度是非常快速的;
2. 盡可能使用 Sequential 層
第二個技巧就是采用Sequential 層來讓代碼看起來更加簡潔。
第一種搭建網絡模型的代碼如下:
class ExampleModel(nn.Module):def __init__(self):super().__init__()input_size = 2output_size = 3hidden_size = 16self.input_layer = nn.Linear(input_size, hidden_size)self.input_activation = nn.ReLU()self.mid_layer = nn.Linear(hidden_size, hidden_size)self.mid_activation = nn.ReLU()self.output_layer = nn.Linear(hidden_size, output_size)def forward(self, x):z = self.input_layer(x)z = self.input_activation(z)z = self.mid_layer(z)z = self.mid_activation(z)out = self.output_layer(z)return out其運行效果如下:
而采用 Sequential 來搭建網絡模型的寫法如下所示:
class ExampleSequentialModel(nn.Module):def __init__(self):super().__init__()input_size = 2output_size = 3hidden_size = 16self.layers = nn.Sequential(nn.Linear(input_size, hidden_size),nn.ReLU(),nn.Linear(hidden_size, hidden_size),nn.ReLU(),nn.Linear(hidden_size, output_size))def forward(self, x):out = self.layers(x)return out其運行效果如下:
可以看到用 nn.Sequential 來搭建網絡模型的代碼是更加的簡潔。
3. 不要使用列表來存放網絡層
第三個技巧是不建議使用列表來存放創建的網絡層,因為 nn.Module 類不能成功注冊他們。相反,應該把列表傳入到nn.Sequential 中。
首先是展示一個錯誤的例子:
class BadListModel(nn.Module):def __init__(self):super().__init__()input_size = 2output_size = 3hidden_size = 16self.input_layer = nn.Linear(input_size, hidden_size)self.input_activation = nn.ReLU()# Fairly common when using residual layersself.mid_layers = []for _ in range(5):self.mid_layers.append(nn.Linear(hidden_size, hidden_size))self.mid_layers.append(nn.ReLU())self.output_layer = nn.Linear(hidden_size, output_size)def forward(self, x):z = self.input_layer(x)z = self.input_activation(z)for layer in self.mid_layers:z = layer(z)out = self.output_layer(z)return outbad_list_model = BadListModel() print('Output shape:', bad_list_model(torch.ones([100, 2])).shape) gpu_input = torch.ones([100, 2], device='cuda') gpu_bad_list_model = bad_list_model.cuda() print('Output shape:', bad_list_model(gpu_input).shape)上述寫法在打印第二句的時候,會報錯:
正確的寫法:
class CorrectListModel(nn.Module):def __init__(self):super().__init__()input_size = 2output_size = 3hidden_size = 16self.input_layer = nn.Linear(input_size, hidden_size)self.input_activation = nn.ReLU()# Fairly common when using residual layersself.mid_layers = []for _ in range(5):self.mid_layers.append(nn.Linear(hidden_size, hidden_size))self.mid_layers.append(nn.ReLU())self.mid_layers = nn.Sequential(*self.mid_layers)self.output_layer = nn.Linear(hidden_size, output_size)def forward(self, x):z = self.input_layer(x)z = self.input_activation(z)z = self.mid_layers(z)out = self.output_layer(z)return outcorrect_list_model = CorrectListModel() gpu_input = torch.ones([100, 2], device='cuda') gpu_correct_list_model = correct_list_model.cuda() print('Output shape:', correct_list_model(gpu_input).shape)其打印結果:
4. 好好使用 distributions
第四個技巧是PyTorch 的 torch.distributions 庫中有一些很棒的對象和方法來實現分布式,但是并沒有得到很好地使用,官方文檔鏈接:
https://pytorch.org/docs/stable/distributions.html
下面是一個使用的例子:
5. 在長期指標上使用 detach
第 5 個技巧是在每個 epoch 之間如果需要存儲張量指標,采用 .detach() 來防止內存泄露。
下面用一個代碼例子來說說明,首先是初始配置:
# Setup example_model = ExampleModel() data_batches = [torch.rand((10, 2)) for _ in range(5)] criterion = nn.MSELoss(reduce='mean')錯誤的代碼例子:
losses = []# Training loop for batch in data_batches:output = example_model(batch)target = torch.rand((10, 3))loss = criterion(output, target)losses.append(loss)# Optimization happens hereprint(losses)打印結果如下:
正確的寫法
losses = []# Training loop for batch in data_batches:output = example_model(batch)target = torch.rand((10, 3))loss = criterion(output, target)losses.append(loss.item()) # Or `loss.item()`# Optimization happens hereprint(losses)打印結果如下:
這里應該調用 loss.item() 方法來保存每個 epoch 中的 loss 數值。
6. 刪除 GPU上模型的技巧
第六個技巧是可以采用 torch.cuda.empty_cache() 來清理 GPU 緩存,這個方法在使用 notebook 的時候很有幫助,特別是你想要刪除和重新創建一個很大的模型的時候。
使用例子如下所示:
import gcexample_model = ExampleModel().cuda()del example_modelgc.collect() # The model will normally stay on the cache until something takes it's place torch.cuda.empty_cache()7. 測試前調用 eval()
最后一個是開始測試前別忘了調用 model.eval() ,這個很簡單但很容易忘記。這個操作會讓一些在訓練和驗證階段設置不一樣的網絡層有必要的改變,會有影響的模塊包括:
- Dropout
- Batch Normalization
- RNNs
- Lazy Variants
這個可以參考:https://stackoverflow.com/questions/66534762/which-pytorch-modules-are-affected-by-model-eval-and-model-train
使用例子如下:
example_model = ExampleModel()# Do trainingexample_model.eval()# Do testingexample_model.train()# Do training again總結
以上是生活随笔為你收集整理的7 个有用的 PyTorch 技巧的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 搞清这些陷阱,NULL和三值逻辑再也不会
- 下一篇: MATLAB中saveas函数使用