N高校生python備忘録

N高校生python備忘録

python始めたけど一向に勉強しないのでいい加減やります

MacBook Pro をデュアルモニタに

久しぶりのブログ

先日頼んでいたモニターが届いたのでレビューしていきます

経緯

元々デュアルディスプレイに興味があったのと、数ヶ月前に勢いで購入したPS4プレイステーション4)が自室にテレビがないことから完全放置されていたので、何か良い方法がないものかと思案していたところ、Amazonで良さげな商品を発見

お値段いちまんろくせんえん
なんか知らんけどお安くなっていたしTGSのおかげ?)、お金もたまっていたので購入!

レビュー

第一印象、デカイ
サイズは確認していたので予想はしていたものの、商品の厚みもあってかかなり大きい

モニタ自体は23.6インチなのでそこそこ大きい程度ですが、枠と台がごついです

私がこのモニタを選んだ最大の理由が……これ!

そう、HDMIポートが二つあるんです
先ほど述べた通り私はこのモニタをPS4にも使いたかったのですが、その際HDMIポートが一つしかないとPC・PS4間でいちいち抜き差ししなければならず、それはどうしても避けたいところでした
実際これは大正解 PCとPS4を同時に刺してますが切り替えもモニタで操作できるので楽チンです
私が一通り探したところこの価格帯、一万円前後でHDMIポートが2つ存在するモニタはこれくらいしかありませんでした

PCとの接続自体は簡単 HDMIケーブルをそのまま繋ぐだけ 後は勝手にMacBookくんが認識してくれます

最近のMacはパソコン側にあるのがUSB-CだけなのでUSBハブで追加しましょう
私が使ってるやつ

まあまあ……まあまあいいです!

あとはモニタの位置を好みに調整します f:id:python_nnn:20180925224259p:plain

私は勉強机の右端に設置したのでっと

半日ほど使用しての感想ですが、やっぱり便利です
今もこれ書きながら隣でニコニコ動画流してます 楽しい
N高生としての使い方としては、片方でN予備校の動画を流してもう片方で問題を解くorメモをとる、とか

PS4でも軽く使ってみましたが画面光沢がないので普通のテレビよりは見やすいです
なんかflicker freeとか応答速度が2msとからしいですが特に実感はないです

不満らしい不満が特に見つからないのですが、強いて言うならゴツいこと、くらいですか

うそです、ありました モニタにスピーカー内臓されてないじゃん!! どうしてくれんの!? 同価格帯だと大抵安物ながらもスピーカーが入っていたので完全に油断してました 幸いオーディオ用ジャックはあるのでそこ繋ぐか、パソコンを経由させるほかないですね

あとはそう、私はMacBook Pro13インチの一番安いやつなのですが、やはりHG画質のモニタを二枚描画させるのはかなり負荷がかかります 買ったモニタでアニメを見ていたらMacちゃんのファンが爆音をあげていたので要注意です 一番安いMacBook or Airだと厳しいかも

でもドット落ちとかもないし、予想をはるかに超える画質の良さだし

とりあえずは満足です

みなさんぜひ大画面でドキドキ文芸部をやりましょう

f:id:python_nnn:20180925232555j:plain

ゼロから作るDeep Learning 4章 雑感

前回のまとめ
ニューラルネットワークの仕組みについて理解し、さらにすでに用意されたデータを元に実装まで行いました
なかなかに感動的でしたね だが無意味だ
前回一通り実装して気づいたと思いますが、常識的に考えて場合によっては万を軽く超えるであろう重みやバイアスの値を、人間が試行錯誤して設定するのは不可能です

ニューラルネットワークの学習

と、いうわけで4章ではどのように重みやバイアスなどのパラメータを機械に設定させるのかについて見ていきます
なおニューラルネットワークの学習と銘打っていますが実質機械学習のやり方です

損失関数(loss function)

