機械学習(1)パーセプトロンまで

この記事は学習が始まったばかりです。

機械学習

人間が自然としているような認識能力をコンピューターに獲得させるにはどうするかを考える。

基本的には関数についてる係数(重み)を反復的に自動調整することを指す。

特徴量

認識に寄与するパラメータ。
ロボに世界を認識させたいのであれば、それは物理的なセンサーからの入力として長さ、重さ、硬さなどが手掛かりとなるであろう。

画像の場合、特徴はアルゴリズムを用いて抽出可能なものでなければならない。画素ごとに色をカウントするなどは比較的簡単な特徴である。
コンピュータービジョン、画像処理、特徴抽出として括られるジャンルから、コーナー検出、エッジ検出、ハフ変換などを用いて有意義な特徴を抽出することができる。

また、画像を拡大縮小、回転などしても破壊されない特徴を得る手段としてSIFTやSURFなどが知られる。このあたりの特徴量は画像から物体を個別に認識するとか、人間を認識するとかいった目的で用いられる。

機械学習の文脈では、このような特徴量の獲得もプログラムにやってもらうことを目指す場合がある。

画像認識

量子化、サンプリング

コンピューター上で扱われるデータは必ず離散化される。必ず切れ目がある。対して現実世界は連続しているとみなされる。
離散化の過程で量子化とサンプリングが行われる。例えばデジタルカメラを用いて画像を生成した場合、一つの画素に対してどれだけの情報量を用いるのか、定められた情報量で画素を表すのが量子化である。画像に対してどれだけの画素を用いるのかがサンプリングである。

量子化は、例えば白黒2値画像なら1画素2ビットであろう。
グレースケールなら8ビット1バイト、0~255の濃度でもって1つの画素が描画される。RGBないしRGBAなどであるならば、その画素は255の3乗か4乗で量子化されていると言える。

正規化
機械学習の文脈では
グレースケール値0~255は特にGPUに対する利便性のために255で除されて0~1の範囲に収められることがある。こんなような、状況に応じたデータの帳尻合わせを正規化という。

サンプリングはどれだけ細かく現実世界を画素に分解するかを決定する。
いわゆる解像度という概念は現実世界の1インチを表現するのにどれだけの画素を用いるかの単位である。

画像のサイズは最終的に画素の個数と、1つの画素に用いられるデータのサイズの積となる。

画像認識の場合、
手元にあるデジタル画像をさらに量子化、サンプリングすることでこれをそのまま特徴として用いることができる場合がある。
特に数字や文字の認識はこの特徴が効果的である場合がある。
形状に関する認識を試みる場合、グレースケール化はほぼ必須の操作となる。

畳み込みニューラルネットワーク
すなわちCNN(Convolutional neural network)に画像を突っ込む場合、
RGBを残すなどして、チャンネル×横×縦なるテンソルの演算となる場合がある。
ただし、画像の縦横は行列(2重配列)からベクトル(配列)に変換されて使用される場合があるし、RGBなどのチャンネルはintにまとめて格納される場合もある。つまり状況による。

識別関数

認識の一つの出力は分類である。
ある画像群の中から犬の画像を抽出したい場合、ある種の関数を立て、その値が閾値を超えていれば『犬である』とし、そうでなければ『犬ではない』とすることができる。これは2値分類である。
また、『犬』『猫』『鳥』なるフォルダを用意して、与えられた画像群をそれらに振り分けていくのは多クラス分類である。

画像認識の場合、入力は画像の全ての画素と考える。
グレースケールであるならば、入力は画素の数だけ成分を持つベクトルとなる。100×100ピクセルの画像であるならば、そのベクトルの成分数は1万である。

$$
\bm x = (x_0,x_1,x_2…x_{pixelcount})
$$

画像の全ての画素に対して重みを乗じることを考える。
これは画像に関して重要な特徴を示す画素に対しては影響力を大にし、重要でない画素に対しては影響力を小にするということである。
重みを表すには画素の数と同じ成分数を持つ重みベクトルをもってして、成分同士の積の総和はそれすなわち内積であるから

