SJE2015 ex12

課題A

シグモイドを gnuplot でぐりぐり

次のような関数 \( s(x) \) を考える.これはシグモイド関数と呼ばれるものの一つの形である.

\[ s(x) = \frac{1}{1+\exp(-x)} \]

gnuplot でこの関数のグラフを描いてみよう.参考: wiki:Docs/gnuplot

$ gnuplot
gnuplot> s(x) = 1.0/(1+exp(-x))
gnuplot> plot s(x)

式の形とこの結果を元に,次の問に答えなさい.

  1. s(0) の値はいくつ?
  2. s(x) の値域はどんな?

次に,\( a, b, c \) を定数として,\( z = s(ax+by+c) \) とおいてみる.(x,y,z)の3次元空間にこの曲面を描いて眺めよう.マウスでで3次元グラフをぐりぐり回したりズームしたりできるはず.

gnuplot> z(x, y, a, b, c) = s( a*x + b*y + c )
gnuplot> splot z(x,y,1,0,2)
gnuplot> splot z(x,y,1,0,-2)
gnuplot> splot z(x,y,1,1,-2)
gnuplot> splot z(x,y,1,-1,-2)

ぐりぐりできない場合は,デフォルトの描画環境が対応してないのかもしれない.

gnuplot> set terminal x11    出力先を X11 に変更.
gnuplot> replot                    再描画.これでぐりぐりできるかも

びぶん

\( z = s(x) \) の導関数 \( \frac{dz}{dx} \) を求めよう.求めた式をながめていると,\( z \) 自身を使うと簡潔に

\[ \frac{dz}{dx} = z \times \mbox{hoge} \]

という形に表すことができることに気づく.hoge の部分には,\( z \) を使った式が入る.これを求めなさい.

びぶんぶん

\( X = ax+by+c \) とおくと,高校で習った合成関数の微分を思い出すと,

\[ \frac{\partial z}{\partial a} = \frac{\partial}{\partial a} s(ax+by+c) = \frac{\partial s(X)}{\partial X}\frac{\partial X}{\partial a} \]

である.これと↑の結果を用いて,\( z \)\( a \) に関する微分, \( b \) に関する微分,\( c \) に関する微分をそれぞれ,\( z,a,b,c,x,y \)を用いた式で表しなさい.

びぶんぶんぶん

\( t \) を定数として,

\[ h = -t\log z - (1-t) \log (1-z) \]

とおく.\( \frac{\partial h}{\partial a} \),同 b, c を↑と同様に式で表しなさい.

なんじゃこりゃ

次の課題を待て

課題B

以下を読んで理解しなさい.

ロジスティック回帰と2クラス識別

\( D \)次元特徴ベクトルで与えられるデータを「ほげクラス」に属するものとそれ以外(「ほげじゃないもののクラス」)に分類する問題(すなわち2クラスの識別問題)を考える.以下では簡単のため,\( D = 2 \) の場合に限定する.

ある2次元データを \( \bm{x} = (x, y) \) とする.このとき,先の課題で登場した \( z = s(ax+by+c) \) という式の値によって,データ \( \bm{x} \) が「ほげクラス」に属する確率を推定することにしよう(このようなモデルをロジスティック回帰モデルという).パラメータ \( a, b, c \) を調節するとこの推定確率が変化するので,クラス既知の学習データを用いてこれらのパラメータを学習させる.

学習データとして,\( N \)個の特徴ベクトル \( \bm{x}_1, \bm{x}_2, \dots , \bm{x}_{N} \)\( \bm{x}_n = (x_n,y_n) \))と,それぞれの所属クラスを表す教師信号 \( t_1, t_2, \dots , t_N \)\( \bm{x}_n \) が ほげクラスなら \( t_n = 1 \),さもなくば \( t_n = 0 \) )を用意する.この学習データに対して,\( z_n = s(ax_n+by_n+c) \) が正解 \( t_n \) に近づくようにパラメータ \( a,b,c \) を決定したい.そこで,\( z_n \) の正解との近さの規準として

\[ h_n = -t_n\log z_n - (1-t_n)\log ( 1 - z_n) \]

というものを考える.今の問題では \( t_n \) が 0 か 1 であるから,式の形から,\( t_n = 0 \) ならば \( z_n \) が小さい(0に近い)ほど \( h_n \) が小さくなり,\( t_n = 1 \) ならば逆に\( z_n \) が大きい(1に近い)ほど \( h_n \) が小さくなることがわかる.全ての学習データに対する \( h_n \) の和を \( H \) と表すことにする.つまり

\[ H = \sum_{n=1}^{N} h_{n} \]

である.この \( H \) を最小化するようにパラメータ \( a,b,c \) を決めれば,学習データをうまく2クラスに分類できるだろう.これが,ロジスティック回帰による2クラス識別の考え方である.なんでシグモイドかとかなんで \( H \) という式(これを交差エントロピーという)を考えるのかとかは省略.