損失関数とは、そのニューラルネットワークがどれほどの精度なのかを示す指標となる関数です
返す値が大きければ大きいほどそのニューラルネットは出来が悪いと判断することができ、逆説的にこの値を最小化すること(minimize)で性能のよいニューラルネットを作ることができるでしょう
ここの説明に関してはスタンフォード大の教授Mr.アンドリューのCoursera machine learningや、やさしく学ぶ 機械学習を理解するための数学のきほん ~アヤノ&ミオと一緒に学ぶ 機械学習の理論と数学、実装まで~にわかりやすい説明が乗っているので参考に

二乗和誤差

損失関数として用いられる数式にはいくつかあるが、その中でももっとも有名なのが二乗和誤差(mean squared error)

\displaystyle E=\frac{1}{2} \sum_{k}(y_k-t_k)^{2}

ここでのykはニューラルネットの出力、tkは教師データを表し、kはデータの次元数を表す
つまりニューラルネットからの出力と教師データの各要素の差の二乗を計算し、その総和を求める
pythonの実装

def mean_squared_error(y, t):
    return 0/5 * np.sum((y-t)**2)

交差エントロピー誤差

二乗和誤差とは別の関数として、交差エントロピー誤差(cross entropy error)もよく用いられる

\displaystyle E=-\sum_{k}t_k\log{y_k}

またログかよ!という私の叫びが聞こえてくるようです
たまに中学生や高校生で機械学習に関して詳しい方がおりますが、一体彼ら/彼女らはどのようにして学習していったのでしょう
ここでのlogには底数の表記がないので自然対数(log_e)を表す
ykは同じくニューラルネットの出力、tkは正解ラベルとする 正解ラベルとは、教師データのように正解か不正解かが示された数値で、さらにここでは正解ラベルとなるインデックスだけが1で、それ以外は0であるとする(one-hot表現)例:0〜5までで2が正解ラベルの場合の行列は[0, 0, 1, 0, 0, 0]

上のグラフ(自然対数y=log_x)を見ると分かるが、xが1の時にyが0となり、xが0に近くにつれてyの値はどんどん小さく(マイナスに)なる そのため上記の式は正解ラベルに対応する出力が大きければ大きいほど0になる
pythonでも実装する

def cross_entropy_error(y, t):
    delta = 1e-4
    return -np.dum(t * np.log(y + delta))

実装ではdeltaという式が足されているが、これはnp.log(0)のような計算が発生した場合python側がマイナス無限大を返してしまい、それ以上計算が続行できなくなってしうのを防ぐため 1e-4は1/10000以下の極小の値

ミニバッチ学習

さて、前回三章で用いられたMNISTデータセットは訓練データが60000個もあった
本来であれば全てのデータを対象に損失関数を計算することが望ましいが、それでは少々時間がかかってしまうし、ビッグデータともなるとその数は数千万を超え、それら全てを対象とした損失関数の計算を行うのは現実的ではない
そこでデータの中から一部を無作為に抽出し、その一部のデータを全体の「近似」として利用する この部分的なデータをミニバッチ(小さな塊)と呼ぶことから、ミニバッチを元に機械学習を行う方法をミニバッチ学習という
例えば本書では60000個あるMNISTデータではそこから100枚を無作為に抽出して学習に使用する

np.random.choice(60000, 10)
#([ 8013, 14666, 58210, 23831, 52091, 10153, 8107, 19410, 27260, 21411])

NumPyのrandom.choiceを用いれば選び出すインデックスを配列として簡単に取得できる 上記のコードは0〜60000のうちランダムに10個の数字を選び出す

[バッチ対応版]交差エントロピー誤差の実装

先ほどのミニバッチ学習を踏まえた上で再度交差エントロピー誤差の実装を行う

#one-hot表現
def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    return -np.sum(t * np.log(y + 1e-7)) / batch_size

#ラベルとして与えられた場合
def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7) / batch_size

数値微分

微分とはある瞬間においての変化の量を示したものである  わか、わからない……

微分については私がまだお勉強していないので割愛 正直今も微分について理解せずに機械学習の勉強を進めています なぜ勉強しようと思ったのか…
どうやら微小な差分によって微分を求めることを数値微分と呼ぶらしい

偏微分と勾配

f(x_{0}, x_{1})=x^{2}_{0}+x^{2}_{1}

