LoginSignup
6

More than 3 years have passed since last update.

アプリでまなぶNN:動かす人工知能ーテンソルフロープレイグラウンド

Last updated at Posted at 2019-08-16

直感的にニューラルネットワークの仕組みを理解してみましょう。

深層学習とかニューラルネットワークとか、人工知能という言葉が世間で飛び交っています。いったい、これらがどのようなものなのかを理解したいと思っている人は多いのではないでしょうか?でもプログラミングの知識もなければ、ITの知識もないという人には高いハードルのように感じられます。そのような人のために、テンソルフロープレイグラウンドというツール、アプリが用意されているのをご存知ですか。

ブラウザーを開いてつぎのURLを開いてみてください。

つぎのような画面が現れます。

image.png

これはニューラルネットワークを学ぶための学習ツールです。ニューラルネットワーク・シミュレーターとでも呼んだらいいのでしょうか?

この場合には、入力データは$X_1$と$X_2$が選ばれています。また出力はサークルが描かれています。青い点が円形に、赤い点がそれを取り巻く輪として配置されています。このニューラルネットワークでは隠れ層(Hidden layers)が2つでそれぞれに4つのニューロンと2つのニューロンが配置されています。ニューロンって何だろうと思ってしまいます。でも何か聞いたこともありそうです。そうです。たぶん聞いたことがあるはずです。脳を構成する神経細胞のことです。

image.png

大きく頭の部分としっぽの部分、そしてそれをつなぐ筒のような胴体の3つの部分で構成されています。この神経細胞(ニューロン)の機能は数学的にモデル化されています。数学的にモデル化されたと聞くとこれからたくさん数式が出てきて厄介だと思われる方もいるかもしれません。心配いりません。極力、直感を頼りに理解できるように説明して行きます。

実際のニューロンは複数の電気信号を入力として受けとり、それを加工してつぎのニューロンに電気信号として出力しています。簡単な図で示すとつぎにようになります。

image.png

実は人間の脳では入力も出力も電気パルスという電気信号であったり、化学物質の1つであるシナプスであったりと、いろいろな媒介をとおして情報のやり取りをしています。上図の赤い点はこのシナプスをイメージしています。つぎの図を見てください。$X_1$, $X_2$が入力でyが出力です。

image.png

ニューロンを大まかに表現すると多数決素子といえます。入力を受け取るとその総和を計算します。興奮した情報をたくさん受け取ると、その情報は強まり、抑制性の情報を受け取るとその分差し引かれます。さらに簡単に書き表してみましょう。〇と→のついた直線で書き表してみました。矢印は情報の流れを表しています。電気パルスもシナプスという難しい仕組みは忘れてもっと単純化しましょう。

image.png

このモデルを単純パーセプトロンと呼びます。

ニューロンの頭には木の枝のようなものがたくさん付いていました。ここで他のニューロンからの情報を受け取っています。数が多ければその分多くの情報を受け取れます。多数決の判断も多い分正確になる可能性があります。実際のニューロンも数千、数万の情報を受け取っています。実際の脳では1000億個のニューロンが網目構造を作っています。この網目構造ですが、19世紀の後半の脳の研究では、この構造に議論が巻き起こりました。ニューロンの先端がつながっているのか、離れているのかが問題となったのです。結局、両方の説の主張者にノーベル賞が授与されました。真実は先端がつながっていないニューロン説でした。
image.png

ニューロンの頭には木の枝のようなものがたくさん付いていました。ここで他のニューロンからの情報を受け取っています。数が多ければその分多くの情報を受け取れます。

image.png

複雑な問題を解く場合に、ニューロンの数が足らなければ増やすことができます。3個に増やしてみましょう。

image.png

ニューロンの数だけではなく、層の数も増やせます。

image.png

書き直すと

image.png

となります。まとめると

image.png

このイメージにヒントを得て作られたのがニューラルネットワークです。ニューラルネットワークは分類問題を解くことを得意としているので、テンソルフロープレイグラウンドではディフォルトとして分類問題を解くように設定されています。つまり私たちの目の前にあるのはニューラルネットワーク(NN) なのです。これをいじってNNを理解していこうというのです。まず最初に左上の黒い丸の中に三角形が白抜きされている実行ボタンを押してみてください。

image.png

結果はつぎのようになるはずです。

image.png
背景の色と点の色が同じで何か境界線で2つの色の点が分離されていれば分類は成功したといえます。きれいなマルとはいえないまでも何となく分類されています。

DATA(データ):4つの模様(出力)から1つ選びます。

