【自分メモ】深層学習(ディープラーニング)を用いた画像処理にむけて

#はじめに
物体を分類して、何をしているのかを認識させるプログラム作成を目指している。
上記を目指すための最適なやり方を見つける/勉強のためにこの記事では、関連知識についてまとめる。
学習過程で記述するので、きれいに並んでいない・・・

#画像処理の手法について
顔や物体を認識する方法は、入力として入った画像の"特徴量"を抽出し、特徴量を学習/照合させること。

特徴量の抽出方法は以下のような物が有名
・Haar-Like特徴
　　画像を切り出して黒/白 領域の合計画素値差を特徴量とする
・LBP（Local Binary Pattern）特徴
　　輝度分布を特徴量とする
・HOG（Histogram of Oriented Gradients）特徴
　　輝度変化の方向と輝度変化の大きさを特徴量とする
※上記抽出方法は、OpenCV等のオープンソースでも実装されており、特徴点をまとめた学習データをカスケード分類器と呼ぶ

これに対して、特徴量を自動で抽出するのがディープラーニングであり、画像処理においては、画像を構成するピクセルの画素値の傾向を自動で読み取ってくれる。
今回画像処理にディープラーニングを用いるのは、ディープラーニングを用いた時の物の分類/認識精度が一般的に高そうと認識したからで、これ以降ではディープラーニングについて学んだことをまとめる

#ディープラーニングとは
ニューラルネットを3層以上重ねた(多層パーセプロン)を一般的に"ディープ・ニューラル・ネットワーク(DNN)"と呼ぶ。
DNNを使用した機械学習をディープラーニングと呼ぶ。
ディープラーニングでの使われ方：
　教師あり学習-回帰/分類
　教師なし学習-特徴量抽出/次元削減
　中間的手法-異常検知/強化学習
フレームワーク：
　TensorFlow, Pytorch, Chainer

#パーセプトロン
複数の信号を受け取り、1つの信号を出力するアルゴリズムのこと
出力されるものは、信号を流す(1) or 流さない(0)の2値で、重みも含めて計算した値の大小関係から判断される。この(0, 1)の出力の仕組みにはステップ関数が使われる。
パーセプトロンを使うとAND/NAND/ORゲートの実現が可能。ただし、XORゲートの実現は不可非線形な線でないといけない。※ゲートを複数組み合わせることで実装可能(多層化することで非線形な関係の描画が可能)

#ニューラルネットワーク(多層パーセプトロン)とは
人の神経を模したネットワーク構造のことで、神経細胞(ニューロン)の接続モデルである形式ニューロンを複数につなぎ合わせたもの。
万能近似定理: ノードを増やしていくと、ニューラルネットワークの表現力がどんどん上がっていく。学習データをほぼ完全に説明できるニューラルネットワークが実現できる。※これは訓練誤差が0に近いモデルができるということであるが、汎化誤差に対する性能は最大かどうか不明

畳み込みニューラルネットワーク(CNN)：
画像処理でよく使われるニューラルネットワークの一つで、以下で構成されている。

```math
入力画像 -[畳み込み層-正規化層-プーリング層-全結合層]→出力画像
```
※Network in network(NIN)と呼ばれる手法で全結合層が不要になっている形態が今は一般的になっている。

・畳み込み層
入力画像にフィルタ処理をして、特徴マップを作成する。
画像に対しては平滑化(ぼかし)/エッジ抽出/エンボスなどとして反映される。出力画像の大きさは、フィルタの大きさに応じて小さくなる。

・正規化層
畳み込み層で処理されたg増の全画素値の平均を0にする減山正規化や分散を抑える除算正規化を行う。

・プーリング層
画像の情報を残しながら元の画像の縮小を行う。
特徴量の圧縮に効果があり、物体認識で有利に働く。

形式ニューロン：
McCulloch-Pittsモデルで考案された神経細胞の接続モデルのことで、入力(x)として数値を受け取り、それを合算してさらにフィルタをかけて出力(y)する素子のような役割を示すもの。

```math
ｘ -関数(f)→ y
```
※McCulloch-Pittsモデルでは該当関数がヘヴィーサイドの階段関数(x<0: y=0, x>0: y=1, x=0: 0<=y<= 1 ステップ関数と似ている)で決めつけられ、この関数は活性化関数と呼ばれる。それぞれの形式ニューロンの重みは入力/出力の関係で変化し、重み係数を更新する誤差逆伝播法(バックプロパゲーション)がディープラーニングで重要な役割を示す。

#活性化関数とは
活性化関数が無いと、単なる線形結合となり線形回帰とほぼ同じ計算モデルとなる。
線形回帰でモデリングできるのであれば、ニューラルネットワークでモデリングする必要はなくなるため、活性化関数は非線形なモデルとなる。

#順伝播計算とは
入力層から出力層に向かって、データを流していくことを順伝播計算という。
※出力層から入力層に向かって計算することは逆伝播計算という
コード上の計算は行列計算で表されることが一般的(計算処理も早い)

