Pythonいぬ

pythonを使った画像処理に関する記事を書いていきます

Pytorch でOptimizerのパラメータにアクセス

Pytorchはdefine by run(実行しながら定義)なライブラリなので、 学習の途中でoptimizerにアクセスして、 learning rateを変更したりしてみたい。ということで、optimizerを定義した後でlearning rateなどにどのようにアクセスするかを調べてみた。

単純にLearning rateを変えたいだけなら以下のように書けばよい。

import torch
model = torch.nn.Conv2d(1,1,3, bias=False)
opt = torch.optim.Adam(model.parameters(), lr=0.00001)
pg = opt.param_groups[0]
pg['lr'] = 0.1

Optimizerのメンバへアクセス

optimzerのメンバへアクセスするには、下記のようにopt.param_groups[0]を使う。

import torch
from torch import nn

model = nn.Conv2d(1,1,3, bias=False)
opt = torch.optim.Adam(model.parameters())

lr = opt.param_groups[0]['lr']

上記のように書くと変数lrに learning rateの値が入る。opt.param_groups[0]の中身をもう少し見てみる。ipythonで上記のコマンドを実行後に以下のコマンドを打ってみる

print(opt.param_groups[0])

出力は以下

{'params': [Parameter containing:
  tensor([[[[ 0.1461,  0.2775, -0.1896],
            [ 0.0344, -0.1396,  0.2176],
            [-0.0873,  0.2879, -0.0561]]]], requires_grad=True)],
 'lr': 0.001,
 'betas': (0.9, 0.999),
 'eps': 1e-08,
 'weight_decay': 0,
 'amsgrad': False}

試しにlrの値を変更して、もう一度出力を見る

opt.param_groups[0]['lr'] = 0.1
print(opt.param_groups[0])

出力は以下

{'params': [Parameter containing:
  tensor([[[[-0.1734, -0.0178, -0.0896],
            [-0.2925, -0.1085,  0.3080],
            [ 0.2562, -0.0101,  0.1187]]]], requires_grad=True),
  Parameter containing:
  tensor([-0.0762], requires_grad=True)],
 'lr': 0.1, # <--ここが変化
 'betas': (0.9, 0.999),
 'eps': 1e-08,
 'weight_decay': 0,
 'amsgrad': False}

lrの値が変化していることがわかる。

params以外のパラメータのみを出力

今は例として非常に小さいモデル(nn.Conv2dのみ)を使っているが、一般的にはニューラルネットのモデルは大きいので、paramsの部分に大量のデータが入る。paramsをはずして出力したい場合は以下。

pg = opt.param_groups[0]
{i: pg[i] for i in list(pg.keys())[1:]}

下記のような出力が得られる。

{'lr': 0.001,
 'betas': (0.9, 0.999),
 'eps': 1e-08,
 'weight_decay': 0,
 'amsgrad': False}

Adamでイテレーション回数を出力

Adamは移動平均を使っているので、実はoptimizerはイテレーション回数(opt.step()を行った回数)を保持している。これを使えばepochではなく、イテレーション回数で学習パラメータを変えることもできる。アクセスするには以下のようにopt.state[p]['step']を見ればよい。ただし、1回以上loss.backward()とopt.step()を実行している必要がある。

import torch
from torch import nn

model = nn.Conv2d(1,1,3, bias=False)
opt = torch.optim.Adam(model.parameters())

x = torch.randn(1,1,3,3), 
y = torch.randn(1,1,1,1)

y_ = model.forward(x)
loss = torch.mean(y-y_)

opt.zero_grad()
loss.backward()
opt.step()

p = opt.param_groups[0]['params'][0]
iiter = opt.state[p]['step']

これでiiterの中にイテレーション回数が入る。