体験授業

講師:大森田不可止



AI プログラミング体験




矢印キーの左右 と上下 でスライドを操作します。

spaceshift + space での操作が快適です。

スライドの操作

キー操作
or lスライドを右方向に進む
or h前のスライドに移動
or j下のスライドに移動
or k上のスライドに移動
Space or n次のスライドへ垂直→水平の順に移動
Shift + spaceSpace の順序を逆にたどる。
Home最初のスライドへ
End最後のスライドへ
Esc or o概要表示
f全画面表示。Escで戻す。




AI・機械学習・ディープラーニング

今日の授業

  • 「AI」でグーグルニュース検索をかけると沢山の記事がヒットします。AI - Google 検索
  • これらの記事の中では AI は、一番広い意味で使われてますが、内容を読むと「ディープラーニング」を使った「ニューラルネットワーク」のことを AI と呼んでる場合が多いです。
  • 今日は、各用語の違いを理解して、「ディープラーニング」のプログラムを体験してみます。
  • 初めて聞くような用語が多いと思いますが、言葉に惑わされずに、どんなものなのかを覗いてみましょう。

AI の歴史

  • 1956年 ダートマス会議で、Artificial Intelligence (AI) という用語が初めて使われました。日本語訳は「人工知能」。翌年に、 人工ニューラルネットワークの萌芽である、パーセプトロンが発表されます。
  • パーセプトロンは、単純な分類問題しか解けませんでしたが、工夫された 多層フィードフォワードニューラルネットワーク が考案されます。ただし、このシステムは複雑すぎて、どう扱えば良いのかは手探り状態で、ゆっくり進歩していきます。
  • 長年、華々しい成果が無かった技術ですが、ここ5年ほどで、数学的に厳密な解析手法が確立され、巨大データ処理技術を背景に ディープラーニングという手法が、現在驚異的な発展段階にあります。

ai history

ニューロン (神経細胞)

  • 最初のアイデアは、動物の感覚神経です。触覚・視覚・聴覚・味覚・嗅覚の五感を脳に伝える仕組みは、精巧なシステムです。例えば、嗅覚は新しい匂いには敏感ですが、その刺激が続くと無視するようになります。
  • この仕組をプログラムで実現しようとしたのが、ニューラルネットワークです。

  • Dendrites: (神経細胞の) 樹状突起
  • Cell nucleus: 細胞核
  • Axon: (神経細胞の) 軸索
  • Myelin: ミエリン(髄鞘を組織する脂肪質の物質)
  • sheath: さや、おおい、被覆

パーセプトロン

  • ある入力に対して、その出力を分析して「学習」する仕組みを実現するシステムを「 機械学習」と呼びます。
  • 下図は機械学習の基本の1957年発祥の「パーセプトロン」の概念図です。ニューラルネットワークによるディープラーニングが成果を挙げてますが、基本構造はパーセプトロンが原点です。ただ、最近はより複雑になってきています。

多層パーセプトロン

  • 下図は「多層フィードフォワードニューラルネットワーク」(multi-layer feedforward neural network)、多層パーセプトロン(Multi-Layer Percepton: MLP) とも呼ばれる概念図である。
  • 隠れ層(hidden layer)のユニットは入力層と完全に結合しており、出力層は隠れ層と完全に結合してる。このように隠れ層が1つ以上存在するものを「ディープ」人工ニューラルネットワークと呼ぶ。隠れ層も含めた沢山の「重み」を学習させないといけないので、高度な技術が必要になります。

ニューラルネットワーク

  • 隠れ層が多くなると、出力をフィードバックして学習させる事が困難になってきます。この解決のために、以下のふたつの技術が登場しました。
    1. 1986年 バックプロパゲーション(Backpropagation)。日本語訳は誤差逆伝播法。
    2. 2012年頃以降 ディープラーニング(deep learning)。日本語訳は深層学習。
  • ディープラーニングの考え方は 1980年頃からあったが、近年のデータ分析手法の発達と、計算機資源の進化とが合致して、爆発的な成果を出すに至っている。
  • データ分析手法は、近年のデータマイニングからビッグデータと呼ばれる、雑多な巨大データから、意味のある情報を取り出そうとする流れです。オープンソースでくくられてる Rという統計ソフトが貢献してます。例えば改札を利用した個々の乗客がどの路線のどの区間を利用したかを集計して、混雑を緩和する最適解を探すような技術です。
  • 計算機資源は、最近ではグラフィック表示を行うGPUを計算機として利用する、GPGPU (General-purpose computing on graphics processing units) という技術の発展があります。複雑な計算は出来ませんが、PCの計算能力を数十倍に引き上げることができます。




