LogoMark.png

データサイエンス/あふれ原稿1 のバックアップの現在との差分(No.4)


#author("2023-08-29T12:11:29+09:00;2023-08-17T17:04:44+09:00","default:inoue.ko","inoue.ko")
*第11回 機械学習2
[[データサイエンス/2023]]
~

***CONTENTS
#contents2_1
~
~
**ニューラルネットワークとは
ニューラルネットワーク(Neural Network:NN)とは、人間の脳内にある神経細胞(ニューロン)とその回路網を、人工ニューロンという数式的なモデルで表現したものです。ニューラルネットワークモデルは、シナプスの結合強度を学習によって調整することで、入力データを識別する能力を獲得していきます。
-[[GoogleImage:ニューラルネットワーク]]
-[[GoogleImage:ニューロン シナプス モデル]]

~

***人工ニューロン
#image(NeuralNetwork/ArtificialNeuron.png,right,40%)
人間の脳の中にはニューロンという神経細胞が約千億個あり、各ニューロンがシナプスと呼ばれる接合部位によって繋がっています。ニューロンは入力される電気信号の総和がある一定の量を超えると発火し、次のニューロンに電気信号を出力します。

この仕組みを模したのが「人工ニューロン(artificial neuron)」で、1943年に神経生理学者ウォーレン・マカロックと数学者ウォルター・ピッツが発表した「形式ニューロン(formal neuron 別名:Threshold Logic Unit )」がその最初のものです。 右図は1個の形式ニューロンの模式図で、中心のCELLが細胞。xSUB{1};〜xSUB{n}; が入力信号で、それぞれが一定の重み(w:値の大きいものが影響力大)で、細胞に接続されています。その総和が閾値(θ)を超えると、細胞が「発火」して次の細胞へと信号を送り出します。式で表すと以下のようになります。

 '''''y = f ( wSUB{1};・xSUB{1};  +  wSUB{2};・xSUB{2};  + ・・・・ +  wSUB{n};・xSUB{n};   -   θ )'''''

'''W = ( wSUB{1};, wSUB{2};, ・・wSUB{n}; )'''は、多次元空間における法線ベクトルで、関数式の内部ではまず、これとデータ '''X = ( xSUB{1};, xSUB{2};, ・・xSUB{n}; )''' との内積をとっていることになります。法線ベクトルと同じ向きにあれば内積は + 、反対向きにあれば内積は - で、要するに、上の関数式は、データが存在する空間を分割する多次元空間上の境界(2次元なら直線、3次元なら平面)であるということができます(詳細は次節)。

一般に、出力 y は0または1。つまり、細胞は抑制されるか興奮するかの2状態しかありません。このような細胞が何個も並び、それが何層にも連結されたものがニューラルネットワークになります。

~

***識別の原理
'''''W''''' の調整はどう行うのか、視覚的に説明してみましょう。x0, x1 を2軸とした平面に、データ X (x0,x1) が散布されていて、それらがTYPE A と TYPE B の2クラスに分類できる状態を仮定します(下図を参照)。

#image(NeuralNetwork/identification.png)

以下の式は、原点を通る直線で、その法線ベクトルは(w0, w1)です。
'''''w0・x0 + w1・x1  = 0'''''

図の状態を仮定して識別問題を考えた場合、w0, w1 が適切な値をとると、データは直線によってきれいに識別されることになります。学習による最適化とは、境界線の位置を学習データを読みながら調整する、すなわちこの場合、''法線ベクトルの向きを回転させて2つのタイプの境界に位置するように調整する作業''であるということができます。

(x0,x1)と法線ベクトルの内積  = '''w0・x0 + w1・x1'''  を計算すると同時に、それを正解ラベル( 1:TYPE A ,  -1:TYPE B )と照らすと、境界線が正しく2者を分離しているかどうかを判定することができます。
-内積が+で、正解ラベルが +1 > TYPE A を正しく判定している
-内積が+で、正解ラベルが -1 > TYPE  B を TYPE  A と誤判断している
-内積が - で、正解ラベルが +1 > TYPE  A を TYPE  B と誤判断している
-内積が - で、正解ラベルが -1 > TYPE  B を正しく判定している

つまり、ひとつのサンプルについての判定とその後の作業は以下のように記述することができます。
-内積 IP × 正解ラベル >  0 ならばOK > W の修正は行わない
-内積 IP × 正解ラベル <= 0 ならば誤認と判断 > W の修正を行う