#出力層の設計について
回帰問題では、恒等関数を用いる。
2クラス分類問題では、シグモイド関数を用いる。
2クラス分類問題を多クラス分類問題とみなして、ソフトマックス関数を用いることもできるが、最適化するパラメータが多くなってしまう。
※ソフトマックス関数を使用する場合は、オーバーフローに注意する

#学習について
大きく分けて2種類の学習法に分けられる
バッチ学習：学習用データを一度すべてに入力して、重みを更新する学習方法
　一度にすべての学習データの損失を算出して、その和(or平均)を最小化する
　利点-バッチサイズが大きいほど勾配推定が正確、学習係数が大きい
　欠点-メモリ使用量が大きい
ミニバッチ学習：学習用データを小さなバッチに分けてバッチごとに重みを更新する方法
　ミニバッチ毎に損失の平均を算出して、それを最小にする。それをバッチ毎に進める。
　全ミニバッチを1巡することを1エポックと数える。通常は、計算収束までに、10~数100エポックくらい繰り返す。基本的に非復元抽出でエポックは作る
　※エポック毎にシャッフルしてもよい/復元抽出にしてもよい/抽出されるラベルの割合が一定になるように抽出してもよい
　利点-正則化の効果をもたらし、局所的最小解にトラップされてしまうリスクを低減できる
　欠点-計算時間が長い
正則化：過学習を抑制する機能で、訓練誤差が最下点になる手前で止める機能
勾配降下法：重みを少しづつ変更して、最小点を見つける手法
学習係数：1回で進む学習進捗

ただし、ディープラーニングでは計算量の問題もありミニバッチ学習をすることが多い。

#学習の最適化(パラメータ更新関数)
確率的勾配降下法(SGD)の学習を効率的に実施する方法について、
1次/2次の方法が挙げられ、DNNでは1次の方法が使われる。
Momentum, NesterovAcceleratedGradient, NesterovAG, AdaGrad, RMSProp, AdaDelta, Adam等が挙げられる

#損失関数について
損失関数は、ニューラルネットワークの悪さを示す指標(訓練誤差)
ニューラルネットワークの一番出力に近い層で使われる関数(2乗和誤差等)
機械学習/ディープラーニングでは、汎化誤差が小さくようなパラメータが最適
※訓練誤差が最小なものが最適ではない。訓練誤差は小さいが汎化誤差が大きい状態を過学習と呼ぶ。訓練誤差が最小なパラメータを採用しないような機能を正則化と呼ぶ
現在の重みが、教師データに対してどの程度適合しているかを示す。
回帰問題では2乗和誤差、分類問題ではクロスエントロピー誤差が使われる
※クロスエントロピー：2つの確率分布の異なりを示す指標で、正解の分布と予想結果の分布の異なり具合を示す
※ワンホットベクトル：ある要素だけが1であり、その他の要素は0であるベクトル


#誤差逆伝播法
勾配降下法で最小値を求めるには、損失関数の偏微分が必要であるが、
ディープラーニングの損失関数が非常に複雑で、微分が困難。
そこでこの方法が利用されている。
出力層から入力層へ向かって勾配を伝播させていく方法
微分計算は処理が大きいため連鎖律の原理を使用して計算される(合成関数の微分)
※数値微分計算は実施されない。つまり数値微分を正として誤差逆伝播法を検定するようなイメージ
※バッチ数がNの時の勾配は、バッチ数分合計された値となる

```math
∂L/∂x = ∂L/∂y * ∂y/∂x 
```

勾配消失：
逆伝播で計算していくと、勾配がなくなってしまうケースがある。この状態では、重みの更新ができなくなってしまい、問題である。活性化関数設定が勾配値に影響するので、関数選定は非常に大切
※シグモイド関数は勾配消失が起こりやすい

アフィンレイヤの逆伝播：
重みを掛け算してバイアスを足すことがアフィン変換に相当する。
アフィンレイヤでの逆伝播計算では、出力値に対してバイアスを足して逆伝播的に計算する。

#ディープラーニングを用いた画像処理に向けて
ディープラーニングを実践するために、オープンソースで公開されているTensorFlowを用いる。

#勉強ログ
【目標設定】
課題に対して機械学習/ディープラーニング的アプローチを活用することができる。

【1日目学習内容】
機械学習：教師あり学習/教師なし学習/半教師あり学習/強化学習など
半教師あり学習：教師あり学習におけるラベル付けの負荷低減のために、ラベルをすべてついていないデータを用いた機械学習のこと
強化学習：収益を最大化する方策を獲得することを目的とする

機械学習をさらに発展させる
より効率よく更新する：
オンライン学習：訓練データを取り出してパラメータの更新をする
アンサンブル学習：複数の学習器を組み合わせる

大規模なデータを利用する：
分散学習：データの一部を抜粋して学習

より複雑な特徴を利用する：
深層学習：教師なし学習で与えられたデータからアルゴリズムを作る