さて、こちらの関数には変数が二つ存在する こういった複数の変数からなる関数の微分偏微分というらしい
偏微分する場合それぞれの変数に対して微分値が導き出されるが、それらの数値をベクトルとしてまとめたものを勾配(gradient)という
実装

def numerical_gradient(f, x):
    h = 1e-4  # 0.0001
    grad = np.zeros_like(x)    
    for idx in range(x.size):
        tmp_val = x[idx]
        x[idx] = float(tmp_val) + h
        fxh1 = f(x)  # f(x+h)        
        x[idx] = tmp_val - h 
        fxh2 = f(x)  # f(x-h)
        grad[idx] = (fxh1 - fxh2) / (2*h)        
        x[idx] = tmp_val  # 値を元に戻す       
    return grad

?…………?……?
一瞬戸惑ったがどうやらxにNumPy配列を対応させたものらしい コードよめないけど
さて、上記の関数で返される勾配にはどのような意味があるのか
まずこちらが偏微分の対象となるような複数の変数をもつ関数のグラフ
式はx^{2}_{0}+x^{2}_{1}

そして勾配の結果にマイナスをかけたベクトルの描画

高校数学では微分をするときに増減表(矢印)を作るが、マイナスをかけたということはつまり矢印はその地点から低い方向を指していると言えるでしょう 

勾配法

勾配がわかることによって何が起こるのか
機械学習の問題の多くは、学習の際に最適なパラメータを探索する ニューラルネットでは重みとバイアスにおいて、最適なものを見つけなければならない ここで、最適なパラメータというのは損失関数が最小値を取るときのパラメータの値だ
つまり損失関数における勾配を利用して、損失関数の最小値を探せばいい、ということらしい
この方法を勾配法(gradient method)という
より具体的には、まず関数において適当な場所をとり、その地点においての勾配(つまり最も関数の値を減らす方向)を求めその方向へ一定距離進む 続いて再び移動した先で勾配を求め、またさらに一定距離移動する……というのを繰り返せば、いずれはその関数においての最小値(および極小点)にたどり着ける
勾配法を数式で表すと次のようになる

\displaystyle x_{0}:=x_{0}- \eta \frac{\partial f}{\partial x_{0}}

\displaystyle x_{1}:=x_{1}- \eta \frac{\partial f}{\partial x_{1}}

式のη(イータ)は更新の量(勾配方向にどれだけ進むか)を表す ニューラルネットにおいては学習率(learning rate)と呼ばれ、また重みやバイアスとは違い人の手によって設定される値であることからハイパーパラメータと呼ばれるものの一種
学習率は基本的に大きすぎても小さすぎても「良い場所」にたどり着くことができない 大きすぎる場合最小値を飛び越えて進んでしまい、小さすぎても最小値にたどり着くのに時間がかかりすぎてしまう
ではpythonでの実装

def gradient_descent(f, init_x, lr=0.01, step_num=100):
    x = init_x
    for i in range(step_num):
        grad = numerical_gradient(f, x)
        x -= lr * grad
    return x

引数fはファンクション、init_xは初期値、lrはラーニングレート、step_numは勾配法の繰り返しの回数 関数の勾配は前回実装したnumerical_gradientを利用し、返した値にlrをかけて更新、それをstep_numをリスト化してforループで規定回繰り返す
さて果たしてうまく最小値、および極小値にたどり着けるのか

def function_2(x):
    return x[0]**2 + x[1]**2

init_x = np.array([-3.0, 4.0])
gradient_descent(function_2, init_x=init_x, lr=o.1, step_num=100)
#array([ -6.1110793e-10, 8.14814391e-10])

最終的な結果は(-6e-10, 8e-10)と、真の最小値である(0, 0)に限りなく近い数値なので成功したといって良いでしょう
こちら更新のプロセスを可視化した図

ニューラルネットワークについても同様、本質的な仕組みは同じなので上記コードをNumPy行列にも拡張すればよい

学習アルゴリズムの実装