修正は、以下のように行います。正解ラベル を学習率( Learning_Rate )を 0.1 とすると、学習は以下の式で実現できます。
'''''W = W  + X *  正解ラベル * 0.1''''' 
正解ラベルが 1, -1 に設定されていることで、2種類のエラータイプに対して、同じ計算式を適用できるわけです。
~

学習率とは「どの程度強く修正をかけるか」を意味する値で、これは人間が設定するしかない・・という意味で、ハイパーパラメータといいます。
-学習率が大きいと、1回の学習での回転角が大きくなりすぎて、バタバタすることになります。これを「発散」といいます。
-学習率が小さいと、正解に近づくには時間を要しますが、すこしずつ確実に正しい境界線の角度になっていきます。これを「収束」といいます。

以上、学習率を正しく見極めた上で、この手順で、データを読んでは修正を繰り返せば、境界線は正しい位置に収まります。
~

***ニューラルネットワークの概念図
#image(NeuralNetwork/NeuralNetwork.png,right,40%)
右図はニューラルネットワークのイメージです。Input Layer(入力層)は、最初のデータが入ってくる部分、Hidden Layer(隠れ層)は入力信号を受けて様々な興奮状態をつくる中間処理機関、そして Output Layer(出力層)は結果としての興奮状態を表現する部分す。例えば、気温、湿度、現在時刻という3種類のデータから、1時間後が「晴れている」か「雨が降る」かを予測する(ちょっと無理がありますが例え話です)という場合は、入力層が3、出力層が2となるモデルをつくって、過去の大量の気象データから、気温・湿度・時刻(説明変数)、そして 1時間後の天気(目的変数)というデータセットをつくって学習させることになります。
~

***活性化関数
ニューラルネットワークにおいて線形変換(重み付き入力の総和)後に最終的な出力を決める関数のことを「活性化関数(Activation Function)」と言います。中間層と出力層では用いる関数が異なるのが一般的で、以下のように分類できます。

-中間層で用いる活性化関数
--''ステップ関数(形式ニューロン)''
結果が閾値θよりも大きいか否かで、出力が単純に0または1の2値に区別されるものです。
''' f( x ) = 0(x≦θ),  1(x>θ)'''
--''線形結合(単純パーセプトロン)''
結果の値にバイアスを加えただけです。出力は線形連続になります。
''' f( x ) = ax + b'''
--''シグモイド関数''
入力した値が大きければ大きいほど1に近づき、小さければ小さいほど0に近づく・・[[ロジスティック関数>LogisticCurve]]の特殊ケースにあたります。[[バックプロパゲーション>Google:バックプロパゲーション]]を伴うニューラルネットワークで使われます。
'''f( x ) = 1 / ( 1 + exp(-x) )'''
--''tanh関数''
出力が−1から1なので出力がゼロになることでシグモイド関数に比べて学習の収束が容易になります。
'''f( x ) = ( exp(x) - exp(-x) ) / ( exp(x) + exp(-x) )'''
--''ReLU(ランプ関数)''
入力が 0以下のときは 0、1より大きいときは入力をそのまま出力します。
''' f( x ) = 0(x<θ),  x(x≧θ)''' あるいは '''f( x ) = max( x, 0 )'''

