#author("2024-09-10T11:56:57+09:00;2024-09-09T12:34:09+09:00","default:inoue.ko","inoue.ko") #author("2024-12-09T18:45:48+09:00;2024-09-10T11:56:57+09:00","default:inoue.ko","inoue.ko") *ニューラルネットワーク NeuralNetwork ~ ニューラルネットワーク(Neural Network:NN)とは、人間の脳内にある神経細胞(ニューロン)とその回路網を、人工ニューロンという数式的なモデルで表現したものです。ニューラルネットワークモデルは、シナプスの結合強度を学習によって調整することで、入力データを識別する能力を獲得していきます。 -[[GoogleImage:ニューラルネットワーク]] -[[GoogleImage:ニューロン シナプス モデル]] -http://ncase.me/neurons/ &small(ニューロンの働きを体験的に理解できるサイト); ~ ~ ***CONTENTS #contents2_1 ~ **人工ニューロン #image(ArtificialNeuron.png,right,40%) 人間の脳にはニューロンという神経細胞が、大脳だけで160億、脳全体で860億あって、各ニューロンがシナプスと呼ばれる接合部位によって繋がっています。ニューロンは入力される電気信号の総和がある一定の量を超えると発火し、次のニューロンに電気信号を出力します。 この仕組みを模したのが「人工ニューロン(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状態しかありません。このような細胞が何個も並び、それが何層にも連結されたものがニューラルネットワークになります。 ~ ~ **識別の原理 ***2次元の散布図を直線で分離 '''''W''''' の調整はどう行うのか、視覚的に説明してみましょう。x0, x1 を2軸とした平面に、データ X (x0,x1) が散布されていて、それらがTYPE A と TYPE B の2クラスに分類できる状態を仮定します(下図を参照)。 #image(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回の学習での回転角が大きくなりすぎて、バタバタすることになります。これを「発散」といいます。 -学習率が小さいと、正解に近づくには時間を要しますが、すこしずつ確実に正しい境界線の角度になっていきます。これを「収束」といいます。 以上、学習率を正しく見極めた上で、この手順で、データを読んでは修正を繰り返せば、境界線は正しい位置に収まります。 ~ ***付記:平面の概念について 一般に高校の数学では、平面の式を &mathjax( z = ax + by );のように書きますが、この式は次元を拡張して考えることができます。 - y = w・x ・・1次元の平面 = 直線 - y = w1・x1 + w2・x2 ・・2次元の平面([[Google:z=0.3x+0.5y]]) : - y = w1・x1 + w2・x2・・+ wn・xn ・・N次元の平面 ~ ~ **ニューラルネットワーク #image(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}; ) の値をすべての '''i''' について合計すると 100% になるもので、例えば画像認識問題で「猫:70%, トラ:20%, 犬:10%」 といったような回答を得たい場合に用います。 ''' f( xSUB{i}; ) = exp(xSUB{i};) / ΣSUB{j}; exp(xSUB{j}; )''' 参考:__[[出力結果表示の例>https://koichi-inoue.github.io/TensorFlowJS_MobileNet/]]__ --''恒等関数'' 最もシンプル、入力値をそのまま出力するものです。 '''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]] ~ ~ &aname(DL); ~ **ディープラーニング ニューラルネットワークの基本的なアイデアは3層構造ですが、中間層の数を数十〜百段階程度まで増やして、多段階の神経接続で出力を得よう・・という発想から誕生したのがディープラーニングです。多層化に耐えられるだけの計算力(演算速度向上とメモリの増大)が実現したことで、現在の人工知能はこの技術が主役になっています。 -[[GoogleImage:ディープラーニング]] -[[体験サイト:Playground>http://playground.tensorflow.org]] ~ ***インターネットの存在が技術発展に貢献 ディープラーニング を成立させるには、入力と出力のデータセット、言い換えれば、学習のための「問題と答え」を大量に用意して、それを読み込ませることが必要ですが、これを実現したのが、現代のインターネットです。例えば、インターネット上には大量の画像とそれにタグ付けされた単語が存在します。これを使えば、「この画像は犬」、「この画像は猫」という学習素材が大量に得られます。画像認識システムはこれらを使って、認識能力を高めています。 ~ ***ディープラーニング の構造 以下の5つの構造があります。 -''FFNN''(Feedforward Neural Network|順伝播型ニューラルネットワーク) 入力層>多段階の中間層>出力層と単一方向へ信号が伝播するシンプルな構造をもったもので、これが基本になります。 -''CNN''(Convolutional Neural Network|畳み込みニューラルネットワーク) 畳み込みニューラルネットワークは、人間の視覚情報処理の動きを簡易的に再現したもので、 画像処理に適した構造です。 畳み込みとは「画像から特徴を抽出する操作」を意味します。 -''RNN''(Recurrent Neural Network|再帰型ニューラルネットワーク) 再帰型ニューラルネットワークは、人間の聴覚情報処理、すなわち時系列情報処理のためのネットワークで、機械翻訳や音声認識などに利用されます。 -''LSTM''(Long Short-Term Memory|長・短期記憶ユニット) RNNには、短時間のデータしか処理できないという問題がありますが、神経科学の短期記憶(作業記憶)、長期記憶からヒントを得た考え方により長時間のデータ処理に対応できるようにしたネットワークです。 -''GAN''(Generative Adversarial Network|敵対的生成ネットワーク) GANは生成器(Generator)と識別器(Discriminator)の2つのニューラルネットワークを競合させて学習する方法です。生成器は識別器に見破られないように真のデータに似るように生成、一方の識別器は真のデータなのか、生成器がが生成したデータなのかを識別するように成長します。CNN、RNN、LSTMはニューラルネットワークの内部構成の位置づけですが、これにより、効率よくデータが生成できるだけでなく、人間から見て非常に高品質なデータが生成可能です。 ~ ***ディープラーニングの活用事例 -AI端末 Googe Home(Googleアシスタント) -AIコンシェルジュ [[OK,Google>Google:OK,Google]] [[Siri>Google:Siri]] -翻訳 [[Google翻訳>https://translate.google.com/?hl=ja]] &small(従来は PBMT(フレーズベース翻訳)、2016以降 GNMT(ニューラル機械翻訳)); ~ ***機械学習API([[Google Cloud platform>https://www.google.co.jp/aclk?sa=l&ai=DChcSEwiyvM2ihM7SAhXIAyoKHbH2Ab0YABAAGgJ0bQ&sig=AOD64_10rOFo1qr110-DZ9D4EN6W1SRnYQ&q=&ved=0ahUKEwjOp8mihM7SAhVGebwKHRp0BJMQ0QwIHQ&adurl=]]) -Cloud Vision API -Speech API -Natural Language API -Translate API ~ ~ **サンプルプログラム1|Iris の分類学習 [[Iris>https://archive.ics.uci.edu/ml/datasets/iris]] は、植物学者 R. Fisher による「あやめ」のデータで、統計ソフトの練習用として最も有名です。 Iris setosa、 Iris virginica、Iris versicolor 3種について、がく片の長さ、がく片の幅、花弁の長さ、花弁の幅の4つの計測データが、各 50、計 150 件含まれます。 ~ ***サンプル|JupyterNotebook ipynb(JupyterNotebook)形式で、GitHubに置いています。 -GitHub:[[NeuralNetwork_Iris.ipynb>https://github.com/koichi-inoue/DataScience/blob/main/NeuralNetwork_Iris.ipynb]] ~ ***使用しているライブラリ -[[scikit-learn]] ~ ***使用しているデータ:IRIS 以下の項目をもつ150の計測データ -Sepal Length(がく片長 cm) -Sepal Width(がく片幅 cm) -Petal Length(花びら長 cm) -Petal Width(花びら幅 cm) -Species:setosa, versicolor, virginica ~ ***参考になるサイト -ネコでも分かる「簡単な分類AI」の作り方(図がとてもわかりやすい) https://zenn.dev/nekoallergy/articles/sklearn-nn-iris ~ ~ **サンプルプログラム2|手書き文字認識 手書き数字の画像データ(28 × 28px) と正解ラベルのペアを学習用 60,000個、評価用 10,000個をセットにしたデータサンプル、[[MNIST>http://yann.lecun.com/exdb/mnist/]]を使用します。 ~ ***サンプル|JupyterNotebook 以下に、サンプルを掲載しています。 -GitHub:[[NeuralNetwork_MNIST.ipynb>https://github.com/koichi-inoue/DataScience/blob/main/NeuralNetwork_MNIST.ipynb]] -nbviewer:[[NeuralNetwork_MNIST.ipynb>https://nbviewer.jupyter.org/github/koichi-inoue/DataScience/blob/main/NeuralNetwork_MNIST.ipynb]] ~ ***使用しているライブラリ -[[scikit-learn]] ~ #image(DataScience/MNIST.jpg,right,30%) ***使用しているデータ:MNIST(エムニスト) 手書き文字認識用のサンプルデータ -28px x 28px の画像 70,000枚 #clear ~ **サンプルプログラム3|画像の分類 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]] ~ ~ //**サンプルプログラム4|その他 //[[ml5.js]] というJavaScriptAPI を利用した画像の分類その他について、以下のページにまとめています。 //> [[ml5.js]] //~ //~ //~ **APPENDIX ***関連ページ -[[DataScience]] -[[Data]] -[[Statistics]] -[[MachineLearning]] //-[[NeuralNetwork]] -[[DataMining]] -[[ArtificialIntelligence]] -[[ArtificialIntelligence/Links]] ~ ~ **APPENDIX 2 サンプルプログラム1で紹介した「Iris の分類」を TensorFlow と Kerasを用いて実装した例です。 ~ ***サンプル|JupyterNotebook ipynb(JupyterNotebook)形式で、GitHubに置いています。 -GitHub:[[NeuralNetwork_Iris_TensorFlow.ipynb>https://github.com/koichi-inoue/DataScience/blob/main/NeuralNetwork_Iris_TensorFlow.ipynb]] ~ ***使用しているライブラリ -TensorFlow -Keras ~ ***使用しているデータ:IRIS 以下の項目をもつ150の計測データ -Sepal Length(がく片長 cm) -Sepal Width(がく片幅 cm) -Petal Length(花びら長 cm) -Petal Width(花びら幅 cm) -Species:setosa, versicolor, virginica ~ ***モデルの定義(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')) ~ ~ **APPENDIX 3 サンプルプログラム2で紹介した「手書き文字認識」を TensorFlow と Kerasを用いて実装した例です。 ~ ***サンプル|JupyterNotebook 以下に、サンプルを掲載しています。 -GitHub:[[NeuralNetwork_MNIST_TensorFlow.ipynb>https://github.com/koichi-inoue/DataScience/blob/main/NeuralNetwork_MNIST_TensorFlow.ipynb]] ~ ***使用しているライブラリ -TensorFlow -Keras ~ #image(DataScience/MNIST.jpg,right,30%) ***使用しているデータ:MNIST(エムニスト) 手書き文字認識用のサンプルデータ -28px x 28px の画像 70,000枚 -訓練用 60,000枚 -テスト用 10,000枚 ~ ***モデルの定義 入力層 784、中間層 64、出力層 10(1-hot ベクトル) オプティマイザーを2種類試しています。 -[[SGD>Google:最適化 SGD]]:Stochastic Gradient Descent -[[Adam>Google:最適化 Adam]]:Adaptive Moment estimation ~ ***Python ソースコード mnist.py などの [[Python]] ファイルとしてお試し下さい。 #1. Load Data from tensorflow.python.keras.datasets import mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() #2. Reshape X x_train = x_train.reshape(60000, 784) x_test = x_test.reshape(10000, 784) x_train = x_train/255. x_test = x_test/255. #3. Reshape Y from tensorflow.python.keras.utils import to_categorical y_train = to_categorical(y_train, 10) y_test = to_categorical(y_test, 10) #4. Model Setting from tensorflow.python.keras.models import Sequential from tensorflow.python.keras.layers import Dense model = Sequential() model.add( Dense( units=64, input_shape=(784,), activation='relu ') ) model.add( Dense( units=10, activation='softmax') ) #5. Model Compile model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy']) #6. Train model.fit(x_train, y_train, epochs=10, batch_size=32, verbose=2, validation_split=0.2) #7. Result : Accuracy score = model.evaluate(x_test, y_test, batch_size = 1) print("accuracy =", score[1]) #8. Check 100 Test Data : Confusion Matrix import numpy as np from sklearn.metrics import confusion_matrix predict_classes = model.predict_classes(x_test[1:100,]) true_classes = np.argmax(y_test[1:100], 1) print(confusion_matrix(true_classes, predict_classes)) ~ ***出力結果 Epoch 1/10 - 2s - loss: 0.7345 - acc: 0.8129 - val_loss: 0.3914 - val_acc: 0.8964 Epoch 2/10 - 1s - loss: 0.3720 - acc: 0.8965 - val_loss: 0.3191 - val_acc: 0.9114 Epoch 3/10 - 1s - loss: 0.3199 - acc: 0.9099 - val_loss: 0.2861 - val_acc: 0.9203 Epoch 4/10 - 1s - loss: 0.2905 - acc: 0.9183 - val_loss: 0.2666 - val_acc: 0.9260 Epoch 5/10 - 1s - loss: 0.2693 - acc: 0.9239 - val_loss: 0.2497 - val_acc: 0.9315 Epoch 6/10 - 1s - loss: 0.2515 - acc: 0.9295 - val_loss: 0.2384 - val_acc: 0.9339 Epoch 7/10 - 1s - loss: 0.2364 - acc: 0.9335 - val_loss: 0.2252 - val_acc: 0.9379 Epoch 8/10 - 1s - loss: 0.2231 - acc: 0.9370 - val_loss: 0.2159 - val_acc: 0.9404 Epoch 9/10 - 1s - loss: 0.2119 - acc: 0.9401 - val_loss: 0.2071 - val_acc: 0.9430 Epoch 10/10 - 1s - loss: 0.2018 - acc: 0.9427 - val_loss: 0.1999 - val_acc: 0.9453 10000/10000 [==============================] - 2s 176us/step accuracy = 0.9434 [[ 8 0 0 0 0 0 0 0 0 0 ] [ 0 14 0 0 0 0 0 0 0 0 ] [ 0 0 7 0 0 0 0 1 0 0 ] [ 0 0 0 11 0 0 0 0 0 0 ] [ 0 0 0 0 13 0 1 0 0 0 ] [ 0 0 0 0 0 6 1 0 0 0 ] [ 0 0 0 0 0 0 10 0 0 0 ] [ 0 0 0 0 0 0 0 14 0 0 ] [ 0 0 0 0 0 0 0 0 2 0 ] [ 0 0 0 0 0 0 0 0 0 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を誤認するエラーが確認できます。 ~ ~