さてこの章で学んだことを一旦整理し、その上でそれらを組み合わせ学習アルゴリズムを実装していく

  1. 前提
    ニューラルネットワークには適応可能な重みとバイアスがあり、この重みとバイアスを訓練データに適応するように調整することを「学習」と呼ぶ

  2. ミニバッチ
    訓練データの中からランダムに一部データを選び出す

  3. 勾配の算出
    ミニバッチにおける損失関数を減らすために、各重みパラメータの勾配を算出 ここで勾配は、損失関数を最も減らす方向を示す

  4. パラメータ更新
    重みパラメータを勾配方向へ微小量だけ更新

  5. 繰り返し
    2, 3, 4を繰り返す

上記の方法では学習にミニバッチを用いてるため、確率的勾配降下法(stochastic gradient descent)と呼ばれる

二層ニューラルネット

長いです

class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
        # 重みの初期化
        self.params = {}
        self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * 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']
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)
        return y
    # x:入力データ, t:教師データ
    def loss(self, x, t):
        y = self.predict(x)
        return cross_entropy_error(y, t)
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        t = np.argmax(t, axis=1)
        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy
    # x:入力データ, t:教師データ
    def numerical_gradient(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'])
        return grads

ながい つらい

まずW1, W2, b1, b2をそれぞれ入力層×隠れ層分、正規分布に基づいて乱数を生成する
続いてそれらを層状に、入力×W1+b1=a1 → a1×sigmoid=z1 → z1×W2+b2=a2 → a2×softmax → 出力!
loss(self, x, t)で出力した結果と正解ラベルを元に損失関数を求め、またpredictを元に出力した数列からaxis=1で最大値の場所を抽出、正解ラベルとの正答率を求める
最後にnumerical_gradientで勾配を求める

う、うーん もう厳しくなってきたぞう

ミニバッチ学習実装

上で実装したTwoLayerNetを対象にミニバッチ学習を行う
では実装

import sys, os
sys.path.append(os.pardir)  # 親ディレクトリのファイルをインポートするための設定
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet

# データの読み込み
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)

iters_num = 10000  # 繰り返しの回数を適宜設定する
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1

for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    
    # 勾配の計算
    grad = network.numerical_gradient(x_batch, t_batch)
    #grad = network.gradient(x_batch, t_batch)
    
    # パラメータの更新
    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]
    
    loss = network.loss(x_batch, t_batch)
    train_loss_list.append(loss)
    

f:id:python_nnn:20180909163600p:plain:w200:right おおー
理論の話はわかるけどこれを実装できる気がしない

テストデータによる評価

上記のコードを実装し、徐々に損失関数の値が現象していくことを確認したが、この損失関数の値は訓練データに対する損失関数の値であり、他のデータセットにも同じ精度を発揮できるかどうかは分からない
ニューラルネットの学習において、ある特定のデータセットに適合してしまい汎用性を失うことを過学習という
それを避けるために定期的に訓練データとテストデータを対象に認識精度を記録する 本書では1エポックごとに認識精度を記録する

青線が訓練データに対する認識精度、オレンジ破線がテストデータに対する認識精度

これをみると両者ともに認識精度が上がっており、また二つとも認識精度に大きな差はないように見える
このことから今回は過学習は起きていないと言える

……なかなかに長かった上に私があまり理解できていませんが、お疲れ様でした

ゼロから作るDeep Learning 3章 雑感

前回のまとめ
2章ではパーセプトロンと呼ばれるアルゴリズムについて確認、実装し、さらにはパーセプトロン同士を繋げることによって単純な直線だけでなく非線形を描けることを確認しました
ここから難しくなっていきます(当社比)

ニューラルネットワーク

ニューラルネットワーク(神経回路網、英: neural network、略称: NN)は、脳機能に見られるいくつかの特性を計算機上のシミュレーションによって表現することを目指した数学モデルである。研究の源流は生体の脳のモデル化であるが、神経科学の知見の改定などにより次第に脳モデルとは乖離が著しくなり、生物学や神経科学との区別のため、人工ニューラルネットワーク(artificial neural network、ANN)とも呼ばれる。ニューラルネットワーク - Wikipedia

