Ubuntu 20.04 / 18.04 環境で eddy_cuda10.2 (in FSL 6.0.5.x), PyTorch, Tensorflow 2 を使えるようにCUDA 10.2, 11.0, 11.5をセットアップする方法

私のメインマシンは Lin4Neuro 18.04 ですが、そろそろ Lin4Neuro 20.04 への移行を考えています。

今、実験機には NVIDIA GeForce RTX 2070 が備え付けられています。
これを使って、FSL 6.0.5 の eddy をGPUが使えるように設定し、なおかつ、Tensorflow, Pytorch といった Deep Learning のフレームワークも使えるようにしたいと思います。

FSL 6.0.5 にはデフォルトで CUDA 10.2 に対応した eddy_cuda10.2 が配布されています。なので、CUDA 10.2を入れることにします。

なお、これは Ubuntu 18.04 でも全く問題なくできることがわかりましたので、タイトルを変更しました。

続きを読む

【PyTorch】サンプル① 〜NUMPY〜


1. 目的
2. 前準備
3. 予備知識
4. NumPyのインポート
5. データ
6. 重み付けの初期化
7. 学習
8. データの入力
9. 重み(Weight)の勾配計算
10. 損失の計算
11. 重みの更新
12. 実行
12.1. 1_numpy.py


1. 目的

PyTorchのチュートリアルWarm-up: numpyを参考にNumpyを使って、損失(loss)や重み(weight)の計算をする。

PyTorchの特徴の一つである、テンソルとNumpyの違いを理解するための前準備。

2. 前準備

PyTorchのインストールはこちらから。

初めて、Google Colaboratoryを使いたい方は、こちらをご覧ください。

3. 予備知識

脳神経細胞は、樹上突起(Dendrites)、細胞体(Soma)、核(Nucleus)、軸索(Axon)、軸索終末(Axon Terminals)で構成されます。

(Credit: https://commons.wikimedia.org/wiki/File:Neuron_-_annotated.svg)

この脳神経細胞を数学的にモデルしたのが、パーセプトロンです。
神経樹上から細胞体に向けてやってくる信号(Xn)は、すべてが重要であるわけではありません。
入力される信号の中には、必要なものとそうでないものが混じっていると考えて、各信号に対して重み付け(Wn)をします。
神経樹上からの信号(Xn)は重みづけ(Wn)され、合算(Sum Σ)されます。
その合算した信号(z)が、その神経細胞を活性化させるかどうかを活性化関数(Activation function σ)でモデルします。
最後に、活性化関数からの出力に対して重み付けをして次のパーセプトロンに信号(a)を渡します。

(Credit: https://pythonmachinelearning.pro/perceptrons-the-first-neural-networks/)

今回は、パーセプトロンを用いて、入力される信号(x)からyを予測するケースを考えます。

4. NumPyのインポート

import numpy as np

5. データ

バッチサイズNを64、入力の次元D_inを1000、隠れ層の次元Hを100、出力の次元D_outを10とします。

# N is batch size; D_in is input dimension;
# H is hidden dimension; D_out is output dimension.
N, D_in, H, D_out = 64, 1000, 100, 10

入力(x)と予測したい(y)を乱数で定義します。

# Create random input and output data
x = np.random.randn(N, D_in)
y = np.random.randn(N, D_out)

6. 重み付けの初期化

乱数を使って重みを初期化します。

# Randomly initialize weights
w1 = np.random.randn(D_in, H)
w2 = np.random.randn(H, D_out)

7. 学習

学習率を1e-6として、学習回数を500回とします。

learning_rate = 1e-6
for t in range(500):

8. データの入力

入力(x)と重み(w1)を掛け算.dotすることで重み付けをします(h)。
重み付けした値(h)の要素から、np.maximum(h,0)で、0以上のものは残し、0以下のものは0とします。
最後に、重み(w2)を掛け合わせて重み付けします。この値がパーセプトロンの予測値(y_pred)となります。

    # Forward pass: compute predicted y
    h = x.dot(w1)
    h_relu = np.maximum(h, 0)
    y_pred = h_relu.dot(w2)

9. 重み(Weight)の勾配計算

これより先は、パーセプトロンが予測した値(y_pred)と答え(y)を見比べて、正しく答え(y)を予測できるようにパーセプトロンのパラメータを更新していきます。

まず、重み(w1, w2)の勾配(grad_w1, grad_w2)を計算します。

    # Backprop to compute gradients of w1 and w2 with respect to loss
    grad_y_pred = 2.0 * (y_pred - y)
    grad_w2 = h_relu.T.dot(grad_y_pred)
    grad_h_relu = grad_y_pred.dot(w2.T)
    grad_h = grad_h_relu.copy()
    grad_h[h < 0] = 0
    grad_w1 = x.T.dot(grad_h)

10. 損失の計算

パーセプトロンが予測した値(y_pred)と答え(y)との間の二乗誤差を計算しこれを損失(loss)とします。
np.squreareでy_predとyの差を二乗して、sum()で平均しています。
各学習回数ごとに、学習回数(t)と二乗誤差(loss)を表示します。

    # Compute and print loss
    loss = np.square(y_pred - y).sum()
    print(t, loss)

11. 重みの更新

計算した勾配(grad_w1, grad_w2)をもとに、重み(w1, w2)を更新します。

確率勾配降下法(SGD: stochastic gradient descent)は、重みを更新する上でよく使われる最適化アルゴリズムで、以下の式で表されます。

weight = weight - learning_rate * gradient

SGDは、以下のコードで実行できます。

    # Update weights
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2

12. 実行

以下のコードを1_numpy.pyとして保存します。

12.1. 1_numpy.py

import numpy as np

# N is batch size; D_in is input dimension;
# H is hidden dimension; D_out is output dimension.
N, D_in, H, D_out = 64, 1000, 100, 10

# Create random input and output data
x = np.random.randn(N, D_in)
y = np.random.randn(N, D_out)

# Randomly initialize weights
w1 = np.random.randn(D_in, H)
w2 = np.random.randn(H, D_out)

learning_rate = 1e-6
for t in range(500):
    # Forward pass: compute predicted y
    h = x.dot(w1)
    h_relu = np.maximum(h, 0)
    y_pred = h_relu.dot(w2)

    # Compute and print loss
    loss = np.square(y_pred - y).sum()
    print(t, loss)

    # Backprop to compute gradients of w1 and w2 with respect to loss
    grad_y_pred = 2.0 * (y_pred - y)
    grad_w2 = h_relu.T.dot(grad_y_pred)
    grad_h_relu = grad_y_pred.dot(w2.T)
    grad_h = grad_h_relu.copy()
    grad_h[h < 0] = 0
    grad_w1 = x.T.dot(grad_h)

    # Update weights
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2

保存ができたら実行しましょう。
左の数字が学習回数、右の数値がパーセプトロンの推定値と実際の答えと二乗誤差です。
学習を重ねるごとに、二乗誤差が小さくなることがわかります。

$ python3 1_numpy.py 
0 33318410.89325847
1 33449484.266180404
2 42189212.89431849
3 51379306.420906566
4 48992878.8013583

...

499 1.529654790074364e-05