
- Week2
- OctaveをGNU/Linuxにインストールする
- 複数要素(Multiple Features)
- 多変量のための最急降下法 (Gradient Descent For Multiple Features)
- 最急降下法の演習Ⅰ - 特徴値の縮小 (Gradient Descent in Practice I - Feature Scaling)
- 最急降下法の演習Ⅱ - 学習率 (Gradient Descent in Practice II - Learning Rate)
- 特徴値と多項式回帰 (Features and Polynomial Regressions)
- 正規方程式 (Normal Equation)
- 正規方程式の非正則性 (Normal Equation NonInvertibility)
- クイズ
- Octaveチュートリアル
- 基本操作(Basic Data Operation)
- データ操作周り(Moving Data Around)
- データを計算する(Conputing on Data)
- データをプロットする(Plotting Data)
- 制御構文: for, while if (Control Statements: for, while, if statement)
- ベクトル化 (Vectorization)
- Octave/Matlabを使ったクイズ
- Octaveを使ったWEBテスト
[機械学習]
Week2
OctaveをGNU/Linuxにインストールする
- Linuxだと簡単ですね
# apt-get update && apt-get install octave
複数要素(Multiple Features)
表記
まずは要素が増えた場合の表記の方法を学ぶ
- \( x^{(i)}_{j} \) = トレーニングセット内にあるベクトルのある入力値
- \( x^{(i)} \) = トレーニングセット内にある全ての入力値のベクトル
- \( m \) = トレーニングセットの数
- \( n \) = 要素の数
要はプログラミングで言うところの添え字アクセスを数学で表したもの。
- 以下のようなデータセットがあった場合、iはただのインデックス値
i | x1 | x2 | x3 | x4 | y |
---|---|---|---|---|---|
1 | 2104 | 5 | 1 | 45 | 460 |
2 | 2500 | 6 | 4 | 60 | 880 |
3 | 2790 | 7 | 6 | 100 | 1260 |
- \( \begin{eqnarray} x^{(2)} = \left[ \begin{array}{ccc} 2500\\6\\4\\60 \\ \end{array} \right] \end{eqnarray} \)
- 2番目のインデックスに入っているベクトルを示す表記
- \( x^{(2)}_1 = 2500 \)
- 2番めのインデックスに入っているベクトルの1番目を示す表記
複数要素の場合のhypothesis (仮説)
\( h_\theta(x) = \theta_0 x_0 + \theta_1 x_1 + \theta_2 x_2 + \cdots + \theta_n x_n \)
そしてこいつを転置して
\( h_\theta(x) = \theta^T x \) と書く、TはTransposeのT
こういうのを多変量の線形回帰(Multivariate linear regression)という
アイエエエエ!転置ナンデ!!
知識が足りないのでグーグル先生にいろいろ聞く
- ベクトル (Vector)
- ベクトルは英字の小文字で表す.ベクトルを表す時に、丸括弧( )ではなく 角括弧[ ] で表現することもある.(Ng先生はベクトルを角括弧で書く傾向がある)
- 転置行列
- Wikipediaにも解説があるが、自分はプログラミングのための線形代数の解説を読んだ
- \( \begin{eqnarray} (2, 3, 5, 8)^T = \left[ \begin{array}{ccc} 2 \\ 3 \\ 5 \\ 8 \\ \end{array} \right] \end{eqnarray} \) と書けるし、逆に \( \begin{eqnarray} \left[ \begin{array}{ccc} 2 \\ 3 \\ 5 \\ 8 \\ \end{array}\right]^T = (2, 3, 5, 8) \end{eqnarray} \) となるらしい
- 行列の積
- 文系なので行列習ったこと無いんですが…とりあえず計算は以下のような法則でできるようです
- \( \begin{eqnarray} (a, b) \left[ \begin{array}{ccc} p \\ q \\ \end{array} \right] \end{eqnarray} = (ap + bq ) \)
- \( \begin{eqnarray} (a, b, c) \left[ \begin{array}{ccc} p \\ q \\ r \\ \end{array} \right] \end{eqnarray} = (ap + bq + cr) \)
「転置は実際計算式を簡単化する。いいね?」「アッハイ」
式変形して長い式と短い式がおなじであることを確認してみる。
- \( h_\theta(x) = \theta_0 x_0 + \theta_1 x_1 + \theta_2 x_2 + \cdots + \theta_n x_n \)
- 最初の式
- \( h_\theta(x) = (x_0,x_1,\cdots,x_n) \left[ \begin{array}{ccc} \theta_0 \\ \theta_1 \\ \vdots \\ \theta_n \\ \end{array} \right] \)
- 行列の積で書き直すとこうなる
- \( h_\theta(x) = \theta^T x \)
- 転置して完了
ということは、xもθも行列として扱われているということなのかな。
多変量のための最急降下法 (Gradient Descent For Multiple Features)
最初、目的関数が簡単だった時の最急降下法は
- 仮説: \( h_\theta(x) = \theta_0 + \theta_1 x 、変数: \theta_0 , \theta_1 \)
- \( \theta_j = 0 : \frac{\delta}{\delta\theta_0} J(\theta_0 , \theta_1) = \frac{1}{m} \sum_{i=1}^m (h_\theta(x^{(i)}) - y^{(i)}) \)
- \( \theta_j = 1 : \frac{\delta}{\delta\theta_1} J(\theta_0 , \theta_1) = \frac{1}{m} \sum_{i=1}^m (h_\theta(x^{(i)}) - y^{(i)}) \cdot x^{(i)} \)
変数が無限に増えたので、
- 仮説: \( h_\theta(x) = \theta_0 x_0 + \theta_1 x_1 + \theta_2 x_2 + \cdots + \theta_n x_n 、変数: \theta_0 , \cdots , \theta_n \)
仮説関数が無限に増えてわかりみが消え失せた。だけど思ったより式自体は難しくない(?)ただし手計算出来る気がしない。 変数θが出来上がりの回帰関数を形作るのだと思うのだが、一体コレ何次関数になるのだろう。
最急降下法の演習Ⅰ - 特徴値の縮小 (Gradient Descent in Practice I - Feature Scaling)
- 最急降下法を早く収束させるためのテクニック
特徴値の圧縮 (Feature Scaling)
- 例えば使用するデータセットX1が病院のサイズ(feet)、X2がベッド数だとする。おそらくそのときX1,X2の比は極端に大きくなる(等高線図は楕円状になるかもしれない)
- そのまま最急降下法を適用すると、収束が遅くなるかもしれない
- なので、X1,X2それぞれの比を圧縮するように式を修正する
- そうすれば等高線は円に近くなり、最急降下法の収束は早くなるだろう
平均の正規化 (Mean Normalization)
参考ブログ
- \( x_i := \frac{x_i - \mu_i}{s_i} \) 、μ:それの平均値、Si:値の取る範囲 or 標準偏差
最急降下法の演習Ⅱ - 学習率 (Gradient Descent in Practice II - Learning Rate)
- 最急降下法をデバッグする
- X軸をθ、Y軸をJ(θ)とおいたグラフを書くことで、うまく最急降下法が収束しているかどうか確認できる
- → ちゃんと最小化できていなければ学習率αを見直す必要がある
特徴値と多項式回帰 (Features and Polynomial Regressions)
- 例えば特徴値X1, X2, X3があり、X1=size, X2=size^2,X3=size^3みたいになるとき
- それぞれの取る範囲が予測できる
正規方程式 (Normal Equation)
- これまでは最急降下法でJ(θ)のグローバル最適な最小値を頑張って求めていた
- しかし、J(θ)は実際普通の式なので、二次関数の最小値を求めるように最小値が求められる場合がある
- 我々はトレーニングセットの大きさによってこれらを使い分けなければいけない
データセットによる例
- 以下のようなデータセットがあり、m = 4
x0 | x1 | x2 | x3 | x4 | y |
---|---|---|---|---|---|
1 | 2104 | 5 | 1 | 45 | 460 |
1 | 1416 | 3 | 2 | 40 | 232 |
1 | 1534 | 3 | 2 | 30 | 315 |
1 | 852 | 2 | 1 | 36 | 178 |
これらは行列にすると
- \( \begin{eqnarray} X = \left[ \begin{array}{ccc} 1 & 2104 & 5 & 1 & 45 \\ 1 & 1416 & 3 & 2 & 40 \\ 1 & 1534 & 3 & 2 & 30 \\ 1 & 852 & 2 & 1 & 36 \\ \end{array}\right] \end{eqnarray} \)
- \( \begin{eqnarray} Y = \left[ \begin{array}{ccc} 460 \\ 232 \\ 315 \\ 178 \end{array}\right] \end{eqnarray} \) と書ける
- design matrix
- この行列の1行1行は \( (x^{(1)})^T , (x^{(2)})^T, (x^{(3)})^T \) を上から順番に重ねていったものとなる、まあ単に表の1行目、2行目、3行目と同じです
正規方程式の解
この正規方程式は \( \theta = (X^T X)^{-1} X^T y \) のとき最小値になる、nが大きいと解くのに時間がかかる
正規方程式の非正則性 (Normal Equation NonInvertibility)
- 何らかの行列に対する逆行列が常に存在するとは限らないようだ
- 非正則行列
逆行列について
- 逆行列の求め方
- わかりやすい
- \( \begin{eqnarray} A = \left( \begin{array}{ccc} 2 & 5 \\ 1 & 3 \end{array}\right) \end{eqnarray} \) のとき
- \( \begin{eqnarray} \left( \begin{array}{ccc} 2&5 \\ 1&3 \end{array}\right) \end{eqnarray} \begin{eqnarray} \left( \begin{array}{ccc} 3&-5 \\ -1&2 \end{array}\right) \end{eqnarray} = \begin{eqnarray} \left( \begin{array}{ccc} 1&0 \\ 0&1 \end{array}\right) \end{eqnarray} \)
- \( \begin{eqnarray} \left( \begin{array}{ccc} 3&-5 \\ -1&2 \end{array}\right) \end{eqnarray} \begin{eqnarray} \left( \begin{array}{ccc} 2&5 \\ 1&3 \end{array}\right) \end{eqnarray} = \begin{eqnarray} \left( \begin{array}{ccc} 1&0 \\ 0&1 \end{array}\right) \end{eqnarray} \)
よって \( \begin{eqnarray} A^{-1} = \left( \begin{array}{ccc} 3&-5 \\ -1&2 \end{array}\right) \end{eqnarray} \)
まあ、必ずしも逆行列がなさそうなことはわかる。
それでも、octave上(というかコンピュータ上)は逆行列がなくてもその近似値を求めるので問題にはならないそうだ。
クイズ
- Feature scalingの式は覚えているだろうか?
- 正規方程式 (Normal Equation)を使う時、Xという行列はfeatureの数+1の列を持つことを忘れないこと!
5回ぐらいやり直してやっと合格した
Octaveチュートリアル
まずは試作をOctaveなどを使って作り、それから一般的なプログラミング言語で組み上げていこう。とのこと。
基本操作(Basic Data Operation)
- LinuxでGUIなしで起動させると、授業で見るような画面になる。
$ octave --no-gui
- 行列は角括弧(だからng先生は手書きでも角括弧で行列を書く)、改行はセミコロン
>> A = [ 1 ]; >> B = [ 1 ; 2 ; 3 ];
- ベクトルを作るいろいろな方法がある
- 1で始まって0.1刻みで2まであるベクトル
- 1で始まって1刻みで6まであるベクトル
>> v = 1:0.1:2 >> v = 1:6
- 行列を作る面白い方法
- onesに行列の行と列の数を入れて使う
- 掛け算も出来る
>> ones(2,3) ans = 1 1 1 1 1 1 >> 3*ones(2,3) ans = 3 3 3 3 3 3
- hist関数を使うとデータセットに対するヒストグラムが出力される
データ操作周り(Moving Data Around)
- size と length
>> A = [ 1 2; 3 4; 5 6]; >> size(A) ans = 3 2 >> B = 1:10; >> length(B) ans = 10
- ls とか pwd がそのまま使える
- who / whos
>> who Variables in the current scope: A B ans >> whos Variables in the current scope: Attr Name Size Bytes Class ==== ==== ==== ===== ===== A 3x2 48 double B 1x10 24 double ans 1x14 14 char Total is 30 elements using 86 bytes
- saveするとファイルに書き出せる
- clearするとoctaveのワーキングスペースから変数が消える
- loadでファイルを読み込める
>> save A.mat A; >> whos Variables in the current scope: Attr Name Size Bytes Class ==== ==== ==== ===== ===== A 3x2 48 double B 1x10 24 double ans 1x14 14 char Total is 30 elements using 86 bytes >> clear A; >> whos Variables in the current scope: Attr Name Size Bytes Class ==== ==== ==== ===== ===== B 1x10 24 double ans 1x14 14 char Total is 24 elements using 38 bytes >> A = load('A.mat'); >> A A = scalar structure containing the fields: A = 1 2 3 4 5 6
- 行列同士を縦や横で連結できる
>> V1 = ones(3,3); >> V2 = 2*ones(3,3); >> V3 = [ V1 V2 ]; >> V3 V3 = 1 1 1 2 2 2 1 1 1 2 2 2 1 1 1 2 2 2 >> V4 = [ V1 ; V2 ]; >> V4 V4 = 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2
なかなか高性能ですね〜
データを計算する(Conputing on Data)
- 行列同士の演算
- サイズが同じでないと計算できない
>> A = [1 2; 3 4; 5 6] A = 1 2 3 4 5 6 >> B = [11 12; 13 14; 15 16] B = 11 12 13 14 15 16 >> A .* B ans = 11 24 39 56 75 96 >> A * B error: operator *: nonconformant arguments (op1 is 3x2, op2 is 3x2) >> C = [1;2]; >> A * C ans = 5 11 17 >> A .^ 2 ans = 1 4 9 16 25 36
- ベクトルに対する演算
>> v = [1;2;3] v = 1 2 3 >> 1 ./ v ans = 1.00000 0.50000 0.33333 >> 1 ./ A ans = 1.00000 0.50000 0.33333 0.25000 0.20000 0.16667 >> log(v) ans = 0.00000 0.69315 1.09861 >> exp(v) ans = 2.7183 7.3891 20.0855 >> abs(v) ans = 1 2 3 >> v v = 1 2 3 >> v + ones(length(v), 1) ans = 2 3 4 >> length(v) ans = 3 >> v + 1 ans = 2 3 4
- 逆行列、シングルクォートをつけるだけ
>> A' ans = 1 3 5 2 4 6 >> a = [1 15 2 0.5] a = 1.00000 15.00000 2.00000 0.50000 >> val = max(a) val = 15 >> [val, ind] = max(a) val = 15 ind = 2 >> find(a < 3) ans = 1 3 4
- 魔法陣、サンプルとして使うだけ
>> A = magic(3) A = 8 1 6 3 5 7 4 9 2 >> [r,c] = find(A >=7) r = 1 3 2 c = 1 2 3 >> sum(a) ans = 18.500 >> prod(a) ans = 15 >> floor(a) ans = 1 15 2 0 >> ceil(a) ans = 1 15 2 1 >> rand(3) ans = 0.74874 0.57485 0.16166 0.49338 0.30616 0.48236 0.94762 0.72698 0.52448 >> max(rand(3),rand(3))~ parse error: syntax error >>> max(rand(3),rand(3))~ ^ >> max(rand(3),rand(3)) ans = 0.51997 0.97522 0.58482 0.91747 0.74610 0.99696 0.76257 0.51738 0.68597 >> A A = 8 1 6 3 5 7 4 9 2 >> max(A,[],1) ans = 8 9 7 >> max(A,[],2) ans = 8 7 9 >> max(A(:)) ans = 9 >> sum(A,1) ans = 15 15 15 >> eye(9) ans = Diagonal Matrix 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1
データをプロットする(Plotting Data)
- plotを使ってグラフを描く
>> t=[0:0.01:0.98]; >> y1 = sin(2*pi*4*t); >> plot(t,y1); >> y2=cos(2*pi*4*t); >> plot(t,y2); >> hold on; >> plot(t,y2,'r'); >> xlabel('time'); >> ylabel('value'); >> legend('sin', 'cos'); >> title('my plot');
- カンマの連鎖で行列をビジュアライズ
>> A = magic(5) A = 17 24 1 8 15 23 5 7 14 16 4 6 13 20 22 10 12 19 21 3 11 18 25 2 9 >> imagesc(A) >> imagesc(A), colorbar, colormap gray;
制御構文: for, while if (Control Statements: for, while, if statement)
- forループ
>> v=zeros(10,1) v = 0 0 0 0 0 0 0 0 0 0 >> for i=1:10, v(i) = 2^i; end; >> v v = 2 4 8 16 32 64 128 256 512 1024 >> indices=1:10; >> indices indices = 1 2 3 4 5 6 7 8 9 10 >> for i=indices, disp(i); end; 1 2 3 4 5 6 7 8 9 10
- whileループ
>> v v = 2 4 8 16 32 64 128 256 512 1024 >> i = 1; >> while i <= 5, v(i) = 100; i = i+1; end; >> v v = 100 100 100 100 100 64 128 256 512 1024 >> i=1; >> while true, v(i) = 999; i = i+1; if i ==6, break; end; end; >> v v = 999 999 999 999 999 64 128 256 512 1024
- if/elseif/else文
>> v(1) ans = 999 >> v(1) = 2; >> if v(1) == 1, disp('The value is one'); elseif v(1) == 2, disp('The value is two'); else disp('The value is not one or two.'); end; The value is two
ベクトル化 (Vectorization)
- Octaveでの仮説関数の計算方法
- \( h_\theta(x) = \sum_{j=0}^n \theta_j x_j = \theta^T \cdot x \)
- これをOctaveのコマンドで書くと
>> theta' * x
- 全ての〜に対して和を求める時?
- \( u(j) = 2v(j) + 5w(j) \text{for all j} \\ u = 2v + 5w \)
- ベクトル化したとたんシグマを使うような行列の和が簡単に求められるようになった…?
Octave/Matlabを使ったクイズ
- 問題の3と4が難しい
- 問題で出てくる行列orベクトルは具体的な数値としては出てこない
- また、すべて答えとして当てはまらない(☑をすべて外す)という解答もないようだ
- 問題3
- 以下の方法でAとxの2つの行列から一つづつ要素を取り出して掛け算したものの合計値を求めた
- これをベクトル化して計算したとき、どういう解き方が出来るか?
v = zeros(10,1); for i = 1:10 for j=1:10 v(i)=v(i) + A(i,j) * x(j); end end
- とりあえず A, xを以下のように置いてみよう
>> A = ones(10,10); >> x = [1;1;1;1;1;1;1;1;1;1]
- A*x = \( \left[ \begin{array}{ccc} 10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\ \end{array} \right] \)
- 行列A×x
- Ax
- これは書けないだろう
- x'*A = \( \left[ \begin{array}{ccc} 10&10&10&10&10&10&10&10&10&10\\ \end{array} \right] \)
- 転置行列x×行列A
- sum(A*x) = 100
- 行列A×xの合計値
よって、ほとんどが当てはまる?
- 問題4
- 以下の方法でvとwの2つの行列(ベクトルかも…)から一つづつ要素を取り出して掛け算したものの合計値を求めた
- これをベクトル化して計算したとき、どういう解き方が出来るか?
v = w = ones(1,7) z = 0; for i = 1:7 z = z + v(i) * w(i) end
- iの全ての要素に対してv×wの演算を行うので、単純にv*wで行けそうなのだが
- octave上でベクトルの掛け算は v.*w(ドットがいる)
- v*wはベクトルの内積になる Octave の使い方その1 、これもうわかんねえな
- sum(v.*w)
- ベクトルvとwをそのまま掛け算して合算
- w'*v
- 転置行列w×行列v、たぶん今回は転置は関係ない
- v*w
- ベクトルvとwをそのまま掛け算
- w*v
- ベクトルwとvをそのまま掛け算
- ベクトルとベクトルの掛け算(ベクトルの内積について)、x,yをn個の数をもつベクトルとしたとき
- \( x \cdot y = x_1 \cdot y_1 + \cdots + x_i \cdot y_i + \cdots + x_n \cdot y_n = \sum_{i=1}^n x_i \cdot y_i \)
- これにより、今回はv*wをi回分行って合計する行為というのがそのままベクトルの内積と同じということがわかる。終わりっ!
- ここが参考になった 2.ベクトルと行列の演算
Octaveを使ったWEBテスト
ポイントのみ述べる
- Octave
- バージョン4.0.1以上を使うこと、4.0.0だとsubmit時にエラーが出る
- Emacs
- Emacs-24からoctave-modeを使う場合、以下のリンクに従う
- H.2 Using Octave Mode
- Emacs 24.5におけるoctave mode