Minetorch教程
關于PyTorch的實驗工具之前我介紹過NVIDIA的runx,歡迎訪問,不過runx是個偏向于集群使用的一個運行實驗工具,我往往只使用其中日志記錄的logx模塊,本文則介紹一個主攻實驗控制和記錄的PyTorch實驗工具—Minetorch,考慮到國內好像還沒有介紹該工具包的文章,因而有了這篇教程,作為一個Minecraft玩家,這個工具作者給我的感覺是很有情懷的。
Minetorch教程
簡介
“在Minecraft中,火把對于挖礦是非常重要的,沒有火把玩家很難獲得大量的鉆石等礦物。在數據科學領域也是如此,一個名為PyTorch的深度學習工具庫可以幫助我們獲得數據中的鉆石等寶藏。Minetorch則作為研究者的工具集,幫助我們以一個更加方便的方式使用PyTorch。”這是Minetorch的官方簡介,說的直白一點,這是一個針對PyTorch的工具箱,包括了訓練控制、訓練日志記錄及可視化等諸多功能。
安裝
首先是該庫的安裝,通過下面的命令使用pip進行安裝即可。
pip install minetorch此外,還需要安裝tqdm、sklearn和jupyter等包,而且需要注意,PyTorch的版本必須大于1.7.0才能運行成功。
使用教程
首先需要說明的是,Minetorch其實對Google Sheets做了非常強大的對接,用戶可以通過配置非常方便地在訓練時自動將實驗記錄上傳到電子表格中,不過由于國內Google Sheets使用不多因此本文將忽略這一部分,感興趣的可以參考官方教程進行配置。下文主要圍繞目前版本Minetorch的核心兩個功能展開敘述,即實驗記錄和訓練控制。
實驗記錄
首先我們來看我們使用實驗記錄工具最關心的實驗記錄功能,這就不得不提到Minetorch的一個核心類Miner,這是一個高度封裝的訓練器(trainer),將Model和Dataloader傳給它即可方便的實現訓練而不需要自己手動寫循環來控制整個流程。下面就是一個Miner的構建方法,它只是將我們原本的訓練流程通過這個類封裝了,模型和數據的構建是不需要改動的,該對象的初始化需要的大部分參數我已經在下面的代碼中詳細備注了,其中drawer這個參數控制繪圖器為tensorboard還是matplotlib,默認為matplotlib,它會自動繪制訓練和驗證損失圖像。
trainer = Miner(alchemistic_directory='./runs', # 日志根目錄train_dataloader=train_loader, # 訓練dataloadermodel=model, # 模型loss_func=loss_fn, # 損失函數optimizer=optimizer, # 優化器code="exp1", # 實驗子目錄val_dataloader=val_loader, # 驗證dataloaderresume=True, # 是否自動加載之前的last模型接著訓練eval_stride=1, # 多少輪進行一次評估persist_stride=1, # 多少輪進行一次checkpoint的保存drawer='tensorboard', # 繪圖器設置hooks=None, # hooks配置logging_format=None, # 日志格式,默認即可max_epochs=50, # 訓練輪數plugins=[MultiClassesClassificationMetricWithLogic(),NoiseSampleDetector(metric=torch.nn.CrossEntropyLoss(reduction='none'))], # 插件accumulated_iter=1, # 累積多少次迭代后進行參數更新trival=True, # 是否同時完成訓練后隨機進行驗證in_notebook=True, # 是否啟用notebook模式,由于該庫默認支持notebook,請務必打開該模式amp=True, # 是否開啟混合精度statable={} # 實現了`state_dict`和`load_state_dict`方法的對象組成的字典,例如一個學習率調度器,trainer會自動保存這個對象的參數,注意優化器和模型默認是保存的因此不需要指定 )只要調用這個trainer的train方法訓練就會開始進行訓練,訓練其實就是類似我們自己for循環取數據進行訓練,需要注意的是,這里默認是將dataloader的整個返回結果送入模型中,如果模型沒有定義解包方式那么需要構建trainer的時候傳入一個自定義的forward函數,參數名為forward。
訓練控制
上面的這些配置只是完成了一些基本的訓練流程,如果想要自定義一些新的功能那么就必須自定義一些東西,為了方便使用者控制在那個階段干些什么,minetorch將訓練分為多個hook點,用戶可以注冊這些hook來在不同的訓練階段做些不同的操作。
| after_init | trainer初始化完成調用該方法 |
| before_epoch_start | 每輪開始時調用該方法 |
| after_epoch_end | 每輪結束時調用該方法 |
| before_train_iteration_start | 每次訓練迭代開始之前調用該方法 |
| after_train_iteration_end | 每次訓練迭代完成后調用該方法 |
| before_val_iteration_start | 每次驗證迭代開始之前調用該方法 |
| after_val_iteration_end | 每次驗證迭代完成之前調用該方法 |
| before_checkpoint_persisted | checkpoint保存前調用該方法 |
| after_checkpoint_persisted | checkpoint保存后調用該方法 |
| before_quit | 訓練完成退出前調用該方法 |
這些hook點的設計使得用戶可以在不同的階段嵌入自己想要增加的功能,例如想在訓練每輪開始的時候打印當前輪次,那么我需要定義下面這個函數,它必須傳入的是一個Miner對象用于訪問miner中的所有成員。
def before_epoch_start(miner: Miner, **kwargs):print("start training, this is epoch {}".format(miner.current_epoch))然后創建trainer的時候傳入hook這個字典即可,那么每次之前就會輸出當前輪數。
trainer = Miner(..., hooks={'before_epoch_start': before_epoch_start})hooks的設計使得訓練的拓展變得上限極高,那么插件Plugin的存在則是更具體的一種實現,它的處理流程和hook函數類似,不同的是它封裝了多個hook點的功能因而實現了一個更加完善的功能,例如上面代碼示例中使用的MultiClassesClassificationMetricWithLogic即實現了多分類任務指標輸出和drawer(通過miner獲得drawer)繪制。設計新的插件需要注冊自Plugin類然后實現自己不同hook點的方法。我這里就不具體講解了,通過閱讀作者實現的異常檢測的plugin,應該可以理解設計的流程,我這里給出代碼。
訓練演示
經過上面的講解,其實可以發現,Minetorch是一個可拓展性非常強的工具庫并且仍在不斷地維護升級中,下面是我隨機生成數據集進行訓練流程測試的代碼,由于是隨機生成的數據所以擬合能力我們可以暫且忽略,可以重點看看該工具庫的日志輸出形式。
import torch import torch.nn as nn import torch.nn.functional as F from torch.utils.data import Dataset, DataLoader from minetorch.miner import Miner from minetorch.metrics import MultiClassesClassificationMetricWithLogic from minetorch.plugins.noise_detector import NoiseSampleDetector# create dataset x = torch.zeros(1600 * 10).view(1600, 10).float() x = x + torch.rand_like(x) y = torch.randint(low=0, high=2, size=(1600, ))class MyDataset(Dataset):def __init__(self, x, y):assert x.shape[0] == y.shape[0]self.x = xself.y = ydef __getitem__(self, index):return self.x[index], self.y[index]def __len__(self):return self.x.shape[0]# create model class Model(nn.Module):def __init__(self):super(Model, self).__init__()self.fc1 = nn.Linear(10, 100)self.fc2 = nn.Linear(100, 2)def forward(self, x):x = self.fc1(x)x = F.relu(x)x = self.fc2(x)return xdef before_epoch_start(miner: Miner, **kwargs):print("start training, this is epoch {}".format(miner.current_epoch))def main():model = Model()train_loader = DataLoader(MyDataset(x, y), batch_size=32, shuffle=True)val_loader = DataLoader(MyDataset(x, y), batch_size=32, shuffle=True)loss_fn = nn.CrossEntropyLoss()optimizer = torch.optim.SGD(model.parameters(), lr=0.001)# create trainertrainer = Miner(alchemistic_directory='./runs',train_dataloader=train_loader,model=model,loss_func=loss_fn,optimizer=optimizer,code="exp1",val_dataloader=val_loader,resume=True,eval_stride=1,persist_stride=1,drawer='tensorboard',logging_format=None,max_epochs=50,plugins=[MultiClassesClassificationMetricWithLogic(),NoiseSampleDetector(metric=torch.nn.CrossEntropyLoss(reduction='none'))],accumulated_iter=1,trival=True,in_notebook=True,amp=True,hooks={'before_epoch_start': before_epoch_start},)trainer.train()if __name__ == '__main__':main()首先,會在trainer構建時指定的日志根目錄里生成以code參數為后綴的當前實驗的日志目錄,然后根據使用的hook和插件以及基本的功能生成如下結構的日志目錄,其中models存放保存的模型,各自插件生成的結果保存在插件名的目錄下,如這里的NoiseSampleDetector和MultiClassesClassificationMetricWithLogic目錄(這是基本設計,不是一定要生成在這里,比如MultiClassesClassificationMetricWithLogic的繪圖結果就在其他目錄里面),和上級目錄同名的目錄里是各種指標的繪圖結果,損失是基本項,其他的均由插件支持生成。此外,還有一個名為log.txt的文本文件記錄輸出的日志,便于我們回顧訓練的各個步驟的執行情況。
└─trival_exp1├─models├─MultiClassesClassificationMetricWithLogic├─NoiseSampleDetector└─trival_exp1├─accuracy│ └─accuracy├─kappa_score│ └─kappa_score└─loss├─train└─val由于我這里采用的tensorboard進行繪制,通過可視化可以看到如下圖所示的各個指標的繪圖結果。
總結
本文主要介紹了一個在競賽和項目中比較使用的PyTorch工具庫—Minetorch,它讓基于PyTorch的訓練變得更加方便,歡迎大家的嘗試使用。
總結
以上是生活随笔為你收集整理的Minetorch教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 0002-Add Two Numbers
- 下一篇: SL解读