Python

プログラム言語 Python

  • Python は日本ではあまり人気がありませんでしたが、世界では人気言語のひとつです。
  • 機械学習に向いたライブラリが多数作成されてますので、機械学習の定番言語となっています。
  • ライブラリは、import 文で手軽に利用できます。
  • 今までは環境構築が大変だったのですが、ANACONDA というソフトをインストールすると、様々なライブラリが最初から利用できて、便利な機能も提供されてます。TECH.C. の PC には、インストールされています。

ipython の起動

  • エクスプローラを起動します。 + e
  • 作業用のフォルダを作成します。
  • そのフォルダでコンソールを起動します。エクスプローラのアドレスバーに、cmd + Enter
  • コンソールが起動したら、 jupyter qtconsole と入力します。

Python ドキュメント

公式サイトの以下の文章を参照。チュートリアルは読み物、それ以外はリファレンスです。

Windows の基本操作

Copyctrl + C HelpF1
Cutctrl + X RenameF2
Pastectrl + V SearchF3
Undoctrl + Z 行頭Home
Select Allctrl + A 行末End
Savectrl + S 上に1ページ移動PageUp
エクスプローラ + E 下に1ページ移動PageDown
窓の最小化・復元 + D IE 開発者ツールF12
コマンド実行 + R IE ReloadF5
タスクマネージャctrl + Shift + ESC IE 完全ReloadCtrl + F5




手書き文字を分類する

手書き文字認識

  • ディープラーニングで、AI研究者向けの手書き文字サンプルデータを使って、トレーニングしてみます。
  • 今までは、手書き文字の認識は、難しいプログラムが必要でした。経験をプログラムにして、より正確な分類が出来るように、プログラムを追加・改良を積み重ねるやり方でした。プログラムは多く、複雑になるし、どうすればより良くなるかはどんどん難しくなります。それを、ディープラーニングが軽々と乗り越えたことの凄さを感じてください。
  • サンプルデータは、28x28 のグレースケール画像に、0~9のどの数字を描いたものかの「正解」が付いてます。
  • 正解付きのデータで学習することを「教師あり学習」と呼びます。
  • 他に「教師なし学習」「強化学習」があり、学習はこの3つに分類されます。

MNISTデータを取得する

  • MNIST (Mixed National Instinute of Standards and Technology) データセットの手書き文字を分類するために、多層ニューラルネットワークをトレーニングする。
  • MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burgesのデータを利用する。4つのデータをZIPファイルにしたものをダウンロードする。 alldata.zip
    • Training set images: train-images-idx3-ubyte.gz (9.9 MB, 47 MB unzipped, 60,000 samples)
    • Training set labels: train-labels-idx1-ubyte.gz (29 KB, 60 KB unzipped, 60,000 labels)
    • Test set images: t10k-images-idx3-ubyte.gz (1.6 MB, 7.8 MB, 10,000 samples)
    • Test set labels: t10k-labels-idx1-ubyte.gz (5 KB, 10 KB unzipped, 10,000 labels)
  • トレーニングデータは学習するためのデータで、学習した結果を評価するためのデータがテストデータです。
  • トレーニングデータセットは250人の手書き数字で構成されている。テストデータセットには、同じ割合で別の人々の手書き文字が含まれている。

MNISTデータを読み込む load_mnist.py

画像はバイトフォーマットで格納されている。それらを NumPy の配列に読み込み、MLP実装のトレーニングとテストに使用する。path にデータがあるフォルダ、kind に train か test を指定して、目的のファイルを読み込み、images と labels のデータを返す関数を提供する。

load_mnist.py … 右クリック→名前を付けて保存で、作業フォルダを選んで保存。

import os
import struct
import numpy as np

def load_mnist(path, kind='train'): # mnist データ読み込みのための関数定義
"""Load MNIST data from `path`"""
labels_path = os.path.join(path,'%s-labels.idx1-ubyte' % kind)
images_path = os.path.join(path,'%s-images.idx3-ubyte' % kind)

with open(labels_path, 'rb') as lbpath:
    magic, n = struct.unpack('>II', lbpath.read(8))
    labels = np.fromfile(lbpath, dtype=np.uint8)

with open(images_path, 'rb') as imgpath:
    magic, num, rows, cols = struct.unpack(">IIII",imgpath.read(16))
    images = np.fromfile(imgpath,dtype=np.uint8).reshape(len(labels), 784)

return images, labels

