optimizer = AdamW(model.parameters(), lr=LR, correct_bias=False)
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=WARMUP_STEPS, num_training_steps=t_total)
for epoch in range(EPOCHS):
loss.backward()
optimizer.step()
scheduler.step()
當保存和加載模型時,需要熟悉三個核心功能: torch.save:將序列化對象保存到磁盤。此函數使用Python的pickle模塊進行序列化。使用此函數可以保存如模型、tensor、字典等各種對象。 torch.load:使用pickle的unpickling功能將pickle對象文件反序列化到內存。此功能還可以有助於設備加載數據。 torch.nn.Module.load_state_dict:使用反序列化函數 state_dict 來加載模型的參數字典。 1.什么是狀態字典:state_dict? 在PyTorch中,torch.nn.Module模型的可學習參數(即權重和偏差)包含在模型的參數中,(使用model.parameters()可以進行訪問)。 state_dict是Python字典對象,它將每一層映射到其參數張量。注意,只有具有可學習參數的層(如卷積層,線性層等)的模型 才具有state_dict這一項。目標優化torch.optim也有state_dict屬性,它包含有關優化器的狀態信息,以及使用的超參數。
當保存成 Checkpoint 的時候,可用於推理或者是繼續訓練,保存的不僅僅是模型的 state_dict 。保存優化器的 state_dict 也很重要, 因為它包含作為模型訓練更新的緩沖區和參數。你也許想保存其他項目,比如最新記錄的訓練損失,外部的torch.nn.Embedding
層等等。
要保存多個組件,請在字典中組織它們並使用torch.save()
來序列化字典。PyTorch 中常見的保存checkpoint 是使用 .tar 文件擴展名。
要加載項目,首先需要初始化模型和優化器,然后使用torch.load()
來加載本地字典。這里,你可以非常容易的通過簡單查詢字典來訪問你所保存的項目。
請記住在運行推理之前,務必調用model.eval()
去設置 dropout 和 batch normalization 為評估。如果不這樣做,有可能得到不一致的推斷結果。 如果你想要恢復訓練,請調用model.train()
以確保這些層處於訓練模式。
input_ids_method1 = torch.tensor(tokenizer.encode(sentence, add_special_tokens=True))
- 從例子中可以看出,encode方法可以一步到位地生成對應模型的輸入。
- 相比之下,tokenize只是用於分詞,可以分成WordPiece的類型,並且在分詞之后還要手動使用convert_tokens_to_ids方法,比較麻煩
Puts each data field into a tensor with outer dimension batch size 即用於對單個樣本生成batch的函數,如果沒有特殊需求其實不用自己寫collate_fn方法,有默認的default_collate方法。
如果模型中有BN層(Batch Normalization)和Dropout,需要在訓練時添加model.train(),在測試時添加model.eval()。其中model.train()是保證BN層用每一批數據的均值和方差,而model.eval()是保證BN用全部訓練數據的均值和方差;而對於Dropout,model.train()是隨機取一部分網絡連接來訓練更新參數,而model.eval()是利用到了所有網絡連接。
因為驗證集的時候,我們只是想看一下訓練的效果,並不是想通過驗證集來更新網絡時,就可以使用with torch.no_grad()。最終,torch.save就是保存的訓練集的訓練模型。
pytorch 的數據加載到模型的操作順序是這樣的: ① 創建一個 Dataset 對象
為面部數據集創建一個數據集類。我們將在__init__
中讀取csv的文件內容,在__getitem__
中讀取圖片。這么做是為了節省內存 空間。只有在需要用到圖片的時候才讀取它而不是一開始就把圖片全部存進內存里。 ② 創建一個 DataLoader 對象 ③ 循環這個 DataLoader 對象,將img, label加載到模型中進行訓練
test_loader 沒有打亂數據。train_loader有打亂數據
model.parameters()與model.state_dict()是Pytorch中用於查看網絡參數的方法。一般來說,前者多見於優化器的初始化,后者多見於模型的保存
總結來說:梯度累加就是,每次獲取1個batch的數據,計算1次梯度,梯度不清空,不斷累加,累加一定次數后,根據累加的梯度更新網絡參數,然后清空梯度,進行下一次循環。一定條件下,batchsize越大訓練效果越好,梯度累加則實現了batchsize的變相擴大,如果accumulation_steps為8,則batchsize '變相' 擴大了8倍,是我們這種乞丐實驗室解決顯存受限的一個不錯的trick,使用時需要注意,學習率也要適當放大。 算一個batch計算一次梯度,然后進行一次梯度更新。這里梯度值就是對應偏導數的計算結果。顯然,我們進行下一次batch梯度計算的時候,前一個batch的梯度計算結果,沒有保留的必要了。所以在下一次梯度更新的時候,先使用optimizer.zero_grad把梯度信息設置為0。
Bert模型類,繼承torch.nn.Module,實例化對象時使用from_pretrained()函數初始化模型權重,參數config用於配置模型參數 模型輸入是: input_ids,token_type_ids(可選),attention_mask(可選),position_ids(可選), head_mask(可選):0表示head無效,1表示head有效。 inputs_embeds (可選)如果不使用input_ids,可以直接輸入token的embedding表示。 encoder_hidden_states(可選):encoder最后一層的隱含狀態序列,模型配置為decoder時,需要此輸入。 encoder_attention_mask(可選):encoder最后一層隱含狀態序列是否參與attention計算,防止padding部分參與,模型配置為decoder時,需要此輸入. 返回類型tuple(torch.FloatTensor): last_hidden_state:模型最后一層輸出的隱含層狀態序列 pooler_output :最后一層隱含層狀態序列經過一層全連接和Tanh激活后,第一個toekn對應位置的輸出。
last_hidden_state:模型最后一層輸出的隱含層狀態序列
pooler_output :最后一層隱含層狀態序列經過一層全連接和Tanh激活后,第一個toekn對應位置的輸出。
hidden_states(可選,當output_hidden_states=True或者config.output_hidden_states=True):每一層和初始embedding層輸出的隱含狀態
attentions(可選,當output_attentions=True或者config.output_attentions=True):attention softmax后的attention權重,用於在自注意力頭中計算權重平均值。
BertForSequenceClassification 這個類用於句子分類或回歸任務,繼承torch.nn.Module,實例化依然使用from_pretrained+ config配置。 輸入相比BertModel多了一個label 輸出主要是loss,logits(softmax之前的分類分數)等tuple(torch.FloatTensor)
pretrained_model_name_or_path :這個參數可以是一個需要下載或緩存中的與訓練模型的快捷名稱,如果本地的緩存中沒有這個模型,就自己去官網下載,緩存到本地.cache中,速度較慢;也可以是使用save_pretrained()保存的模型權重字典的路徑
PyTorch的核心是兩個主要特征:
- 一個n維張量,類似於numpy,但可以在GPU上運行
- 搭建和訓練神經網絡時的自動微分/求導機
PyTorch自動求導看起來非常像TensorFlow:這兩個框架中,我們都定義計算圖,使用自動微分來計算梯度。兩者最大的不同就是TensorFlow的計算圖是靜態的,而PyTorch使用動態的計算圖。
在TensorFlow中,我們定義計算圖一次,然后重復執行這個相同的圖,可能會提供不同的輸入數據。而在PyTorch中,每一個前向通道定義一個新的計算圖。
靜態圖的好處在於你可以預先對圖進行優化。例如,一個框架可能要融合一些圖的運算來提升效率,或者產生一個策略來將圖分布到多個GPU或機器上。如果重復使用相同的圖,那么在重復運行同一個圖時,,前期潛在的代價高昂的預先優化的消耗就會被分攤開。
靜態圖和動態圖的一個區別是控制流。對於一些模型,我們希望對每個數據點執行不同的計算。例如,一個遞歸神經網絡可能對於每個數據點執行不同的時間步數,這個展開(unrolling)可以作為一個循環來實現。對於一個靜態圖,循環結構要作為圖的一部分。因此,TensorFlow提供了運算符(例如tf.scan
)來把循環嵌入到圖當中。對於動態圖來說,情況更加簡單:既然我們為每個例子即時創建圖,我們可以使用普通的命令式控制流來為每個輸入執行不同的計算。