AAI-2017
2017年度Deep Learning基礎講座(公開講座)の第2回のまとめ
(第1回は授業ガイダンスのためまとめはない)
第2回はnumpy,scikit-learn,matplotlibの基本的な使い方を教えた講座
演習システムiLect
講座で利用した演習システム
基本はjupyterの環境なので自分で用意できれば使わなくてもよさそう
講師
Yusuke Sugomori
100 numpy experiment
講座はnumpyなどを使うため授業についてこれるように用意されている練習問題100問
numpy
numpyのまとめ
個人的に知らなかったり忘れていたものだけ載せる
numpyのバージョンを表示
np.__version__
# >>1.11.3等
numpyのコンフィグを表示
np.show_config()
# >> いっぱい情報が出てくる
関数の情報を表示
np.info(np.add)
# > パラメータや戻り値や説明や使用例などが出力される
配列の初期化
スライス
np.arange(1, 2, 0.1) # start = 1, end = 2, slice = 0.1
# > [ 1. 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9]
N等分
np.linspace(0, 2, 5)
# > [ 0. 0.5 1. 1.5 2. ]
配列の操作
スライス
a[start : end : slice]
のslice
を負にすると逆順で取得する
# 2行2列の配列
W = np.array([[1, 2], [3, 4]])
#> [[1 2]
#> [3 4]]
#行を逆順で取得
#列に関しては記載しない(省略記法)ので先頭から取得
W[::-1]
#>[[3 4]
#> [1 2]]
#列を逆順で取得
#行に関しては記載しない(省略記法)ので先頭から取得
W[:, ::-1]
#>[[2 1]
#> [4 3]]
#行も列も逆順で取得
W[::-1, ::-1]
#> [[4 3]
#> [2 1]]
色々なインデックスによる要素のアクセス法
#二次元配列を用意
x = np.arange(1, 9).reshape(2, 4)
# > [[1 2 3 4]
# > [5 6 7 8]]
#xの(0,0), (1,1), (0,2), (1,3)の要素を取得して新しい配列にする
#パターン1
p1 = x[[0, 1, 0, 1], [0, 1, 2, 3]]
#パターン2
p2 = np.array([x[0, 0], x[1, 1], x[0, 2], x[1, 3]])
#パターン3
a = np.array([0,1,0,1])
b = np.array([0,1,2,3])
p3 = x[a,b]
#p1,p2,p3共に
# > [1 6 3 8]
条件がTrueの要素だけ選び出す
#配列を用意
x = np.arange(50, 60)
# > [50 51 52 53 54 55 56 57 58 59]
#index用の配列を用意 偶数indexだけTrue
indexes = np.arange(10)%2==0
# > [ True False True False True False True False True False]
x[indexes]
# > [50, 52, 54, 56, 58]
集約関数のaxis
sum
などの集約関数でaxis
を指定すると行ごと、列ごとなどで集約できる
# 2行2列の配列
W = np.array([[1, 2], [3, 4]])
#> [[1 2]
#> [3 4]]
#普通に全てを合計
#2種類の書き方を記す
W.sum()
np.sum(W)
#> 10
#列方向に足す
W.sum(axis=0)
np.sum(W,axis=0)
#> [4 6]
#行方向に足す
W.sum(axis=1)
np.sum(W,axis=1)
#> [3 7]
ノルム
# 配列を用意
x = np.array([7, 8, 9])
# > [7,8,9]
# (|7|^1+|8|^1+|9|^1)^(1/1)
n = np.linalg.norm(x, ord=1)
# > 24
# (|7|^2+|8|^2+|9|^2)^(1/2)
n = np.linalg.norm(x, ord=2)
# > 13.9283882772
# (|7|^3+|8|^3+|9|^3)^(1/3)
n = np.linalg.norm(x, ord=3)
# > 11.6569533665
newaxis
次元を追加する
# 配列を用意
x = np.array([7, 8, 9])
# > [1 2 3]
x2 = x[np.newaxis,:]
# > [[1,2,3]]
x3 = x[:,np.newaxis]
# > [[1]
# > [2]
# > [3]]
行列積
# 行列を用意
W = np.array([[1, 2, 3], [4, 5, 6]])
x = np.array([7, 8, 9])
#行列積
y1 = np.matmul(W, x)
y2 = np.dot(W, x)
#y1, y2ともに
# > [ 50 122]
テンソル積
このあたりからついていけなくなった
テンソル積自体知らなかったのでこのあたりで勉強
・numpyやchainerでのベクトル、行列、テンソルの積関連演算まとめ
・もういちどだけ内積・外積
# 行列を用意
x = np.arange(8).reshape(2,2,2)
# >[[[0 1]
# > [2 3]]
# > [[4 5]
# > [6 7]]]
a1 = np.tensordot(x, x, axes=2)
# > [[28 34]
# > [76 98]]
a2 = np.tensordot(x, x, axes=1)
# > [[[[ 4 5]
# > [ 6 7]]
# >
# > [[12 17]
# > [22 27]]]
# >
# > [[[20 29]
# > [38 47]]
# >
# > [[28 41]
# > [54 67]]]]
アインシュタインの縮約規則
テンソル積一般を表現できる
3つ以上のテンソル間の演算も一度に実現可能
積和の式が与えられた時のeinsumの表現は一般に次のようにして得る
(例:$c_{ik} = \sum_{j} a_{ij}\times b_{jk}$)
- 変数名を消す(例:$ik = \sum_{j} ij \times jk$)
- 積($\times$)をカンマで置き換える(例:$ik = \sum_{j} ij, jk$)
- シグマを消す(例:$ik = ij, jk$)
- 左辺右辺を反転させ、等号を->にする(例:$ij, jk -> ik$)
(例)
np.einsum('ij,jk->ik', A, B)
:行列積$\sum_{j} a_{ij}b_{jk}$
np.einsum('i,i->', v, u)
:ベクトルの内積$\sum_{i} v_{i}u_{i}$
#行列を用意
A = np.arange(25).reshape(5,5)
# > [[ 0 1 2 3 4]
# > [ 5 6 7 8 9]
# > [10 11 12 13 14]
# > [15 16 17 18 19]
# > [20 21 22 23 24]]
b = np.arange(5)
# > [0 1 2 3 4]
b2 = np.arange(5) + 1
# > [1 2 3 4 5]
# トレース(対角成分の和)
tr1 = np.einsum('ii', A))
tr2 = np.trace(A)
tr3 = A.trace()
#tr1,tr2,tr3共に
# > 60
# 転置
t1 = np.einsum('ji', A))
t2 = A.T
#t1,t2共に
# > [[ 0, 5, 10, 15, 20],
# > [ 1, 6, 11, 16, 21],
# > [ 2, 7, 12, 17, 22],
# > [ 3, 8, 13, 18, 23],
# > [ 4, 9, 14, 19, 24]]
# 内積
in1 = np.einsum('i,i', b, b2))
in2 = np.inner(b, b2)
#in1,in2共に
# > 40
# 対角成分
di1 = np.einsum('ii->i', A))
di2 = np.diag(A)
# di1,di2共に
# > [ 0 6 12 18 24]
# 軸指定和
s1 = np.einsum('ij->j', A))
s2 = np.sum(A, axis=0)
#s1,s2共に
# > [50 55 60 65 70]
# 行列ベクトル積
mat1 = np.einsum('ij,j->i', A, b))
mat2 = np.matmul(A, b)
#mat1,mat2共に
# > [ 30 80 130 180 230]
# outer product(直積。クロス積ではない)
outer1 = np.einsum('i,j->ij', b, b2))
outer2 = np.outer(b, b2)
#outer1,outer2共に
# > [[ 0 0 0 0 0]
# > [ 1 2 3 4 5]
# > [ 2 4 6 8 10]
# > [ 3 6 9 12 15]
# > [ 4 8 12 16 20]]
# 行列積(matmul)
#新しい行列を用意
a1 = np.arange(6).reshape((3,2))
# > [[0 1]
# > [2 3]
# > [4 5]]
a2 = np.arange(12).reshape((4,3))
# > [[ 0 1 2]
# > [ 3 4 5]
# > [ 6 7 8]
# > [ 9 10 11]]
matm1 = np.einsum('ij,ki->jk', a1, a2))
matm2 = np.matmul(a1.T, a2.T))
#matm1,matm2共に
# > [[10 28 46 64]
# > [13 40 67 94]]
# テンソル積(tensordot)
#新しい行列を用意
b1 = np.arange(18).reshape(2,3,3)
# > [[[ 0 1 2]
# > [ 3 4 5]
# > [ 6 7 8]]
# >
# > [[ 9 10 11]
# > [12 13 14]
# > [15 16 17]]]
b2 = np.arange(36).reshape(3,3,4)
# > [[[ 0 1 2 3]
# > [ 4 5 6 7]
# > [ 8 9 10 11]]
# >
# > [[12 13 14 15]
# > [16 17 18 19]
# > [20 21 22 23]]
# >
# > [[24 25 26 27]
# > [28 29 30 31]
# > [32 33 34 35]]]
ten1 = np.einsum('ijk,jkl->il', b1, b2))
ten2 = np.tensordot(b1, b2)
#ten1,ten2共に
# > [[ 816 852 888 924]
# > [2112 2229 2346 2463]]
問題 1
講義中に出た問題。解答は後述
1-1.
x = np.array([7, 8, 9])
W = np.array([[1, 2, 3], [4, 5, 6]])
と同様の x
, W
を得るように np.arange
を用いてコードを書いてください。
1-2.
以下のような表式を得るように W
を変形してください。
[[ 1. 0. -1.]
[ 4. 3. 2.]]
ヒント: 縦の差は3,横の差は-1
1-3.
エディントンのイプシロン
「エディントンのイプシロン」を用いてベクトルの外積(クロス積)を実装してください。
matplotlib
あとで追記...
scikit-learn(sklearn)
pythonの機械学習ライブラリ
深層学習についてはサポートされていないので便利機能を中心に利用する
shuffle
numpy配列の要素の順番をランダムに入れ替える
import numpy as np
from sklearn.utils import shuffle
#seedを設定しないでシャッフル
np.random.seed()
sh1 = shuffle(range(10))
# 実行のたびに変わる
# > [5, 6, 2, 8, 4, 1, 0, 3, 7, 9]
sh2 = shuffle(range(10))
# 実行のたびに変わる
# > [1, 9, 0, 4, 7, 5, 6, 8, 3, 2]
#seedを設定してシャッフル
#1回目
np.random.seed(12345)
x1 = shuffle(range(10))
y1 = shuffle(range(10))
#2回目
np.random.seed(12345)
x2 = shuffle(range(10))
y2 = shuffle(range(10))
#x1,x2共に
# > [0, 7, 3, 9, 6, 4, 1, 8, 5, 2]
#y1,y2共に
# > [4, 0, 9, 5, 7, 3, 8, 6, 1, 2]
#RandomStateによるseedのカプセル化
#rng0とrng1を設定して2回実行
rng0 = np.random.RandomState(12345)
rng1 = np.random.RandomState(34567)
rng0_0_0 = shuffle(range(10), random_state=rng0)
rng1_0_0 = shuffle(range(10), random_state=rng1)
rng0_1_0 = shuffle(range(10), random_state=rng0)
rng1_0_0 = shuffle(range(10), random_state=rng1)
#rng0とrng1を設定して実行順序を変えて2回実行
rng0 = np.random.RandomState(12345)
rng1 = np.random.RandomState(34567)
rng1_0_1 = shuffle(range(10), random_state=rng1)
rng1_1_1 = shuffle(range(10), random_state=rng1)
rng0_0_0 = shuffle(range(10), random_state=rng0)
rng0_0_1 = shuffle(range(10), random_state=rng0)
#rng0_0_0とrng0_0_1が共に
# > [0, 7, 3, 9, 6, 4, 1, 8, 5, 2]
#rng0_1_0とrng0_1_1が共に
# > [4, 0, 9, 5, 7, 3, 8, 6, 1, 2]
#rng1_0_0とrng1_0_1が共に
# > [3, 0, 5, 1, 7, 8, 4, 9, 6, 2]
#rng1_1_0とrng1_1_1が共に
# > [9, 7, 4, 1, 6, 5, 2, 0, 8, 3]
train_test_split
読み込んだデータから得られた配列等を、学習しやすいように学習データとテストデータに分けてくれる
from sklearn.model_selection import train_test_split
import string
#string.ascii_uppercaseで'ABCDEFGHIJKLMNOPQRSTUVWXYZ'の配列を得る
lettersAtoE = string.ascii_uppercase[:5]
# > 'ABCDE'
#入力をいい感じに分けてくれる その時のインデックスも配列として得られる
train0to4, test0to4, trainAtoE, testAtoE = train_test_split(range(5), lettersAtoE)
#train0to4 学習データのindex
# > [3, 1, 2]
#trainAtoE 学習データ
# > ['D', 'B', 'C']
#test0to4 テストデータのindex
# > [4, 0]
#test0to4 テストデータ
# > ['E', 'A']
fetch_mldata
mldata.orgから学習データを取得する
from sklearn.datasets import fetch_mldata
# MNIST originalデータを読み込む、存在しなければネットからダウンロードする
mnist = fetch_mldata('MNIST original')
# mnist.dataにはたくさんの画像データ(手書き数字)がある
#画像サイズを表示
print(mnist.data.shape)
# > (70000, 784) 28*28=784の画像が70000枚
#画像のラベルを表示
print(set(mnist.target))
# > {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0} 0~9の手書き数字
#画像を表示
plt.imshow(mnist.data[0].reshape(28, 28), cmap='gray', interpolation='none')
plt.show()
# > 28*28の画像にしてgrayscaleで表示
機械学習のサンプル
# Select one of Classifeir (LinearSVC, KNeighbor, SDG) using validation set
# and test best set
from sklearn.svm import LinearSVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import SGDClassifier
from sklearn.metrics import accuracy_score
mnist = fetch_mldata('MNIST original')
M = len(mnist.data)
N = 2000 # Use part of MNIST data to save computation time
# randomly select N numbers from 0 to M
selected = shuffle(range(M))[:N]
# Split data into Train, Valid, Test
train_valid_X, test_X, train_valid_y, test_y =\
train_test_split(mnist.data[selected], mnist.target[selected])
train_X, valid_X, train_y, valid_y =\
train_test_split(train_valid_X, train_valid_y)
classifiers = [LinearSVC(), KNeighborsClassifier(), SGDClassifier()]
# Train each classifier with Train set
accs = []
for clf_type, classifier in enumerate(classifiers):
classifier.fit(train_X, train_y)
pred_train = classifier.predict(train_X)
acc_train = accuracy_score(train_y, pred_train)
pred_valid = classifier.predict(valid_X)
acc_valid = accuracy_score(valid_y, pred_valid)
print("classifier type: %d, Train Accuracy: %f, Validation Accuracy %f" \
% (clf_type, acc_train, acc_valid))
accs.append(acc_valid)
# Chose best classifier with the highest validation accuracy
i_clf_best = np.argmax(accs)
print("Best Classifier: %d" % i_clf_best)
clf_best = classifiers[i_clf_best]
# Test selected classifier
pred = clf_best.predict(test_X)
acc = accuracy_score(test_y, pred)
print("Test(Best Classifier): %f" % acc)
collections
あとで追記
問題 2
講義中に出た問題。解答は後述
2-1. mnist.data
には画像は何枚あるか
2-2. 画像データはどのようなグレースケールで表されているか
2-3. 4枚の数字を 縦2 $\times$ 横2 で表示する
2-4. mnist にはどの数字がどれだけ入っているか
問題の解答
1-1
x = np.arange(7,10)
W = np.arange(1,7).reshape(2,3)
1-2
np.arange(-1,5).reshape(2,3)[::,::-1]
1-3
def my_cross(u, v):
eps = np.zeros((3, 3, 3))
eps[0, 1, 2] = eps[1, 2, 0] = eps[2, 0, 1] = 1
eps[0, 2, 1] = eps[2, 1, 0] = eps[1, 0, 2] = -1
return np.einsum('ijk,j,k->i', eps, u, v)
#確認
u = np.array([2,3,4])
v = np.array([1,2,5])
print(my_cross(u, v))
# > [ 7. -6. 1.]
print(np.cross(u, v))
# > [ 7 -6 1]
2-1
import sklearn
mnist = sklearn.datasets.fetch_mldata('MNIST original')
print(len(mnist.data))
# > 7000
2-2
あとで追記...
2-3
あとで追記...
2-4
あとで追記...