2026.03.09 22:51
一応forward側は動いている・・・かな?
・で、プーリング層のバックプロパゲーション部分も書く。こちらはさほどややこしくはない。入力されたものをnp.repeatして引き伸ばしてフォワードのときに作ったマスクパターンと掛け算すれば良い。
・とりあえずテストしようということで、簡単な8x8の縦横パターンを作ってやってみたら変なところでエラー。
・なんかエラーメッセージがよくわからないので、一旦コメントアウトし削ったものを復活させながらチェックしたら、思わぬところで変なミスをしていた。
・というところで気を取り直して改めてテストパターンを入れてテスト。なんとなくそれっぽくなってきたけど、さすがに元画像が8x8だとプーリングしてしまうと小さくなりすぎる。
・仕方ないので、np.repeatして拡張してから実行。ついでなのでnp.padでパディングして畳み込みした後に小さくならないように拡張しておく。
・さて、なんとなくそれっぽい結果にもなったことだし。明日は2層にしてみるか。
2026.03.08 22:09
プーリング処理を書いてみる
・昨日、「ただ、全部ゼロだったらまずいので、そこは避けないとだめだな。
」なんて書いたけど、そもそも「最大値の位置が1」という条件なんだから、全部0ということはありえない。ということに、寝入りばなに気がついた。なんだかボケてるな。
・ということで、プーリング処理をコーディング。
2026.03.07 23:30
プーリング層のコーディング方針を整理
・プーリング層を考えることに。こちらのフォワード側は要するに2x2なり3x3といった領域に分割して、その領域を代表する値を作る。
・最もよく使われるのは最大値をとるMaxプーリングと呼ばれる手法らしい。
・たとえば2x2の領域ごとに分割してMaxプーリングするとき、入力が
1 2 3 4
4 8 6 7
7 3 9 2
4 8 3 7
という具合になっていれば出力は
8 7
8 9
となる。これはnp.maxを使うと割と簡単に抽出できる。
・入力は畳み込み層の出力なので、構造は[バッチサイズ,フィルタ数、 Xサイズ、Yサイズ]な4次元配列なので、ここからプーリングサイズ分切り出して
xmax=np.max(x,axis=(2,3),keepdims=True)
して4次元配列まま最大値位置を取り出す。
・で、バックプロパゲーションのためには最大値がどの場所だったのかも記録しないといけない。こちらは
mask=np.where(x==xmax,1,0)
で一発でいける。めったに無いけど、運悪く全く同じ値になる場所が複数あったときには責任を分け合ったほうが良いのだろうか。もしやるなら、
mask=np.where(x==xmax,1,0)/np.sum(xmax,axis=(2,3),keepdims=True)
で良さそうだ。
・ただ、全部ゼロだったらまずいので、そこは避けないとだめだな。
・あとはバックプロパゲーションするときには戻ってきた行列(仮にerr_inとする)との乗算、つまり
err_in*mask
をしてやれば、NumPyが勝手にブロードキャストしてくれるので、該当箇所だけ値が戻る形にしてくれる。
・…というのが、どうやらプーリング層の実装になるらしい。明日暇があったらコーディングして完成させよう。
・しかし、CNNってやたらと時間かかりそうだな。やはりもっとC/C++なりで作成された高水準ライブラリを使わないと駄目かもしれないな。
・とりあえず実際にMNIST認識をやらせてみてからPyTorchを使う方向も考えよう。
2026.03.06 23:46
バックプロパゲーションもなんとか書けた
・Chromeに脆弱性があったとかでアップデート
・いつものことながら自動ではうまくアップデートしてくれないので、.debパッケージをダウンロードしてsudo apt installでインストール。最後になんかエラーっぽいメッセージは出たけど、Chrome再起動したら「バージョン 145.0.7632.159(公式ビルド) (64 ビット)」となっていたので、たぶん良いのだろう。
・ということで、CNNの続きでバックプロパゲーションを書く。
・行数にすればわずか数行の演算なのだけど、やりたいことをどう書いたら良いのかという感じ。ウェイトやバイアスはまだ良いけど、入力に戻す誤差成分を算出するのはちょっと面倒だった。
・行列の形でいうと、バックプロパゲーションのときに後段から戻ってくる誤差データは[バッチサイズ、出力チャンネル数(フィルタ数)、Yサイズ、Xサイズ]な4次元配列データ。バッチサイズというのは、一度に複数の画像データをまとめて処理するときの画像の枚数。フィルタはたとえば3x3といった小さい領域に対する重みデータで、これが元画像から切り出した同じサイズ(3x3)のデータと積和演算されているわけだ。
・元画像側がカラー画像だと1つの画像がRGBの3枚で形成されている。これが入力チャンネル。
・で、ごちゃごちゃしたけど、1つのニューロンは
・入力:9つ(3x3)の画素データがチャンネル数分
フィルタ(3x3の重みデータ)がチャンネル数分
バイアス値がチャンネル数分
・出力:画素の各位置と対応するフィルタの値を掛けて全部足す、さらにバイアス値も足す
ということをやっていて、これが平面にズラーッと並んだものがあり、更にこれがフィルタ数分あるという感じ。
・重み(フィルタ)
weight[output_ch_num, input_ch_num, fil_xsize, fil_ysize]
・誤差データ
err_in[Bach_Size, output_ch_num, xsize, ysize]
ということで、こいつらの積和ってことなので、まずは掛け算するために次元を揃える。err_in側は1点ずつ(ニューロン1個分ずつ)切り出すので、i,jをy方向、x方向のスキャンとして、
weight_reshape = weight.reshape(1,output_ch_num, input_ch_num, fil_xsize, fil_ysize)
err_reshape = err_in[:,:,i:i+1,j:j+1].reshape(batch_size,output_ch_num,1,1,1)
で、あとは出力チャンネル数方向で積和をとってやる(複数のフィルタをかけたものを通したものからそれぞれ入力に誤差分が戻って合流する感じ)
np.sum(weight_reshape*err_reshape, axis=1)
入力データは[batch_size, input_ch_num, input_xsize, input_ysize]みたいな感じで4次元。ここからフィルタサイズ分切り出したところに足せば良いんだから、
d_input[:,:,i:i+fil_xsize, j:j+fil_ysize] = np.sum(weight_reshape*err_reshape, axis=1)
何ていう感じ。わずか数行だけど、ここにたどり着くのは少々しんどかったよと。
・他の部分もまとめてなんとかバックプロパゲーションは書けた(と思う)
・一応Gemini君は「完璧」と言ってくれたけど、本当にちゃんと動くのかな?
2026.03.05 18:13
CNNのバックプロパゲーションが見えてきた&全結合の修正で認識率96%
・というところで、バックプロパゲーションを・・・と思って書き出そうとしたらいきなりVSCode君がコードを吐き出してくれた。たぶんCoPilotが生成したんだろう。
・なんとなく面白いけどねと思いながら、それを下に置いて1行ずつ自分で改めて書きながら読むということをしていたのだけど、途中でわけがわからなくなってきた。
・ということで、困った時のいつものGCC・・・この手のはGeminiも得意だよねということで質問していたら、なんか話が噛み合わない。
・で、ある程度まとまったコードブロックを提示したら、「それ、変だよ」と指摘してきた。
・いちいち指摘が的確というのか、「なんでこの値を掛けてるんだ?」と疑問に思っていた部分がやはり間違っている。
・「CoPilotが自動生成したんだけどね」といったら「あはは・・そうでしたか」ときて、CoPilotに対してちょっと「あいつのコード生成はね・・・」的な指摘をしてくるのがまた可笑しい。
・というところで、じっと考えて整理できてきた。わかってしまえばそれほど難しくは無いのだけど、バッチサイズ分まとめてたり、フィルタ数分まとめて考えていたりというのを一度に考えると頭の中で行列がごちゃごちゃしてややこしいのだな。
・そんなこんなでやっていたら、全結合の方で軽い勘違いを見つけた。まぁ、2層程度なら問題ないんだけど、バックプロパゲーションで前段に戻すときにもLR(Learning Rate)を掛け算してしまっていたという凡ミス。
・これを修正してLRを更に小さくして(でないと、途中でオーバーフローしやすい)再度全結合でMNISTしてみたら正答率96%となった。うん、標準的な値とされる範囲になったな。
2026.03.04 17:46
とりあえず順方向は良いかな
・ぼちぼちとpythonで書く。四次元配列に混乱しそうになりながらとりあえずCNNクラスの__init__()と順方向はできたかな?
・バックプロパゲーションがちょっと難しい。というのか、4次元の配列を眺めているとどうも頭が混乱しそうになる。
・もう一回ちょっと整理しよう
2026.03.03 23:41
CNNの仕組みがだいぶ見えた・・・かな
・さて、GCC(Gemini/Chatwork/Copilot)君に書かせたコードを眺めていると、フィルタの枚数やX,Yのサイズなどの他にChannelというパラメータがある。何だこれ?ということでお尋ねしたら例えばカラー画像データのRGBのようなものとのこと。なるほどね。
・たとえばRGBであればそれぞれについてフィルタをかけてやって、RGBの三枚分のデータを全部足し算するという流れらしい。
・PyTorchなどのライブラリを使えば楽できるらしいけど、今回はNumPyだけでやるので地道にループさせる。
・で、もう一つ。出力側にもやはりチャンネルがある。画素ごとの重みをつけるフィルタの構造は
filter[出力チャンネル数、入力チャンネル数、Yサイズ、Xサイズ]
という4次元配列になる。たとえば、入力がRGBの3チャンネルあって、フィルタのサイズが5x5ならば
filter[出力チャンネル数,3,5,5]
つまり、入力チャンネル数×出力チャンネル数分のフィルタがあるということ。これはつまり、入力画像の1つのチャンネルの一つずつ(たとえばRGBならばRの画像など)についてN個のチャンネル(つまりN個のフィルタ)があるという具合。
・要するに演算の考えとしては1つのニューロンが元画像の3x3なり5x5なりといった狭い領域について全結合ニューラルネットと同じような積和演算をしていて、これがズラッと並んでいる(元画像の1ドットずつシフトしながら)。
・外から見るとちょうど元画像を底面としたピラミッドがたくさん重なり合いながら並んでいる感じで、これが入力チャンネル数×出力チャンネル数個あるわけだ。
・全結合のように、このニューロンすべてが独立したウェイトとバイアスをもたせるという手もあるけど、そこを節約して同じ出力チャンネルに属するニューロンのウェイトやバイアスは共通で使うことにした。それをフィルタと称している・・・とまぁそんな感じで解釈できるのだろう。
そんなことをすると要求されるメモリ量が膨大なものになってしまう。そこで同じチャンネルのニューロン(要するに一つのピラミッド群)
のウェイトやバイアスは同じものを使うことにしていると思えば良いのだろう。
・
3x3とか5x5とかのパターンを使いまわしているという点
全結合ニューラルネットの1層目なんかと同じようなものと思えば良いのかな?と
イメージ的には全結合のときに同じ入力に対してズラッとニューロンが並ぶようなのと似ていて、同じフィルタをかけたものを
・
2026.03.02 08:33
Claudeか。生成AIの名前はCがお好き?
・米国国防省がらみで花札君がお怒りになったとかいう
Claude(日本語版はこちら)をちょっとお試し。
・アカウントを作らなくても、このAIチャットのところで遊べるのでちょっと試してみたけど、なんとなくしっくりこない。Geminiのおべんちゃら(死語?)にもいささか参るけど、こちらの回答の雰囲気もなんとなく。
・ちょっとしたプログラムを作らせてみたらまぁ普通に生成してくれたし、読みやすくなってはいるけれど、もう少しちゃんとコメント入れてほしいかなという感じ。
・これもお仲間に入れるとGCCCか。生成AIの名称は’C’がお好き?
2026.03.01 07:37
CNNのためのテストパターンを作っておこう
・さて、CNNの仕組みとしてはほぼ正解だった(らしい)ので、現状の全結合ニューラルネットの前処理的に畳み込み層とプーリング層を追加することに。
・いきなりMNISTで試すとわけがわからなくなりそうなので、単純なものでフィルタがどう形成されるのかわかるように8x8の単純なパターンを作成してまずは全結合でテスト。
・最初うっかりして全く同じデータに違う答えを与えたら見事に収束せず。あわてて修正したらすぐ収束して予定通り。
・さて、ぼちぼち書いていこう。
2026.02.28 23:58
CNNってこういう感じで良いのかな?
・CNNのバックプロパゲーションを考える。
・要するにフィルタを移動させて得た画像データを縮小したものに対する補正値が戻ってくるわけだ。
・たとえばフィルタを3x3として、2x2の4ドット分を1ドットに縮小して、このドットのデータが全結合ニューラルネットに入るという構成を考える。
・一応、今の理解では順方向の操作は
1)元画像の4x4の四角い領域を3x3の除き窓で覗く。
2)左上、右上、左下、右下の4箇所の3x3の領域について、それぞれの画素データと、対応する位置のフィルタのデータを掛け算して和を取る。(イメージとしては、照度センサの前にパターンの描かれたシートを貼り付けもので明るさを測っているようもの)
たとえば
フィルタ側を
F0 F1 F2
F3 F4 F5
F6 F7 F8
というデータ、画素側が
G00 G01 G02 G03
G04 G05 G06 G07
G08 G09 G10 G11
G12 G13 G14 G15
として、フィルタが左上なら
F0xG00 F1xG01 F2xG02
F3xG04 F4xG05 F5xG06
F6xG08 F7xG09 F8xG10
となるわけで、これら9つを足したものに更にバイアスを足したものをつくる(仮にSUM00とかする)
3)窓を元画像全体に渡って1ドットずつ(1枠ずつではなく)移動させると
SUM00 SUM01 SUM02 SUM03・・・
SUM10 SUM11 SUM12 SUM13・・・
SUM20 SUM21 SUM22 SUM23・・・
・・・・
となる
4)こうして得られたものをたとえば縦横2ドットずつまとめるなら
SUM00 SUM01 SUM02 SUM03
SUM10 SUM11 SUM12 SUM13
といった4画素分ずつまとめて、たとえばこの中の最大値を採用して4ドットを1ドットにする。これがプーリング層と呼ばれるものの役割ということらしい。
5)全フィルタについて同じようなことをする。ここまでの例なら
元画像の画素数÷4×フィルタの枚数
個のデータ列になる。これを全部まとめて全結合ニューラルネットに食わせる。
という具合。
・さて、このときたとえば、左上の4つをまとめたものに対してバックプロパゲーションで戻ってきた値というのは、SUM00,SUM01,SUM10,SUM11の4つに共通して使われる。
・ただ、「誤差の責任」はプーリングした時に採用したもの・・・たとえばSUM00だけとか、SUM11だけとか・・・にしかないので、バックプロパゲーションで調整するのにつかうのは「採用したもの」だけ
・たとえばSUM00が採用されたものだとすると、これは
F0xG00 F1xG01 F2xG02
F3xG04 F4xG05 F5xG06
F6xG08 F7xG09 F8xG10
の和だったわけで、とすると「誤差の責任の割当」は全結合のバックプロパゲーションと同じ。全結合層から戻された値をVback、学習率をLRとすれば、たとえばF00の補正はF00 ー= Vback*LR*G00てな具合。
・これをプーリング層出力の(元画像画素数÷4)個分処理するとフィルタ1個分が補正される。で、全フィルタ数分やれば全部のフィルタが補正される。以下は繰り返しである。
・ただ、加算されていく数が多いので発散しかねないから、全部足した後でプーリング層出力の数で割って平均を取ると良いんだろうな。
・たぶん、こんな感じで大きく外してはいないと思うのだけど。もう一回本当にそうなのか確認しておこう。
2026.02.27 16:53
CNNを試すか。ちょっと予備学習
・まぁそんなところで、全結合ニューラルネットワークの方はほぼ作り方がわかった(気がする)。活性化関数を色々変わったものに変えたり、ウェイトやバイアスの変化のさせ方を弄ったりしても面白いことが起きるのだろうけど。
・というところで、mnistで遊んでいたためか、GCC(Gemini/Chatwork/Copilot)君からは「CNNやってみない?」というお題がきた。
・全結合だと画像が上下左右に動いたりしたときに全く違うデータとして扱われてしまうので、これをまとめてしまおうという仕掛けがCNNということらしい。
・CNNはConvolutional Neural Networkの頭文字をとったもので一般的には「畳み込みニューラルネットワーク」と訳されているけど、Convolutionalのvolutionって回転を意味してなかったっけ?と辞書を引いたらほら案の定。
・「くるくる撒いた状態、渦巻き、込み入った状態、複雑」っていう感じで、なんとなく糸巻き的なものをイメージするようなネーミングではある。
・やっていることをちょっと検索してみた今現在の理解はこんな感じ
1)に小さい四角い窓(2X2とか3X3とか)を用意して、この中で重み付けをする(フィルタと呼んでいる)。すると、例えば横線と右斜め下がりの線とかの特徴があるとみなせる部分が強く現れる。(真っ白でも反応するけど、まぁそれはそれとして)
2)この窓をスライドさせて新しい行列を作る。
3)そして、このフィルタのパターンを色々用意しておいてそれぞれごとに行列を作る
4)フィルタが画素外に出てしまわないようにすると、その分行列がちいさいなるのでその領域は0などでパディングしておく。
・ここまでが「畳み込み層」とよばれるもので、この後が「プーリング層」とよばれているようだ。
5)こうしてできたものをたとえば縦横1/2に圧縮する。まぁ1/2なら縦横2つの画素の中の最大値をとるという方法が紹介されていたけど、「ぼかしている」という感じでもある。すると、縦横1ドットずれても結果は同じになる。
6)こうして出来上がったもの(縦横1/2の画像データ×フィルタ数)分のデータを全結合ニューラルネットで学習させる。
・そうすると、たとえば、横棒に強く反応した画素の右隣に縦棒に強く反応する画素があったとすればこれはそのあたりの場所で十字とかT型などの交差に反応するようなニューロンが生まれる可能性があるということになるのだろう。
・VOUTIONの字句を活かすなら、製糸工場など糸を紡ぐときのように、「窓」エリアから伸びた細い糸(画素データ)がまとめられていくようなのをイメージすると良いのかなという感じ。
・前処理はたぶんちょっとデータ数も多いけど「難しくはないけど手間はかかる」という類だろう。
・たぶん、フィルタ部分も初期値は適当に決めて学習するに従って最適化していくことになるのだと思うのだけど、この学習のやり方がCNNのツボなんだろうな。
2026.02.26 09:22
全結合2層がmnistで約95%。それなりに認識できた…かな?
・さて、MNISTでいろいろやってみている。先頭の1000個を学習させて同じデータで判定を見るとほぼ100%(正答数が1000個だったり999個だったり)となる。
・ならばということで次の1000個の判定をやらせたら87%程度に落ちてしまった。
・過学習なのかなとパラメータ類をいじってみたり、入力データをシャッフルして順番がバラバラになるようにしてみたけどあまり変わらない。
・ということは学習するパターンが少なすぎるのかなということで、6万個のデータのうち5万個を学習用に使って(1000個ずつ50回に分けて毎回シャッフルしてから学習)これを100回繰り返し学習。その後5000個目からの1000個でテストしたら正答率94.8%と出た。
・まぁ、いまどきmnistでの正答率は99.5%以上が当たり前な世界らしいから誤答率が1桁違うけど、何の工夫もない単純な2層のネットワークでもこのくらいまで追い込めるんだな。
・一般的にはどうなんだろうと思ったけどやった人は少なくてPyTorchを使った例などを見ていても3層にしていて、第1層が画素データ数あることにしているらしい。
・こちらは第1層が128個、出力層が10個ということを考えるとこんなもんか。
2026.02.25 16:24
MNIST面白いな
・ご近所イオンの三井銀行が混んでるなと思ったら今日は25日だったか。
・なんとなく「グノーシア」を見ているけど、なんとなく登場するキャラクタとその色付けだけ決めて、どういう話が作れるかという感じだな。まぁ、Re:ゼロに見られたようなループものの極限というところか。
・というところで、MNISTを扱ってみる
といっても、対して難しいことはなくて、28x28の784バイト分の入力があり、0から9に対応するワンホット出力(正解のところだけ1になる出力)が10個。間は適当で128個の[784,128,10]の2レイヤのニューラルネット。MNISTデータの読み込みはこれまたGCCに尋ねてこんな感じでいけるなというところ
def load_mnist_images(filename):
with open(filename, 'rb') as f:
# 最初の16バイト(ヘッダー情報)を飛ばす
data = np.fromfile(f, dtype=np.uint8, offset=16)
# 28x28の画像に成形し、0.0〜1.0に正規化
return data.reshape(-1, 784) / 255.0
def load_mnist_labels(filename):
with open(filename, 'rb') as f:
# 最初の8バイト(ヘッダー情報)を飛ばす
data = np.fromfile(f, dtype=np.uint8, offset=8)
return data
で、まぁ、こんな感じにすればXに学習データ、Tに答えが入る計算。
X_train = load_mnist_images('../mnist/train-images-idx3-ubyte')
Y_train = load_mnist_labels('../mnist/train-labels-idx1-ubyte')
X_train.reshape(-1,784)
X = np.array(X_train[:1000])
indices = np.array(Y_train[:1000])
size = 10
T = np.eye(size, dtype=int)[indices]
とりあえず6万個は多すぎるので、1000個くらいで試すことにしてどうなるかなとやってみたら、いきなりオーバーフロー連発。ウェイトの初期値にsqrt(2.0/size)を掛けると良いよとか、学習率は0.01くらいにしてみては?というアドバイスをGCCにいただきながらちょこまかと自分なりに調整していったら結構いい感じで収束しはじめた。
だいたい800回くらい回すとほぼ落ちついてきて、学習後の先頭100個の判定結果と教師データ(正解)はこんな感じ
出力結果:
[5 0 4 1 9 2 1 3 1 4 3 5 3 6 1 7 2 8 6 9 4 0 9 1 1 2 4 3 2 7 3 8 6 9 0 5 6 0 7 6 1 8 7 9 3 9 8 5 9 3 3 0 7 4 9 8 0 9 4 1 4 4 5 0 4 5 6 1 0 0 1 7 1 6 3 0 2 1 1 7 9 0 2 6 7 8 3 9 0 4 6 7 4 5 8 0 7 8 3 1]
教師データ:
[5 0 4 1 9 2 1 3 1 4 3 5 3 6 1 7 2 8 6 9 4 0 9 1 1 2 4 3 2 7 3 8 6 9 0 5 6 0 7 6 1 8 7 9 3 9 8 5 9 3 3 0 7 4 9 8 0 9 4 1 4 4 6 0 4 5 6 1 0 0 1 7 1 6 3 0 2 1 1 7 9 0 2 6 7 8 3 9 0 4 6 7 4 6 8 0 7 8 3 1]
・2層にしただけでこんなにうまく行くものなのか。なんだか面白いな。
・もう少しMNISTで遊んでみるか。
2026.02.24 15:40
MNISTの準備
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同士がつながったよう状態になっているので、フィードバックする値は全部のニューロンのフィードバック値を足したものになるはず。ってことは普通に行列演算でいける。