$$
f(\bm x)= \sum\limits_{i=1}^{pixelcount} \bm x_i \bm w_i=\bm x \cdot \bm w
$$

ここで切片的(機械学習の文脈ではバイアスと呼ばれる)な役割を果たす$${w_0}$$を用いて

$$
f(\bm x)= \sum\limits_{i=1}^{pixelcount} \bm x_i \bm w_i + w_0
$$

とすると便利であり、かつ入力画素ベクトル側に帳尻合わせで$${x_0=1}$$を添えるとやはり内積の形に圧縮できて

$$
f(\bm x)= \sum\limits_{i=0}^{pixelcount} \bm x_i \bm w_i = \bm x \cdot \bm w
$$

ここで$${\bm x \cdot \bm w}$$は便利に拡張されたものとそうでないものとで意味が異なることに注意を要する。このような形式のものをだいたい線形識別関数という。グラフで描くと直線になるからである。

『犬である』と『犬ではない』は$${f(\bm x)=\bm x \cdot \bm w}$$が閾値を超えたら『犬である』としても良い。これは2値分類である。

与えられた画像を『犬』『猫』『鳥』に分類する場合は多クラス分類となる。この場合、クラスごとに適切な識別関数を用意し、入力画像が最大値を示す識別関数が画像のクラスである。
すなわちある画像を犬関数、猫関数、鳥関数に順次放り込み、犬関数が最大値であるなら画像は犬である。このやり方はそのまま2値分類にも適用できる。

いずれにせよ、問題はクラスに応じた適切な識別関数が設定できるかであり、識別関数に線形識別関数を用いるのなら、その問題は適切な重みを設定できるかということに帰着する。

最小二乗法、最尤推定

関数に重み、すなわち係数を設定することは、最小二乗法や最尤推定でもできることがある。

また、関数の係数を設定するとか決定するとかは、確率関数に対しても行われることがある。確率関数では、求められる係数はパラメータという。
確率関数の場合、ある程度関数の形が決まっている、あるいはこちらで決め撃つ場合がある(例えばガウシアンなど)。
ガウシアンのパラメータとは$${\mu}$$とか$${\sigma}$$とかである。

正しいかどうか分からない考え方

・世の中の大体のことは微分方程式で記述されるため、微分方程式を自由自在に解きたいという需要がある。
・・ところが大概の微分方程式は簡単に解けないので、近似的に解く必要がある。
・・・微分方程式を近似的に解くには、組み立てた近似的な連立方程式を行列でもって一撃で解くか、反復的に解く必要がある。この時に記述されたプログラムは、微分方程式の解の近似式として機能する。

・世の中には関数の係数の方を未知とみて、この係数を確定させることで関数を便利に使い回したいという需要がある。
・・使い回したい関数がだいたい分かっているケース(正規分布を使いたいとか)とそうでないケースがある。どちらにせよ、適切な係数さえ判明すれば、関数というのは未知のケースに対しても便利に使い回すことができる。
・・・上記最小二乗法や最尤推定は、関数の係数を一撃で、あるいは反復的に解く手法の一派である。

パーセプトロンやニューラルネットは、関数の係数を反復的に収束させるやり方の一つであるとみることができる。また、それをするために関数の入出力を接続して、直列状に組み立てたり、ノードベースで組み立てることができるようにしている。もって組み立てられた関数群を、全体として一つの便利な関数と見ることができる。

学習あるいは訓練

学習、あるいは訓練とは、識別関数の重みを半ば自動的に調整する手法である。

パーセプトロン

重みの学習の可能性を最初に示したのはパーセプトロンである。
パーセプトロン学習則は、入力パターン(例えば画像)が線形分離可能ならば必ず収束する。これをパーセプトロンの収束定理という。

線形分離可能

線形分離可能であるとは以下のような例

ここで図の座標軸は入力パターンの成分、画像の例の場合$${x_1, x_2}$$の2ピクセルである。

$$
f(\bm x)=w_0x_0+w_1x_1+w_2x_2=0
$$