f:id:python_nnn:20180905154507j:plain:w300:right ニューラルネットワークは、文字通り生物の脳にあるニューロンを模して作られたものです
ニューラルネットワークパーセプトロンを複数繋げたような形をしており、一番左を入力層、一番右を出力層、そして間に挟まれているすべてのニューロンを中間層(隠れ層)と呼びます
一見するとニューラルネットワークパーセプトロンをつなげただけのようですね

活性化関数の導入

前章パーセプトロンにおいて0以下であれば0を、0より大きければ1を出力するようyが定義されていたが、それを一個の関数として扱うと次のような式となる

y=h(b + w1x1 + w2x2)

このhは仮説のH(hypothesis)
ここで登場したような、入力信号の総和を出力信号に変換する関数(h)を活性化関数と呼ぶ

なぜ活性化関数を導入するか:結局のところ、活性化関数を導入していないニューロン同士がやっていることは乗算や加算の単純な四則演算であり、それではいくらニューロンを積み重ねても排出されるのはただの回帰直線であって、非線形を表現できません

ということで有名な活性化関数、シグモイド関数を導入する

\displaystyle h(x)=\frac{1}{1+exp(-x)}

えっなにこれは…expってなに? ネイピア数 - Wikipedia

logとか対数は高校三年生までお預けなので今は無視する

このシグモイド関数ニューラルネットワーク内でどのような働きをしてくれるのか、今まで使っていた活性化関数と比べて理解する

前章パーセプトロンで使われていたような、ある値を境目に0か1の出力が決まる関数をステップ関数と呼ぶ

def step_function(x):
    if x > 0:
        return 1
    else:
        return 0

#今後のためにNumPyにも対応させる
def step_function(x):
    y = x > 0
    return y.astype(np.int)

NumPy配列に不等号の演算を行うと、各要素に対して不等号演算が行われる 今回の婆であれば0以下がFalse、0より大きい数がTrueに 我々が欲しいのは0か1かのint型なのでastype(np.int)でTrueが1、Falseが0へと変換され返される

続いてステップ関数のグラフ

def step_function(x):
    return np.array(x > 0, dtype=np.int)

X = np.arange(-5.0, 5.0, 0.1)
Y = step_function(X)
plt.plot(X, Y)
plt.ylim(-0.1, 1.1)  # 図で描画するy軸の範囲を指定
plt.show()

ここでmatplotlib登場 見ての通りでっかいビルか、はたまた階段のよう

続いてシグモイド関数の実装

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

ステップ関数とシグモイド関数ではなだらかさが違いますね ステップ関数は1か0かしか返さないのに対し、シグモイド関数では0.2232…などのような実数を返します
つまり表現の幅が広い、ということですね また、どのような値が入力されても0〜1以内で返してくれるので確率とも解釈できるようです

シグモイド関数は昔から使われてきた関数ですが、最近だとReLU(Rectified Liner Unit)関数がよく用いいられるそう

def relu(x):
    return np.maximum(0, x)

maximumは値の中から最大値を返すので、0未満であれば0が、0以上であればそのままの数値で出力される

行列計算については略します とりあえずスカラーとの計算や内積、行列同士の計算や単位行列などのポイントを軽く抑えて置けばいいと思います

ニューラルネットワークの行列の積

f:id:python_nnn:20180905160831j:plain:w230:right ニューラルネットワークではxに入力された信号をwの値と掛け合わせてそれをyへと出力するが、複数の層がある場合かなりめんどくさい(具体的にはforループ)
が、xとwをそれぞれ行列として一個のデータの塊のように扱えばとても簡単に計算できる それを確かめるためにもNumPyで簡単なニューラルネットワークを実装する

def init_network():
    network = {}
    network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    network['b1'] = np.array([0.1, 0.2, 0.3])
    network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
    network['b2'] = np.array([0.1, 0.2])
    network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
    network['b3'] = np.array([0.1, 0.2])
    return network

def forward(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']
    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)    
    return y

network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y) # [ 0.31682708 0.69627909 ]

さて確認をします
 W1は2×3、W2は3×2、W3は2×2次元の行列 b1は1×3、b2、b3は1×2次元の行列である 入力であるxは1×2次元
