Chainerを始めよう1

Chainerとは
-> Deep learningのモデル、実行コードを直観的に記述できるpythonのフレームワーク
-> 使用することで、ニューラルネットワークやDeep learningの理解も深まる!?

ニューラルネットワークとは、脳のニューロンのネットワークをコンピュータ上で再現したモデル

ニューラルネットワークは、入力層(l-1層)で受け取り、隠れ層(l層)を通り、出力層(l+1層)から答えを返す

正しい答えと、NNの予想した答えとの誤差を損失関数と呼ぶ。損失関数の値が小さくなるよう値を変えていくことで、NNを学習させる


NNではWeight(結合重み)とBiasという二つのパラメータを使って、目的の値を出力する関数に近いものを作る
ニューロン同士のつながりの強さがweight
ニューロン・weightの出力に足すパラメーターbias
この関数をChainerではLinkと呼ぶ

ではchainerをインストールしましょう。

[vagrant@localhost python]$ pip install chainer
Collecting chainer
Downloading https://files.pythonhosted.org/packages/dc/bf/b561706d4e86f055841c7a5a414b5e5423bea230faa92abf5422c82cf995/chainer-6.4.0.tar.gz (876kB)
100% |████████████████████████████████| 880kB 641kB/s
Requirement already satisfied: setuptools in /home/vagrant/.pyenv/versions/3.5.2/lib/python3.5/site-packages (from chainer) (20.10.1)
Collecting typing<=3.6.6 (from chainer) Downloading https://files.pythonhosted.org/packages/4a/bd/eee1157fc2d8514970b345d69cb9975dcd1e42cd7e61146ed841f6e68309/typing-3.6.6-py3-none-any.whl Collecting typing_extensions<=3.6.6 (from chainer) Downloading https://files.pythonhosted.org/packages/62/4f/392a1fa2873e646f5990eb6f956e662d8a235ab474450c72487745f67276/typing_extensions-3.6.6-py3-none-any.whl Collecting filelock (from chainer) Downloading https://files.pythonhosted.org/packages/93/83/71a2ee6158bb9f39a90c0dea1637f81d5eef866e188e1971a1b1ab01a35a/filelock-3.0.12-py3-none-any.whl Requirement already satisfied: numpy>=1.9.0 in /home/vagrant/.pyenv/versions/3.5.2/lib/python3.5/site-packages (from chainer) (1.15.0)
Collecting protobuf<3.8.0rc1,>=3.0.0 (from chainer)
Downloading https://files.pythonhosted.org/packages/81/59/c7b0815a78fd641141f24a6ece878293eae6bf1fce40632a6ab9672346aa/protobuf-3.7.1-cp35-cp35m-manylinux1_x86_64.whl (1.2MB)
100% |████████████████████████████████| 1.2MB 1.2MB/s
Requirement already satisfied: six>=1.9.0 in /home/vagrant/.pyenv/versions/3.5.2/lib/python3.5/site-packages (from chainer) (1.11.0)
Installing collected packages: typing, typing-extensions, filelock, protobuf, chainer
Running setup.py install for chainer … done
Successfully installed chainer-6.4.0 filelock-3.0.12 protobuf-3.7.1 typing-3.6.6 typing-extensions-3.6.6

はや、数秒ですね。
[vagrant@localhost python]$ pip list
Package Version
—————– ———
awscli 1.16.198
beautifulsoup4 4.6.1
botocore 1.12.188
certifi 2018.4.16
chainer 6.4.0

import chainer

print(chainer.print_runtime_info())

Platform: Linux-2.6.32-754.14.2.el6.x86_64-x86_64-with-centos-6.10-Final
Chainer: 6.4.0
NumPy: 1.15.0
CuPy: Not Available
iDeep: Not Available
None

DNN(ディープニューラルネットワーク)

DNNはディープラーニングの一種
多数ライブラリが公開されているが、中でも”chainer”と”TensorFlow”が有名

chainerはPreferred Networksが開発、TensorFlowはGoogle

TensorFlow
https://www.tensorflow.org/

Chainer
https://tutorials.chainer.org/ja/

import data
import numpy as np 

mnist = data.load_mnist_data()
x_all = mnist['data'].astype(np.float32)/255
y_all = mnist['target'].astype(np.int32)

y_all = dense_to_one_hot(y_all)

x_train, x_test = np.split(x_all, [60000])
y_train, y_test = np.split(y_all, [60000])

