LoginSignup
102

More than 3 years have passed since last update.

PyTorch超入門 PyTorchの基礎編

Last updated at Posted at 2019-11-21

はじめに

 このシリーズは、Pythonの機械学習用フレームワークであるPyTorchの学習のまとめとして記述します。
 今回はPyTorchの基礎中の基礎といった部分のまとめを記事とさせていただきました。伝えるためのものというよりも、要点をおさえて書くようにしているので読み物としては読みづらいかもしれませんが、ポイントの理解などに利用して頂ければと思います。

PyTorchとは

 先にも述べましたが、PyTorchはPythonの機械学習用フレームワークです。機械学習用フレームワークといえば、Googleが開発したTensorFlowであったり、Kerasあるいはchainerなどがあります。
 個人的主観が入りますが、これらをざっくりと分けると以下の感じかなという印象です。

フレームワーク 主な特徴
TensorFlow, Keras 産業向け
PyTorch, Chainer 研究向け(カスタマイズ性が高い)

 また、機械学習を始めてみようと思った際に大半の人がTensorFlowから入ると思いますが、define and runというデータ構造の定義と実行を別々に記述するという少し変わったルールがあるため、いまいち馴染めずにフェードアウトする方もいらっしゃるかと思います。
 一方でPyTorchやChainerはdefine by runを採用しているため、普段コーディングしているPythonのコードと同じようにコーディングすることができるため、親しみやすい(好みはありますが)のが特徴です。

 ただし、少しとっつきにくいdefine and runの仕組みは、最適化が容易であったり、先に定義している分計算速度が速いなどのメリットもあるそうです。一長一短あるわけですね。

 それでは、実際にPyTorchの中身について見ていきましょう。

PyTorchの構成

PyTorchは以下のような構成になっています。

構成内容 説明
torch メインのネームスペースでTensorや様々な数学関数がこのパッケージに含まれる。NumPyの構造を模している
torch.autograd 自動微分のための関数が含まれる。自動微分のon/offを制御するコンテキストマネージャのenable_grad/no_gradや独自の微分可能関数を定義する際に使用する基底クラスであるFunctionなどが含まれる
torch.nn ニューラルネットワークを構築するための様々なデータ構造やレイヤーが定義されている。例えばConvolutionやLSTM、ReLUなどの活性化関数やMSELossなどの損失関数も含まれる
torch.optim 確率的勾配降下(SGD)を中心としたパラメータ最適化アルゴリズムが実装されている
torch.utils.data SGDの繰り返し計算を回す際のミニバッチを作るためのユーティリティ関数が含まれている
torch.onnx ONNX(Open Neural Network Exchange)1の形式でモデルをエクスポートするために使用する。

Tensorの生成と変換

Tensorの生成

 Tensorの生成方法はいくつかあります。

Tensorの生成
import numpy as np
import torch

# 入れ子のlistを渡して作成
t = torch.tensor([[1, 2], [3, 4]])

# deviceを指定してGPUにTensorを作成
t = torch.tensor([[1, 2], [3, 4]], device = "cuda:0")

# dtypeを指定して倍精度のTensorを作る
t = torch.tensor([[1, 2], [3, 4]], dtype = "torch.float64")

# 0~9の数値で初期化された1次元のTensor
t = torch.arange(0, 10)

# 全値が0の100x100のTensorを作成し、toメソッドでGPUに転送
t = torch.zeros(100,100).to("cuda:0")

# 100x100のランダムなTensor
t = torch.random(100, 100)

Tensorの変換方法

 TensorはNumPyのndarrayに簡単に変換できます。ただし、GPU上のTensorはそのままでは変換できず、一度CPU上に移す必要があります。

tensorの変換
# numpyメソッドを使用してndarrayに変換
t = torch.tensor([[1, 2], [3, 4]])
nd_arr = t.numpy()

# GPU上のTensorをCPU上に移す
t = torch.tensor([[1, 2], [3, 4]], device = "cuda: 0")
t_cpu = t.to("cpu")
nd_arr = t_cpu.numpy()

# 上記を続けて記入
t = torch.tensor([[1, 2], [3, 4]], device = "cuda: 0")
nd_arr = t.to("cpu").numpy()

Tensorのインデクシング操作

 Tensorでもndarrayと同様ににインデクシング操作2をサポートしています。指定可能な方法は以下。

  • スカラーによる指定
  • 添字リスト
  • ByteTensorによるマスク配列3での指定
Tensorのインデクシング操作

t = torch.tensor([[1, 2, 3], [4, 5, 6]])

# スカラーの添字で指定
t[0, 2] # tensor(3)

# スライスで指定
t[:, :2] # tensor([[1, 2], [4, 5]])

# 添字のリストで指定
t[:, [1, 2]]  # tensor([[2, 3], [5, 6]])

# マスク配列を使用して3より大きい部分のみ選択
t[t > 3] # tensor([4, 5, 6])

# [0, 1]要素を100に置換
t[0, 1] = 100  # tensor([[1, 100, 3], [4, 5, 6]])

# スライスを使用した一括代入
t[:, 1] = 200  # tensor([[1, 200, 3], [4, 200, 6]])

# マスク配列を使用して特定条件の要素のみ置換
t[t > 10] = 20  # tensor([[1, 2, 3], [4, 5, 6]])

Tensorの演算