image.png

FEATURES(入力特徴量)とHIDDEN LAYERS(隠れ層)はニューラルネットワークの骨格の部分です。

image.png

DATA(データ)

まずはDATAです。ここから先ほどの画像に加えてあと3枚の画像を選ぶことが出来ます。ここで選んでいるのはOUTPUTのタイプです。出力される赤と青の点の模様を選んでいると考えてください。

左上はサークル、その右はXOR、左下は正規分布、その右はらせんと名前が付けられています。

入力データの選択

7つの画像をクリックすることで最大7つの入力データを選択することができます。それぞれのボックスには名前がついています。最初は$X_1$、つぎは$X_2$です。

image.png

HIDDEN LAYERS(隠れ層)

HIDDEN LAYERSは隠れ層、中間層のことです。ここには+と-のボタンが付いています。+を押すと隠れ層の数を増やすことができます。-を押すと隠れ層の数を減らすことができます。とりあえず隠れ層を1つとします。

Nuerons(ニューロン、ユニット)

NueronsもHIDDEN LAYERSと同じように+と-のボタンからなりたっています。このボタンはそれぞれの隠れ層についています。特定の隠れ層の+/-のボタンを押せばその層のニューロンの数を増減できます。このニューロンはユニットと呼ばれることもあります。

image.png

正規分布データの分類

つぎの出力データ(模様)を正規分布と呼びます。それぞれ2つの赤と青のデータのグループが正規分布から作られているのでこのように呼ばれています。

image.png

入力データは7つありますが、選択するべきは$X_1$、$X_2$のどちらか1つ、または両方の2つに限ります(少しずつ使うデータの数を増やしていきます)。$X_1$と$X_2$の両方の入力データを選択してみます。

s_perceptron.png

そして、実行ボタンを押してみてください。一瞬のうちにつぎのような結果になるはずです。

image.png

2つがきれいに分離されています。

サークル

つぎに入力データを変えることなくサークルを分類してみましょう。

image.png

隠れ層の数を増やすか、またはニューロンの数を増やすかしてニューラルネットワークを変更していきます。

image.png

結果はマルではなく3角形に近くなりました。それでも分類するという作業は達成されています。乱数により生成されているので形は若干変わります。隠れ層を2層にしてみましょう。

image.png

分離曲線は円形に近くなってきました。ニューロンを増やしたり、隠れ層の数をさらに増やしたりして試してみてください。隠れ層の1層目は線形の分析をしています。2層目からは非線形の分析をしているといわれています。

どちらの結果も2つのデータを分離しているので正解です。ですが、理想的なニューラルネットワークであるかどうかはわかりません。

右側の出力(OUTPUT)の右上の端のところにグラフが表示されています。またその左横には テスト誤差(test loss)と訓練誤差(training loss)が表示されています。誤差は学習の結果として得られた予測値と実際の値との差を示しています。

image.png

グラフは訓練誤差とテスト誤差を可視化したものです。時間の経過とともにどのように変化しているのかが分かります。数値は小さければ小さいほど良い結果です。実際の値が青で予測値も青であれば、予測誤差はゼロになります。また、実効ボタンの横にエポック(epoch)の数が示されています。今回は500個のデータが用いられているので、1エポックは500個のデータになります。(正確には訓練データの総数を1エポックとします。)2エポックでは500×2=1000個のデータになります。

ノイズを加えてみよう

つぎにノイズを加えてみてください。

まずはディフォルトの状態に戻してください。そしてプレイグラウンドの左の中央のnoiseと書かれているスライドをいじります。これのボッチを右にずらすとノイズを加えることができます。50%までめいっぱい増やして実行ボタンを押します。

image.png

今度はきれいに分離ができません。これはニューラルネットワークがノイズに影響されて与えられたデータをきちっと学習できていない証拠です。ニューラルネットワークは自由度が高く、いろいろな問題に対処できるのですが、自由度が高い分、ノイズには弱いのです。ではノイズに強いNNを作るにはどうしたらよいのでしょうか?それは背後にある状況を正確に把握してニューラルネットワークの構造を作ることです。ではやってみましょう。

サークルの答え

image.png

なんとあっという間に分類ができてしまいました。うまくいった原因を考えてみましょう。それは入力データの選択にあります。中学で習った数学を思い出してください。円を描くには$X_1^2+X_2^2=1$とすればよいことを学びました。ニューラルネットワークでも同じことです。