tensorflowの特徴
– ニューラルネットワークだけでなく、機械学習、数値計算をカバー
– 低レベル処理も可能
– GPU利用が用意
– 複数デバイスの並列処理が容易
– 直観的に構築できる
– 難易度が高い
– 利用人口が多い

chainerの特徴
– 直観的かつシンプル
– 初心者に優しい
– 複雑な計算グラフに対応できる
– GPUでの高速処理
– 計算速度が遅い

いよいよ来たか、という感じです。
比較すると、まずはChainerで基礎をやって、それからTensorFlow って流れの方が良さそうですかね。

クロスエントロピー誤差

目的関数J(Θ)を最小にするには、
J(Θ)= 1/2m*mΣi=1(pxi – yi)^2

ただし、0≦pxi≦1でyiは0もしくは1の為、
L(Θ)= – mΣi=1(yilog(pxi)+(1-yi)log(1-pxi))を求めた方がより簡便な計算になる。
これをクロスエントロピー誤差関数という。

def cross_entropy_error(y,t):
	delta = le-7
	return -np.sum(t*np.log(y+delta))

うん、ここは後々復習が必要そうだな。

ロジスティック回帰

[ロジスティック回帰]は、類似度を確立によって表現する
→ ”ユークリッド距離”、”コサイン類似度”に比べて、より踏み込んだ情報を得ることが可能
→ 確率pで1、確率1-pで0を取るような離散確率分布ベルヌーイ分布を元に、確率的に1か0の値を取るものと考える

