蟲ログ
こっちでもブログ始めました。MT楽しい!!
『蟲ログ』
http://blog.bugcube.com/
カッパノイド Movie
カッパノイド(http://kappanoid.com)のムービーができましたぁ。
カッパノイドは、人間が気兼ねなくコミュニケーションできるロボットです。インターフェースとして人間のそばに居てくれる、そんな役割をしてもらいたいなぁと思っています。
好きな食べ物をあげると喜ぶ。
アタマをたたくと起きます!
ActionScriptのメモ
// これはイケナイ while (var obj:Object=array.pop()) { trace(obj); } // これはイケる for (var i:Number=0; i<10; i++){ trace( i ); }
例によってせっぱ詰まるとブログを更新してみたりしているわけです。
カルピスウォーター効果
カルピスウォーターが発売されたとき、僕は『自分で作ったカルピスのほうが絶対おいしい』と思いました。これ絶対そう思う。
なぜか?きっと、混ざりすぎて、濃さが均一だとおいしくないんじゃないか?濃さにムラがあったほうがおいしいんじゃない?!
これを仮に『カルピスウォーター効果』と名づけますと、他にも以下のようなものが考えられます。
- コンビニで売ってるカクテルより、自分で適当に混ぜたほうがおいしい。
- 牛丼に卵をかけたとき、混ぜすぎるとおいしくない。
- カレーライス混ぜすぎるとおいしくない。(?)
似たような話で、『楽器の音を周波数分解して、再び合成すると味気ない音しか出てこない』というのを聞いたことがあります。
そう思ったことある人いませんか?あるいは、似たような話とかありませんか?
Perlでニューラルネットワーク
今回も大学のレポートネタ。ニューラルネットワークを用いたパターン認識 をPerlに移植してみた。バックプロパゲーション法って、意外とシンプルなやり方なんだなぁ。
動かし方
Perlのソースを保存して起動すると、学習を始めます。しばらくするとプロンプトが出てくるので、
の様に、横7×縦11の■□でできた数字のパターンをコピー&ペースト等で入力してあげると、0〜9のどの数字かを判定してくれます。
□□■■■□□
□■□□□■□
■□□□□□■
■□□□□□■
■□□□□□■
■□□□□□■
■□□□□□■
■□□□□□■
■□□□□□■
□■□□□■□
□□■■■□□
ソースコード
use strict; use warnings; use utf8; use Data::Dumper; $Data::Dumper::Terse = 1; $Data::Dumper::Indent = 1; binmode STDOUT, ":encoding(shiftjis)"; binmode STDIN, ":encoding(shiftjis)"; my $WIDTH = 7; # 入力データの幅 my $HEIGHT = 11; # 入力データの高さ my $INPUT = $WIDTH * $HEIGHT; # 入力層の数(入力データ数) my $HIDDEN = 16; # 隠れ層の数 my $PATTERN = 10; # パターンの種類 my $OUTPUT = $PATTERN; # 出力層の数(出力データ数) my $OUTER_CYCLES = 200; # 外部サイクル(一連のパターンの繰返し学習)の回数 my $INNER_CYCLES = 200; # 内部サイクル(同一パターンの繰返し学習)の回数 my $ALPHA = 1.2; # 学習の加速係数 my $BETA = 1.2; # シグモイド曲線の傾斜 my @sample_in = 1 .. $INPUT; # 学習用入力 my @written_in = 1 .. $INPUT; # 認識用手書き入力 my @weight_ih; # 入力層と隠れ層の間の重み係数 INPUTxHIDDEN my @thresh_h = 1 .. $HIDDEN; # 隠れ層の閾値 my @hidden_out = 1 .. $HIDDEN; # 隠れ層の出力 my @weight_ho; # 隠れ層と出力層の間の重み係数 HIDDENxOUTPUT my @thresh_o = 1 .. $OUTPUT; # 出力層の閾値 my @recog_out = 1 .. $OUTPUT; # 認識出力(出力層の出力) my @teach = 1 .. $PATTERN; # 教師信号 # 学習用入力データの基となるパターン my @sample_array = ( [0,0,1,1,1,0,0, # '0' 0,1,0,0,0,1,0, 1,0,0,0,0,0,1, 1,0,0,0,0,0,1, 1,0,0,0,0,0,1, 1,0,0,0,0,0,1, 1,0,0,0,0,0,1, 1,0,0,0,0,0,1, 1,0,0,0,0,0,1, 0,1,0,0,0,1,0, 0,0,1,1,1,0,0], [0,0,0,1,0,0,0, # '1' 0,0,0,1,0,0,0, 0,0,0,1,0,0,0, 0,0,0,1,0,0,0, 0,0,0,1,0,0,0, 0,0,0,1,0,0,0, 0,0,0,1,0,0,0, 0,0,0,1,0,0,0, 0,0,0,1,0,0,0, 0,0,0,1,0,0,0, 0,0,0,1,0,0,0], [0,0,1,1,1,0,0, # '2' 0,1,0,0,0,1,0, 1,0,0,0,0,0,1, 0,0,0,0,0,0,1, 0,0,0,0,0,0,1, 0,0,0,0,0,1,0, 0,0,0,0,1,0,0, 0,0,0,1,0,0,0, 0,0,1,0,0,0,0, 0,1,0,0,0,0,0, 1,1,1,1,1,1,1], [0,0,1,1,1,0,0, # '3' 0,1,0,0,0,1,0, 1,0,0,0,0,0,1, 0,0,0,0,0,1,0, 0,0,0,0,1,0,0, 0,0,0,0,0,1,0, 0,0,0,0,0,0,1, 0,0,0,0,0,0,1, 1,0,0,0,0,0,1, 0,1,0,0,0,1,0, 0,0,1,1,1,0,0], [0,0,0,0,1,0,0, # '4' 0,0,0,1,1,0,0, 0,0,1,0,1,0,0, 0,0,1,0,1,0,0, 0,1,0,0,1,0,0, 0,1,0,0,1,0,0, 1,0,0,0,1,0,0, 1,1,1,1,1,1,1, 0,0,0,0,1,0,0, 0,0,0,0,1,0,0, 0,0,0,0,1,0,0], [1,1,1,1,1,1,1, # '5' 1,0,0,0,0,0,0, 1,0,0,0,0,0,0, 1,0,0,0,0,0,0, 1,1,1,1,1,0,0, 0,0,0,0,0,1,0, 0,0,0,0,0,0,1, 0,0,0,0,0,0,1, 0,0,0,0,0,0,1, 1,0,0,0,0,1,0, 0,1,1,1,1,1,0], [0,0,0,0,1,1,0, # '6' 0,0,0,1,0,0,0, 0,0,1,0,0,0,0, 0,1,0,0,0,0,0, 0,1,0,0,0,0,0, 1,0,0,0,0,0,0, 1,0,1,1,1,0,0, 1,1,0,0,0,1,0, 1,0,0,0,0,0,1, 0,1,0,0,0,1,0, 0,0,1,1,1,0,0], [1,1,1,1,1,1,1, # '7' 0,0,0,0,0,0,1, 0,0,0,0,0,0,1, 0,0,0,0,0,1,0, 0,0,0,0,0,1,0, 0,0,0,0,1,0,0, 0,0,0,0,1,0,0, 0,0,0,1,0,0,0, 0,0,0,1,0,0,0, 0,0,1,0,0,0,0, 0,0,1,0,0,0,0], [0,0,1,1,1,0,0, # '8' 0,1,0,0,0,1,0, 1,0,0,0,0,0,1, 1,0,0,0,0,0,1, 0,1,0,0,0,1,0, 0,0,1,1,1,0,0, 0,1,0,0,0,1,0, 1,0,0,0,0,0,1, 1,0,0,0,0,0,1, 1,0,0,0,0,0,1, 0,1,1,1,1,1,0], [0,1,1,1,1,1,0, # '9' 1,0,0,0,0,0,1, 1,0,0,0,0,0,1, 1,0,0,0,0,0,1, 0,1,1,1,1,1,1, 0,0,0,0,0,0,1, 0,0,0,0,0,0,1, 0,0,0,0,0,0,1, 0,0,0,0,0,0,1, 1,0,0,0,0,0,1, 0,1,1,1,1,1,0] ); my @teach_array; # パターンと出力すべき教師信号の比較表 PATTERNxOUTPUT # 教師信号の設定 for (my $q=0; $q<$PATTERN; $q++) { for(my $k=0; $k<$OUTPUT; $k++){ if($q==$k) { $teach_array[$q][$k] = 1; } else { $teach_array[$q][$k] = 0; } } } #------------------------------------------------------------------- #--------------------------- 学習モード ---------------------------- #------------------------------------------------------------------- # 閾値と重みの乱数設定 for (my $j=0; $j<$HIDDEN; $j++) { $thresh_h[$j] = rand() - 0.5; for(my $i=0; $i<$INPUT; $i++) { $weight_ih[$i][$j] = rand() - 0.5; } } for (my $k=0; $k<$OUTPUT; $k++){ $thresh_o[$k] = rand() - 0.5; for (my $j=0; $j<$HIDDEN; $j++) { $weight_ho[$j][$k] = rand() - 0.5; } } #-------------------------- 学習 -------------------------- print "learning...\n"; for (my $p=0; $p<$OUTER_CYCLES; $p++) { # 外部サイクル my $outer_error = 0.0; # 外部二乗誤差のクリヤー for (my $q=0; $q<$PATTERN; $q++) { # パターンの切り替え # パターンに対応した入力と教師信号の設定 @sample_in = @{$sample_array[$q]}; @teach = @{$teach_array[$q]}; for (my $r=0; $r<$INNER_CYCLES; $r++){ # 内部サイクル # 順方向演算 &forwardNeuralNet(\@sample_in, \@recog_out); # 逆方向演算(バックプロパゲーション) &backwardNeuralNet(); } # 内部二乗誤差の計算 my $inner_error = 0.0; # 内部二乗誤差のクリヤー for (my $k=0; $k<$OUTPUT; $k++) { $inner_error += ($teach[$k] - $recog_out[$k]) * ($teach[$k] - $recog_out[$k]); } $outer_error += $inner_error; # 外部二乗誤差への累加算 } # 外部サイクルの回数と外部二乗誤差の表示 print "OuterCycles=$p "; print "TotalSquaredError=$outer_error\n"; } #--------------------- 学習結果の確認 --------------------- print " "; for (my $k=0; $k<$OUTPUT; $k++) { print " [$k]"; } print "\n"; for (my $q=0; $q<$PATTERN; $q++) { # 入力パターンの設定 @sample_in = @{$sample_array[$q]}; # 順方向演算 &forwardNeuralNet(\@sample_in, \@recog_out); # 結果の表示 print "TestPattern[$q]"; for (my $k=0; $k<$OUTPUT; $k++) { if ($recog_out[$k]>0.99) { # 99% より大 print " YES"; } elsif ($recog_out[$k]<0.01) { # 1% より小 print " NO "; } else{ # 1% 以上 99% 以下 print " ? "; } } print "\n"; } # 解析待ち my %read = ( "■" => "1", "□" => "0", ); @written_in = (); my $count = 1; print "bp[".sprintf("%02d", $count)."]>"; while (my $line = <STDIN>) { chomp($line); last if $line eq ""; if ($line =~ /[0-9]{1}/) { # 0-9 の数字一つ @written_in = @{$sample_array[$line]}; } elsif ($line =~ /[□■]{7}/) { # □■でデータ入力 my @tmp = split(//, $line); while (my $x = shift(@tmp)) { my $data = $read{$x}; push (@written_in, $data); } $count++; } else { print "error! もう一度入力\n" } if (scalar(@written_in) == $INPUT) { print "\n"; &recognizeCharacter(); $count = 1; @written_in = (); } print "bp[".sprintf("%02d", $count)."]>"; } # 順方向演算のメソッド sub forwardNeuralNet { my ($input, $output) = @_; my @out = 1 .. $OUTPUT; my @hidden = 1 .. $HIDDEN; # 隠れ層出力の計算 for (my $j = 0; $j<$HIDDEN; $j++){ $hidden[$j] = -$thresh_h[$j]; for (my $i=0; $i<$INPUT; $i++) { $hidden[$j] += ${$input}[$i] * $weight_ih[$i][$j]; } $hidden_out[$j] = &sigmoid($hidden[$j]); } # 出力層出力の計算 for (my $k=0; $k<$OUTPUT; $k++){ $out[$k] = -$thresh_o[$k]; for (my $j=0; $j<$HIDDEN; $j++) { $out[$k] += $hidden_out[$j] * $weight_ho[$j][$k]; } $${output}[$k] = &sigmoid($out[$k]); } } # 逆方向演算のメソッド sub backwardNeuralNet { my @output_error = 1 .. $OUTPUT; # 出力層の誤差 my @hidden_error = 1 .. $HIDDEN; # 隠れ層の誤差 my $temp_error; # 出力層の誤差の計算 for (my $k=0; $k<$OUTPUT; $k++) { $output_error[$k] = ($teach[$k] - $recog_out[$k]) * $recog_out[$k] * (1.0 - $recog_out[$k]); } # 隠れ層の誤差の計算 for (my $j=0; $j<$HIDDEN; $j++) { $temp_error = 0.0; for (my $k=0; $k<$OUTPUT; $k++) { $temp_error += $output_error[$k] * $weight_ho[$j][$k]; } $hidden_error[$j] = $hidden_out[$j] * (1.0 - $hidden_out[$j]) * $temp_error; } # 重みの補正 for (my $k=0; $k<$OUTPUT; $k++) { for (my $j=0; $j<$HIDDEN; $j++) { $weight_ho[$j][$k] += $ALPHA * $output_error[$k] * $hidden_out[$j]; } } for (my $j=0; $j<$HIDDEN; $j++) { for (my $i=0; $i<$INPUT; $i++) { $weight_ih[$i][$j] += $ALPHA * $hidden_error[$j] * $sample_in[$i]; } } # 閾値の補正 for (my $k=0; $k<$OUTPUT; $k++) { $thresh_o[$k] -= $ALPHA * $output_error[$k]; } for (my $j=0; $j<$HIDDEN; $j++) { $thresh_h[$j] -= $ALPHA * $hidden_error[$j]; } } # Sigmoid関数を計算するメソッド sub sigmoid { my $x = shift; return 1.0/(1.0 + exp(-$BETA * $x)); } # 入力文字を認識するメソッド sub recognizeCharacter { # 順方向演算 &forwardNeuralNet(\@written_in, \@recog_out); # 結果の表示 for (my $k=0; $k<$OUTPUT; $k++) { print "$k である $recog_out[$k]\n"; } }
CAIWA広場
CAIWA広場 という会話プログラムで遊んでみた。今、人工無脳を作るという仕事をもらっているので、しつこく質問して遊んでみた。気づいた点はこんな感じ。
- 会話シナリオがいくつか用意されている。で、話題を指定される。「趣味とか、血液型について質問してね」とか。
- 特定のキーワードにマッチすると、それに対応したシナリオのモードに入る。
- シナリオのモードに入ると、質問が投げかけられる。その質問に対する回答中のキーワードによって、以下のパターンで反応する。
- こちらの返事を無視して、言いたいこと話す独り言モードに入る。
- キーワードを含むコメントを返す。
- ランダムな応答はあまりない。「つかれたので、ちょっと寝るね」というくらい。
- キーワードを学習したりもしていない。外部のデータで学習もしていないようだ。
デモ用だからかもしれないが、シナリオが少なくてすぐ飽きてしまった。自分の使った言葉を学習してくれると、「おっ」という返事が来ることもあるのだけれど。
あと、サイトを見た第一印象。『あ、なんか中華風デザインだぞ!!』で、会社概要を見たら、やっぱり社長が中国人だった。きっとデザインはオフショアしてるんでしょう。