確率的勾配降下法による交差エントロピー最小化

\( H \) を最小にするパラメータ \( a,b,c \) を求める問題は非線形最適化問題なので,一撃で解を求めることは一般に不可能である.このような最適化問題の解法はたくさんあるが,今の場合は目的関数(最小化したい関数)が微分できるので,目的関数の微分すなわち勾配を利用する「勾配法」がよく用いられる.これは,パラメータを適当な初期値に設定した状態からスタートして,\( H \) の微係数の値を調べながら,\( H \) が小さくなる方向に徐々にパラメータを変化させていく方法である.

いまの学習の目的は \( H \) の最小化だから,本来は上記のように \( H \) の勾配を調べてパラメータを修正するべきだが,そのような方法には多少問題がある(ここでは詳しく述べないが,学習の進め方の微調整が必要とか,コンピュータによる計算の効率がよくないとか).実際には,\( H \) の勾配を調べてパラメータを修正するかわりに,\( h_n \) の勾配を用いて個々の学習データごとにパラメータを修正することを繰り返すことで,確率的に \( H \) が最小化されることを期待する,というアプローチをとることがある.このような方法を,確率的勾配降下法(Stochastic Gradient Desecent, SGD)という.

\( h_n \) のパラメータ \( \theta \) に対する偏微係数 \( \frac{\partial h_n}{\partial \theta} \)\( \theta \)\( a,b,c \)を表す)は,先の課題で得た式で計算できる.このとき,SGDによる学習の手順は次のようになる.

  1. パラメータを適当な乱数で初期化する
  2. 以下を適当な回数繰り返す
    1. \( N \) 個の学習データの中から一つをランダムに選択する(その番号を \( n \) とする)
    2. \( (x_n,y_n) \) に対するモデルの出力 \( z_n = s(ax_n + by_n + c) \) を計算する
    3. \( h_n \) を計算する
    4. パラメータ \( \theta \) の値を次式で更新する
      \[ \theta^{\rm new} = \theta -\eta \frac{\partial h_n}{\partial \theta} \]
      \( \eta \) は小さな正の定数である.

\( \frac{\partial h_n}{\partial \theta} \) は現在のパラメータ値の地点における \( h_n \) の傾きであるから,このようにすると,\( h_n \) が少し小さくなる(下る)方向にパラメータを修正することになる.このような計算を何度も繰り返すと,やがて学習データ全体の交差エントロピーを小さくするようなパラメータにたどりつく( \( H \) を最小にするパラメータにたどり着く保証はないけれども,準最適なパラメータを見つけることができる)だろう.これが,(ロジスティック回帰モデルの)SGDによる学習の手順である.

課題C

人工データをロジスティック回帰モデルで識別させてみよう.

データ生成プログラム

以下を適当な名前で保存して,ipython 上で実行してみよう.

import numpy as np


def getData( seed = None ):

    if seed != None:
        np.random.seed( seed )
    
    # three 2-D spherical Gaussians
    X0 = 0.1  * np.random.randn( 200, 2 ) + [ 0.3, 0.3 ]
    X1 = 0.1  * np.random.randn( 200, 2 ) + [ 0.7, 0.6 ]
    X2 = 0.05 * np.random.randn( 200, 2 ) + [ 0.3, 0.7 ]
    X  = np.vstack( ( X0, X1, X2 ) )
    lab0 = np.zeros( X0.shape[0], dtype = int )
    lab1 = np.zeros( X1.shape[0], dtype = int ) + 1
    lab2 = np.zeros( X2.shape[0], dtype = int ) + 2
    label = np.hstack( ( lab0, lab1, lab2 ) )
    K = 3
 
    return X, label


if __name__ == '__main__':

    import matplotlib
    import matplotlib.pyplot as plt

    X, lab = getData()

    fig = plt.figure()
    plt.xlim( -0.2, 1.2 )
    plt.ylim( -0.2, 1.2 )
    ax = fig.add_subplot( 1, 1, 1 )
    ax.set_aspect( 1 )
    ax.scatter( X[lab == 0, 0], X[lab == 0, 1], color = 'red' )
    ax.scatter( X[lab == 1, 0], X[lab == 1, 1], color = 'green' )
    ax.scatter( X[lab == 2, 0], X[lab == 2, 1], color = 'blue' )
    fig.show()
    

このプログラムでは3クラスのデータを2次元の正規分布で生成してますが,次のようにしたら赤と緑の2クラスの分だけを取り出すことができます.

import getdata1214  (たとえば上記を getdata1214.py という名前で保存したとき)

X_org, lab_org = getdata1214.getData()
idx01 = lab_org != 2
X, lab = X_org[idx01], lab_org[idx01]
print X.shape, lab.shape

実験

上記プログラムで得られる2クラスのデータを学習データとして,ロジスティック回帰モデルの交差エントロピーをSGDによって最小化する学習プログラムを作成しよう.


トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2015-12-14 (月) 17:57:07