<?php
/****************************/
/* Winner-Take-All Groups */
/* coded by Y.Suganuma */
/****************************/
/**********************/
/* Winnerクラスの定義 */
/**********************/
class Winner {
private $max; // 最大学習回数
private $n; // 訓練例の数
private $o; // 出力セルの数
private $p; // 入力セルの数
private $W_p; // 重み(ポケット)
private $W; // 重み
private $E; // 訓練例
private $C; // 各訓練例に対する正しい出力
private $Ct; // 作業領域
/******************/
/* コンストラクタ */
/******************/
function Winner($max_i, $n_i, $o_i, $p_i)
{
/*
設定
*/
$this->max = $max_i;
$this->n = $n_i;
$this->o = $o_i;
$this->p = $p_i;
mt_srand();
/*
領域の確保
*/
$this->E = array($this->n);
$this->C = array($this->n);
for ($i1 = 0; $i1 < $this->n; $i1++) {
$this->E[$i1] = array($this->p+1);
$this->C[$i1] = array($this->o);
}
$this->W_p = array($this->o);
$this->W = array($this->o);
for ($i1 = 0; $i1 < $this->o; $i1++) {
$this->W_p[$i1] = array($this->p+1);
$this->W[$i1] = array($this->p+1);
}
$this->Ct = array($this->o);
}
/******************************************/
/* 訓練例の分類 */
/* return : 正しく分類した訓練例の数 */
/******************************************/
function Bunrui()
{
$mx = 0;
$mx_v = 0;
$num = 0;
$sw = 0;
for ($i1 = 0; $i1 < $this->n; $i1++) {
$cor = 0;
for ($i2 = 0; $i2 < $this->o; $i2++) {
if ($this->C[$i1][$i2] == 1)
$cor = $i2;
$s = 0;
for ($i3 = 0; $i3 <= $this->p; $i3++)
$s += $this->W[$i2][$i3] * $this->E[$i1][$i3];
if ($i2 == 0) {
$mx = 0;
$mx_v = $s;
}
else {
if ($s > $mx_v) {
$mx = $i2;
$mx_v = $s;
$sw = 0;
}
else {
if ($s == $mx_v)
$sw = 1;
}
}
}
if ($sw == 0 && $cor == $mx)
$num++;
}
return $num;
}
/**************************/
/* 学習データの読み込み */
/* name : ファイル名 */
/**************************/
function Input($name)
{
$st = fopen($name, "rb");
fgets($st);
for ($i1 = 0; $i1 < $this->n; $i1++) {
$this->E[$i1][0] = 1;
$str = trim(fgets($st));
$this->E[$i1][1] = intval(strtok($str, " "));
for ($i2 = 2; $i2 <= $this->p; $i2++)
$this->E[$i1][$i2] = intval(strtok(" "));
for ($i2 = 0; $i2 < $this->o; $i2++)
$this->C[$i1][$i2] = intval(strtok(" "));
}
fclose($st);
}
/*********************************/
/* 学習と結果の出力 */
/* pr : =0 : 画面に出力 */
/* =1 : ファイルに出力 */
/* name : 出力ファイル名 */
/*********************************/
function Learn($pr, $name = "STDOUT")
{
$mx = 0;
$mx_v = 0;
$n_tri = $this->Pocket($num);
if ($pr == 0)
$out = STDOUT;
else
$out = fopen($name, "w");
fwrite($out, "重み\n");
for ($i1 = 0; $i1 < $this->o; $i1++) {
$str = "";
for ($i2 = 0; $i2 <= $this->p; $i2++)
$str = $str." ".$this->W_p[$i1][$i2];
fwrite($out, $str."\n");
}
fwrite($out, "分類結果\n");
for ($i1 = 0; $i1 < $this->n; $i1++) {
$sw = 0;
for ($i2 = 0; $i2 < $this->o; $i2++) {
$s = 0;
for ($i3 = 0; $i3 <= $this->p; $i3++)
$s += $this->W_p[$i2][$i3] * $this->E[$i1][$i3];
if ($i2 == 0) {
$mx_v = $s;
$mx = 0;
}
else {
if ($s > $mx_v) {
$sw = 0;
$mx_v = $s;
$mx = $i2;
}
else {
if ($s == $mx_v)
$sw = 1;
}
}
}
$str = "";
for ($i2 = 1; $i2 <= $this->p; $i2++)
$str = $str." ".$this->E[$i1][$i2];
$str = $str." Cor ";
for ($i2 = 0; $i2 < $this->o; $i2++)
$str = $str." ".$this->C[$i1][$i2];
if ($sw > 0)
$mx = -1;
$str = $str." Res ".($mx+1);
fwrite($out, $str."\n");
}
if ($this->n == $num)
printf(" !!すべてを分類(試行回数:%ld)\n", $n_tri);
else
printf(" !!%ld 個を分類\n", $num);
}
/********************************************/
/* Pocket Algorith with Ratcet */
/* num_p : 正しく分類した訓練例の数 */
/* return : =0 : 最大学習回数 */
/* >0 : すべてを分類(回数) */
/********************************************/
function Pocket(&$num_p)
{
/*
初期設定
*/
$count = 0;
$mx = 0;
$run = 0;
$run_p = 0;
$sw = -1;
$num_p = 0;
for ($i1 = 0; $i1 < $this->o; $i1++) {
for ($i2 = 0; $i2 <= $this->p; $i2++)
$this->W[$i1][$i2] = 0;
}
/*
実行
*/
while ($sw < 0) {
// 終了チェック
$count++;;
if ($count > $this->max)
$sw = 0;
else {
// 訓練例の選択
$k = intval(mt_rand() / mt_getrandmax() * $this->n);
if ($k >= $this->n)
$k = $this->n - 1;
// 出力の計算
$sw1 = 0;
$cor = -1;
for ($i1 = 0; $i1 < $this->o; $i1++) {
if ($this->C[$k][$i1] == 1)
$cor = $i1;
$s = 0;
for ($i2 = 0; $i2 <= $this->p; $i2++)
$s += $this->W[$i1][$i2] * $this->E[$k][$i2];
$this->Ct[$i1] = $s;
if ($i1 == 0)
$mx = 0;
else {
if ($s > $this->Ct[$mx]) {
$mx = $i1;
$sw1 = 0;
}
else {
if ($s == $this->Ct[$mx]) {
$sw1 = 1;
if ($cor >= 0 && $mx == $cor)
$mx = $i1;
}
}
}
}
// 正しい分類
if ($sw1 == 0 && $cor == $mx) {
$run++;
if ($run > $run_p) {
$num = $this->Bunrui();
if ($num > $num_p) {
$num_p = $num;
$run_p = $run;
for ($i1 = 0; $i1 < $this->o; $i1++) {
for ($i2 = 0; $i2 <= $this->p; $i2++)
$this->W_p[$i1][$i2] = $this->W[$i1][$i2];
}
if ($num == $this->n)
$sw = $count;
}
}
}
// 誤った分類
else {
$run = 0;
for ($i1 = 0; $i1 <= $this->p; $i1++) {
$this->W[$cor][$i1] += $this->E[$k][$i1];
$this->W[$mx][$i1] -= $this->E[$k][$i1];
}
}
}
}
return $sw;
}
}
/****************/
/* main program */
/****************/
if (count($argv) > 1) {
// 基本データの入力
$st = fopen($argv[1], "rb");
fscanf($st, "%*s %ld %*s %ld %*s %ld %*s %ld",$max, $p, $o, $n);
fscanf($st, "%*s %s", $name);
fclose($st);
// ネットワークの定義と学習データ等の設定
$net = new Winner($max, $n, $o, $p);
$net->Input($name);
// 学習と結果の出力
if (count($argv) == 2)
$net->Learn(0);
else
$net->Learn(1, $argv[2]);
}
else
exit("***error 入力データファイル名を指定して下さい\n");
/*
------------------------入力ファイル--------------
最大試行回数 100 入力セルの数 2 出力セルの数 2 訓練例の数 4
入力データファイル or.dat
------------------------or.dat--------------------
OR演算の訓練例.最後の2つのデータが目標出力値
-1 -1 -1 1
-1 1 1 -1
1 -1 1 -1
1 1 1 -1
*/
?>