Python

PyTorchのキホンを理解する

PyTorchのキホンを理解する

Numpyのndarray(多次元配列)との違い

PytorchのTensor(テンソル)はNumpyのndarrayと以下の点で異なります。

  • GPUによる高速化(Google Colab向き)
  • 自動微分(Autograd)機能により勾配演算を自動化できる(順伝播 / 逆伝播)

Tensorの作成

import torch

'''Tensor型(2×3の行列)の作成'''
x = torch.empty(2, 3)
x = torch.rand(2, 3)
x = torch.zeros(2, 3)
x = torch.ones(2, 3)
x = x.new_ones(2, 3)
x = torch.randn(2, 3)
x = torch.ones_like(x, dtype=torch.long)
x = torch.tensor([[100, 200, 300],
                  [400, 500, 600]])

四則演算

'''四則演算'''
x = x + 2
x = x + torch.tensor([1, 2, 3])

型・サイズ

'''型やサイズを調べる(結果:説明)'''
x.type()
x.size()
x.shape
x.ndim
len(x)
x.size(0)

'''型変換(float)'''
x = torch.tensor(x, dtype=torch.float)
x = torch.FloatTensor(x)

'''サイズ変換'''
x.T
torch.t(x)
x.view(3, 2)
x.view(-1, 2)
x.reshape(-1, 1)
x.reshape(-1)

行・列・値の操作

'''行や列の操作'''
x = x[0]
x = x[0,2]
x = x[:,0]
x = x[1:3,0]
x = x[1:3,1:3]

'''値の操作'''
x[0,0] = 2
x[:,0] = 2
x[x > 300] = 2


配列のインデックスは以下のように指定することも可能です。

データセットの扱い

from torch.utils.data import DataLoader, TensorDataset
data_1 = torch.tensor([1, 2, 3, 4])
data_2 = torch.tensor([10, 20, 30, 40])

'''データセットの扱い'''
dataset = TensorDataset(data_1, data_2)
batch_data = DataLoader(dataset, batch_size=2, shuffle=False)

print('batch_data:',batch_data, '\n')
print(iter(batch_data).next(), '\n')
for i, (x, y) in enumerate(batch_data):
  print(str(i+1)+'バッチ目:', '\n', x, '\n', y)

※enumerateは、tensorとは関係ありませんがデータセットと一緒にインデックス番号を取得できる関数です。 データセットが「データと対応する1組のラベルを返すもの」であるのに対して、DataLoaderは「そのデータをバッチ単位(今回は2つのデータ)で扱えるようにしたもの」です。 また、DataLoaderの引数でnum_workerを加えると並列処理を行う数を指定でき、例えばCPUのコアが複数ある場合には格段に処理が速くなります。 DataLoaderはバッチ単位でデータが格納されたものであり、print()で直接その中身を見ることができません。 中身を確認する際はiter().next()で1番目のイテレータを指定することが多いです。 ※イテレータとは「繰り返しを指定するもの」です。

TensorとNumpy(ndarray)

 

 

'''TensorとNumpy(ndarray)'''
x = x.numpy()
x1 = x.to('cpu').numpy()
x = torch.from_numpy(x1)


NumpyはCPUでしか使えない(GPUに対応していない)ので、処理をCPU上で行う必要があります。
またpythonで配列の演算を行う際には「値が上書きされる可能性」「+と+=での挙動の違い」に注意が必要です。
詳しくは下記画像を参考にしてください。

GPU(cuda) or CPU

'''GPU(cuda) or CPUの確認'''
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)

'''モデルをGPU/CPUに移行'''
model.cuda()
model.cpu()

backwardで各変数の微分値を求める

'''backwardで各変数の微分値を求める'''
x = torch.tensor(2.0, requires_grad=True)
y = 3 * (x ** 2)
y.backward()
print("y=3x^2で")
print(" x=2のとき、y'=", x.grad.item())
print("")
x = torch.tensor(np.pi, requires_grad=True)
y = torch.sin(x)
y.backward()
print("y=sin(x)で")
print(" x=πのとき、y'=", x.grad.item())


.backward()」が呼ばれるとrequires_grad=TrueなTensorの勾配を自動で計算し、その結果を.gradに入れてくれるという仕組みです。

学習モード(train)と評価モード(eval)

model = nn.Sequential(
    nn.Linear(64, 32),
    nn.ReLU(),
    nn.Linear(32, 10)
)

'''訓練モードと評価モードで処理を早める'''
for i in range(100):
  model.train()
  '''訓練の処理をここに書く'''
  model.eval()
  '''評価の処理をここに書く'''


.train()」と「.eval()」を使い分けることで、勾配の計算を不要にし処理を早めることができます。
※訓練では勾配計算を利用し最適なパラメータを探しますが、テスト用の処理では勾配計算は必要ありません。

Dropout

'''Dropoutで過学習を防ぐ'''
class Net(nn.Module):
  def __init__(self):
    super(Net, self).__init__()
    self.fc1 = nn.Linear(13, 128)
    self.fc2 = nn.Linear(128, 2)
    self.dropout = nn.Dropout()
  def forward(self, x):
    x = F.relu(self.fc1(x))
    x = self.dropout(x)
    x = self.fc2(x)
    return x
net = Net()