つぎにノイズを加えてみてください。
image.png
なんとさきほどよりもずっと原型をとどめてくれます。これはNNの構造が入力データの選択、隠れ層の数、ニューロンの数と出力に対して適切だからです。もちろん他にもいろいろな方法でノイズに強いNNを作ることができますが、まずは構造が重要です。左下のGENERATEボタンを押すと乱数をリセットでき、いろいろなノイズを試すことができます。やってみましょう。

誰でもわかるニューラルネットワーク:貧困の撲滅

AIの使い道が急激に広がっています。多くの人がそれを実感しているのではないでしょうか。いたるところでAIと接する機会が増えました。しかし、ここでは一般とはちょっと違う別の用途を紹介します。

貧困の撲滅

 AIが活躍するのは先進国だけではありません。開発途上の国々では先進国以上にAIに注目が集まっています。特に災害時の緊急対応、農業、医療、教育の分野で注目されています。過疎の地域では、教育、医療の問題は深刻です。今まで何の解決策も見いだされなかった分野に光が灯ろうとしています。また、貧困の撲滅にもAIは一役買っています。衛星からの高密度精細画像を分析することで貧困地域を発掘し解決策を見出そうとしているのです。昼夜の衛星写真から経済の活動度を推定し、貧困の撲滅に活かそうとする試みがあります。つぎの図はそのような活動に使われる夜間の衛星写真です。

image.png

出所:http://sustain.stanford.edu/predicting-poverty

 AIは開発途上の国々の子供たちに教育の機会を与えることを可能とします。それが貧困の連鎖を断ち切り貧困の撲滅につながるのです。
image.png

出所:「シミュレーターでまなぶニューラルネットワーク」(アマゾンkindle出版)
(https://www.amazon.co.jp/gp/product/B07MJ9R2T8?pf_rd_p=7b903293-68b0-4a33-9b7c-65c76866a371&pf_rd_r=4JRRRHRRE1FHXSY1EP5G)
image.png

 2015年のネパール、カトマンズの大地震ではドローンが被害状況の把握と地図の作成に利用され、救助活動の加速化を可能としました。

image.png

出所:「シミュレーターでまなぶニューラルネットワーク」(アマゾンkindle出版)
(https://www.amazon.co.jp/gp/product/B07MJ9R2T8?pf_rd_p=7b903293-68b0-4a33-9b7c-65c76866a371&pf_rd_r=4JRRRHRRE1FHXSY1EP5G)

 また、AIは地震、森林火災、洪水、台風、ハリケーンの予測などに活かされようとしています。

世界の貧困は多くの人たちの努力により減っています。しかし、サハラ以南のアフリカは別です。

過去30年で世界の貧困層の割合は確実に減っていますが、グラフにあるように減り方が頭打ちになりつつあります。根深い貧困の原因があるからです。

アジアは極貧状態を克服できましたが、サハラ以南の地域では増えています。

全体では減っているが、新しい局面に到達!
image.png
出所:Ending Extreme Poverty and sharing prosperity:Progress and Policies, World Bank Group
http://pubdocs.worldbank.org/en/109701443800596288/PRN03Oct2015TwinGoals.pdf

サハラ以南の極貧状態に注目!
image.png
出所:Ending Extreme Poverty and sharing prosperity:Progress and Policies, World Bank Group

今ある富の分配に問題が!

青いバーは人口全体の収入の増加率を示しています。
橙のバーは収入の低い40%の人達の収入の増加率を示しています。

image.png
出所:Poverty & Equity Data Portal, World Bank Group
http://povertydata.worldbank.org/poverty/home/

今気になるWEBサイト

gapminder

貧困の傾向 extreme poverty

image.png

世界の貧困率は改善している。しかし、...

平均寿命

本のついこの間まで、世界の平均寿命は短かった。
image.png
https://www.gapminder.org/topics/life-expectancy/
image.png

地域別収入

image.png

Global Poverty|WorldDataLab

AI Based Poverty Mapping
image.png

北朝鮮の貧困状態を衛星写真から人工知能で把握。全く光がない。
image.png

Global Poverty
image.png

Global Poverty Data

3D プリンター

貧困とテクノロジー:AIが貧困者を予測し、3Dプリンタが格安住宅を建てる

image.png

つぎのURLをクリックすると3つの記事が出てきます。

AI IMPROVES FARMING WITH GOOGLE’S TENSORFLOW

A LOOK AT THE POSITIVE SIDE OF AI AND DRONES

ARTIFICIAL INTELLIGENCE, GLOBAL POVERTY, HEALTH, TECHNOLOGY ON ARTIFICIAL INTELLIGENCE AND POVERTY

参考文献

貧困の終焉(ジェフリー・サック)
https://www.amazon.co.jp/貧困の終焉-2025年までに世界を変える-ハヤカワ文庫-NF-404/dp/4150504040/ref=sr_1_fkmr1_1?__mk_ja_JP=カタカナ&keywords=ジェフリーサック+貧困&qid=1562760131&s=gateway&sr=8-1-fkmr1

image.png

sustainability and artificial intelligence lab
http://sustain.stanford.edu/predicting-poverty

Kerasでテンソルフロープレイグラウンドを理解する

しかし、より詳細にその内容を理解するためには同じものを別のプログラミング言語で作ってみるのも一つの手です。本記事ではこれをkerasを用いて行います。

サークル

上述の画像はテンソルフロープレイグラウンドの初期画面です。出力データにサークルが選択され、入力データにX1とX2が選ばれています。実行してみます。

image.png

これが何を行っているかを正確に理解するために、同じ動きをKerasで実現してみるのも一つの手です。そこでつぎのようなプログラムを作ってみました。

# 初期化
%matplotlib inline
import pandas_datareader.data as web
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import datetime

import keras

from keras.models import Sequential
from keras.layers import Dense, Activation

from keras.optimizers import SGD
from keras import models
from keras import layers
from keras import regularizers

from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split

データの構築

n=250
theta=np.random.uniform(0, 360, n)

x1=np.sin(theta)*np.random.uniform(3,5, n)
x2=np.cos(theta)*np.random.uniform(3,5, n)
y=np.ones(n)

plt.figure(figsize=(4, 4), dpi=50)
plt.scatter(x1,x2)

theta=np.random.uniform(0, 360, n)

x11=np.sin(theta)*np.random.uniform(-0, 2, n)
x22=np.cos(theta)*np.random.uniform(-0,2, n)

yy=np.zeros(n)

plt.scatter(x11,x22)

実行結果
image.png

# 訓練データ、テストデータの作成
x1=np.concatenate([x1,x11],axis=0)
x2=np.concatenate([x2,x22],axis=0)
y=np.concatenate([y,yy],axis=0)
X=np.stack([x1,x2],1)#.reshape(-1,2)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.5, random_state=42)

ネットワークの構築と最適化

model = models.Sequential()
model.add(layers.Dense(8, activation='tanh', input_shape=(2,)))
model.add(layers.Dense(8, activation='tanh'))
model.add(layers.Dense(1, activation='sigmoid'))

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])
model.fit(
    X_train,
    y_train,
    batch_size=10,
    epochs=500,
    verbose=0)