サポートベクターマシン(SVM)
教師あり学習であり、マージン最大化学習を行う2値分類器
また、カーネル関数を使うことで、非線形な識別関数を作る方法である。
カーネル関数例：線形/多項式/RBF(Gaussian Radial Basis Function)/シグモイド

機械学習手法の評価
k分割交差検証：学習用のデータをk個に分割して、k回学習する方法
ホールドアウト検証：訓練データとテストデータに分けて学習する方法

グリッドサーチ
ハイパーパラメータの候補を出し、交差検証を用いて精度の高いパラメータを算出する手法
ハイパーパラメータとは、エンジニアが事前に調整するパラメータ

#関連する数学知識
・数値微分
　微小な差分によって微分を近似的に求めること
・解析微分(普段の数学計算)
　式の展開によって微分を求めること
→計算が難しい場合に解析微分ではなく数値部分を使用する場合がある

・勾配ベクトル
偏微分をひとまとまりで表現したもの
例: x, y両方の微分を同時に実施した時の解

・勾配降下法(パラメータ更新式)
勾配ベクトルを用いて、関数の最小/最大を目指す方法
ニューラルネットワークでは、一般的に確率的勾配降下法を用いる。
※確率的勾配降下法(SGD)は、無作為に選びだしたデータに対して行う勾配降下法(ミニバッチ学習で実施した勾配降下法のこと)

・最急降下法(パラメータ更新式)
勾配ベクトルを用いて、訓練誤差の最下点の方向を算出してパラメータ更新を繰り返す方法
関数の勾配が最も急な方向に探索の方向を取りながら最下点にたどり着く方法

・鞍点
大局的最小値でないにもかかわらず勾配=0となる箇所
勾配=0になると最小値の探索が終了してしまうので注意

・プラトー
ほとんど勾配がない地帯のこと
学習が進まない停滞期に陥るので注意
損失関数の値が離散的な値になると、計算が円滑に進まなくなる場合がある
→クロスエントロピー誤差関数などの連続的な値を出力する損失関数に設定すると、損失変化が滑らかになり、重みの探索が円滑になる

【用語】
バッチ処理：入力データを束ねる(バッチ)ことによって計算を効率的に行う手法




【関連リンク】
[【TensorBoard入門:image編】TensorFlow画像処理を見える化して理解を深める](https://qiita.com/FukuharaYohei/items/fae6896e041235033454)
[【入門者向け解説】TensorFlow基本構文とコンセプト](https://qiita.com/FukuharaYohei/items/0825c3518d8596c09396)
[TensorFlow理解のために柏木由紀さん顔特徴を調べてみた【前編】](https://qiita.com/FukuharaYohei/items/c3fb29fc8b42e0dfad0f)
[【TensorFlowのTutorialをざっくり日本語訳していく】1. MNIST For ML Beginners](https://qiita.com/_kazuki_yoshida_/items/3719fec3cfe764674fb9)
[TensorFlowのTensorオブジェクトに慣れたい](https://qiita.com/everylittle/items/d90ac57cce4aabb26f16)
[多分もっともわかりやすいTensorFlow 入門 (Introduction)](https://qiita.com/junichiro/items/8886f3976fc20f73335f)
[機械学習を1ヵ月で実践レベルにする #1 (とっかかり編)](https://qiita.com/junichiro/items/ee50af10df77d52cd432)
[機械学習をゼロから1ヵ月間勉強し続けた結果](https://qiita.com/junichiro/items/3457e33e502086a200f1)
[TensorFlow & Keras で TFRecord & DataSetを使って大量のデータを学習させる方法](https://qiita.com/everylittle/items/1d8a6267b0967346767a)
[TensorFlowのチュートリアルを通して、人工知能の原理について学習する](https://qiita.com/jintaka1989/items/3b70b5c5541620536fa2)
[kerasのConv2D（2次元畳み込み層）について調べてみた](https://qiita.com/kenichiro-yamato/items/60affeb7ca9f67c87a17)
[Conv2D（CNN）の意味・用法](https://child-programmer.com/ai/keras/conv2d/)
[畳み込みニューラルネットワーク_CNN(Vol.16)](https://products.sint.co.jp/aisia/blog/vol1-16)
[新たな活性化関数「FReLU」誕生&解説！](https://qiita.com/omiita/items/bfbba775597624056987)
[KerasのConv2Dの行列式演算](https://qiita.com/nishiha/items/bfd5dfcd7fffd3c529bc)
[MaxPooling2DをConv2Dのみで表現する](https://qiita.com/nishiha/items/49fdd119dfa2567e272b)
[第2回　ニューラルネットワーク最速入門 ― 仕組み理解×初実装（中編）](https://www.atmarkit.co.jp/ait/articles/1910/17/news026.html)
[第1回　初めてのニューラルネットワーク実装、まずは準備をしよう ― 仕組み理解×初実装（前編）](https://www.atmarkit.co.jp/ait/articles/1909/19/news026.html)
[犬と猫の写真を判定するウェブサービスを作ってみた](https://qiita.com/elm200/items/5b04a2be69a6fdf1e19c)