MachineLearning

【初心者向け】ニューラルネットワークとは?Python(tf.keras)を使った実装も解説

ニューラルネットワーク Python

こんにちは、はやたす(@hayatasuuu )です。

普段はフリーランスでデータサイエンス案件を請けていて、本業(?)では登録者2万人越えのYouTubeでPythonの動画講義をアップしています。

そんな僕が「ニューラルネットワークの概要とPythonを使った実装」について紹介していきます。

もしも、

  • 本を使って勉強しているけど、イマイチよく分からないな…
  • 最新のTensorFlowを使ったニューラルネットワークの実装を知りたいな…
  • とりあえず動かしてみたいから、ネット上に”良い感じのコード”が載っていないかな…

このように感じていたら、ぜひこの記事を読んでみてください。

PythonのコードはGoogle Colabに対応してるので、誰でも100%実行できるようになっています。

ニューラルネットワークとは

ニューラルネットワーク

ひとことで言えば、ニューラルネットワークとは「ヒトの脳の構造を模倣した機械学習アルゴリズム」です。

ヒトの脳内は、ニューロンと呼ばれる神経細胞が大量に存在して、それがネットワーク状に結合することで神経回路が形成されています。

この「ヒトの脳内で形成される神経回路をコンピューターで実現できないか?」と考えられたのがニューラルネットワークです。

ネーミングはニューロンのネットワークでニューラルネットワーク。そのままです(笑)

ニューラルネットワークのイメージ図

言葉だけだと分かるようで分からないので、イメージ図を見ていきましょう。

ニューラルネットワークは以下のような層構造になっています。

ニューラルネットワーク 構造

入力層からデータを受け取り、中間層を経由して最終的に出力層まで渡っていきます。

図で描かれている中間層は便宜上1つですが、例えば2, 3つのように数を増やすことが可能です。(それもPythonであればカンタンに…!)

各ニューロンの動き

各ニューロンでは、1つ前の層から重み付きの入力を受け取ります。

ここでは1つ前の層に、3つのニューロンが格納されている場合を考えてみましょう。つまり、以下のような図になります。

ニューロン 構造

上から1つ目のニューロンの入力は\(x_1\)、重みは\(w_1\)で表しています。ということで、上から2つ目と3つ目は…、図で書いているとおりですね!

このとき、緑色のニューロンが受け取る入力は、

  • ①受け取った重み付き入力
  • ②バイアスと呼ばれる閾値

を足し合わせた重み付き和になります。

バイアスという言葉が初めて登場しました。これは図の中で\(b\)のことです。

重みがついた入力は分かりやすいですが、バイアスはあまり直感的ではないですよね。でも、そこまで身構えなくて大丈夫です。バイアスは単純に”調整役をになっている人”だと思ってください。

このバイアスを考慮すると、緑色のニューロンが前3つのニューロンから受け取る入力は、結局以下のようになります。

$$w_1x_1 + w_2x_2 + w_3x_3 + b$$

実は、ニューロンの動きを理解するのに必要な要素はこれだけです。

このような構造がネットワーク状になっているのが、ニューラルネットワークの全貌になります。

なので、もしも緑色のニューロンが次のニューロンに情報を渡すとすれば、

$$w_1x_1 + w_2x_2 + w_3x_3 + b$$

を渡してあげれば良い…、と言いたいところですが、これだけではありません。これはあくまでも「入力」の部分で、次のニューロンの情報を渡すには「出力に適切なかたち」に変えてあげる必要があります。

例えば、お寿司屋さんを考えると分かりやすいかもしれないですね。

お寿司屋さんは魚を入力として受け取っても、自分たちお客さんに物体のまま魚を渡してきません。(それはそれで楽しそうですが…)

そうではなく、お寿司屋さんでは魚を一枚切れの状態にして、自分たちお客さんに適切な形で渡してくれます。

このとき、お寿司屋さんが魚を入力から出力に換えるために使ったのは「包丁」という武器ですね。

ニューラルネットワークの場合、この武器は「活性化関数」になります。活性化関数を使うことで、受け取った入力を適切な出力に変換します。

活性化関数は色々な種類があり、そこでは数学の知識が必要になってきます。

なので、この記事では紹介を割愛しますが…、「活性化関数を使ってから次のニューロンに情報を渡すんだな」とおさえておいてください!

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

今回の例では、重みやバイアスを僕が勝手に決めました。でもニューラルネットワークでは、この重みとバイアスを求めることになります。

最適な重みとバイアスを発見すれば、正しい予測をおこなえるモデルを作成できるというわけです。

もちろん、最適な重みとバイアスはヒトが決めるわけではありません。それでは職人芸です。