# 結果の評価
results = model.evaluate(X_train, y_train)
results

# 8/8 [==============================] - 0s 1ms/step - loss: 3.0139e-05 - accuracy: 1.0000
# [3.0139368391246535e-05, 1.0]

results = model.evaluate(X_test, y_test)
results

# 8/8 [==============================] - 0s 2ms/step - loss: 1.6788e-04 - accuracy: 1.0000
# [0.0001678814151091501, 1.0]

どちらの結果も誤差はゼロです。全問正解でした。
さらに理解を深めるために入力データを変更してみます。

image.png
単純パーセプトロンでデータをきれいに分類できました。これをKerasで行ってみましょう。

X2=np.stack([x1**2,x2**2],1)#.reshape(-1,2)
X2_train, X2_test, y_train, y_test = train_test_split(
    X2, y, test_size=0.33, random_state=42)

model = models.Sequential()
model.add(layers.Dense(1, activation='tanh', input_shape=(2,)))
model.add(layers.Dense(1, activation='sigmoid'))

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])
model.fit(
    X2_train,
    y_train,
    batch_size=10,
    epochs=500,
    verbose=0)

結果はつぎに様になりました。

results = model.evaluate(X2_train, y_train)
results
# 11/11 [==============================] - 0s 3ms/step - loss: 8.3843e-08 - accuracy: 1.0000
# [8.38432754335372e-08, 1.0]

results = model.evaluate(X2_test, y_test)
results
# 6/6 [==============================] - 0s 2ms/step - loss: 8.3747e-08 - accuracy: 1.0000
# [8.374658477805497e-08, 1.0]

どちらも正解率100%で誤差はゼロです。

正規分布

つぎは正規分布です。

image.png

まずはデータを構築します。

n=250
x1=np.random.normal(2,0.5, n)
x2=np.random.normal(2,0.5, n)
y=np.ones(n)