Tensorは四則演算や数学関数、線形代数計算などを行うことができます。ndarrayでもできることですが、特に行列積や特異値分解4などの線形代数計算はGPUが使用可能ということもあって大規模データの場合にはNumPy/SciPyを使用するよりも良いパフォーマンスが多々あります。

Tensorの四則演算

 Tensorの四則演算の可否は以下の通りです。

Tensor Tensor(同じ型)
Tensor Tensor(異なる型)
Tensor Pythonのスカラー
Tensor ndarray

 Tensor同士での四則演算でも同じ型である必要がある点が注意すべきポイントです。
 四則演算を行う際には、ベクトルとスカラーや行列とベクトル間の演算でも自動的に次元が補完されます(ブロードキャスト)。

Tensorの四則演算
# ベクトル
v = torch.tensor([1, 2, 3])
w = torch.tensor([4, 5, 6])

# 行列
m = torch.tensor([[0, 1, 2], [10, 20, 30]])
n = torch.tensor([[3, 4, 5], [40, 50, 60]])

# ベクトル - スカラー
v_pl = v + 10  # tensor([11, 12, 13])
v_mi = v - 10  # tensor([-9, -8, -7])
v_mu = v * 10  # tensor([10, 20, 30])
v_di = v / 10  # tensor([0, 0, 0])

# ベクトル - ベクトル
v_pl = v + w  # tensor([5, 7, 9])
v_mi = v - w  # tensor([-3, -3, -3])
v_mu = v * w  # tensor([4, 10, 18])
v_di = v / w  # tensor([0, 0, 0])

# 行列とベクトル
v_pl = m + v  # tensor([[ 1,  3,  5], [11, 22, 33]])
v_mi = m - v  # tensor([[-1, -1, -1], [ 9, 18, 27]])
v_mu = m * v  # tensor([[ 0,  2,  6], [10, 40, 90]])
v_di = m / v  # tensor([[ 0,  0,  0], [10, 10, 10]])

# 行列と行列
v_pl = m + n  # tensor([[3, 5, 7], [50, 70, 90]])
v_mi = m - n  # tensor([[-3, -3, -3], [-30, -30, -30]])
v_mu = m * n  # tensor([[0, 4, 10], [400, 1000, 1800]])
v_di = m / n  # tensor([[0, 0, 0], [0, 0, 0]])


 除算の際に出力が0となる箇所がありますね。お分かりかとは思いますが、演算の結果が小数点以下の値を示しても、tensorの型がintとなっているためです。回避したい場合はあらかじめfloatなどを指定しておきましょう。

PyTorchで利用可能な数学関数

 PyTorchではTensorに対して様々な数学関数を用意しています。

Tensorの各値に作用する数学関数

関数名 概要
abs 絶対値
sin 正弦
cos 余弦
exp 指数関数
log 対数関数
sqrt 平方根

集計関数

関数 概要
sum tensor内の値の合計
max tensor内の最大値
min tensor内の最小値
mean tensor内の値の平均値
std tensor内の値の標準偏差

線形代数の演算子

関数 概要
dot ベクトルの内積
mv 行列とベクトルの積
mm 行列と行列の積
matmul 引数の種類によって自動的にdot、mv、mmを選択して実行
gesv LU分解による連立方程式の解
eig, symeig 固有値分解。symeigは対象行列用
svd 特異値分解

 どのような結果が出るのか確認してみましょう(結果はかなり長い値になるので表示していません)。

線形代数の演算
m = torch.randn(100, 10)  # 100x10の行列テストデータを作成
v = torch.randn(10)

# 内積
torch.dot(v, v)

# 行列とベクトルの積
torch.mv(m, v)

# 行列積
torch.mm(m.t(), m)

# 特異値分解
u, s, v = torch.svd(m)

その他よく使う関数

関数名 概要
view Tensorの次元を変更する
cat, stack Tensor同士を結合する
transpose 次元を入れ替える

自動微分

 Tensorの持つrequires_gradTrueにすると、自動微分を行うフラグが有効になります。ニューラルネットワークを扱う場合のパラメータやデータはこのフラグがすべて有効になっています。
 requires_gradが有効なTensorに様々な演算を積み重ねていくことで、計算グラフが構築され、backwardメソッドを呼ぶことでその情報から自動微分されます。

おわりに

 今回は主にPyTorchの構成や機械学習を扱う上で必須となるTensorについてまとめました。最後までお読みいただいた皆さん、ありがとうございました。
 次回以降少しずつニューラルネットワークの構築などを行っていこうと思いますので、ご興味ある方はぜひご覧頂ければと思います。

参考

杜世橋(2018年)『現場で使える!PyTorch開発入門 深層学習モデルの作成とアプリケーションへの実装


  1. 様々な深層学習のフレームワーク間でモデルを共用するためのフォーマット 

  2. 添字を指定して配列の値を取得したり変更したりすること 

  3. 元の配列と同じサイズの配列で、配列内の各要素がTrue/Falseになっているもの。 

  4. 特異値分解(Singular Value Decomposition、 SVD)は線形代数でよく使用される計算であり、行列AをUSVのように3つの行列の積に分解する計算。
     UとVは直行行列、Sは対角成分のみの正方行列で、最小二乗法を解く際や、行列の近似・圧縮などに利用されます。 

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
102