ニューラルネットワーク応用。
やっと学習した後、解く。という意味がわかった。
つまり、out値が教師信号と一致していたら、学習したことになる。
ということである。
これを今日理解するまで1年かかった。
やはりSUGSIのシステム上しかたがないことなのかもしれないが、
学習する相手がいないのはつらい。
教えたり教えてもらったりする人が絶対に必要である。
と、昔の指導教官の先生もいってたなぁ。
「だから、京大っていうのは、ドクターからマスターまでいるから、そこで、
教え、教えられる風土があるから強い。」と。

今、ものすごく身にしみて感じている。
おそらく、SUGSIの先生もそれがわかっているので、
SUGSIの掲示板サービスを作ったのだろうが、
http://cai.cs.shinshu-u.ac.jp/cgi-bin/bbs/Yorozu/mqbbs.cgi
いまいち、そういう系には機能していないのが、現実である。

これを、簡単なRSSで配信とかしてくれるだけで相当違うと思うが・・。
また、各教科ごとに一覧で確認できる掲示板がほしい。これはWikiで実装することにしよう。

そういうわけで、超簡単な
http://ipr20.cs.ehime-u.ac.jp/column/neural/chapter4.html
をプログラミングできた。

<?php
//4.2節 誤り訂正学習法の学習例
//http://ipr20.cs.ehime-u.ac.jp/column/neural/chapter4.html

$isContinueRoutine = 1;

	$w = array(0,0,0);	//荷重
	$x = array(1,-500,-500);//入力信号 (x0は、常に1)
	$y = array(0,1,1,1);		//教師信号 これになったらOK
	$iLearnNum = 0; //学習回数.

while ( $isContinueRoutine != 0 ) {
	$iLearnNum++;
	$isContinueRoutine = 0;

	$net = 0;	//net値を一応初期化する.
	//入力パターンは4つある.
	$isContinueRoutine = 0;
	$x[0]=1;$x[1]=0;$x[2]=0;
	$isContinueRoutine += trial($w, $x, $y[0]);
	$x[0]=1;$x[1]=0;$x[2]=1;
	$isContinueRoutine += trial($w, $x, $y[1]);
	$x[0]=1;$x[1]=1;$x[2]=0;
	$isContinueRoutine += trial($w, $x, $y[2]);
	$x[0]=1;$x[1]=1;$x[2]=1;
	$isContinueRoutine += trial($w, $x, $y[3]);
	
	print "isContinueRoutine is ". $isContinueRoutine."\n";
}

print "$iLearnNum 回の学習で終了しました.\n";
print "実際に確かめてみましょう.\n";
$x[0]=1;$x[1]=0;$x[2]=0;
print "■x=($x[0],$x[1],$x[2])=\t".f(getNET($w,$x))."\n";
$x[0]=1;$x[1]=0;$x[2]=1;
print "■x=($x[0],$x[1],$x[2])=\t".f(getNET($w,$x))."\n";
$x[0]=1;$x[1]=1;$x[2]=0;
print "■x=($x[0],$x[1],$x[2])=\t".f(getNET($w,$x))."\n";
$x[0]=1;$x[1]=1;$x[2]=1;
print "■x=($x[0],$x[1],$x[2])=\t".f(getNET($w,$x))."\n";


//重みの変更の確認まで.
function trial(&$w, $x, $y){
	$isChangeWeight = 0;
	print "----------x[0]=$x[0] x[1]=$x[1] x[2]=$x[2]----------\n";
	$net = getNET($w, $x);
	print "net = $net\n";
	$out = f($net);
	$val = $out-$y;
	print "out-y = ".$out."-".$y."=[$val]\n";
	print "old w = ($w[0],$w[1],$w[2])\n";
	if ( $val > 0 ) {
		print "重みの変更あり.減らす方向で。\n";
		$isChangeWeight = 1;
		$w = reChangeWeight(-1, $w, $x);
	} else if ( $val < 0 ) {
		print "重みの変更あり.増やす方向で。\n";
		$isChangeWeight = 1;
		$w = reChangeWeight(1, $w, $x);
	} else {
		print "重みの変更なし\n";
	}
	print "new w = ($w[0],$w[1],$w[2])\n";
	return $isChangeWeight;
}


//				}
/** 重みの変更をする.
 * @param plusminus 増やす方向か、減らす方向か.
 */
function reChangeWeight($plusminus, $w, $x) {
	for ( $iCounter = 0; $iCounter < count($w); $iCounter++ ) {
		$w[$iCounter] = $w[$iCounter]+$plusminus*$x[$iCounter];
	}
	return $w;
}
/** net値を求める. 
 * net値は、 w1*x1+w2+x2である.
 * @param w 重み
 * @param x 入力
 * @return iRet net値.
 */
function getNET ($w, $x) {
	$dwRet = 0.0;
	for ($i = 0; $i <= count($w); $i++) {
		$dwRet += $w[$i]*$x[$i];
	}
	return $dwRet;
}

/** net値をもとに、f関数にかけてoutを求める.
 * @param $net net値
 * @return iRet out値
 */
function f($net) {

	$iRet = -100;
	if ( $net >= 0 ) {
		$iRet = 1;
	} else {
		$iRet = 0;
	}
	return $iRet;
}

?>