2026.02.23 06:57

画像認識に発展させてみようか


・さて、せっかく作ったのでもうちょっと遊ぶ。
・簡単な画像認識というのか、手書き文字認識くらいはできるんだろうか。
・今のプログラムではたとえば[4,8,3]というリストを与えればとやれば4入力3出力で入力層が8個、出力層が3個のネットワーク、[4-8-5-3]なら、入力と出力の間にニューロン5個の隠れ層が1層構築されるという具合で結構いろいろな形を作って遊べる。
・ということで、出力をワンホット化して、3x3の画像の分類をさせてみる。まぁ、とりあえず4-8-2で、"|"と"ー"のパターンという単純なもの。正解は"[0,1]"と"[1,0]"でやってみると100回もしないうちに収束。
・それならば・・・とちょっと意地悪して実数の乱数で3x3のパターンを3つ作ってこれを同じように分類。更に6個、12個と作ってこれを3分類させてみたけど、割と良い感じで収束する。
・つまり、これって人間の目にはランダムパターンにしか見えないけど、ニューラルネットは数字として認識できているということだな。なんとなく暗号みたいに使えそうだな。
・超有名なMNISTだと28x28で、784点あるのか。訓練用データ6万個を一気に始末するのはさすがに大変かと思ったけど784×60,000=47,040,000。まぁ44M程度という感じか。1データ4バイト実数にして176Mbytes。メモリ量的には思ったほど大したことないけど、これを行列演算に使うとなったらやはり大変だろうしな。まぁ100個なり1000個なりごとに分割して学習させる感じかな。

2026.02.22 07:51

XOR対応であれこれお試し


・XORは実はそこそこ厳しいものらしいので、しばらくこれで遊んで見ることに。
・LayerStruc=[2,8,4,1]みたいな感じでニューロンのレイヤ構成を自由に作れるように書き換えて、レイヤ構成を変えてみたり、初期値を変えてみたりして試してみている。
・とりあえず2-4-4構成でウェイトを-0.5〜+0.5の一様乱数、バイアスの初期値を0.2程度にして活性化関数をLeaky ReLUにしてみたらこんな感じでサクッと落ち着くことが多くなった。
・一般的には0を中心に正規分布させたほうが良い結果が得られやすいようだけど、XORに関してはそうもいかないのかな?

2026.02.21 13:30

2層でXORができた


・さて、なんとなく1層を任意の入力点数、任意のニューロン数で作ることができるようになったので、2層…2段カスケード接続したらどう?というのをやってみる。
1層目が2入力のニューロン4個、2層目が4入力のニューロン4個。で教師データは同じものを与えて同時に教育してみる。ウエイトやバイアスの初期値は乱数なので、4回分同時にチェックする格好。
で、最終段の偏差の自乗がどうなるのかを見てみたのがこのグラフ。上が1層にしたとき。圧倒的な収束の速さだな。
・調子に乗ってXORをやらせてみたら収束したりしなかったり…さて、何が悪いのかな。

・というところでGCCへのお問い合わせなどもしていろいろいじっていたらXORでも収束するようになってきた。乱数をstandard_normal、つまり0を中心にした正規分布乱数にして、Learning Rateもちょっといじったり。更に1層目のニューロン数を8個に増量。これが一番効いたようだ。XORを教師データとして入力して誤差(前回のは偏差の自乗をグラフにしたけど、これは符号付き)の変化を撮ってみたらこんな感じ。繰り返しやってみるとだいたい500回くらいで収束する。実務的にはこの収束した状態を見て学習済みとして推論用のパラメータにすれば良いんだろうな。
・この学習過程で時々発振というのかリンギングを起こしたような波形が出てくるのが面白いところ。フィードバックがかかっていて、位相が180度反転してループゲインが1未満ならこういう減衰振動になる。
・電子回路ならここでダンピング抵抗を入れたりフェライトビーズを入れたりする感じかな。
・GCCにお尋ねしていたら、AIの世界でもこうした現象を抑制するフィルタみたいな式を入れ込むことが実際に行われることがあるらしい。いろいろつながってるな。

2026.02.20 22:59

ぼちぼちと