MNISTデータ の内容

  • load_mnist関数は戻り値として配列を2つ返す。1つめは \(n \times m\) 次元の NumPy配列 images である。この場合の \(n\) はサンプルの個数、\(m\) は特徴量の個数を表す。トレーニングデータセットには、6万個のサンプルが含まれており、テストデータには1万個のサンプルが含まれている。MNISTデータセットに含まれている画像は \(28 \times 28\) ピクセルで構成されており、各ピクセルはグレースケールの輝度を表す。この関数は、\(28 \times 28\) ピクセルを1次元の行列ベクトルとして展開されている。それらのベクトルは画像配列の行を表す。
  • 2つめの配列 labels には対応する目的変数が含まれている。目的変数は手書きの数字のクラスラベル(0~9の整数)を表す。

ここから、実際にプログラムを動かします。

  • 読み込みんで、そのデータを確認します。
    トレーニング: 画像: X_train, ラベル: y_train、 テスト: 画像: X_test, ラベル: y_test

%run load_mnist.py  # load_mnist 関数の定義を実行
X_train, y_train = load_mnist('mnist/', kind='train')  # mnist/ の train-images-idx3-ubyte / train-labels-idx3-ubyte を読みこむ
print('Rows: %d, columns: %d' % (X_train.shape[0], X_train.shape[1]))
X_test, y_test = load_mnist('mnist/', kind='t10k')  # mnist/ の t10k-images-idx3-ubyte / t10k-labels-idx3-ubyte を読みこむ
print('Rows: %d, columns: %d' % (X_test.shape[0], X_test.shape[1]))

  • 扱いにくそうだったデータが、4つの「変数」に、入力されました。こういった、統一的な扱いが出来るようになって、ニューラルネットワークが飛躍的に進歩しました。

MNISTデータの可視化: データセット表示

MNIST の画像データを可視化してみよう。

import matplotlib.pyplot as plt  # プロットライブラリ

fig, ax = plt.subplots(nrows=2, ncols=5, sharex=True, sharey=True,)
ax = ax.flatten()
for i in range(10):  # 繰り返し i = (0,1,2,...,9)
    img = X_train[y_train == i][0].reshape(28, 28)  # 行の真ん中あたりの [0] を [1] [2] などに変更して違う画像表示
    ax[i].imshow(img, cmap='Greys', interpolation='nearest')

ax[0].set_xticks([]) # 画像表示
ax[0].set_yticks([])
plt.tight_layout()
# plt.savefig('./figures/mnist_all.png', dpi=300)  # 表示した画像をファイルとして保存
plt.show()

MNISTデータの可視化: 同じ数字の表示

  • サンプルの数字の例をいくつか描画して、それらの筆跡の違いを実際に確かめてみよう。
fig, ax = plt.subplots(nrows=5, ncols=5, sharex=True, sharey=True,)
ax = ax.flatten()
for i in range(25):
    img = X_train[y_train == 7][i].reshape(28, 28)  # [y_train == 7] の 7 を変更して違う数字の表示
    ax[i].imshow(img, cmap='Greys', interpolation='nearest')

ax[0].set_xticks([]) # 画像表示
ax[0].set_yticks([])
plt.tight_layout()
# plt.savefig('./figures/mnist_7.png', dpi=300)  # 表示した画像をファイルとして保存
plt.show()

多層パーセプトロンを実装する

  • Code: neuralnetmlp.py File: neuralnetmlp.py
  • クラス NeuralNetMLP() が記述されてる。「クラス」は、ある機能をパッケージしたものだと思ってください。
  • def __init__ は、コンストラクタと呼ばれ、様々な値を設定して、働きの違う クラスのコピーを作ることができる。
  • def fit() が、学習(入力データに対する適応、 fitting) を実行する関数。引数に、トレーニングデータを与える。
  • ソースコードは、コメント(説明書き)部分(緑色の文字)を除くと200行程度。他の言語なら10倍位の行数が必要になる。Python が様々な処理を簡略化してくれるお陰である。
  • 世間で騒がれてる AI の正体そのものがこのソースコードで、コア部分は簡単なコードで記述できることがわかる。

MLPの初期化

  • クラス NeuralNetMLP に様々な初期値を設定した実体を、nn という変数に入れる。
%run neuralnetmlp.py
nn = NeuralNetMLP(n_output=10,
                  n_features=X_train.shape[1],
                  n_hidden=50,
                  l2=0.1,
                  l1=0.0,
                  epochs=1000,
                  eta=0.001,
                  alpha=0.001,
                  decrease_const=0.00001,
                  minibatches=50,
                  shuffle=True,
                  random_state=1 )