ニューラルネットワークの重みとバイアスは、誤差逆伝播法(バックプロパゲーション)と呼ばれる手法でコンピューターが自動的に計算します。

この辺りは、いよいよ行列や微分などの数学が必要になってきます。なので、このタイミングでPythonを使った実装に逃げましょう(笑)

Pythonを使ったニューラルネットワークの実装

それではGoogle Colaboratory上で、ニューラルネットワークを実装していきましょう。

先に手順だけ書いておくと、以下の4ステップになります。

  • 手順① : ライブラリのインポート
  • 手順② : 手書き数字データの読み込みと前処理
  • 手順③ : ニューラルネットワークの構築
  • 手順④ : モデルを使った学習と推論

順番に見ていきましょう。

手順① : ライブラリのインポート

まずは今回必要になるライブラリをインポートしていきます。

Pythonでニューラルネットワークを実装するなら、以下の方法が挙げられます。

  • TensorFlowを使うパターン
  • PyTorchを使うパターン
  • スクラッチで書くパターン

このうち最も直感的で分かりやすく記述できるのがTensorFlowです。

今回は「初心者がとりあえず実装する」ことを目的としているので、TensorFlowの中でもkeras APIを使って実装していきます。

%tensorflow_version 2.x

import tensorflow as tf

import numpy as np
import matplotlib.pyplot as plt

 

ちなみにTensorFlowのバージョンを確認しておくと、この記事の執筆時点で2.5.0になっていました。

print(tf.__version__)
# --> 2.5.0

 

※TensorFlowについては以下の記事で詳しくまとめたので、合わせて確認してみてください。

TensorFlow とは
【初心者OK】TensorFlowとは?最新版2.xの特徴を分かりやすく解説『ディープラーニングを勉強していると、TensorFlow(テンソルフロー)って聞くけど、いったい何なんだろう...。TensorFlowとは?で検索しても、あんまりよく分からないな...。』このような悩みを解決する記事になっています。TensorFlowとは何か知りたい人は必見の記事です。...

また、今回はTensorFlowの最新版である2系を使っていくので、マジックコマンドで%tensorflow_version 2.xを書いておきます。

手順② : 手書き数字データの読み込みと前処理

ライブラリのインポートが完了したら、ニューラルネットワークで使うデータを読み込みます。

今回はサンプルコードでお馴染みのMNISTを使っていきます。

MNISTは手書き数字のデータセットです。学習用に60,000枚、テスト用に10,000枚の手書き数字が正解ラベルとセットで格納されています。

あとでどんな画像データなのか、一緒に確認していきましょう。

今は以下のコードを実行してデータを読み込んだあと、学習用(X_train, y_train)とテスト用(X_test, y_test)に振り分けておきます。

(X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data()

 

ここで正しくデータセットを読み込めているか確認してみます。それぞれの変数に対して.shapeを使って型を見てみましょう。

print(X_train.shape)
print(y_train.shape)

# --> (60000, 28, 28)
# --> (60000,)

print(X_test.shape)
print(y_test.shape)
# --> (10000, 28, 28)
# --> (10000,)

 

そうすると学習側(X_train, y_train)は60,000件、テスト側(X_test, y_test)は10,000件のデータが格納されていることが分かりました。

また画像データ(X_train, X_test)は、(28, 28)のようになっていて28×28ピクセルのデータであることが分かります。

それでは、今回使うデータがどんな画像になっているのか確認してみましょう。以下のコードを実行すると、10枚の手書き数字を表示できます。

fig, ax = plt.subplots(nrows=2, ncols=5, figsize=(10, 10), tight_layout=True)

n = 0
for i in range(2):
  for j in range(5):
      ax[i][j].imshow(X_train[n], cmap=plt.cm.binary)
      n += 1

 

MNIST サンプル

これが今回使っていく手書き数字の画像データです。

最終的には、60,000枚の学習用データを基に作られたニューラルネットワークを使って、正しく手書き数字を認識できたか判定していきます。

あとは前処理としてX_trainX_testを255で割っておきましょう。

X_train, X_test = X_train / 255.0, X_test / 255.0

 

これでデータの読み込みから前処理まで完了しました。

手順③ : ニューラルネットワークの構築

それでは、メイントピックになるニューラルネットワークの構築をおこなっていきましょう。

この記事では、以下のニューロンを持った3層のニューラルネットワークを構築していきます。

  • 入力層 : 784(=28 × 28)
  • 中間層 : 128
  • 出力層 : 10(=0〜9の正解ラベル数)

このモデルをTensorFlowで記述したのが以下です。

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28), name='InputLayer'),
  tf.keras.layers.Dense(128, activation='relu', name='MiddleLayer'),
  tf.keras.layers.Dense(10, activation='softmax', name='OutputLayer')
])

 