plt.figure(figsize=(4, 4), dpi=50)
plt.scatter(x1,x2)

x11=np.random.normal(-2,0.5, n)
x22=np.random.normal(-2,0.5, n)

yy=np.zeros(n)

plt.scatter(x11,x22)
x1=np.concatenate([x1,x11],axis=0)
x2=np.concatenate([x2,x22],axis=0)
y=np.concatenate([y,yy],axis=0)
X=np.stack([x1,x2],1)#.reshape(-1,2)

image.png
ニューラルネットワークはサークルのときと同じものを使います。その結果は

results = model.evaluate(X_train, y_train)
results
# 8/8 [==============================] - 0s 1ms/step - loss: 3.0139e-05 - accuracy: 1.0000
# [3.0139368391246535e-05, 1.0]

ふたたび誤差ゼロの正解率100%となりました。

この場合には
image.png
ともなります。

XOR

つぎはXORです。
image.png

n=125
x1=np.random.uniform(0,5, n)
x2=np.random.uniform(0,5, n)
y=np.ones(n)
x11=np.random.uniform(-5,0, n)
x22=np.random.uniform(-5,0, n)
yy=np.ones(n)
x1=np.concatenate([x1,x11],axis=0)
x2=np.concatenate([x2,x22],axis=0)
y=np.concatenate([y,yy],axis=0)

plt.figure(figsize=(4, 4), dpi=50)
plt.scatter(x1,x2)

x11=np.random.uniform(0,5, n)
x22=np.random.uniform(0,-5, n)
yy=np.zeros(n)
x111=np.random.uniform(-5,0, n)
x222=np.random.uniform(0,5, n)
yyy=np.zeros(n)
x11=np.concatenate([x11,x111],axis=0)
x22=np.concatenate([x22,x222],axis=0)
yy=np.concatenate([yy,yyy],axis=0)

plt.scatter(x11,x22)
len(x1),len(x2)
# (250, 250) 

250個のデータができたのが分かります。
image.png
訓練データとテストデータにシャッフルをして分割します。

x1=np.concatenate([x1,x11],axis=0)
x2=np.concatenate([x2,x22],axis=0)
y=np.concatenate([y,yy],axis=0)
X=np.stack([x1,x2],1)#.reshape(-1,2)
len(y)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.5, random_state=42)

このデータを2層(第一層4ユニット,第二層2ユニット)のNNで分類を試みます。結果は

results = model.evaluate(X_train, y_train)
results
# 8/8 [==============================] - 0s 2ms/step - loss: 0.0818 - accuracy: 0.9640
# [0.08181502670049667, 0.9639999866485596]

results = model.evaluate(X_test, y_test)
results
# 8/8 [==============================] - 0s 2ms/step - loss: 0.1269 - accuracy: 0.9520
# [0.1269153356552124, 0.9520000219345093]

誤差はほぼゼロで、正解率も9割を超えています。

つぎにデータの構造をつぎにように変えてみます。
image.png

X_train, X_test, y_train, y_test = train_test_split(
    x1*x2, y, test_size=0.33, random_state=42)

model = models.Sequential()
model.add(layers.Dense(1, activation='tanh', input_shape=(1,)))
model.add(layers.Dense(1, activation='sigmoid'))

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])
model.fit(
    X_train,
    y_train,
    batch_size=10,
    epochs=500,
    verbose=0)

結果はつぎのようになりました。

results = model.evaluate(X_train, y_train)
results
# 11/11 [==============================] - 0s 1ms/step - loss: 5.6793e-04 - accuracy: 1.0000
# [0.0005679333116859198, 1.0]

results = model.evaluate(X_test, y_test)
results
# 6/6 [==============================] - 0s 3ms/step - loss: 0.0070 - accuracy: 0.9939
# [0.007003221195191145, 0.9939393997192383]

誤差はほぼゼロで、正解率もほぼ100%になりました。

誰でもわかるニューラルネットワーク:正則化をテンソルフロープレイグラウンドで試してみた

参考:

「シミュレーターでまなぶニューラルネットワーク」(アマゾンkindle出版)
((https://www.amazon.co.jp/gp/product/B07MJ9R2T8?pf_rd_p=7b903293-68b0-4a33-9b7c-65c76866a371&pf_rd_r=4JRRRHRRE1FHXSY1EP5G))
image.png

「脳・心・人工知能 数理で脳を解き明かす」(ブルーバックス)
「圧縮センシングにもとづくスパースモデリングへのアプローチ」

誰でもわかるニューラルネットワーク:分類の仕組み

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6