誤差逆伝播法
誤差逆伝播法
前回までは、勾配の計算は数値微分で行いました。数値微分は、実行に時間がかかるため、より早い誤差逆伝播法を使います。
加算ノード
定義
入力x,yで出力zのとき、順伝播は
逆伝播は
なので、上位層からの出力をEとすると、
コード
class AddLayer: def __init__(self): pass def forward(self, x, y): out = x + y return out def backward(self, dout): dx = dout*1 dy = dout*1 return dx,dy
乗算ノード
定義
順伝播
逆伝播
ひっくり返る。
出力をEとすると
コード
class MulLayer: def __init__(self): self.x = None self.y = None def forward(self, x, y): self.x = x self.y = y out = x * y return out def backward(self, dout): dx = dout * self.y dy = dout * self.x return dx,dy
Affineノード
定義
順伝播
逆伝播
出力をEとすると
コード
class Affine: def __init__(self, W, b): self.W = W self.b = b self.x = None self.dW = None self.db = None def forward(self, x): self.x = x out = np.dot(x, self.W) + self.b return out def backward(self, dout): dx = np.dot(dout, self.W.T) self.dW = np.dot(self.x.T, dout) self.db = np.sum(dout, axis=0) return dx #必要なのは入力xの逆伝播のみ
ReLU
定義
順伝播
y = x (x > 0)
y = 0 ( x <= 0)
逆伝播
∂y/∂x = 1 (x > 0)
∂y/∂x = 0 (x <= 0)
コード
class Relu: def __init__(self): self.mask def forward(self, x): self.mask = (x <= 0) out = x.copy() out[self.mask] = 0 return out def backward(self, dout): dout[self.mask] = 0 dx = dout return dx
SoftmaxWithLoss
コード
class SofmaxWithLoss: def __init__(self): self.y = None self.t = None def forward(self, x, t): self.y = sofmax(x) self.t = t loss = cross_entropy_error(self.y, self.t) return loss def backward(self, dout=1): batch_size = self.t.shape[0] dx = (self.y - self.t) / batch_size #データ1個当たりの誤差 return dx
レイヤの生成
from collections import OrderedDict self.layers = OrderedDict() self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1']) self.layers['Relu1'] = Relu() self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2']) self.lastLayer = SoftmaxWithLoss()
順伝播
def predict(self, x): for layer in self.layers.values(): x = layer.forward(x) #それぞれのレイヤの順伝播を実行 return x def loss(self, x): y = self.predict(x) return self.lastLayer.forward(y, t) def gradient(self, x, t): #forward self.loss(x, t)
逆伝播を追加
def gradient(self, x, t): #forward self.loss(x, t) #backward dout = 1 dout = self.lastLayer.backward(dout) layers = list(self.layers.values()) layers.reverse() for layer in layers: dout = layers.backward(dout) grads = {} grads['W1'] = self.layers['Affine1'].dW grads['b1'] = self.layers['Affine1'].db grads['W2'] = self.layers['Affine2'].dW grads['b2'] = self.layers['Affine2'].db return grads
重みの初期値
重みの初期値
ハイパラメータとして他にも重要なのが、重みの初期値です。ここでは、XavierとHeの初期値を使ってXOR回路のニューラルネットワークを実行したいと思います。
Xavier
定義
ランダムで選んだ初期値に、前層のノードの個数nの平方で割ります。
コード
def __init__(self, input_size, hidden_size, output_size): self.params = {} self.params['W1'] = np.random.randn(input_size, hidden_size) / np.sqrt(input_size) self.params['b1'] = np.zeros(hidden_size) self.params['W2'] = np.random.randn(hidden_size, output_size) / np.sqrt(hidden_size) self.params['b2'] = np.zeros(output_size)
He
定義
Xavierの初期値にを掛けます。
コード
def __init__(self, input_size, hidden_size, output_size): self.params = {} self.params['W1'] = np.random.randn(input_size, hidden_size) / np.sqrt(input_size) * np.sqrt{2} self.params['b1'] = np.zeros(hidden_size) self.params['W2'] = np.random.randn(hidden_size, output_size) / np.sqrt(hidden_size) * np.sqrt{2} self.params['b2'] = np.zeros(output_size)
他にも
標準偏差0.01
def __init__(self, input_size, hidden_size, output_size): self.params = {} self.params['W1'] = 0.01 * np.random.randn(input_size, hidden_size) self.params['b1'] = np.zeros(hidden_size) self.params['W2'] = 0.01 * np.random.randn(hidden_size, output_size) self.params['b2'] = np.zeros(output_size)
間違ったら良くなった初期値
def __init__(self, input_size, hidden_size, output_size): self.params = {} self.params['W1'] = 1.1 ** np.random.randn(input_size, hidden_size) self.params['b1'] = np.zeros(hidden_size) self.params['W2'] = 1.1 * np.random.randn(hidden_size, output_size) self.params['b2'] = np.zeros(output_size)
出力
Xavier
('ans:', 15, '/ 100') ('ans:', 10, '/ 100') ('ans:', 22, '/ 100')
He
('ans:', 18, '/ 100') ('ans:', 17, '/ 100') ('ans:', 13, '/ 100')
標準偏差0.01
('ans:', 15, '/ 100') ('ans:', 16, '/ 100') ('ans:', 14, '/ 100')
間違ったら良くなった初期値
('ans:', 44, '/ 100') ('ans:', 40, '/ 100') ('ans:', 40, '/ 100')
結論
XavierもHeもあまりよくならなかった。ハイパラメータを自動で決めることで、良い結果が得られるかも。 ちなみに一番良かった初期値(間違ったやつ)にMomentumを使うと、
('ans:', 76, '/ 100') ('ans:', 71, '/ 100') ('ans:', 64, '/ 100')
なかなかすばらしい。
MomentumとAdaGrad
MomentumとAdaGrad
前回まではパラメータの更新に確率的勾配降下法(SGD)を使いました。精度は30%ぐらいだったので、今回はMomentumとAdaGradを使ってどの位変わるか試してみます。
SGD
定義
コード
SGDクラスを作成する。
class SGD: def __init__(self, lr=0.5): self.lr = lr def update(self, paramas, grads): for key in params.keys(): params[key] -= self.lr * grads[key]
Momentum
定義
コード
Momentumクラスを作成する。
class Momentum: def __init__(self, lr=0.01, momentum=0.9): self.lr = lr self.momentum = momentum self.v = None def update(self, params, grads): if self.v is None: self.v ={} for key, val in params.items(): self.v[key] = np.zeros_like(val) for key in params.keys(): self.v[key] = self.momentum*self.v[key] - self.lr*grads[key] params[key] += self.v[key]
AdaGrad
定義
[tex: {h←h+\frac{∂L}{∂W}\frac{∂L}{∂W}}]
[tex: {W←W-η\frac{1}{\sqrt{h}}\frac{∂L}{∂W}}]
学習回数が増えるにしたがい、パラメータ更新が小さくなる。
コード
AdaGradクラスを作成する。
class AdaGrad: def __init__(self, lr=0.01): self.lr = lr self.h = None def update(self, params, grads): if self.h is None: self.h = {} for key, val in pramas.items(): self.h[key] = np.zeros_like(val) for key in params.keys(): self.h[key] += grads[key] * grads[key] params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]+1e-7))
mainプログラム
最適化手法を選べるようにプログラムを修正する。
ans_label = np.argmax(t_train, axis=1) ans = 0 for i in range(100): network = LayerNet(2, 2, 2) optimizer = Momentum() #最適化手法を選択 for step in range(1001): batch_mask = np.random.choice([0,1,2,3], 1) x_batch = x_train[batch_mask] t_batch = t_train[batch_mask] grads = network.training(x_batch, t_batch) params = network.params optimizer.update(params, grads) if step == 1000: y = np.argmax(network.predict(x_train), axis=1) print("y:", y) a = (y == ans_label) if a.all(): ans += 1 print("ans:", ans, "/ 100")
出力
Momentum
学習率0.01 運動量0.9
('ans:', 52, '/ 100') ('ans:', 53, '/ 100') ('ans:', 51, '/ 100')
学習率0.5 運動量0.9
('ans:', 0, '/ 100') ('ans:', 0, '/ 100')
学習率0.05 運動量0.9
('ans:', 18, '/ 100')
学習率0.01 運動量0.5
('ans:', 39, '/ 100')
AdaGrad
学習率0.01
('ans:', 0, '/ 100') ('ans:', 0, '/ 100')
学習率0.5
('ans:', 7, '/ 100') ('ans:', 6, '/ 100')
結論
学習率と運動量をうまく設定すれば、Momentumを使用することで精度があがる。 AdaGradはXOR回路ではうまくいかない。 ハイパーパラメータ(学習率,運動量など)はランダムに選んで、良い結果を導けるプログラムに修正すると尚よい。
NumPyだけでXOR回路
XOR回路
XOR回路は入力x1,x2に対して、出力yを行います。 | x1| x2| y | |:-:|:-:|:-:| | 0 | 0 | 0 | | 0 | 1 | 1 | | 1 | 0 | 1 | | 1 | 1 | 0 |
多層パーセプトロン
隠れ層をもつニューラルネットワークのことです。 単純パーセプトロンを何層にも重ねたので、多層パーセプトロンといいます。 XOR回路は線形分離可能ではないため、多層パーセプトロンで解きます。
ニューラルネットワークを作成する
基本AND回路と同じで、 1.パラメータの宣言 2.学習 2.1.訓練データの推論 2.2.損失の計算 2.3.勾配の計算 2.4.パラメータの更新 3.テストデータの推論 です。
パラメータの宣言
2層で行います。
def __init__(self, input_size, hidden_size, output_size): self.params = {} self.params['W1'] = 1.5**np.random.randn(input_size, hidden_size) self.params['b1'] = np.zeros(hidden_size) self.params['W2'] = 1.5*np.random.randn(hidden_size, output_size) self.params['b2'] = np.zeros(output_size)
学習
def training(self, x, t): loss_W = lambda W: self.loss(x, t) grads = {} grads['W1'] = numerical_gradient(loss_W, self.params['W1']) grads['b1'] = numerical_gradient(loss_W, self.params['b1']) grads['W2'] = numerical_gradient(loss_W, self.params['W2']) grads['b2'] = numerical_gradient(loss_W, self.params['b2']) for key in ('W1', 'b1', 'W2', 'b2'): self.params[key] -= 0.5*grads[key] #return grads
推論
def predict(self, x): W1, W2 = self.params['W1'], self.params['W2'] b1, b2 = self.params['b1'], self.params['b2'] h1 = np.dot(x, W1) + b1 z1 = relu(h1) h2 = np.dot(z1, W2) + b2 y = softmax(h2) return y
損失の計算
def loss(self, x, t): y = self.predict(x) loss = mean_squared_error(y, t) return loss
勾配の計算
def numerical_gradient(f, x): h = 1e-4 # 0.0001 grad = np.zeros_like(x) it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite']) while not it.finished: #全ての組み合わせを計算 idx = it.multi_index tmp_val = x[idx] x[idx] = float(tmp_val) + h fxh1 = f(x) # f(x+h) x[idx] = float(tmp_val) - h fxh2 = f(x) # f(x-h) grad[idx] = (fxh1 - fxh2) / (2*h) x[idx] = tmp_val # 値を元に戻す it.iternext() return grad
パラメータの更新
for key in ('W1', 'b1', 'W2', 'b2'): self.params[key] -= 0.5*grads[key]
推論
for i in range(x_train.shape[0]): print(x_train[i], "answer", network.predict(x_train[i]))
ソースコード
#!/usr/bin/env python # -*- coding: utf-8 -*- #たまにうまくいく import numpy as np class LayerNet: def __init__(self, input_size, hidden_size, output_size): self.params = {} self.params['W1'] = 1.5**np.random.randn(input_size, hidden_size) self.params['b1'] = np.zeros(hidden_size) self.params['W2'] = 1.5*np.random.randn(hidden_size, output_size) self.params['b2'] = np.zeros(output_size) def predict(self, x): W1, W2 = self.params['W1'], self.params['W2'] b1, b2 = self.params['b1'], self.params['b2'] h1 = np.dot(x, W1) + b1 z1 = relu(h1) h2 = np.dot(z1, W2) + b2 y = softmax(h2) return y def loss(self, x, t): y = self.predict(x) loss = mean_squared_error(y, t) return loss def training(self, x, t): loss_W = lambda W: self.loss(x, t) grads = {} grads['W1'] = numerical_gradient(loss_W, self.params['W1']) grads['b1'] = numerical_gradient(loss_W, self.params['b1']) grads['W2'] = numerical_gradient(loss_W, self.params['W2']) grads['b2'] = numerical_gradient(loss_W, self.params['b2']) for key in ('W1', 'b1', 'W2', 'b2'): self.params[key] -= 0.5*grads[key] #return grads def relu(x): return np.maximum(x, 0) def softmax(a): c = np.max(a) exp_a = np.exp(a-c) sum_exp_a = np.sum(exp_a) y = exp_a / sum_exp_a return y def mean_squared_error(y, t): loss = np.sum(0.5*(y-t)**2) return loss def numerical_gradient(f, x): h = 1e-4 # 0.0001 grad = np.zeros_like(x) it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite']) while not it.finished: #全ての組み合わせを計算 idx = it.multi_index tmp_val = x[idx] x[idx] = float(tmp_val) + h fxh1 = f(x) # f(x+h) x[idx] = float(tmp_val) - h fxh2 = f(x) # f(x-h) grad[idx] = (fxh1 - fxh2) / (2*h) x[idx] = tmp_val # 値を元に戻す it.iternext() return grad x_train = np.array([[0,0], [0,1], [1,0], [1,1]]) t_train = np.array([[0,1],[1,0],[1,0],[0,1]]) #[1,1]のとき[0,0]と間違っていた network = LayerNet(2, 2, 2) for step in range(10001): batch_mask = np.random.choice([0,1,2,3], 1) x_batch = x_train[batch_mask] t_batch = t_train[batch_mask] network.training(x_batch, t_batch) #for key in ('W1', 'b1', 'W2', 'b2'): # network.params[key] -= 0.5*grad[key] if step % 1000 == 0: print("step", step) for i in range(x_train.shape[0]): print(x_train[i], "answer", network.predict(x_train[i]))
出力
たまに正しく出力されます。
('step', 10000) (array([0, 0]), 'answer', array([ 0.01287935, 0.98712065])) (array([0, 1]), 'answer', array([ 0.99375572, 0.00624428])) (array([1, 0]), 'answer', array([ 0.99372009, 0.00627991])) (array([1, 1]), 'answer', array([ 0.00540053, 0.99459947]))
100回中何回成功するかを計測するプログラム
#network = LayerNet(2, 2, 2) ans_label = np.argmax(t_train, axis=1) ans = 0 for i in range(100): network = LayerNet(2, 2, 2) for step in range(1001): batch_mask = np.random.choice([0,1,2,3], 1) x_batch = x_train[batch_mask] t_batch = t_train[batch_mask] network.training(x_batch, t_batch) if step == 1000: y = np.argmax(network.predict(x_train), axis=1) print("y:", y) a = (y == ans_label) if a.all(): ans += 1 print("ans:", ans, "/ 100")
学習率0.5のプログラムを3回実行した結果。
('ans:', 26, '/ 100') ('ans:', 30, '/ 100') ('ans:', 27, '/ 100')
およそ30/100でしか正解しない。
学習率0.01
('ans:', 15, '/ 100') ('ans:', 29, '/ 100')
改良点
パラメータを最適化していく。
1.確率的勾配降下法ではなく、Momentum、AdaGradを使ってみる。
2.重みの初期値を変える。Xavierの初期値か、ReLUをつかっているためHeの初期値を使う
NumPyだけでAND回路
AND回路
AND回路は入力x1,x2に対して、出力yを行います。 | x1| x2| y | |:-:|:-:|:-:| | 0 | 0 | 0 | | 0 | 1 | 0 | | 1 | 0 | 0 | | 1 | 1 | 1 |
入力は2つ、出力は1つですが、one-hot表現以外のやり方ができなかったので、出力も2つにします。
単純パーセプトロン
単純パーセプトロンは、隠れそうのないニューラルネットワークのことです。 AND回路の線形分離可能であるため、単純パーセプトロンのニューラルネットワークで作成することができます。
ニューラルネットワークを作成する
ニューラルネットワークの基本は、 1.パラメータの宣言 2.学習 2.1.訓練データの推論 2.2.損失の計算 2.3.勾配の計算 2.4.パラメータの更新 4.テストデータの推論 です。
パラメータの宣言
隠れそうはありません。
def __init__(self,input_size, output_size): self.params = {} self.params['W'] = np.zeros([input_size,output_size]) self.params['b'] = np.zeros([output_size])
学習
学習データの推論
行列積とソフトマックス関数で出力を計算します。
def predict(self, x): W = self.params['W'] b = self.params['b'] z = np.dot(x, W)+b y = softmax(z) return y
損失の計算
推論で得た出力をもとに、損失の大きさを計算します。
def loss(self, x, t): y = self.predict(x) return mean_squared_error(y,t) #損失を返す
パラメータの更新
損失をもとにパラメータを更新します。損失が正ならば負の向きに更新します。損失が大きいほど大きい値で更新します。
self.params['W'] -= 0.5*grads['dW'] self.params['b'] -= 0.5*grads['db']
テストデータの推論
for i in range(x_train.shape[0]): print(x_train[i], "answer", network.predict(x_train[i]))
ソースコード
#!/usr/bin/env python # -*- coding: utf-8 -*- import numpy as np class LayerNet: def __init__(self,input_size, output_size): self.params = {} self.params['W'] = np.zeros([input_size,output_size]) self.params['b'] = np.zeros([output_size]) def predict(self, x): W = self.params['W'] b = self.params['b'] z = np.dot(x, W)+b y = softmax(z) return y def loss(self, x, t): y = self.predict(x) return mean_squared_error(y,t) #損失を返す def training(self, x, t): loss_W = lambda W: self.loss(x, t) grads = {} grads['dW'] = numerical_gradient(loss_W, self.params['W']) #勾配を代入 grads['db'] = numerical_gradient(loss_W, self.params['b']) #勾配を代入 self.params['W'] -= 0.5*grads['dW'] self.params['b'] -= 0.5*grads['db'] #return grads def mean_squared_error(y, t): return np.sum(0.5*(y-t)**2) def softmax(a): c = np.max(a) exp_a = np.exp(a-c) sum_exp_a = np.sum(exp_a) y = exp_a / sum_exp_a return y def numerical_gradient(f, x): h = 1e-4 # 0.0001 grad = np.zeros_like(x) it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite']) while not it.finished: #全ての組み合わせを計算 idx = it.multi_index tmp_val = x[idx] x[idx] = float(tmp_val) + h fxh1 = f(x) # f(x+h) x[idx] = float(tmp_val) - h fxh2 = f(x) # f(x-h) grad[idx] = (fxh1 - fxh2) / (2*h) x[idx] = tmp_val # 値を元に戻す it.iternext() return grad x_train = np.array([[0,0], [0,1], [1,0], [1,1]]) t_train = np.array([[0,1],[0,1],[0,1],[1,0]]) network = LayerNet(x_train.shape[1], t_train.shape[1]) for step in range(1001): batch_mask = np.random.choice([0,1,2,3], 1) x_batch = x_train[batch_mask] t_batch = t_train[batch_mask] network.training(x_batch, t_batch) #network.params['W'] -= 0.5*grad['dW'] #network.params['b'] -= 0.5*grad['db'] if step % 100 == 0: print("step", step) for i in range(x_train.shape[0]): print(x_train[i], "answer", network.predict(x_train[i]))
出力
正しく出力されました。
('step', 1000) (array([0, 0]), 'answer', array([ 7.61342093e-04, 9.99238658e-01])) (array([0, 1]), 'answer', array([ 0.08064322, 0.91935678])) (array([1, 0]), 'answer', array([ 0.0666248, 0.9333752])) (array([1, 1]), 'answer', array([ 0.89151362, 0.10848638]))
NumPyの基本
NumPy
NumPyは数値計算を簡単に行うためのライブラリです。
特に強力なのが行列計算です。ディープラーニングの計算はほとんどが行列計算です。NumPyでは多次元の行列計算も簡単に行うことができます。
NumPyのインポート
NumPyは外部ライブラリです。そのため、初めにインポートする必要があります。 インポートするときは便宜上、次からnpと省略して使えるようにします。
import numpy as np
NumPy配列の作成
それでは、NumPy配列を作成したいと思います。 NumPy配列は以下のように作成します。比較のため普通のリストも作成しましょう。
np_array1 = np.array([1,2,3]) np_array2 = np.array([4,5,6]) array1 = [1,2,3] array2 = [4,5,6]
型を見ると、それぞれの型が違うことがわかります。
print(type(np_array1)) #numpy.ndarray print(type(array1)) #list
NumPy配列はshapeメソッドを使うことで、形を知ることができます。
np_array1 = np.array([[1,2,3],[4,5,6]]) np_array2 = np.array([[1,2],[3,4],[5,6]]) print(np_array1.shape) #(2, 3) print(np_array2.shape) #(3, 2)
NumPyの加減乗除
NumPy配列の足し算について、見ていきたいと思います。 NumPy配列の足し算を以下のコードで行います。
print(np_array1+np_array2) #[5,7,9] print(array1+array2) #[1,2,3,4,5,6]
結果から分かるように、NumPy配列の場合には2つの配列の要素ごとに足し算が行われ、要素数は変わりません。 それに対し、リストの足し算の場合には2つのリストの連結が行われています。
同様にかけ算についても、以下のように行います。
print(np_array1*np_array2) #[4,10,18] print(array1*array2) #エラー
NumPy配列は各要素ごとのかけ算であったのに対し、リストではエラーとなります。 引き算、割り算も同様の結果になります。
NumPyの行列積
NumPyでは行列積の計算を簡単に行うことができます。 まずは、多次元配列を作成します。
np_array2_3 = np.array([[1,2],[3,4],[5,6]]) np_array3_2 = np.array([[1,2,3],[4,5,6]]) array2_3 = [[1,2],[3,4],[5,6]] array3_2 = [[1,2,3],[4,5,6]]
リストを使っての行列積の計算の場合には、2×3の行列と3×2の行列をfor文のループを使って行い、2×2の行列を作成すると思います。
sum_array = [[0,0],[0,0]] for i in range(len(array2_3)): for j in range(len(array2_3)): for k in range(len(array2_3[0])): sum_array[i][j] += (array2_3[i][k] * array3_2[k][j]) print(sum_array) #[[22, 28], [49, 64]]
NumPyを使うと、簡単に多次元配列の計算が可能です。 NumPyで作成した配列の場合には以下のようにできます。
print(np.dot(np_array2_3, np_array3_2)) #[[22, 28], [49 64]] 多少表記は異なる
NumPyのライブラリ
行列積の計算では、NumPyのdotというメソッドが使われました。NumPyには他にも便利なメソッドが多くあるので、後で使うものも含めて見ていきたいと思います。
三角関数
np_array = np.array([3.141,-3.141]) print(np.sin(np_array)) #[ 0.00059265 -0.00059265] print(np.cos(np_array)) #[-0.99999982 -0.99999982] print(np.tan(np_array)) #[-0.00059265 0.00059265]
指数関数
np_array = np.array([0, 1]) print(np.exp(np_array)) #[ 1. 2.71828183]
対数関数
np_array = np.array([1, 2.71828]) print(np.log(np_array)) #[ 0. 0.99999933]
最大値
np_array = np.array([-1,-2,1,2,0]) print(np.max(np_array)) #2 print(np.min(np_array)) #-2
NumPy配列の行ごと(列ごと)の合計
行を軸として合計をとる
np_array1 = np.array([[1,2,3],[4,5,6]]) np_array2 = np.array([[1,2],[3,4],[5,6]]) print(np.sum(np_array1, axis=0)) #[5 7 9] print(np.sum(np_array2, axis=0)) #[ 9 12]
列を軸として合計をとる
np_array1 = np.array([[1,2,3],[4,5,6]]) np_array2 = np.array([[1,2],[3,4],[5,6]]) print(np.sum(np_array1, axis=1)) #[ 6 15] print(np.sum(np_array2, axis=1)) #[ 3 7 11]
ランダム値の生成
x~yの範囲の中から1つ取り出す。np.random.uniform(x,y)
print(np.random.uniform(-3,3)) #-3~3の範囲の数字を出力 print(np.random.uniform(-3,3,[2,3])) #-3~3の範囲の数字を[2,3]で出力
0~xの範囲の中からy個取り出す。np.random.choice(x,y)
print(np.random.choice(10,5)) #0~10の範囲の数字を5個取り出した配列を出力
標準正規分布から値を取り出し、行数x,列数yの配列を作成する。np.random.randn(x,y)
print(np.random.randn(2,3)) #2×3の行列を出力
平均x,分散yに従う正規分布から値を1個取り出す。np.random.normal(x,y)
print(np.random.normal(50,10)) #平均50,分散10の正規分布に従う
コインを投げるという試行が、試行回数n,表の出る確率pとき、コインの表が出る確率は二項分布に従う。np.random.binomial(n,p)
print(np.random.binomial(n=100,p=0.3)) #試行回数50,確率0.3 nを増やすほど3割に近づく
Pythonの基本
Pythonの基本
データ型
今のディープラーニングのフレームワークのほとんどが、Pythonで書かれています。ここでは、必要最低限の知識を書いていきたいと思います。
Pythonでは、変数への代入の際に型変換を自動で行ってくれます。そのため、変数宣言は不要となります。 以下のコードで変数に代入を行います。下のコードを書いたら、Shit+Enterを押しましょう。
x = 5 y = 3.14 z = "Hello"
それでは、それぞれの型を見てみたいと思います。 型の表示には、typeメソッドを使います。
print(type(x)) #int print(type(y)) #float print(type(z)) #str
すると、それぞれint, Float, strと出たと思います。
リスト
次に重要なのが、リストです。これはC言語の配列と同じです。宣言するには要素を} ]と書いていきます。
a = [0,1,2,3,4]
リストの型と、全要素を表示するには次のようにします。
print(type(a)) #list print(a) #[0,1,2,3,4]
また、3番目の要素だけを抜き出したいときには次のようにします。リストの番号は0から始まることに注意です。
print(a[2]) #2
次にすべての要素を一つずつ取り出しましょう。
このとき、for文を使いたいと思います。
for i in a: print(i) #0~4までを出力
すべての要素がひとつずつ取り出され、出力されていることがわかると思います。
次に多次元リストも作成しましょう。
a_2 = [[1,2,3],[4,5,6]]
1行2列の取り出し方は次のようになります。
print(a_2[0][1]) #2
また、1行目だけを取り出すには次のようにします。
print(a_2[0]) #[1,2,3]
スライシング
そして、すごく重要なのがスライシングです。これは、リストに含まれる必要な要素だけを取り出すことができます。 例えば、さきほどのリストを使いましょう。
a = [0,1,2,3,4]
このとき、左から0番目の要素と名付けたとします。 0~2番目の要素(1,2,3)を取り出したいときは次のようにします。
print(a[0:3]) #[0,1,2]
1~2番目の要素を取り出したいときは次のようにします。
print(a[1:3]) #[1,2]
また、0~2番目まで、3~4番目までの要素を取り出したいときは次のようになります。
print(a[:3]) #[0,1,2] print(a[3:]) #[3,4]
次に,0~4番目の要素を2ステップごとに取り出したいときは次のように書きます。
print(a[0:5:2]) #[0,2,4] print(a[::2]) #[0,2,4]
ディクショナリ
ディクショナリはキーと値のペアを作成します。C++だとMAPに相当します。
ディクショナリはのように書いていきます。
dic = {'key1': 1, 'key2': 2, 'key3': 3}
出力をするときはキーを指定すると、値が返されます。
print(dic['key1']) #1
また、値を変更する際には次のように行います。
dic['key1'] = 10 print(dic['key1']) #10
他にもタプルなどのデータ型がありますが、あまり使用しないため、説明しません。
次はnumpyの説明をしたいと思います。