これをTensorFlowで可視化するには、以下のコードを記述します。

tf.keras.utils.plot_model(model, show_shapes=True, dpi=80, show_layer_names=True)

 

作成したニューラルネットワーク

上画像まで見ると、今回作成しているニューラルネットワークの形が分かってきますね。

ちなみに以下のコードを入力すると、より簡潔なネットワーク構造を把握できます。

model.summary()

 

モデルの概要を把握できたら、最後に以下のコードをセルに入力して実行します。

model.compile(optimizer='adam', 
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

 

今は意味不明だと思いますが、今回は深追いしなくて大丈夫です。まずはPythonを使った実装だけやっていきましょう。

手順④ : モデルを使った学習と推論

それでは、作成したニューラルネットワークを使って「学習」と「推論」をおこなっていきます。

まずは60,000枚の画像データとそのラベルを使って「学習」する必要があります。

そのためには、以下のようにコードを書いてあげます。(他の機械学習ライブラリでも、学習で使うメソッドはfit()です。)

history = model.fit(X_train, y_train, epochs=5)

 

コードを実行すると、以下のような出力になるはずです。

学習の履歴これは学習の経過を表しています。accuracyが精度になるので、だんだん精度が上がってきていることが分かりますね。

コードの実行が完了すると、これだけでニューラルネットワークの学習は完了しています。TensorFlowは神です。

あとは10,000枚のテスト用データを使ってモデルの精度を見てあげましょう。そのためには、以下のコードを入力して実行します。

model.evaluate(X_test,  y_test, verbose=2)

# 313/313 - 0s - loss: 0.0735 - accuracy: 0.9787
# [0.0735192596912384, 0.9786999821662903]

 

この出力でaccuracyをみれば、60,000枚の画像データを基に学習したニューラルネットワークの精度が分かります。

今回、僕の環境で試してみたところ、約97.9%であることが分かりました。そこそこの出来ですよね…!

あとはX_testで使っていた画像に対して、ニューラルネットワークが予測したラベル、つまり「0〜9のうち、どの数字だと予測したのか」を確認してみましょう。

そのためには「予測」を意味するpredict()を使います。

predictions = model.predict(X_test)

 

これで変数predictionsに予測結果を格納できました。

それでは、テスト用画像の1つ目が、どの数字だと予測されたのか見ていきましょう。

念の為、Matplotlibを使ってテスト用画像の1つ目を可視化しておきます。Pythonで最初の1つ目を選択するには、インデックス番号で”0″を選択ですね!

plt.imshow(X_test[0], cmap=plt.cm.binary)
pass

 

MNISTの可視化

テスト用画像の1枚目は数字の”7″であることが分かりました。

ということは、ニューラルネットワークでテスト用画像の1枚目が数字の”7″だと予測できていれば良いですね!

変数predictionsから予測結果を取得するには、以下のようなコードを書いてあげます。

print('正解:', y_test[0])
print('予測:', np.argmax(predictions[0]))

 

np.argmax()が理解しづらいですが、これはカッコ内で最大の数字になるインデックスを取得するという意味です。

例えば、以下のようなPythonリストがあったとします。

l = [1, 5, 3]

 

このときnp.argmax()を使うと、リスト内で最大の数字は5なので、そのインデックス番号である”1″が出力されます。

今回、0〜9の数字を予測していたので、インデックス番号がそのまま予測ラベルと一致するというわけですね!

それではコードを実行して、どのラベルだと予測したのか確認してみましょう。

ニューラルネットワークの予測結果

コードを実行してみると、しっかり数字の”7″を予測できていることが分かります。最初のテスト用画像は、正しく予測できているみたいですね!

まとめ

というわけで、今回はニューラルネットワークの概要とPythonを使った実装を紹介しました。

この記事を書いていて思ったのが、やはりディープラーニングは楽しいですね!

あと、普段はYouTubeで多少アルゴリズムやウケを気にしている部分があるので、自由にかけるのも嬉しいです(笑)

個人的には、従来の機械学習を勉強するより、ディープラーニングやったほうが良くない?って思っています。

それは実生活に取り入れやすいし、目で見える形でアウトプットが出てくるので、勉強していて楽しいからです。

それに「機械学習がわからないとディープラーニングをやってはいけない」みたいなルールなんてないですからね。

とにかく楽しいと感じることから着手するのが良いと思います。プログラミングもそうですが、楽しくないと続かないですからね!

ABOUT ME
はやたす
たくさんPythonを紹介するYouTuberです(登録者1.94万人) | フリーランスで機械学習/分析案件も請けています(経験業界 : 金融, 情報通信, サービス) | 元プログラミングスクール講師