・20日ということで、ちょっと現金をおろして記帳。ついでにキャッシュレス関係にチャージもしておく。
・ということで書いたついでにバックプロパゲーションの処理部分を独立させて、多層化しやすそうな構造に書き換えておく。
・なんとなく頭の中もプログラムも整理されてきたな。
・太田光が首相に対して「消費税減税ができなかったらどうするのか」と訪ねたら「意地悪な質問ですね」と答えたとかいうことをラジオで取り上げていた。
・「普通な質問なのに・・」と言ったあとに沖縄の知事が地元の案件について同じような質問を受けたときに「できなければ腹を切る」と言ったとかいうことを持ち上げて「覚悟が聞きたかった]などと言っていた。
・絶対うそだろう。この質問は「言質を取ろう」という悪意ある質問であろう。それは、この質問がどのような答えを期待しているのかを考えればすぐわかることだ。「できないかもしれない]といえば無責任だと非難し、「できなければ辞職だ]と「覚悟」とやらを語れば後日成立が遅れたり先送りになったときに「辞職だと言ったくせに」といって非難する。そのための材料をを得ようとしているのだろうとしか考えようがない。
・「違う。単に覚悟の程を聞きたかっただけだ」というなら「後日これをネタに非難することがないと言い切れるのか。もし非難するような言動をしたらどう責任を取るのか」と尋ねればきっと、「首相という立場とは重さが違う」とか「ジャーナリズムは・・・」とか言って逃げるのだろうな。



2026.02.19 22:27

バックプロパゲーションでフィードバックする値は


・だいぶ形になったので、多層化を考えていくことにする。
・となると、今までニューロンクラスの中でやっていた教師データとの比較は外に出すことになるわけか。
・ところで、今のプログラムだと入力のデータパターンについて同時演算させている。今は2入力ANDを扱っているので、[00][01][10][11]のそれぞれごとに初期値の違うN個のニューロンがどういう値を出力するのかを4行N列の行列で得ているという具合。
・ここからバックプロパゲーションで戻す値はというと、セルごとの入力点数(この場合なら2)にセルの数を掛けた分の入力端子があるようなイメージになって、それをそれぞれのニューロンが持っているバックプロパゲーションでフィードバックする値をウェイト値で按分したもの・・・だから2N行1列の行列を得るのか?いや、でもそれはなんかおかしいのではないか。
・と、考えていてなんのことはないと気付く。それぞれのニューロンの入力端子をA,Bとしたとき、全部のニューロンの入力端子A同士、B同士がつながったよう状態になっているので、フィードバックする値は全部のニューロンのフィードバック値を足したものになるはず。ってことは普通に行列演算でいける。

2026.02.18 19:27

セルを4つにしてみる


・間違っていたところがわかった。うっかりnp.sum()を残していたために2個の入力に同じ値がフィードバックされてしまっていた。
・修正してみたら良い感じ。ついでなので、セルを4つに増やして改めて学習の進み方を見た。4つのセルの学習の進み方を見ると面白いように同じところにおちついていく。
・そういうものかな。

2026.02.17 11:36

ニューロン1個で少し遊ぶ