-出力層で用いる活性化関数
--''ソフトマックス関数''
各出力 f( xSUB{i}; ) の値をすべての '''i''' について合計すると 100% になるもので、例えば画像認識問題で「猫:70%, トラ:20%, 犬:10%」 といったような回答を得たい場合に用います。([[結果表示の事例>https://koichi-inoue.github.io/TensorFlowJS_MobileNet/]])
''' f( xSUB{i}; ) = exp(xSUB{i};) / ΣSUB{j}; exp(xSUB{j}; )'''
--''恒等関数''
最もシンプル、入力値をそのまま出力するものです。
'''f( x ) = x '''
~

***最適化アルゴリズム(オプティマイザ)
ニューラルネットの文脈では、最適化とは「出力の誤差が最小になるように調整すること」を意味します。誤差を表す関数は何らかのカーブを示しますが、このカーブをたどって、最下点に至るように、パラメータを調整するわけです。その方法には様々あります。以下リンクで紹介します。
-[[SGD>Google:最適化 SGD]]:Stochastic Gradient Descent 確率的勾配降下法
-[[Momentum>Google:最適化 SGD]]
-[[Nesterov Accelerated Gradient>Google:最適化 Nesterov Accelerated Gradient]]
-[[Adaptive Learning Rate>Google:最適化 Adaptive Learning Rate]]
Momentum法と異なり、学習率を自動調整することを目指したのが Adaptive Learning Rate を用いた手法です。
Adagrad, RMSProp, Adadelta, Adam, Adamax, Eve,
-[[YellowFin>Google:最適化 YellowFin]]
~

***参考:ディープラーニング
ニューラルネットワークの基本的なアイデアは3層構造ですが、中間層の数を数十〜百段階程度まで増やして、多段階の神経接続で出力を得よう・・という発想から誕生したのがディープラーニングです。多層化に耐えられるだけの計算力(演算速度向上とメモリの増大)が実現したことで、現在の人工知能はこの技術が主役になっています。
-[[GoogleImage:ディープラーニング]]
-[[体験サイト:Playground>http://playground.tensorflow.org]]
~

***ディープラーニングの活用事例
-AI端末 Googe Home(Googleアシスタント)
-AIコンシェルジュ [[OK,Google>Google:OK,Google]] [[Siri>Google:Siri]]
-翻訳 [[Google翻訳>https://translate.google.com/?hl=ja]]
&small(従来は PBMT(フレーズベース翻訳)、2016以降 GNMT(ニューラル機械翻訳));
~
~


**演習11|NNによる手書き文字認識
手書き数字の画像データ(28 × 28px) と正解ラベルのペアを学習用 60,000個、評価用 10,000個をセットにしたデータサンプル、[[MNIST>http://yann.lecun.com/exdb/mnist/]]を使用します。
~

***ノートブックの新規作成
-ブラウザ上の Google Colaboratory で ファイル> ノートブックを新規作成
-Untitled0.ipynb というファイル名を変更 > NeuralNetworkMNIST.ipynb
~

***サンプルデータ
MNIST(エムニスト):手書き文字認識用のサンプルデータ
http://yann.lecun.com/exdb/mnist/

#image(DataScience/MNIST.jpg,right,30%)
-28px x 28px の画像 70,000枚
-訓練用 60,000枚
-テスト用 10,000枚
#clear
~

***サンプルプログラム
JupyterNotebook形式(.ipynb)でプログラムを提供します。
-https://github.com/koichi-inoue/DataScience/blob/main/NeuralNetworkMNIST.ipynb
~

-使用しているライブラリ
--TensorFlow
--Keras

-モデルの定義
入力層 784、中間層 64、出力層 10(1-hot ベクトル)

//オプティマイザーを2種類試しています。
//-[[SGD>Google:最適化 SGD]]:Stochastic Gradient Descent
//-[[Adam>Google:最適化 Adam]]:Adaptive Moment estimation
~

***学科サイトにリンク掲載
ノートを、学科サイトの個人ページからリンクして下さい。以下、手順です。

-1. 自分のノートを開いた状態で、右上の「共有」をクリック

-2. 共有設定を変更して、以下のように表示される状態にします。
 このリンクを知っているインターネット上の全員が閲覧できます。

-3. 「リンクをコピー」をクリックして、そのアドレスを、以下の形式で、学科サイトの「Jupyter Notebooks」の部分に掲載して下さい。
 -[[ニューラルネットワーク(MNIST)>https://colab.research.go・・=sharing]]

-4. 以下のようになればOKです。
https://design.kyusan-u.ac.jp/socialdesign/?JohnSmith/DataScience
~
~

**演習11|プログラムの解説
手書き文字認識のプログラムについて解説します。

-1) データのインポート ライブラリからデータを読み込みます。
--x は入力画像、 y は正解ラベル。
--train が学習用、test が評価用です。

- 2) 入力画像データのスケール変換
--2次元画像 (28 × 28px) を1次元 (784px) に変形しています。 
--輝度(0〜255)を 最小値 0、最大値1にな るよう正規化しています。

-3) 正解ラベルの対応づけ
0 〜9の正解ラベルをカテゴリーデータに変形しています。

-4) 学習モデルの構築
--モデルには中間層の追加が簡単な Sequential モデルを選択
--入力層は、データ仕様から 784。
--中間層は 64 と設定しています。
ニューロンの出力を判定する活性化関数には relu( ランプ関数 ) を使用。
--出力層は、正解数の 10。
判定には Softmax 関数 を設定しています。

-5) モデルに訓練過程を設定
--model.compile で訓練過程を設定します。
--最適化の手法として、確率的勾配降下法 (SGD)を選択しています。
--損失関数に多値分類 (categorical_crossentropy) を選択しています。

-6) 機械学習の実行(数十秒かかります)
--model.fit で学習開始。
--epochs は学習反復回数 で、ここでは 10 回反復。
--loss は正解とのズレで、 0 に近いほど正解に近い。
--accuracy は正確性で、100% に近いほど正解に近い。

-7) 評価用のデータで正解率を検証
--評価用データに対する正解率を model.evaluate で計算。
--結果、94.3% 正解するモデルができています。 

-8) 混同行列でミスの発生状況を確認
--100 件のテストデータで、実際にどこにミスが生じているかを検証。
--出力された表は、混同行列
---行が予測された数字で、列が実際の正解に対応します。
---対角線上にあるのが正しく分類されたものです。
---対角線外のセルは、誤って予測されたものです。
--表からは、2 と 7、4 と 6、 5 と6を誤認するエラーが確認できます。
~
~

#hr
CENTER:'''以下は、その他の参考事例です'''
'''参考情報なので、取り組みは任意です。'''
#hr
~
~

**参考1|NNによる Iris の分類
[[Iris>https://archive.ics.uci.edu/ml/datasets/iris]] は、植物学者 R. Fisher による「あやめ」のデータで、統計ソフトの練習用として最も有名です。 Iris setosa、 Iris virginica、Iris versicolor 3種について、がく片の長さ、がく片の幅、花弁の長さ、花弁の幅の4つの計測データが、各 50、計 150 件含まれます。
~

***サンプルデータ
IRIS:植物学者 R. Fisher による「あやめ」のデータ
https://archive.ics.uci.edu/ml/datasets/iris

以下の項目をもつ150の計測データ
-Sepal Length(がく片長 cm)
-Sepal Width(がく片幅 cm)
-Petal Length(花びら長 cm)
-Petal Width(花びら幅 cm)
-Species:setosa, versicolor, virginica
~


***サンプルプログラム
JupyterNotebook形式(.ipynb)でプログラムを提供します。
https://github.com/koichi-inoue/DataScience/blob/main/NeuralNetworkIris.ipynb
~

-使用しているライブラリ
--TensorFlow
--Keras

-モデルの定義(Kerasを使用)
入力層4、中間層32、出力層3 で構築しています。
 model = Sequntial()
 model.add(Dense(32, input_dim=4)) 
 model.add(Activation('relu'))
 model.add(Dense(4))
 model.add(Activation('softmax'))
~
~

**参考2|SVMによる分類
分類の手法は NN だけではなく、SVM(サポートベクターマシン)など、他の手法でも可能です。Python の機械学習ライブラリ __[[Scikit-learn>https://scikit-learn.org/stable/]]__を使って手書数字を認識するプログラムを概説します。
~

***サンプルプログラム
JupyterNotebook形式(.ipynb)でプログラムを提供します。
https://github.com/koichi-inoue/DataScience/blob/main/DigitRecognition.ipynb

-1. データ読み込み
-2. 訓練データとテストデータに分割
-3. 学習(''fit'')
-4. 予測(''predict'')と 評価(score)

という流れが開発の定番スタイルです。
~
~


**APPENDIX
以下は、JavaScript用の機械学習ライブラリーを用いて、ブラウザ上で画像の認識を行うサンプルです。参考までにご紹介します。
~

***TensorFlow.js 
MobileNetの学習済みモデルと [[TensorFlow.js]]を利用して、画像の対象物を推論するサンプルです。手元の画像のドラッグ&ドロップで、対象を推論するサンプルです。上位4件の候補を、その確率とともに表示します(人や人物の顔は対象外なので、人物の画像を投入すると「T-シャツ」や「ネクタイ」が検知されます。)。

-CODE:https://github.com/koichi-inoue/TensorFlowJS_MobileNet
-DEMO:https://koichi-inoue.github.io/TensorFlowJS_MobileNet/
~

-WebGL経由でGPUを利用するので、古い環境では動かない場合があります。
-認識できる物体のラベル一覧は以下の検索でヒットします。
[[Google:imagenet 1000 classes list]]
-詳細 > [[TensorFlow.js]]
~

***ml5.js
[[ml5.js]] というJavaScriptAPI を利用した画像の分類その他について、以下のページにまとめています。
> [[ml5.js]]

~
~
~

~