翻了很多博客和論壇,一般凍結參數都包括兩步:
- 設置參數的屬性爲False,即requires_grad=False
- 定義優化器時過濾掉不進行梯度更新的參數,一般都是這樣
optimizer.SGD(filter(lambda p: p.requires_grad, model.parameters()), lr=1e-3)
上面就不細講了,百度大部分都是這種。
先說下我的任務:
我有一個模型由encoder和decoder組成,在預訓練時固定decoder的參數,只訓練encoder的參數。然後在fine-tune的時候訓練所有的參數。
問題:
按照上面的方法,在重新加載模型時會報長度不一致的錯誤。
ValueError: loaded state dict contains a parameter group that doesn't match the size of optimizer's group
調試了半天發現我加載的模型只保存了encoder部分的參數,但是新的模型是encoder和decoder兩部分的參數。所以無法將預訓練的參數加載到新的模型裏。
解決方法:
只設置參數的屬性是True/False,不用過濾優化器中的參數,這樣長度就會一致了。
而且在預訓練過程中固定的參數確實沒有被更新,在fine-tune的時候所有的參數都被更新了,正好符合我們要求。
附上我調式的過程:
- 預訓練:只修改屬性,不過濾參數
for param in model.parameters():
param.requires_grad = False
for param in model.encoder.parameters():
param.requires_grad = True
輸出兩次更新的參數,可以發現確實只有encoder更新了,decoder沒有被更新。
- fine-tune:
for param in model.parameters():
param.requires_grad = True
同樣輸出兩次更新的參數,可以發現decoder的參數也被更新了。over!