昆虫食1
少し前から夏休みだが、小5の息子は自由研究に昆虫食について調べるのだとか。
SDGs関連で、将来の食糧問題対策に有効か、と聞いて触発されたのか、よくわからないが。興味を持つことはよいことだ。とことん調べるのなら協力しようと、古くから信州伊那谷で食されている、昆虫食の甘露煮セットを買ってみました。
瓶詰4種、イナゴ、蚕のさなぎ、ザザムシ、はちのこ。結構高いです。
自分はこれらの昆虫食を全く食べたことがない。
今日初めて、イナゴ、蚕のさなぎの甘露煮を息子と試食してみました。
まずはイナゴ。5-7cmぐらいのやや小さめのイナゴが結構原型をとどめて入っています。口の中に入れると、パリパリ、歯触りはえび、かにの甲殻類のようだ。味は甘露煮が支配的だが、若干えび、かにの香ばしさがあるかな。
続いて蚕のさなぎ。蚕自体は絹を生み出すというので教科書などでよく見かけるが、さなぎは見たことがない。写真のように5cmぐらいの芋虫ちっくな形です。イナゴではなかったようなクセのある匂いがしてきます。歯触りはツルツル、これは形状によるものかな?少しナッツのような味がします。ネットで調べると、信州では蚕のさなぎを普通にスーパーで売っているらしい。独特な食文化があるんですね。
イナゴや蚕のさなぎを食べてみて、味自体は「もう勘弁、食べたくない。」というものでは全然ありませんでした。甘露煮で食べづらいにおいを消しているのでしょうが、面白い触感を瓶が空になるまでゆっくり味わってみようと思います。また、後日残りのはちのことザザムシの甘露煮を試食します。
深層学習day4
1.強化学習
強化学習とは、長期的に報酬を最大化できるように環境のなかで行動を選択できるエージェントを作ることを目標とするもの。行動の結果として与えられる利益(報酬)をもとに、行動を決定する原理を改善していく仕組みである。
教師あり学習、教師なし学習はデータに含まれるパターンを見つけ出し、正解に対する誤差を小さくすることが目標であった。強化学習では優れた方策を見つけ出し、報酬を最大化することが目標である。
- 方策関数 方策ベースの強化学習手法において、ある状態でどのような行動を採るのかの確率を与える関数
- 価値関数 ある状態の価値に注目する場合を状態価値関数と呼び、ある状態にある行動を実施した時の価値に注目する場合を行動価値関数と呼ぶ。
方策勾配法
2.Alpha Go
強化学習で有名な囲碁ソフトAlpha Goは2016年にグーグル傘下のDeepMind社によって開発された。初版のAlpha Go(Lee)は以下の特徴を持つ。
- 方策関数、価値関数とも盤面の状況を表す19×19マス 48チャンネル(価値関数は1つ増えて49)を入力とする。
- 方策関数は、畳み込み層、活性化関数を繰り返し、最後はSoftMax層を介して19×19のマスの着手予想確率が出力される。
- 価値関数は、畳み込み層、活性化関数を繰り返し、最後は全結合層、および活性化関数(tanh)を介して、現局面の勝率が-1~1の範囲で出力される。
2017年に開発されたAlphaGoでは、AlphaGo(Lee)に比べ、以下の点を改善している。
3.軽量化・高速化技術
深層学習は多くのデータを使用したり、パラメータ調整のために多くの時間を使用したりするため、高速な計算が求められる。その中で、計算機資源を有効に活用し、高速に演算する手法として、以下が挙げられる。
a.データ並列化
親モデルを各計算機へ子モデルとしてコピーする。データを分割し、各計算機へ並列して計算させる。各モデルが同期しながらパラメータを合わせるか、それぞれ独立にパラメータを合わせるかで同期型か非同期型か決まる。同期型の計算が安定で精度が高いため、よく使用されている。
b.モデル並列化
親モデルを各ワーカーに分割し、それぞれのモデルを学習させる。全てのデータで学習が終わった後で、一つのモデルに復元する。モデルが大きい時に適した手法である。
a.量子化
計算精度ビット数を落とすことで多少精度が低下する反面、高速化、省メモリ化のメリットが得られる。倍精度演算(64 bit)から単精度演算(32 bit)に落とすと、GPUの処理性能は約2倍になる。
b.蒸留
精度が高い故、ニューロンの規模が大きいモデルに対して、モデルの知識を使って、軽量なモデルを生成すること。知識の継承により、軽量でありながら複雑なモデルに匹敵する精度のモデルを得ることが期待できる。(例 教師モデルと生徒モデル)
4.応用技術
a.MobileNet
b.DenseNet
- ニューラルネットワークでは層が深くなるにつれて、学習が難しくなるという問題があった。
- 前方の層から後方の層へアイデンティティ接続を介してパスを作ることで層が深くても学習できるようにした。
- 前方の各層からの出力を全て後方の層への入力に用いる。
c.BatchNorm
- レイヤー間を流れるデータの分布を、ミニバッチ単位で平均が0、分散が1になるように正規化する。
- ニューラルネットワークにおいて学習時間の短縮や初期値への依存低減、過学習の抑制など効果がある。
- Batch Sizeが小さい条件下では、学習が収束しないことがあり、代わりにLayer Normalizationなどの正規化手法が使われることが多い。
d.LayerNorm
- 全てのチャネルの平均と分散を求め正規化する。
- 入力データや重み行列に対して、入力データをスケールしても、出力が変わらない。
- 入力データや重み行列に対して、重み行列をスケールやシフトしても、出力が変わらない。
e.WaveNet
- 生の音声波形を生成する深層学習モデル
- Pixel CNN(高解像度の画像を精密に生成できる手法)を音声に応用したもの
- 時系列データに対して畳み込み(Dilated convolution)を適用する層が深くなるにつれて畳み込むリンクを離すDilated convolutionを提案した。
5.実装演習
kerasによる演習。一部を取り上げる。
a.分類問題(iris)
入力が4(がくの長さなど)、中間層が12、出力が3(iris(アヤメ)の種類、活性化関数はソフトマックス)のニューラルネットワークを構築。中間層の活性化関数をReLU、シグモイド、tanhにした時の収束推移を比較した。シグモイド関数では勾配消失が起きているようで、5回程度で精度が上がらなくなってしまった。tanhはシグモイド関数よりも傾きが大きいからか勾配消失が起きず、むしろReLUよりも少ない回数でAccuracyが1に近づく。
b.分類問題(MNIST)
入力が28×28=784、中間層が512の2層、ドロップアウト付き、出力が10(0~9の数字、活性化関数はソフトマックス)のニューラルネットワークを構築(上2つと左下の3つ)。右下のグラフは、入力が28×28、中間層は畳み込み層、Maxプーリング、ドロップアウトで構成、出力層には全結合層を介して10(0~9の数字)のCNNによるものである。最適化手法にAdamを適用し、学習率を変化させてニューラルネットワークの収束推移を比較した。学習率lrが0.001、0.0001よりも0.01と大きいときにはAccuracyが低い結果となった。また、CNNはニューラルネットワークよりも高いAccuracyを得ることができた。特にテストデータによる結果が素晴らしい。縦横二次元の関係を保ちながら計算しているメリットが発揮されたものと推測する。
深層学習day3
1.時系列データに対するニューラルネットワーク
時間的順序を追って一定間隔ごとに観察され、しかも相互に統計的依存関係が認められるようなデータの系列を時系列データと呼ぶ。時々刻々変化する状態量(音声やテキストも含む)は時系列データに含まれる。
時系列データの分析上の特徴としては、データそれぞれを独立したものと見なすのではなく、「ある時点のデータが、それ以降に発生するデータに何らかの影響を及ぼしている」と考えることである。時系列データに対するニューラルネットワークは時間的な依存関係を活かした構成となっている。最も基本的なものはRNN(Recurrent Neural Network、再帰型ニューラルネットワーク)という。
1-1.RNNの構成
RNNの構成で特徴的な所は、各層の出力が、次の層の入力としても利用されることである。これは、「ある時点の入力が、それ以降の出力に影響を及ぼす」ことを表している。 数式で関係を記述する。
はそれぞれ中間層、出力層への活性化関数
RNNのネットワークでは、3つの重みがある。
・入力から現在の中間層を定義する際にかけられる重み
・中間層から出力を定義する際にかけられる重み
・1つ前の中間層から現在の中間層を定義する際にかけられる重み
それぞれの重みの更新式は次の通りとなる。
演習問題として、バイナリ(2進数)加算を扱った。RNNにより各桁の繰上りを考慮した2つの数の加算結果を推論していく。
中間層の次元は8、16、32あたりが一番早く収束する。4だと収束せず、64だと収束するが、回数がかかる。
従来型が最も早く収束する。
シグモイドが一番良好、ReLUだと勾配爆発、tanhだと勾配消失により収束しない。
1-2.LSTM(Long Short-Term Memory)
RNNの問題点は短時間(せいぜい10-100程度)のデータしか処理できないことである。さらに長い時間のデータを利用しようとすると、勾配消失/爆発の問題が発生する。
LSTMはRNNの勾配消失問題を解決すべく作られた。中間層の単純なニューロンの代わりにLSTMブロックで置き換えることで長期の時間依存性も短期の時間依存性も学習できる。
- CEC(Constant Error Carousel) 誤差を維持することによって、誤差勾配が1と一定になり勾配消失や誤差は発生しない。その反面、ニューラルネットワーク特有の学習特性を持っていない。
- 入力ゲートと出力ゲート 学習特性を持たせるため入力ゲートと出力ゲートを追加し、それぞれのゲートへの入力値の重みを重み行列W、Uで可変可能とした。
- 忘却ゲート 過去の情報が要らなくなった(例 劇的な変化が発生した)場合、そのタイミングで情報を忘却させる。
- 覗き穴結合 CECの値がゲートの制御に用いられていないため、出力ゲートが閉じている状態だと、どのゲートもCECにアクセスすることができない。覗き穴結合はCECの情報が3つのゲートの制御に関与できるようにする構造を指す。
1-3.GRU (Gated Recurrent Unit)
LSTMでは、長い時間のデータを利用できる反面、パラメータ数(CEC、入力ゲート、出力ゲート、忘却ゲート)が多く、計算負荷が高くなる問題があった。GRUでは、入力ゲートと忘却ゲートを統合し、「更新ゲート」とまとめることで計算負荷を低減している。
1-4.双方向RNN
これまで説明したネットワークは過去の情報だけを扱う前提だが、双方向RNNは未来の情報も加味することが可能なモデルである。当然ながら、未来の情報が分かっていなければ使えないが、文章の推敲や、機械翻訳に適している。
2.RNNによる自然言語処理
2-1.Seq2Seq
通常のRNNは入力と出力の長さや順序が同じでなければならない。
一方、Seq2Seqはオートエンコーダーと同様、Encoder-Decoderモデルの一種で、入力側と出力側で別々のRNNを使い、情報の縮約をしてから復元を実施する。
機械対話や機械翻訳に使用される。
Encoder RNN
各時刻ごとに時系列データ(文章など)が入力される。
EncoderのRNNレイヤでは、入力シーケンスを処理した結果として内部状態を入力した文の意味を表すベクトルとして返す。
Decoder RNN
ターゲットとなるシーケンスの前の文字が与えられた場合、ターゲットシーケンスの次の文字を予測するように訓練する。
【Decoder RNNの処理手順】
1. Decoder RNN:Encoder RNNのfinal state(thought vector)から、各tokenの生成確率を出力していく。final stateをDecoder RNNのinitial stateとして設定し、Embeddingを入力。
2. Sampling:生成確率に基いてtokenをランダムに選ぶ。
3. Embedding:2で選ばれたtokenをEmbeddingしてDecoder RNNへの次の入力とする。
4. Detokenize:1-3を繰り返し、2で得られたtokenを文字列に直す。
HRED
過去n-1個の発話から次の発話を生成する。
Seq2seqでは会話の文脈無視で応答がなされたが、HREDでは前の単語の流れに即して応答されるため、より人間らしい文章が生成される。
Seq2seqとContext RNN(Encoderのまとめた各文章の系列をまとめて、これまでの会話コンテキスト全体を表すベクトルに変換する構造)を組み合わせた構造により、過去の発話の履歴を加味した応答を生成している。
課題1:確率的な多様性が字面にしかなく、会話の「流れ」のような多様性がない。
→ 同じコンテキスト(発話リスト)を与えられても、答えの内容が会話の流れとしては毎回同じものしか出せない。
課題2:短く情報量に乏しい答えをしがちである。
→ 短いよくある答えを学ぶ傾向がある。
VHRED
HREDにVAEの潜在変数の概念を追加することにより、HREDの課題を解決した構造。
2-2.Word2Vec
RNNでは、単語のような可変長の文字列をニューラルネットワークに与えることはできない。
word2vecでは学習データからボキャブラリを作成し、「ボキャブラリ数×任意の単語ベクトルの次元数」の重み行列により、大規模データの分散表現の学習を現実的な計算速度とメモリ量で実現可能にした。
結果の数値ベクトルは、生のテキストをデータの視覚化、機械学習、および深層学習に適した数値表現に変換するために使用できる。
Word2Vecには、skip-gram法(Continuous Skip-Gram Model)とCBOW(Continuous Bag-of-Words Model)のふたつのモデルが内包されている。skip-gram法は、中心のある単語から周辺の単語を予測する手法である。一方、CBOWは周辺の単語から中心語を予測するという逆の手法を取る。
2-3.Attention
連続したデータを扱う際に過去の重要なポイントに着目する(=Attention)手法を指す。具体的には質問に回答するときに、相手の質問の中の特定キーワードに注目する。
- Seq2SeqとAttentionの違い Seq2Seqでは入力情報をEncoderで圧縮したベクトルをDecoderに伝えるため、入力文章が長いとその情報をDecoderに正確に伝えることが難しくなる。この問題に対して、AttentionではDecode時に入力/出力の相互の関連性について重みを付与した。
深層学習day2
1.勾配消失問題
勾配消失問題とは、「誤差逆伝播法が下位層に進んでいくに連れて、勾配がどんどん緩やかになっていくため、勾配降下法による更新では下位層のパラメータはほとんど変わらず、訓練は最適値に収束しなくなる」現象を指す。活性化関数にシグモイド関数を適用した場合、勾配消失問題が発生しやすい。(参考 シグモイド関数の勾配最大値は、入力0の時の値、である。)
勾配消失問題の対策方法を以下に挙げる。
a.RELU関数
活性化関数勾配消失問題の回避とスパース化に貢献することで良い成果をもたらしている。
b.重みの初期値設定
Xavier:前の層のノード数がnであるとき、 重みの要素にで乗算した値。活性化関数はReLu、シグモイド(ロジスティック)関数、双曲線正接関数(tanh)。
He:前の層のノード数がnであるとき、 重みの要素にで乗算した値。活性化関数はReLu。
重みの初期値に0を設定すると、どのような問題が発生するか?
→ 全ての値が同じ値で伝わるため。パラメータのチューニングが行われなくなる。
c.バッチ正規化
ミニバッチ単位で入力値のデータの偏りを抑制する手法である。 中間層出力を正規化する処理を孕んだ層を加えることで、出力が常に平均0、分散1の分布に従うように強制する。
計算の高速化、勾配消失が起きづらくなるというメリットがある。
ミニバッチの平均と分散はそれぞれ以下の通り。
出力を以下の式で正規化する。
この正規化された出力を学習可能なスケーリングパラメータ 、シフトパラメータ で線形変換する。
活性化関数と重み初期値について、mnistの数字分類問題で精度を確認する演習を実施した。活性化関数がシグモイド関数で重み初期値で対策がない場合、勾配が消失し精度が上がらないが、活性化関数をRELU関数にするか、重み初期値でXavier、Heを選択すると、うまくパラメーター調整が機能する。
2.学習率最適化手法
勾配降下法の式において、学習率を[\tex \epsilon]いかに設定するかも重要な問題である。
学習率の値が大きい場合、最適値にいつまでもたどり着かず発散してしまう可能性がある。
逆に学習率の値が小さい場合、収束するまでに時間がかかってしまったり、大域局所最適値に収束しづらくなる。
そのため、以下に示す最適化手法が開発されている。
a.モメンタム
誤差をパラメータで微分したものと学習率の積を減算した後、現在の重みに前回の重みを減算した値と慣性の積を加算する。
メリットとしては、1)局所最適解にはならず、大域的最適解が得られやすい、2)谷間に着いてから最も低い位置(最適値)に行くまでの時間が早い、ことが挙げられる。
mnistの数字分類問題でモメンタムによる精度の違いを確認した。使用しない場合、精度は向上するがステップ数を要している。使用すると、600ステップでaccuracy=0.90前後まで到達している。
b.AdaGrad
誤差をパラメータで微分したものと再定義した学習率の積を減算する。勾配の緩やかな斜面に対して最適値に近づけることがメリットである。
c.RMSProp
誤差をパラメータで微分したものと再定義した学習率の積を減算する。大域的な最適解になり、ハイバーパラメータの調整が必要な場合が少ないことがメリットである。
d.Adam
モメンタムの、過去の勾配の指数関数的減衰平均、RMSPropの、過去の勾配の2乗の指数関数的減衰平均を含んだ最適化アルゴリズムである。それ故、モメンタムとRMSPropのメリットを持っている。
3.過学習
下図の右側のように、テスト誤差と訓練誤差とで学習曲線が乖離することである。
原因としては、ネットワークの自由度が高すぎるが故、学習に与えられたデータに対し、厳密に重みをあてはめすぎてしまうためである。その結果、汎用性が落ちてしまい、テストデータに対する精度が低下してしまう。
ネットワークの自由度を落として汎用性を高める手法として、以下が挙げられる。
a.L2ノルム(Ridge推定量)を使用
ペナルティとして学習モデルのパラメータの二乗の総和を用いる。データの大きさに応じて0に近づけて、滑らかなモデルとする。
b.L1ノルム(Lasso推定量)を使用
ペナルティとして学習モデルのパラメータの絶対値の総和を用いる。特定のデータの重みを0にする事で、不要なデータを削除する。
4.畳み込みニューラルネットワークの概念
a.畳み込み層
畳み込み層では、画像の場合、縦、横、チャンネルの3次元のデータをそのまま学習し、次に伝えることができる。その特性により、3次元の空間情報も学習が可能である。
特徴量を抽出するために以下の処理を実施する。
a-1.バイアス
各要素に同じ値を加算することを指す。
a-2.パディング
出力サイズを調整するため、畳み込み層の処理を行う前に、入力データの周囲に例えば0などの固定のデータを埋めることを意味する。
b.プーリング層
プーリング層では、画像内の局所的な情報をまとめる操作を行います。具体的には、Max Pooling(最大値抽出)とAverage Pooling(平均値抽出)と呼ばれる2種類のプーリング操作がよく使用されている。
c.全結合層
畳み込み層、およびプーリング層で3次元データになっているものを、1列に並べた1次元のベクトルにしたもの。ただし、画像に使用する場合RGBの各チャンネル間の関連性が、学習に反映されないため注意。
5.最近のCNN
AlexNetは畳み込み層→プーリング層→畳み込み層→プーリング層→畳み込み層→畳み込み層→畳み込み層→全結合層(3層)の構成である。全結合層の出力にドロップアウトを適用している。
Googleによって開発されたInception-v3は、ILSVRCという大規模画像データセットを使った画像識別タスク用に1,000クラスの画像分類を行うよう学習されたモデルで、非常に高い精度の画像識別を達成している。
さらにResNetでは、層をさらに多くする(超深層とも言う)ことで精度を向上させている。ResNetの特徴は、ある層で求める最適な出力を学習するのではなく、層の入力を参照した残差関数を学習する、ことである。
深層学習day1
0.ニューラルネットワークの構成
ディープラーニングの目的は重みとバイアスを最適化して、誤差を最小化するパラメータを発見すること。そのk本的な構成がニューラルネットワークである。
1.入力層~中間層
入力層
説明変数(特徴量)の値が入力される個所。
具体例:犬や猫など動物を分類するとき、説明変数は体長、体重、ひげの本数、平均寿命、などになり、それぞれの値(体長=40cm、体重=10kg、ひげの本数=300本、平均寿命=15年、…)が入力され、中間層へ伝達される。
2.活性化関数
ニューラルネットワークにおいて、次の層への出力の大きさを決める非線形の関数。入力値の値によって、次の層への信号のON/OFFや強弱を定める働きをもつ。
※非線形、線形の違い
線形とは、相互間の関係が比例関係にある状態。 グラフを描くと真っ直ぐな線になる。
非線形とは、相互間の関係が比例関係で表せない状態。
ステップ関数は、 で表現される。しきい値を超えたら発火し、出力は常に1か0である。線形分離である、簡単なものにしか適用できない。
シグモイド関数は、 で表現される。0 ~ 1の間を緩やかに変化する関数で、ステップ関数ではON/OFFしかない状態に対し、信号の強弱を伝えられる。その反面、大きな値では出力の変化が微小なため、勾配消失問題を引き起こす事が課題である。
RELU関数は、 で表現される。今最も使われている活性化関数勾配消失問題の回避とスパース化に貢献することで良い成果をもたらしている。
入力層から中間層、活性化関数の整理として、順伝播で入力層:4ノード1層、中間層:3ノード1層、中間層活性化関数:シグモイド関数を適用、の事例を計算した。
# 順伝播(単層・複数ユニット) # 重み W = np.array([ [0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5], [0.4, 0.5, 0.6] ]) print_vec("重み", W) # バイアス b = np.array([0.1, 0.2, 0.3]) print_vec("バイアス", b) # 入力値 x = np.array([1.0, 5.0, 2.0, -1.0]) print_vec("入力", x) # 総入力 u = np.dot(x, W) + b print_vec("総入力", u) # 中間層出力 z = functions.sigmoid(u) print_vec("中間層出力", z)
3.出力層
推定結果(構成図中の)が得られる層。真の出力値(教師データともいう、構成図中の)との誤差を確認する。誤差の大きさ、特徴に応じて各層の重みをのちに調整する。中間層と同様に前の層の値と重みより内積演算を実施する。活性化関数も適用するが、使用する関数が中間層と異なる。
a.恒等写像
で表現される。回帰問題によく使用される。
b.シグモイド関数
で表現される。前述の通り、0~1の値を取るため、二値分類問題に適用される。
c.ソフトマックス関数
で表現される。3つ以上の多クラス分類問題に適用される。
誤差関数については、回帰問題では二乗誤差、分類問題では交差エントロピーが一般的に使用される。
a.二乗誤差
で表現される。ここで差の値のままでなく二乗するのは、誤差の向きが正でも負でも評価値を大きくする(誤差が大きいと表示する)ためである。また、1/2を掛けているのは微分するときに二乗の「2」と打ち消すためである。
4.勾配降下法
深層学習の目的は、学習を通して誤差を最小にするネットワークを作成すること
→ 誤差 を最小化するパラメータ を発見すること
a.勾配降下法
全サンプルの平均誤差から勾配を取り、学習率を掛けて、重みを修正する。
b.確率的勾配降下法
ランダムに抽出したサンプルの誤差を取る。メリットとしては、データが冗⻑な場合の計算コストの軽減、望まない局所極小解に収束するリスクの軽減、オンライン学習(学習データが入ってくるたびにその都度、新たに入ってきたデータのみを使って学習を行うこと)ができる、が挙げられる。
c.ミニバッチ勾配降下法
ランダムに分割したデータの集合(ミニバッチ)に属するサンプルの平均誤差を取る。メリットとしては、確率的勾配降下法のメリットを損なわず、計算機の計算資源を有効利用できることである。
5.誤差逆伝播法
誤差勾配を数値微分で計算すると、各パラメータ それぞれについて や を計算するために、順伝播の計算を繰り返し行う必要があり負荷が大きい。
誤差逆伝播法は、算出された誤差を出力層側から順に微分し、前の層へと伝播することにより、不要な再帰的計算を避けて各パラメータの微分値を計算する手法である。
最後に演習で入力層:2ノード1層、中間層:3ノード1層、出力層:2ノード1層の2値分類ネットワークで逆誤差伝播を確認した。ポイントになる部分にはコメントを追記した。いかに効率よく勾配および重みの修正しているか、イメージをつかむことができた。
# ウェイトとバイアスを設定 # ネートワークを作成 def init_network(): print("##### ネットワークの初期化 #####") network = {} network['W1'] = np.array([ [0.1, 0.3, 0.5], [0.2, 0.4, 0.6] ]) network['W2'] = np.array([ [0.1, 0.4], [0.2, 0.5], [0.3, 0.6] ]) network['b1'] = np.array([0.1, 0.2, 0.3]) network['b2'] = np.array([0.1, 0.2]) print_vec("重み1", network['W1']) print_vec("重み2", network['W2']) print_vec("バイアス1", network['b1']) print_vec("バイアス2", network['b2']) return network # 順伝播 def forward(network, x): print("##### 順伝播開始 #####") W1, W2 = network['W1'], network['W2'] b1, b2 = network['b1'], network['b2'] u1 = np.dot(x, W1) + b1 z1 = functions.relu(u1) u2 = np.dot(z1, W2) + b2 y = functions.softmax(u2) print_vec("総入力1", u1) print_vec("中間層出力1", z1) print_vec("総入力2", u2) print_vec("出力1", y) print("出力合計: " + str(np.sum(y))) return y, z1 # 誤差逆伝播 def backward(x, d, z1, y): print("\n##### 誤差逆伝播開始 #####") grad = {} W1, W2 = network['W1'], network['W2'] b1, b2 = network['b1'], network['b2'] # 出力層でのデルタ(yに対するu2の偏微分) delta2 = functions.d_sigmoid_with_loss(d, y) print(delta2) # b2の勾配→u2に対するb2の偏微分は1、よってdelta2を保持 grad['b2'] = np.sum(delta2, axis=0) print(grad['b2']) # W2の勾配→u2に対するw2の偏微分はz1、よって転置したものにdelta2と内積を取る grad['W2'] = np.dot(z1.T, delta2) # 中間層でのデルタ(yに対するu1の偏微分→u2に対するz1の偏微分はw2、z1に対するu1の偏微分は*の後) delta1 = np.dot(delta2, W2.T) * functions.d_relu(z1) # b1の勾配→ u1に対するb1の偏微分は1、よってdelta1を保持 grad['b1'] = np.sum(delta1, axis=0) # W1の勾配 →u1に対するw1の偏微分はx、よって転置したものにdelta1と内積を取る grad['W1'] = np.dot(x.T, delta1) print_vec("偏微分_dE/du2", delta2) print_vec("偏微分_dE/du1", delta1) print_vec("偏微分_重み1", grad["W1"]) print_vec("偏微分_重み2", grad["W2"]) print_vec("偏微分_バイアス1", grad["b1"]) print_vec("偏微分_バイアス2", grad["b2"]) return grad # 訓練データ x = np.array([[1.0, 5.0]]) # 目標出力 d = np.array([[0, 1]]) # 学習率 learning_rate = 0.01 network = init_network() y, z1 = forward(network, x) # 誤差 loss = functions.cross_entropy_error(d, y) grad = backward(x, d, z1, y) for key in ('W1', 'W2', 'b1', 'b2'): network[key] -= learning_rate * grad[key] print("##### 結果表示 #####") print("##### 更新後パラメータ #####") print_vec("重み1", network['W1']) print_vec("重み2", network['W2']) print_vec("バイアス1", network['b1']) print_vec("バイアス2", network['b2'])
機械学習2
1.主成分分析
相関のある多数の変数から相関のない少数で全体のばらつきを最もよく表す主成分と呼ばれる変数を合成する多変量解析の一手法である。データにもよるが、分散が大きい主成分を選択することで少ない次元のデータで元のデータの特徴を表現することが可能になる。それぞれの主成分を表現する固有ベクトルは互いに直交する。
第k主成分の分散の全分散に対する割合を寄与率(全体に対する情報量の割合)と呼ぶ。すべての主成分の寄与率の総和は1になる。kについては、データの各成分に対する分散が大きい順(つまり、情報量が大きい順)に1、2、…と割り振られる。
演習問題では、乳ガン診断結果のデータを扱った。(サンプル数は569、説明変数は30、目的変数は診断結果(良性/悪性))
説明変数の主成分に対する寄与度を降順に並べてみた。
第一主成分で40%強、第二主成分を合わせると約60%の寄与度であり、多くの情報が2つの主成分だけで集約できていると期待できる。
2つの主成分だけでxy座標分布にプロット(横:第一主成分スコア、縦:第二主成分スコア)すると、若干混在エリアがあるものの分離境界が見えてくる。(図中、〇が良性、三角が悪性。)
2つの主成分で情報圧縮の後、ロジスティック回帰で診断結果を推定した。その結果、実績に対して、訓練データで97%、テストデータで94%の割合で推定が一致することを確認した。60%の情報量で90%以上正しく診断できるとは驚いた!
2.アルゴリズム
a.k近傍(k-NN)法
k-NNとはあるデータ点のラベルを予測する際、あらかじめラベルが与えられているデータの中で、予測対象データ点とのデータ点を距離が短い順にk個取り出し、それらのラベルの最頻値を割り当てる手法である。分類問題の一種で直感的にアルゴリズムを理解しやすい特徴がある。
例えば0、1のラベルがあり、予測対象データ点のラベルを予測するとき、k=3でそれらのラベルが0、0、1ならば予測対象データ点は0と判定される。つまり、予測対象データ点、空間でもkの値によって、異なるラベルが与えられることがある。
一般的に最近傍法はkが大きいほど、決定境界は滑らかになる。また、参照されるラベルは与えられるため、判定ステップはある反面、訓練ステップがない。
numpyによる演習問題をやってみた。ランダムにクラスターを2つ作り、k-NN法により境界を作成した。上がk=3、下がk=9の場合。k=9の方が境界は滑らかだが、中央にある黄色の2点をうまく分類できていない。
b.k-means法
教師なし学習のクラスタリング手法である。ちなみに、クラスタリングは分類と異なる。「分類」は事前に決まっている分類(例えば犬や猫など)に未知のデータに対して振り分けることを意味する。クラスタリングはデータの中で(特に事前に定義されていない)集まりを見つけることを意味する。なお、クラスタリングに際し、k(いくつに分けるか)は事前に与えられる。
具体的な手順は以下の通り。
1.各クラスタ中心の初期値(k個)を設定する。
2.各データ点に対して、各クラスタ中心との距離を計算し、最も距離が近いクラスタを割り当てる
3.すべてのデータ点にクラスタを割り振ったら、各クラスタの平均ベクトル(中心)を計算する→1.を更新
4.収束するまで2, 3の処理を繰り返す
演習問題をやってみた。
まずは3つの集団をベースにランダムに発生させた2次元分布。
これをk=3でk-means法にかけてみた。
きれいに分割。k=5でもやってみた。
微妙かな。kの選定は結構大事ですね。時間があれば、しらみつぶしにやってみるのもありかと思いますが。
3.サポートベクターマシン
サポートベクターマシンは教師あり学習で分類問題にも回帰問題にも用いられる。
一番基本となる問題としては、2値の分類問題になります。
サポートベクターマシンでは、2値の分布に対して「最も近い点(サポートベクター)までの距離が遠くなるよう決定境界を決めます」。このことを「マージン最大化」と呼びます。
簡単な例として、直線で分離できるような下図のような2つの分布について、黄色と紫色の点のうち、境界線に最も近い、黒丸で囲んだ点をサポートベクターという。サポートベクターから判別する境界の距離(図中ピンクの方向に延ばす)をマージンというが、その値が最大になるよう、分類境界(図中実線)を決める。
ということは、分類境界に最も近いデータ以外を取り除いてしまっても、分類境界は変化しない。また、サポートベクターの点数は分離境界の両端1つずつ、つまり2点以上存在する。
線形で分類できない場合、低次元のデータを高次元に写像して分離するカーネルトリックという手法を用いる。下の図は、目玉焼きのような分布に対して、RBFカーネル(ガウシアンカーネル)を利用し、超平面で(非線形的に)分離した例である。
カーネルの種類としては、ほかにシグモイドカーネル、多項カーネルなどがある。
マージン最大化の定義については、厳密に制約を守る条件で分類する「ハードマージン」と、制約を緩和し、データ点がマージン内部に入ることや誤分類を許容することで、ハードマージンでは解が得られないケースを回避する「ソフトマージン」という考え方がある。
機械学習1
1.回帰問題
回帰問題とは、ある入力から出力の値を予測する問題を指す。機械学習の世界では、回帰問題と分類問題に大きく分かれる。
回帰問題の中でも、関数の勉強で中学で最初に出てくる1次関数の形で推定するものを線形回帰問題と言う。
線形回帰モデル-Boston Housing Data-をいじってみた。
skl_regression.ipynbを使う。内容は以下の通り。
・データセット(sklearn)をインポート
・データフレーム型(pandas)へ変換
・回帰分析
・モデルの検証(平均二乗誤差、R^2決定係数)
一連の計算の中で、RM(一戸当たりの平均部屋数)、CRIM(犯罪率)、AGE(築年数)からPrice(家の価格)を重回帰分析を推定する。
print(model2.coef_)
print(model2.intercept_)
[-0.21102311 8.0328382 -0.05224283]
-23.605561276868794
model2.predict(0.2, 7, 100)
array([27.35781896])
このとき、トータル506個のデータについて、Train(訓練)とTest(テスト)の割合を7:3で分割、推定した時の、相互の平均二乗誤差、R^2決定係数の傾向について調べてみた。
# 平均二乗誤差を評価するためのメソッドを呼び出し
from sklearn.metrics import mean_squared_error
# 学習用、検証用データに関して平均二乗誤差を出力
print('MSE Train : %.3f, Test : %.3f' % (mean_squared_error(y_train, y_train_pred), mean_squared_error(y_test, y_test_pred)))
# 学習用、検証用データに関してR^2を出力
print('R^2 Train : %.3f, Test : %.3f' % (model.score(X_train, y_train), model.score(X_test, y_test)))
MSE Train : 39.109, Test : 31.845
R^2 Train : 0.566, Test : 0.554
個人的には、線形回帰よりもむしろ、データをデータフレーム型へあてはめる一連の操作を理解できてためになった。
2.非線形回帰モデル
線形回帰では表現しづらい場合、非線形な構造を適用することで高い精度を得ることができる場合がある。
回帰関数として、基底関数と呼ばれる既知の非線形関数とパラメータベクトルの線型結合で表現される、基底展開法が用いられる。
基底関数の例として以下が挙げられる。
多項式
ガウス型基底
演習問題では、4次の多項式にノイズを加えたデータ分布に対して、1)カーネルリッジ回帰、2)1-5次の多項式による回帰を実施したときの当てはまり度合いを確認した。
カーネルリッジ回帰はほぼ正確に推定できている。多項式は、4次と5次(紫色)は一致しており、ほぼ正確に推定できているが、3次以下では当然ながら推定精度は低下する。
このように、様々な基底関数をつかって回帰式を作成できるが、そのときに未学習や過学習に陥ってないか確認することが重要になる。
未学習:学習データで推定したとき、十分小さな誤差が得られない。→「表現力が低いモデル」
過学習:学習データでは十分小さな誤差が得られるが、テストデータへ適用したとき、誤差が大きくなってしまう。→「表現力が高いモデル」
未学習対策としては、基底関数またはアルゴリズムを変える、説明変数のパラメーターの数を増やす、が挙げられる。
過学習対策としては、サンプル数を増やす、不要な基底変数を削除する、正則化法によって表現力を抑える、ことが挙げられる。
3.ロジスティック回帰モデル
通常の回帰分析で得られるような数値で予測とは異なり、複数の変数からある事象の発生の有無を確率的に予測する。
m次元パラメータの線形結合を入力としたシグモイド関数が出力となる。
補足すると、は各変数がxで表されるとき、事象(Y)が1になる確率である。
演習問題としてタイタニック号の乗客情報と(沈没時の)生死データより、(沈没時の)生死をロジスティック回帰モデルで推定するものだった。
最後のプロットでは、男性より女性の生存率が高い、女性の年齢別では年配の方が生存率が高い、男性の年齢別では若いの方が生存率が高いものでそれなりに推定できている。
少し前にテレビで女性を優先させて沈没時に船へ乗せているシーンがあったなぁ、と思い出した。