MLPのトレーニング

  • MLPのトレーニング(fit) をする。これには、10~30分掛かるので、走らせておいて、授業を進める。
    
    # nn (NeuralNetMLP) のトレーニングを実行
    nn.fit(X_train, y_train, print_progress=True)
    

  • 「手書き数字認識」は、日本では 1968年の郵便番号の導入時から、郵便区分機の導入が始まってる。初期の正読率は75% 程度であったらしい。
  • 1997年 郵便番号データにみる手書き数字認識技術の現状 によると、郵便番号導入から約30年で、正読率98.20%に向上。「いわゆる達筆」の数字や、筆ペンで書かれた数字などでは解読不能な場合があり、ほぼ上限と思われる。
  • 手書き文字認識に人生を掛けて 98.20%を30年技術を積み上げて実現した技術者が居たということを思って欲しい。機械学習は、蓄積された技術とは関係なく、悠々と同レベルの正読率を実現してる。

MLPのトレーニング終了

  • 各エポックのコストを cost_ リストに保存しておき、それを可視化すれば、最適化アルゴリズムが収束したことを確認できる。
  • import matplotlib.pyplot as plt
    plt.plot(range(len(nn.cost_)), nn.cost_)
    plt.ylim([0, 2000])
    plt.ylabel('Cost')
    plt.xlabel('Epochs * 50')
    plt.tight_layout()
    # plt.savefig('./figures/cost.png', dpi=300)
    plt.show()
    

    最適化アルゴリズムの収束

    • 以下の図に示されているように、コスト関数のグラフはノイズだらけに見える。これは、確率的勾配降下法の一種であるニューラルネットワークをミニバッチ学習でトレーニングしたためである。

    最適化アルゴリズムの収束(2)

    • グラフから、最適化アルゴリズムが \(40000 \div 50 = 800\) エポックほどで収束したことが見て取れる。平均化して、より滑らかなコスト関数をプロットする。
    • batches = np.array_split(range(len(nn.cost_)), 1000)
      cost_ary = np.array(nn.cost_)
      cost_avgs = [np.mean(cost_ary[i]) for i in batches]
      plt.plot(range(len(cost_avgs)), cost_avgs, color='red')
      plt.ylim([0, 2000])
      plt.ylabel('Cost')
      plt.xlabel('Epochs')
      plt.tight_layout()
      #plt.savefig('./figures/cost2.png', dpi=300)
      plt.show()
      

    モデルの性能評価

    • 予測の正解率を計算することで、このモデルの性能を評価してみよう。
      y_train_pred = nn.predict(X_train)
      acc = np.sum(y_train == y_train_pred, axis=0) / X_train.shape[0]
      print('Training accuracy: %.2f%%' % (acc * 100))
      
    • このモデルはトレーニング用の数字のほとんどを正しく分類してるが、未知のデータに対する汎化はどうなるか、テストデータの正解率を計算してみる。
      y_test_pred = nn.predict(X_test)
      acc = np.sum(y_test == y_test_pred, axis=0) / X_test.shape[0]
      print('Test accuracy: %.2f%%' % (acc * 100))
      

    モデルの性能評価(2)

    • トレーニングとテストの正解率がわずかに異なることから、このモデルはトレーニングデータをわずかながら過学習してると結論付けることができる。
    • このMLP実装が奮闘する様子を示す画像を見てみよう。
    miscl_img = X_test[y_test != y_test_pred][:25]
    correct_lab = y_test[y_test != y_test_pred][:25]
    miscl_lab = y_test_pred[y_test != y_test_pred][:25]
    fig, ax = plt.subplots(nrows=5, ncols=5, sharex=True, sharey=True,)
    ax = ax.flatten()
    for i in range(25):
        img = miscl_img[i].reshape(28, 28)
        ax[i].imshow(img, cmap='Greys', interpolation='nearest')
        ax[i].set_title('%d) t: %d p: %d' % (i+1, correct_lab[i], miscl_lab[i]))
    
    ax[0].set_xticks([])
    ax[0].set_yticks([])
    plt.tight_layout()
    # plt.savefig('./figures/mnist_miscl.png', dpi=300)
    plt.show()
    

    モデルの性能評価(3)

    • このコードを実行すると、\(5 \times 5\)の行列としてサブプロットが表示される。小見出しの数字は、プロットインデックス、正しいクラスラベル\((t)\)、予測されたクラスラベル\((p)\) を表してる。
    • 図が示しているように、人が見ても正しく分類するのが難しいものも含まれてる。