であり、$${x_0=1}$$であったから

$$
-\frac{w_0}{w_2}-\frac{w_1}{w_2}x_1=x_2=f(\bm x)
$$

が上の図である。

図で示された直線は$${f(\bm x)=\bm x \cdot \bm w=0}$$である。この関数は3次元では平面を成す。すなわち空間の次元-1の構造物であり、こういうのを超平面という。

多クラス分類の図の場合、入力パターン(今の例の場合、たかだか2ピクセルの画像)が$${f(\bm x)=\bm x \cdot \bm w>0}$$であるならば入力画像は識別関数(超平面)の左にあると読むことができる。自動的に、対応クラスでない画像が入力された場合、識別関数は負値を出力する。

これは多クラス分類における、入力画像に対して最大値を吐いた識別関数を画像のクラスと認識するというやり方を満たすことができる。


パーセプトロン学習則

2値分類
唯一の識別関数を用いてクラスAとクラスBを分類する。
いくらかの画像に対し、あらかじめその画像がA、Bどちらのクラスに属するか紐づけておく。これを訓練パターンと呼ぶ。
適当な重みベクトル$${\bm w}$$をつくる。

訓練パターンを唯一の識別関数$${f(\bm x)=\bm w \cdot \bm x}$$に放り込む。この唯一の識別関数はクラスAに対して$${f(\bm x)>0}$$であって欲しく、クラスBに対して$${f(\bm x)<0}$$であって欲しい。

訓練パターンから画像を取り出す。
この画像がクラスAにも関わらず$${f(\bm x)\leqq0}$$であった場合

$$
\bm w' = \bm w + \rho \cdot \bm x
$$

クラスBにも関わらず$${f(\bm x)\geqq0}$$であった場合

$$
\bm w' = \bm w - \rho \cdot \bm x
$$

としてウェイトベクトルを順次更新する。ただし$${\rho}$$は適当な係数。
訓練パターンの全ての画像を正しく識別できたら訓練を終了する。また、訓練パターンが線形分離可能であるなら必ず訓練は完了する。

多クラス分類の場合
識別関数がクラスの数だけ存在するため、調整すべき重みもクラスの分だけ存在する。

クラスAであるべき入力がクラスBであると判断された場合
各々のクラスに紐づいた識別関数の重みを調整する。

$$
\bm w_A'=\bm w_A+\rho \cdot \bm x\\
\bm w_B'=\bm w_B-\rho \cdot \bm x
$$

なんで重みベクトルは収束するのか

収束することの証明はなされているが、ここでは証明そのものの説明でなく、収束している時の動作の説明にとどめる。

参考:
わかりやすいパターン認識 単行本 – 1998/8/1
石井 健一郎 (著), 前田 英作 (著), 上田 修功 (著), 村瀬 洋 (著)

ここで上図の座標軸は重みの成分である。

入力パターンを適切なクラスに分類する識別関数は、その係数であるところの重みが、上図の重み系において解領域に座標値をとる必要がある。逆に言うと、重みが上図の重み系において解領域に座標値とっていれば、識別関数は入力パターンを適切に分類できる。線形分離できる。

図が2次元平面であるのなら、その座標軸は$${w_0, w_1}$$であり、これは画像に例えるなら1ピクセルしかないということである。図が3次元であるならば2ピクセルまで許される。
図で示された直線は$${f(\bm x)=\bm x \cdot \bm w=0}$$である。この関数は3次元では平面を成す。

$${f(\bm x)=\bm x \cdot \bm w=0}$$において、縦軸を$${w_0}$$、横軸を$${w_1}$$とするならば、$${x_0}$$は常に1であって、グラフの形は$${w_0=x_1w_1}$$であり、常に原点を通る。

座標軸にウェイトを用いたウェイト系で、ウェイトベクトルに対してバターンベクトル(今の場合ピクセルベクトル)を足したり引いたりすると、ウェイトベクトルは超平面に垂直な方向に動く。
パーセプトロンの学習則のアルゴリズムにより、ウェイトベクトルは最終的にウェイト系の解領域に座標値を持つ。学習が完了する。