・とりあえず2入力のニューロン2個を並列配置して行列使って同時進行させてみる。
・要は[[0,0],[0,1],[10],[11]]の二次元行列を入力、[[0,0],[0,0],[0,0],[1,1]]を正解データ(実際には[[0],[0],[0],[1]]をブロードキャストで拡張するけど)として、出力として[[0,0],[0,0],[0,0],[1,1]]が得られるかどうかというところ。
・実際には浮動小数点データで得られるのだけど。なぜイマイチ収束しないんだろうと思いながら、コードの間にprint(f"...")なのを挟んでいく。printf()ではなくprint(fというあたりにちょっと感じるものも。
・見にくいのでnp.where(x>0.5,1,0)を使って1/0に変換したらそれなりになった。なんとなく目がくらんでいただけで、結構それなりだったのか。
・学習の回数と教師データとの誤差をグラフかすることにして、初期値やら学習率(LR)やら活性化関数(Leaky ReLUにしてみたけど)にちょっと細工をしてみたりするといろいろ面白い。
・学習を0.001からドンドン・・と増やしてみたのがこれ。

 で、まぁこれは一例でやるたびにグラフの形状は大きく変わる(初期値を乱数にしているからでもあるけど)けど、大まかにはLRを大きくすると学習は早く進むようだけど、暴れやすくなる。オーバーシュートやアンダーシュート、リンギング波形みたいなものも出てきたりして、なんとなくハード屋さんの世界とも通じるものを感じたり。
・だとすると、バックプロパゲーションにLPFなんか入れて「誤差が大きく変わったら少し抑える」とかすると暴れにくくなるのかな?
・・・・・
・2/18追記:と思ったのだけどプログラムでなんか変なところがあった。リトライだな。


2026.02.16 17:57

行列演算やらnp.sum()やら・・・と


・車があまりにも汚くなってきた。灯油とガソリンの補充をしたとき、洗車機があいていたのと、気温もちょっと高めで寒くなかったので洗車することに。今夜雨か雪という予報もでているけども。
・ここは最初にメニューを選ぶのではなく、最初に支払い方法の選択なんだな。拭き上げ用のタオルの置き場とかも悩んでしまったり。
・というところで、帰ってきてから振り込みもしておく。
・毎度のことながら社会保険料は高いな。まぁ3月に入ったら給与減額して社会保険料もガクッと落とせる予定だけど。
・そんなところで、昨日の続きである。
・普通にスカラーなら、入力X1、X2にウェイトW1,W2を掛けてバイアス値を足すのだから、普通なら(X1*W1+X2*W2+B)というだけで良いのだけど、ここで、配列だからXは[[0,0],[0,1],[1,0],[1,1]]という二次元配列で、ウェイトWは[[W1],[W2]]という二次元風味な2行1列の配列で
np.dot()を使って掛け算してやれば、縦方向に答えが並ぶ。
・というのは数学の行列式ではイメージできるけど、こんなふうにプログラミング言語で[]が並ぶとつい混乱しそうになる。慣れの問題なんだろうけどな。
・こうやって得られたものからバックプロパゲーションをするとき、左から(1,1,1,1)を掛けるのも面倒そうだなと思ってGCCにお尋ねしたら、np.sum()が使えるし、速いよと教えてくれた。
・さて、とりあえず実行してエラーにはならなくなったけどうまく収束しない。たぶんどこかで凡ミスしているのだろうな。



2026.02.15 17:40

2層化は行列演算で考えよう


・とりあえず積和+活性化関数のニューロン1個だけ動いたのだけど、これではORが実現できない。これが1960年代にパーセプトロン・・・1層(入力層と出力層のみ)のニューラルネットだと駄目だということで、第一次のAIブームを終焉に追い込んだという。
・現在から過去に向かって「天の声」を下ろすなら、1個のニューロンでNORは実現できるし、NORを組み合わせればXORは実現できるんだから…ということになるけど、当時はここで行き詰まったらしい。
・ということで、こちらも多層化してXORを解いてみよういうところだけど、その前にまとめて行列演算で片付けることを考えてみる。
・以前はとにかく先に進みたくてニューロンのオブジェクトを一つずつ並べてループで回して処理してみたのだけど、コードがやたらと多くなってうっとおしくて仕方なかった。やはり複数の入力を行列で処理するほうがずっと美的だろう。
・たとえば2入力のセルを2個をまとめたものを1つのオブジェクトにして2つのオブジェクトに4パターン([0,0][0,1][1,0][1,1])を入れた時の答え(合計8個)を一回の行列演算で得てみようということ。数学的な式としては簡単だけど、プログラムはなにせ1次元的な文字列の並びなので書き方にちょっと気を使う。
・もちろん、教師データセットが膨大になるとメモリも食いそうだけど、今はとりあえず2入力でXORが解けるかということだしな。

2026.02.14 23:34

ニューロン1層目


・ニューロンの基本がそれぞれの入力に重みパラメータを書けて足し算し、更にバイアスを足し込んで活性化関数で非線型性を与えるということか。
・GCC(Gemini/ChatGPT/Copilot)はシグモイド関数を使った例を示してきたけど、ReLUが主役じゃないの?ということで書き換えてみる。
・積和部分の出力をzとして出力yは
 y=z if (z>=0) else 0.01*z
 オリジナルのReLUだと負の領域で微分値が0になるけど、ニューロンが死んで出力が0に固着する可能性があるかな?ということで、ちょっとだけ残すようにしてみる。これをLeaky ReLUと呼ぶらしいことをGCCに教えてもらった。
・ちょっと調べるとNumpyにも三項演算子的なものはあって
 y=np.where(z>0,z,0)
とか書けて、こいつは行列でも一発でやってくれるというスグレモノなので、
z=np.array([-2,-1,0,1,2])で
 y=np.where(z>0,z,0)
 なんて書くとyがarray([0,0,1,2])になると知った。
・np.whereは第一引数がarray型なら良いので
 z=[-2,-1,0,1,2]
y=np.where(np.array(z)>0,z,0)
なんてやっても、zをarray型に勝手に変換してくれるのか。なるほど。