次元数の確認 x[1, 2] * W1[2, 3] = a1[1, 3] (バイアスの次元数とも一致) z1[1, 3] * W2[3, 2] = a2[1, 2] z2[1, 2] * W3[2, 2] = a3[1, 2] 答えと次元数は一致する
コードに書かれていることはまだ私でも理解できるので省略

ソフトマックス関数

機械学習の問題は大別して二つ、「分類問題」と「回帰問題」である 前者は類似傾向から画像等を分類する、後者は金額予想などの連続値に関する予測だが、結局のところ両者とも線形を描いていることになるので、どちらもニューラルネットで扱うことができる ただどちらの問題を扱うかによって微妙な違いがあるようで、出力層においては回帰問題に恒等関数を、分類問題にはソフトマックス関数が使われる

恒等関数は入力された値をそのまま出力する関数、上記のコードでの identity_function に相当する なので特に説明なし

一方でソフトマックス関数は次のような式で表される

yk=\displaystyle \frac{exp(ak)}{\sum_{i=1}^{n}exp(ai)}

またexpend、今度はシグマ
出力層が全部でn個あるとして、k番目の出力ykを求める計算式らしい
図にするとこう→

f:id:python_nnn:20180905161102j:plain:h200:right んにゃぴ……よくわからないですね

とりあえず実装

def softmax(a):
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

あー、一度シグマで合計を出した上でそれを分母にしているから、層aのk番目が層a全体から見てどれほどの大きさなのか(占める割合の多さ、つまりは重要度?)を指数関数を使って出している……?
よく分かんないっす
他サイトを巡っても微妙でわからなかったのだが、重要なのは一つ これが確率を表しているということ
なるほど、だから分類問題に適しているのですね

初級者向けMNISTデータのインポートの解説

三章では、このあとMNISTデータセットと呼ばれる画像認識の実験においてよく使われるデータセットを使って、手書き文字認識をおこなっていくのですが省略します

ただこのデータのインポートが私のような初級者にはかなり大変でして、またあまりにも初歩的な問題であることからか、グーグルで調べて上位に出てくるようなブログだと記述も非常に少ない
私はこれを解決するのに一晩かかりましたので、今後私みたいな人(多分出ないしこの記事にたどり着かないと思うけど!)を出さないために電子の藻屑に流しときます といっても苦労して解決した割には作業はめちゃ楽です

まずデータのインポートのためにGitHubからダウンロードしたファイルをカレントディレクトリに設定しなければなりません python上でディレクトリ変更(チェンジディレクトリ)をするにはまずosモジュールをインポートします

import os

os.chdir('絶対パス')

chdirはchange directory の略 絶対パスというのは郵便番号みたいなものですが、とりあえず置きたいディレクトリ(フォルダ、今回でいうと「ch03」)からコマンドプロンプト(ターミナル)にドラッグ&ドロップした際に表示される長い文だと思えばいいです てか私が理解できてないし

あとは記載されたコードを打ち込むだけですね!

import sys, os
sys.path.append(os.pardir)  
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image


def img_show(img):
    pil_img = Image.fromarray(np.uint8(img))
    pil_img.show()

(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)

これでロードが始まったら成功です

お疲れ様でした!

次回

python-nnn.hatenadiary.jp

ゼロから作るDeep Learning ? ―自然言語処理編

ゼロから作るDeep Learning ? ―自然言語処理編



参考にさせていただいたサイト様 こっちの方がわかりやすくて素敵な解説が付いてますよ!

ゼロから作るDeepLearning第三章 ニューラルネットワーク
ゼロから作るDeep Learning 3章「ニューラルネットワーク」 - Miyamo’s blog

ブログの書き方参考

はてなブログで数式が綺麗に書けるTeXの便利ワザ for 見たままモード - cBlog
機械学習でも定番のPythonライブラリ「NumPy」の初心者向け使い方チュートリアル - paiza開発日誌

ゼロから作るDeep Learning 1〜2章まで雑感


とりあえず機械学習やりたいなーと思うだけ思って実行に移さず数ヶ月、ニートだから毎日が夏休み、暇だしとこの界隈でめちゃ評判が高くいろんな方もおすすめしている例の本購入