パターンベクトルはなんで超平面に直交するのか

平面に垂直なベクトル、すなわち法線ベクトルと平面は切っても切れない関係にある。そも、平面というのは法線ベクトルに直交するベクトル全部と定義しても良いものであって、空間中の1点と、そこから発すると仮定できる法線によって完全に定められる。

平面の方程式は2つの直交するベクトルの内積で表される。座標値でいうと3つ。パラメータでいうと9つ必要。

法線を$${(a,b,c)}$$
空間中の1点を$${(x_0,y_0,z_0)}$$
平面上の任意の点を$${(x,y,z)}$$
とすると

得られる方程式は

$$
(a,b,c)\cdot (x-x_0,y-y_0, z-z_0)=0\\
a(x-x_0)+b(y-y_0)+c(z-z_0)=0
$$

あるいは

$$
ax-ax_0+by-by_0+cz-cz_0=0\\
ax+by+cz-(ax_0+by_0+cz_0)=0\\
ax+by+cz+d=0
$$

直線の場合も同じことになる

$$
(a,b)\cdot (x-x_0,y-y_0)=0\\
a(x-x_0)+b(y-y_0)=0\\
ax+by+c=0
$$

勾配法と誤差逆伝播法との関係

重みの調整に誤差関数の勾配(微分値)を使うと勾配法。
その時に使う誤差関数の勾配を効率的に求めるのが誤差逆伝播法。

勾配には入力の変位に対する関数値の変位が最大となる方向を向く性質がある。そのような方向に進むということは、山の山頂や穴の底に至るということを示す。山の山頂への最短ルートとは、関数値の変位が最大であるような方向への移動の累積である。(ただし局所的な穴に落ち込んだりして死ぬことはある)

参考その1


パーセプトロンの機械学習文脈での実装

参考:
ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装 単行本(ソフトカバー) – 2016/9/24

パーセプトロンは入力を受ける。
受けた入力に重みを乗じて総和する。
その結果が閾値以上なら1を返す。
そうでなければ0を返す。

以上を満たせばパーセプトロンとなる。
これは外界からの刺激を受けてニューロンが発火することのモデル化である。
重みに関してはパーセプトロンが内部に保持する必要がある。

//疑似コード

class Perceptron
{
  double threshold = 0;
  double bias;
  double[] weight;

  bool exe(double[] input)
  {
    double temp = dot(input, weight) + bias;
    if(temp>=threshold)
    {
      return true;
    }
    else
    {
      return false;
    }
  }
}

double dot(double[] x, double[] y)
{
  double ret = 0;
  for(int i = 0; i<x.length; i++)
  {
    ret += x[i]*y[i];
  }
  return ret;
}

このパーセプトロンクラスはバイアスとウェイトを調整するだけでAND,OR,NAND回路を実現することができる。XORは単一ではできない。多層化する必要がある。

//試してない

class Perceptron
{
  static Perceptron GetAND()
  {
    Perceptron p = new Perceptron();
    p.weight = new Array(){0.5, 0.5};
    p.bias = -0.7;
    return p;
  }
  static Perceptron GetNAND()
  {
    Perceptron p = new Perceptron();
    p.weight = new Array(){-0.5, -0.5};
    p.bias = 0.7;
    return p;
  }
  static Perceptron GetOR()
  {
    Perceptron p = new Perceptron();
    p.weight = new Array(){0.5, 0.5};
    p.bias = -0.2;
    return p;
  }





  static bool AND(double[] x)
  {
    var p = Perceptron.GetAND();
    return p.exe(x);
  }
  static bool NAND(double[] x)
  {
    var p = Perceptron.GetNAND();
    return p.exe(x);    
  }
  static bool OR(double[] x)
  {
    var p = Perceptron.GetOR();
    return p.exe(x);    
  }
  static bool XOR(double[] x)
  {
    var output1 = NAND(x);
    var output2 = OR(x);
    var result = AND(new Array(){output1, output2});
    return result;
  }
}



この記事が気に入ったらサポートをしてみませんか?