公式
ある入力xを、出力y={1,0}のいずれかに分類することを考え、y=1となる条件付き確率p(y=1|x;θ)を以下のように定義する
p(y=1|x;θ) = 1 / (1 + exp(-θ^Tx)

※p(θ)= 1/(1*exp(-θ)) はロジスティック関数

from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_validate

def main():
	dataset = datasets.load_breast_cancer()
	X, y = dataset.data, dataset.target

	clf = LogisticRegression()
	skf = StratifiedKFold(shuffle=True)
	scoring = {
		'acc' : 'accuracy',
		'auc': 'roc_auc',
	}
	scores = cross_validate(clf, X, y, cv=skf, scoring=scoring)

	print('Accuracy(mean):', scores['test_acc'].mean())
	print('AUC(mean):', scores['test_auc'].mean())

if __name__ == '__main__':
	main()

Accuracy(mean): 0.9490299823633156
AUC(mean): 0.992996071668104

TF-IDF(Term Frequency-Inverse Document Frequency)

TFはTerm Frequency(単語頻度)
IDFはInverse Document Frequency(逆文章頻度): 単語を含む文章がどれだけの頻度で出現していないか、珍しさを表す指標

TFはN個の単語の内、n回表示だと、n/N で表すので、そのまま。
IDFはD個の文で単語tを含む文がd個ある時、 IDF = -log[10]d/D = log[10]D/d となる。指標が、[文章]単位に変わる。

TF-IDFはTFとIDFの積
単語の頻度と文章の頻度を掛ける

では実践してみましょう。

from math import log
import pandas as pd 

docs = [
	["ノンプレイヤーキャラクター", "プレイヤー","操作","キャラクター"],
	["プレイヤー","操作","キャラクター","プレイヤーキャラクター"],
	["NPC","PC"],
	["RPG用語","コンピューターゲーム","キャラクター","人間らしく","操作"],
	["NPC","ゲームマスター","プレイヤー","キャラクター","ゲーム","イベント","バランス","プレイヤー"]
]

words = list(set(w for doc in docs for w in doc))
words.sort()
print(words)

# TF-IDF
N = len(docs)

def tf(t, d):
	return d.count(t)/len(d)

def idf(t):
	df = 0
	for doc in docs:
		df += t in doc

	return log(N/df)+1

def tfidf(t,d):
	return tf(t,d)* idf(t)

# TF
result = []
for i in range(N):
	result.append([])
	d = docs[i]
	for j in range(len(words)):
		t = words[j]

		result[-1].append(tf(t,d))

tf_ = pd.DataFrame(result, columns=words)
print(tf_)

# IDF
result = []
for j in range(len(words)):
	t = words[j]
	result.append(idf(t))

idf_ = pd.DataFrame(result, index=words, columns=["IDF"])
print(idf_)

# TF-IDF
result = []
for i in range(N):
	result.append([])
	d = docs[i]
	for j in range(len(words)):
		t = words[j]

		result[-1].append(tfidf(t,d))

tfidf_ = pd.DataFrame(result, columns=words)
print(tfidf_)

[vagrant@localhost python]$ python app.py
[‘NPC’, ‘PC’, ‘RPG用語’, ‘イベント’, ‘キャラクター’, ‘ゲーム’, ‘ゲームマスター’, ‘コンピューターゲーム’, ‘ノンプレイヤーキャラクター’, ‘バランス’, ‘プレイヤー’, ‘プレイヤーキャラクター’, ‘人間らしく’, ‘操作’]
NPC PC RPG用語 イベント キャラクター … バランス プレイヤー プレイヤーキャラクター 人間らしく 操作
0 0.000 0.0 0.0 0.000 0.250 … 0.000 0.25 0.00 0.0 0.25
1 0.000 0.0 0.0 0.000 0.250 … 0.000 0.25 0.25 0.0 0.25
2 0.500 0.5 0.0 0.000 0.000 … 0.000 0.00 0.00 0.0 0.00
3 0.000 0.0 0.2 0.000 0.200 … 0.000 0.00 0.00 0.2 0.20
4 0.125 0.0 0.0 0.125 0.125 … 0.125 0.25 0.00 0.0 0.00

[5 rows x 14 columns]
IDF
NPC 1.916291
PC 2.609438
RPG用語 2.609438
イベント 2.609438
キャラクター 1.223144
ゲーム 2.609438
ゲームマスター 2.609438
コンピューターゲーム 2.609438
ノンプレイヤーキャラクター 2.609438
バランス 2.609438
プレイヤー 1.510826
プレイヤーキャラクター 2.609438
人間らしく 2.609438
操作 1.510826
NPC PC RPG用語 イベント … プレイヤー プレイヤーキャラクター 人間らしく 操作
0 0.000000 0.000000 0.000000 0.00000 … 0.377706 0.000000 0.000000 0.377706
1 0.000000 0.000000 0.000000 0.00000 … 0.377706 0.652359 0.000000 0.377706
2 0.958145 1.304719 0.000000 0.00000 … 0.000000 0.000000 0.000000 0.000000
3 0.000000 0.000000 0.521888 0.00000 … 0.000000 0.000000 0.521888 0.302165
4 0.239536 0.000000 0.000000 0.32618 … 0.377706 0.000000 0.000000 0.000000

[5 rows x 14 columns]


TFは頻度なので、0≦TF≦1になってますね。
IDFは、”プレイヤー”や”キャラクター”など、使用頻度の高い方が、値が小さくなってます。log[10]D/dなので、dの値が大きくなるほど、IDFは小さくなることがわかります。
そしてTF-IDFは、TF同様、文章ごとに値が表示されます。

あ、IDFは珍しいワードの方が値が大きくなるので、TF-IDFで各単語の重み付けをして特徴を示しているんですね。

このロジック考えたの誰だよ、すごいな。。。

Bag-of-Words

単語にベクトルの各列を割り当てておいて、出現回数などを要素とすることで文章をベクトル化したものを、Bag-of-Wordsベクトルと呼ぶ。

scikit-learnのCountVetctorizer
トランプ大統領の発言を解析します。

import numpy as np 
from sklearn.feature_extraction.text import CountVectorizer
count = CountVectorizer()
docs = np.array([
		'If you want freedom, take pride in your country. If you want democracy, hold on to your sovereignty. If you want peace, love your Nation',
		'President Donald J. Trump has shown that the path to prosperity and strength lies in lifting up our people and respecting our sovereignty'
	])
bag = count.fit_transform(docs)
print(count.vocabulary_)

[vagrant@localhost python]$ python app.py
{‘if’: 7, ‘you’: 32, ‘want’: 31, ‘freedom’: 4, ‘take’: 25, ‘pride’: 19, ‘in’: 8, ‘your’: 33, ‘country’: 1, ‘democracy’: 2, ‘hold’: 6, ‘on’: 13, ‘to’: 28, ‘sovereignty’: 23, ‘peace’: 16, ‘love’: 11, ‘nation’: 12, ‘president’: 18, ‘donald’: 3, ‘trump’: 29, ‘has’: 5, ‘shown’: 22, ‘that’: 26, ‘the’: 27, ‘path’: 15, ‘prosperity’: 20, ‘and’: 0, ‘strength’: 24, ‘lies’: 9, ‘lifting’: 10, ‘up’: 30, ‘our’: 14, ‘people’: 17, ‘respecting’: 21}

アメリカの大統領ともなると、”you”って言葉を多用されるのでしょうか。
単語ベクトルと言うと、mecabの頻出単語とは異なる印象です。

MSEとR^2

MSEとR^2 って、六本木のバーのような名前ですが、
Mean Squared Error: MSE
→残差の2乗平均を取ったもの
1/n*nΣi=1(y実測値i – y予想値i)^2
あれ、MSEって、テストデータと検証データのnが一緒でないといけない??

決定係数: R^2
R^2 = 1 – MSE – / 1/n*nΣi=1(y実測値i – y予想値i)^2 (0≦R^2≦1)

MSE

from sklearn.metrics import mean_squared_error
y_true = [4, -0.2, 3, 6]
y_pred = [3.5, 0.0, 2, 8]

print(mean_squared_error(y_true, y_pred))

[vagrant@localhost python]$ python app.py
1.3225

R^2

from sklearn.metrics import r2_score
y_true = [4, -0.2, 3, 6]
y_pred = [3.5, 0.0, 2, 8]

print(r2_score(y_true, y_pred))

[vagrant@localhost python]$ python app.py
0.7365537848605578

交差検証法

統計学において標本データを分割し、その一部を解析して、残る部分で解析のテストを行い、解析の妥当性の検証・確認に当てる
→ これ以上標本を集めるのが困難な場合に有効

主な種類
– ホールドアウト検証
初期標本群から事例を無作為に抽出
– K-分割交差検証
標本群をK個に分割し、その一つをテスト事例、残りを訓練事例
– Leave-one-out cross validation
標本群から一つだけ抜き出し、残りを訓練。これを全事例が一回ずつテスト事例になるよう繰り返す

色々手法があるが、やはり信ぴょう性にはデータ量が物を言うような印象

正則化(Reguralization)

正則化とは、モデルが複雑になると、ペナルティが課されるような項を追加することで過学習を防ぐ
一般的には、L1正則化、L2正則化を用いる
正則化項 λE(w) = λLΣK=1|Wk|
重みWのノムルが大きくなりすぎない(複雑になりすぎない)ようにL2ノムルを追加し、Dを最小化する。
ここでλは、定数値として定め、λが大きいと、ノムルの値が小さくなる。
λの値を調整することで、正則化の度合いを調整する。

えーと、確かL1ノムルは絶対値の値、L2ノムルはユークリッド距離でしたね。
あれ、ってことは、L1ノムル(絶対値の和)で正則化することもあれば、L2ノムル(ユークリッド距離)で正則化することもあるってことね。
関数Dの最小化だから、微分するってことなんだろうけど、例えば重回帰分析とかなら、正則化の項は付いてなかったように記憶しているが、、、

ここは理解が乏しいな。。

最小二乗法

まず、散布図を作成します。

import matplotlib.pyplot as plt 

x = [1,2,3,4,5]
y = [1571,1630,1681,1603,1623]

plt.scatter(x, y)

合計距離の最小値を求める
D = 5Σ[t=1]*{yl – (w0 + w1xl)}^2

実装する

import numpy as np
import matplotlib.pyplot as plt 

x = np.array([1,2,3,4,5])
y = np.array([1571,1630,1681,1603,1623])

def reg1dim(x, y):
	a = np.dot(x, y)/ (x ** 2).sum()
	return a 

a = reg1dim(x, y)

plt.scatter(x, y, color="k")
plt.plot([0,x.max()], [0,a * x.max()])

ああああああああああ、全然やりたいことと違う
plotする時に、0からスタートすると駄目なのか。。

平均(mean)は、np.mean()だから、こうか?

x = np.array([1,2,3,4,5])
y = np.array([1571,1630,1681,1603,1623])

m = np.mean(y)

def reg1dim(x, y):
	a = np.dot(x, y)/ (x ** 2).sum()
	return a 

a = reg1dim(x, y)

plt.scatter(x, y, color="k")
plt.plot([0,x.max()], [m,a * x.max()])

あれ、なんかちゃうなー、 [m,a * x.max()]のところがおかしい。。

最小二乗法はこういう図になるはずなんだけど。。