ゼロから作るDeep Learning


いまいち理解できていない、というか正直さっぱりわからないのでメモ替わりに作業をアウトプットしていきます あとPCに不慣れすぎてかなり苦労したから私みたいな人を減らしたい
自分用メモなので内容が雑そして黒歴史確定ですが、高校生が書いているので簡単かつ幼稚ですので安心してください



0.そもそも機械学習ってなんですか



ここは飛ばしていいです
様々なことを学んでいく上でその対象の定義を明確にすることは重要なことだと思うのですが、機械学習というものが一体全体どのようなものなのかということに未だはっきりとした回答を得ていません
前提として私は現役高校生、ただし頭は中学生から進歩なし
多少人工知能等に関する書籍を漁ってはいるものの、なにか実態があるものを見たわけでもないので機械学習に対して正しい知見は持っていないでしょう

ただ本書を軽く触った上で誤解はしていたな、というのはあって機械学習」は「機械が学習するコト(およびモノ)」ではなく、「学習する機械(を作る)」だと
前者と後者では主体が違う 前者は教師と生徒のように教える側と教えられる側が明白だが、後者の場合は人間が最低限御膳たてをして後は機械に参考書を持たせて勉強させる
みたいな風に現時点で私は思っている
つまりこの程度の浅い理解しか得てない人でもこの本を進めることはできます まだ終わってないけど

間違っていたら教えてください

1.Python下準備



この本の学習に必要な道具はパソコン一台
あとはpythonおよびAnaconda、そしてGithubにあるソースコードをダウンロードするだけです リンク間違ってるかも

ちなみに私は入れるアプリを一括で管理したかったのでAnacondaをパッケージマネージャ経由でインストールしました
Macって少し特殊らしく、Windowsだとそう苦労しないと思いますが一度ホームページから直にインストールしたpythonを消去するのがめっちゃ大変だったのです

参考までにこちらのスペック
MacBook pro late2016
OS High Sierra 10.13
N高校通学コースに入学するとMacBook強制的に買わされるんですよね…おのれカドカワ

複数のサイトを参考にさせていただいたのですがとりあえずひとつ貼っておきます qiita.com 注意事項としてはどうやらhomebrewとanacondaは相性が悪いらしいということ

GitHubからダウンロードしたフォルダは、今後python上でディレクトリ変更をする必要が出てくるのでデスクトップ等わかりやすい場所に展開した方がいいと思います

この本ではpythonのコードが載っており、それを写経していくことでDeep learningの仕組みを理解していこうというものです
ですので最低限pythonの使い方、読み方は習得しておいたほうがいいでしょう
pythonの学習を疎かにし現在進行形で苦労してる私が言うのですから間違いありません

ちなみに私はこの本を買って勉強していました 途中で投げ出したけど 正直オススメしません

わかるPython[決定版] (Informatics&IDEA)

わかるPython[決定版] (Informatics&IDEA)

一応擁護しておくと、何か別言語をすでに習得している方はこの本は非常に分かりやすいものかと思います が、私みたく純度100%の初心者は私の二の舞にならないよう、背伸びせず初歩の初歩から始めましょう

2.パーセプトロン


パーセプトロン(英: Perceptron)は、人工ニューロンニューラルネットワークの一種である。心理学者・計算機科学者のフランク・ローゼンブラットが1957年に考案し、1958年に論文[1]を発表した。モデルは同じく1958年に発表されたロジスティック回帰と等価である。ウィキペディア

こちらの章ではパーセプトロンと呼ばれるアルゴリズムが紹介されています
詳しいコトは書籍を読めばわかると思います

f:id:python_nnn:20180903230650j:plain:w200

二つの入力層とそれぞれと一本線で繋がる出力層
入力層に信号が送られるとそれが入力ワイヤを通して出力層へと流れる
この際入力ワイヤには固有の値(これを重みと呼ぶ weightのW?)が振られており、入力信号と値が乗算されたものが出力層へと送られる つまりその値が信号の強さ(重要度と言い換えてもいいかもしれない)を決めており、高ければ高いほど入力層からの信号が大きく伝わる
そして出力層では送られてきた信号の総和が算出され、その総和がある限界値を超えた場合にのみ1を出力する
この限界値を閾値(いきち)と呼ぶらしい