Dropoutとは出力層以外のノードを一定確率で無効化し過学習を抑えるという手法です。
※過学習(over fitting)とは「あるデータに特化したモデルが構築され、未知のデータに弱い(汎用性が低い)状態」のことを指します。
実装が簡単かつ過学習を抑える効果も高いので、初心者でも気軽に利用することができます。
※デフォルトでは0.5、すなわち半分のノードが毎回ランダムに無効化されます。
しかし、Dropoutには以下のようなデメリットもあるので画像処理などでは用いられません。
△:重要な特徴を捕まえにくい。
△:最適解を見つけるまでの学習速度が遅い。
△:学習時とテスト時で分散が変わってしまうため*Batch Normalizationと併用できない。

Batch Nomalization

'''Batch Nomalizationで過学習を防ぐ'''
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.layer = nn.Sequential(
            nn.Conv2d(1, 16, kernel_size=5, padding=2),
            nn.BatchNorm2d(16),
            nn.ReLU(),
            nn.MaxPool2d(2))
        self.fc = nn.Linear(7 * 7 * 16, 10)
    def forward(self, x):
        x = self.layer1(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x
net = Net()


Batch Nomalizationとは、各層の出力を正規化した値で置きなおし過学習を抑えるという手法です。
※「正規化」=(データ – 全体の平均)/(全体の標準偏差)
近年では以下のメリットがあり、(特に画像処理では)Dropoutの上位互換のような形で使われます。
・内部の変数分布や勾配が大きく変わるのを防ぐことができる
・初めに設定したネットワークの重みの影響を受けにくい
・(特に平均0,分散1とすれば)学習速度が大幅に向上する
※Dropoutの学習速度が低下するという欠点を完全に補っています。
強いて欠点を挙げるとすれば以下の2つがあります。
△:バッチサイズが小さいと使えない
△:RNNなどの時系列データに使えない

活性化関数

◆Pytorchで用意されている活性化関数(オレンジは微分値)
ELU, Hardshrink, Hardtanh, LeakyReLU, LogSigmoid, MultiheadAttention, PReLU, ReLU, ReLU6, RReLU, SELU, CELU, GELU, Sigmoid, Softplus, Softshrink, Softsign, Tanh, Tanhshrink, Threshold, Softmin, Softmax, Softmax2d, LogSoftmax, AdaptiveLogSoftmaxWithLoss

最適化手法(損失関数)

◆SGD(Stochastic Gradient Decent : 確率的勾配降下法)
ランダムに拾った1つのデータを使って、求めた勾配方向に求めた大きさだけパラメータを更新する手法。
△:複雑な状況では最適化が進みにくい。並列処理ができない。

◆SDG – ミニバッチ(Mini-batch)
SDGでミニバッチを使い、1回の更新で一定数のデータを使って学習する手法。
△:データによっては学習が異常に遅くなることがある。

◆SDG – モーメンタム(Momentum)
過去の動き(勾配の移動平均)を考慮することでSDGの振動を抑えるという手法。
△:過去の結果が間違ったベクトルであっても反映されてしまう。

◆Adagrad(Adaptive Gradient Algorithm)
学習率を学習の中で更新し続ける手法。
パラメータの学習率を制御し大きな勾配の影響を小さくすることで、効率的に最適化を進めることができる。
△:学習が進むと学習率が小さくなり更新されなくなる。

◆RMSprop(Root Mean Square propagation)
Adagradに比べ、古い勾配情報よりも新しい勾配情報が反映されやすい手法。
学習が進んでも学習率の調整が適切に行われる。

◆Adam(Adaptive Moment Estimation)
移動平均で振動を抑制するモーメンタムと、学習率で振動を抑制するRMSpropを組み合わせたもの。
複雑な形状でも適切な方向を探すことができる。

◆Adadelta
更新量 = (過去の更新量の移動平均)/(過去の勾配の移動平均)*(現在の勾配)
△:収束が少し遅い。

◆AdamW
Adamよりも最適な重み減衰(Weight decay)を加えた手法。
損失関数計算およびパラメータ更新時にリッジ回帰を追加したもの。

参考文献

PyTorchのテンソル&データ型のチートシート
PyTorch超入門 PyTorchの基礎編
【PyTorch】Tensorを操作する関数(transpose、view、reshape)
PyTorchでMNISTする
プログラムを関数にまとめて、実行結果をグラフにプロットしよう (2/2)
Batch Normalization と Dropout は併用しない方が良いという話
Batch Normalization の理解
活性化関数一覧 (2020)
【前編】Pytorchの様々な最適化手法(torch.optim.Optimizer)の更新過程や性能を比較検証してみた!
【2020決定版】スーパーわかりやすい最適化アルゴリズム -損失関数からAdamとニュートン法-
【GIF】初心者のためのCNNからバッチノーマライゼーションとその仲間たちまでの解説

関連記事

  1. Python

    わかりやすいPyTorch入門⑤(CNNとデータの拡張)

    CNNとデータの拡張データの拡張とは今回は前回学んだCNNの練…

  2. Python

    Python クローリング&スクレイピング

    最初に顧客マスタのデータに別の角度から考察を加えたいとき、外部から…

  3. Python

    pythonを使ったダミーデータ生成

    最初になにか発見したことを総合研究所で発表したり、デモ資料を作った…

  4. Python

    わかりやすいPyTorch入門④(CNN:畳み込みニューラルネットワーク)

    MNISTの手書き数字画像をCNNで分類前回の記事でも利用したMN…

  5. Adobe Analytics

    Google Analytics検証を効率的に進める方法

    0.初めにGoogle Analyticsがデータをとれているか検…

  6. Python

    わかりやすいPyTorch入門②(ニューラルネットワークによる分類)

    ニューラルネットワークを使ってワインの種類を分類する今回はscik…

PAGE TOP