私の説明が下手なので分かりづらいですね 説明だけ聞いてもわからないのでここでANDゲートと呼ばれるものを実装する

ANDゲートは「〜かつ〜」の場合、つまりx1からの信号も1、x2からの信号も1の場合、y=1になるよという論理ゲート
pythonコード

def AND(x1, x2):
    w1, w2, theta = 0.5, 0.5, 0.7
    tmp = x1*w1 + x2*w2
    if tmp <= theta:
        return 0
    if tmp > theta:
        return 2

x1×w1(0.5) + x2×w2(0.5) の解が0.7以下の場合は0、それより大きい場合は1を返す
確かに計算してみると x1=1,x2=1 の時のみ y=1 になる へー

さて続きの論理ゲートを実装する前に、バイアスと呼ばれるものを導入するようです
先ほど実装したANDゲートにおいて閾値は0.7だったがそれだとどうにも分かりづらい
そこで0以上か、0未満かで区別できるようにバイアス(b)を設定する

先ほどの場合だと右辺に当たるthetaの値を0にしたい  ということは移行の要領で

def AND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.7
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

ここでnumpyが出てきます 参考 機械学習でも定番のPythonライブラリ「NumPy」の初心者向け使い方チュートリアル - paiza開発日誌
arrayは行列作成、sumは合計を演算

続いてNANDゲートとORゲートを実装

#NANDゲート
def NAND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([-0.5, -0.5])
    b = 0.7
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1
#ORゲート
def OR(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.2
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

NANDはNOT AND回路、つまりAND以外で1を返す
ORは「〜または〜」なのでどちらか片方のxが1ならyも1を返す
ANDもNANDもORも結局のところwの重みの値、bのバイアスの値がそれぞれ違うだけで仕組みそのものは一緒なのです 感動ですね! 中学校であのつまらない技術の授業を受けててよかった!

さてここまで三つの回路を作ってきましたが、ではこれら以外も単純パーセプトロンで表現可能なのかというと、残念ながらそうではないようです

XORゲート

XORゲートは排他的論理和とも呼ばれる論理回路です
さて先ほどのORゲートと何が違うのか

例えば、○○さんはアメリまたはイギリスにいます、と言われた場合、彼/彼女はアメリカにいてなおかつイギリスにいる、と言う状況は考えられない
しかし先ほどのORゲートを見ると、x1を米、x2を英とした場合、x1、x2両方が1の場合でもy=1が成立してしまう ということでまたはには二種類あるということ で、いいんですよね先生

XORゲートではx1かx2どちらか片方が1の時(つまり片方は0の時)1を返すゲートです 0,0 もしくは 1,1 の時には0を返します

しかし……これまで見てきた既存のパーセプトロンではこれを表現できません

f:id:python_nnn:20180904003313j:plain:w300

ざっくりと、今までののAND、NAND、ORを回帰直線(図)で表現すると、一本の直線を引きそれで領域を分けていることになる
けどXORゲートは直線では表せない ではどうするか

どうやらパーセプトロン同士を組み合わせることによって解決できるらしい

先ほどの入力層(x)と出力層(y)の間に隠れ層(s)を挟む
x1からs1とs2へ、x2からもs1とs2へワイヤーを結び、s1とs2からゲートを通してyを出力する

def XOR(x1, x2):
    s1 = NAND(x1, x2)
    s2 = OR(x1, x2)
    y = AND(s1, s2)
    return y

s1にNAND、s2にOR、yにANDゲートと、いままで定義してきた関数を流用することで非線形の表現ができるようになった すごい 感動である

次回 python-nnn.hatenadiary.jp

python始めました

機械学習に興味あったしせっかくN高校に入ったのだからとpython始めたけど、スマホ依存症で気づけばソシャゲばかりやっている マズイ

せっかくなのでアウトプットとメモを兼ねてブログ開設

このブログがモチベに繋がると信じて

これ絶対10年後とかに見返して身悶える自分語り系黒歴史ブログでしょ