趣味のプログラミングが楽しいです。
これは、どういう事か内容を教えてください。と、AIに解説してもらったり
この内容を実装してみたいです。と、AIにお願いしてみたり
この結果は、こういう理由でこうなっているのではないか?こういう風に実装を変えて試してもらえないでしょうか?と、AIにお願いしたり
個人でアイディアをぶつけて、実験する敷居がものすごく下がりました。
なんなら、AIの方から提案してくれたり、お?それいいね!やってみましょう!と二人三脚で、いろいろ試せる
いい時代になりましたね!
以下、こんなアホな事をやらせてました。
EDLA (Error Diffusion Learning Algorithm) 実装履歴
概要
誤差拡散法(ED法)を用いたニューラルネットワーク学習の実験記録。 バックプロパゲーション(BP)を使わない学習手法の可能性を探った。
時系列実験ログ
Phase 1: ED法の基本理解と初期実装
着想
- Qiitaの記事からED法について学習開始
- 10層の深いネットワークで勾配消失問題が発生することを確認
実装ファイル
ed_entropy.py: Python版EDLA(エントロピーベースのu0調整)ed_mnist.py: MNIST用Python実装ed_network.cpp: C++版(高速化目的)
課題
- 深いネットワークで学習が進まない
- sigmoidの飽和による情報伝達の問題
Phase 2: 論文準拠の正確な実装
着想
- arXiv論文(2504.14814v3)を発見
- 公式GitHub実装と比較して、重要な違いを発見
重要な発見: sign(w) の欠落
// 修正前(誤り)
delta = (target - output) * g_prime;
// 修正後(正しい)
delta = (target - output) * g_prime;
delta *= sign(w); // ← この行が重要!
実装
edla_paper.cpp: 論文準拠の正確な実装
結果
| テスト | 修正前 | 修正後 |
|---|---|---|
| XOR | - | 41エポック |
| Parity | - | 7エポック |
収束安定性が向上。
Phase 3: 活性化関数の比較実験
着想
- 情報伝達問題の原因は活性化関数の飽和
- 様々な活性化関数でg'(a)の健全性を検証
実装オプション(edla_paper.cpp)
--sigmoid : 標準sigmoid
--tanh : tanh(a/5)をスケーリングして[0,1]へ
--wavelet : Mexican Hat Wavelet
--softmax : Softmax出力層
--linear : 線形活性化(実験用)
MNIST結果
| 活性化関数 | Epoch 1 | 最終精度 | 勾配 g'(a) |
|---|---|---|---|
| sigmoid | 87.76% | 94.99% | 0.0217 |
| tanh (スケーリングなし) | 56.87% | ~50% | 0.0058 |
| tanh(a/5) | 95.01% | 97.66% | 0.0504 |
| wavelet | 42.34% | - | - |
| softmax | 88.20% | 88.34% | 0.0315 |
| linear | NaN | NaN | 発散 |
結論
- tanh(a/5) が最良(勾配がsigmoidの2.3倍)
- softmaxはED法のP/N構造と相性が悪い(88%で停滞)
- linearは出力が発散してNaN
Phase 4: Logic Gate Networks論文の調査
着想
- arXiv:2411.04732(NeurIPS 2024)を調査
- 論理ゲートによる超高速推論の可能性を検討
論文の要点
- 16種類の論理ゲートを学習可能に
- Residual Initialization: Identity(素通り)を90%で初期化
- 訓練時は浮動小数点(微分可能)、推論時はバイナリ
- CIFAR-10で86%達成
CIFAR-10比較実験(cifar10_compare.cpp)
| モデル | Epoch 5精度 | 時間 |
|---|---|---|
| EDLA | 17.32% | 1071s |
| Logic Gate (簡易版) | 10.00% | 151s |
考察
- LGNは畳み込み構造が必須(今回は全結合のみ)
- 重要な発見: LGNも訓練時は微分が必要 → 勾配消失問題あり
Phase 5: Residual概念のED法への適用
着想
- LGNのResidual Initializationは「Identity経路で勾配を維持」
- ED法でも同様の効果が得られるのでは?
実装1: Gated EDLA(edla_residual.cpp, edla_residual2.cpp)
// 各ニューロンでα確率でIdentity、(1-α)で通常計算
output = α × prev_layer_mean + (1-α) × tanh_scaled(activation)
結果(3層ネットワーク)
| 手法 | MNIST精度 |
|---|---|
| オリジナル EDLA (tanh/5) | 95.01% |
| Gated EDLA | 86.54% |
→ 浅いネットワークでは効果なし(むしろ悪化)
Phase 6: Identity経路の導入(ユーザー提案)
着想(ユーザー)
「100x100の入力を400x400に拡張し、25%をIdentityに割り当てる」
層のニューロンを「計算ニューロン」と「Identityニューロン」に分離する方式。
実装(edla_identity.cpp)
隠れ層構成:
[計算ニューロン 75%][Identityニューロン 25%]
↑
入力平均をそのまま出力
結果(3層、XORテスト)
| Identity比率 | XOR収束エポック |
|---|---|
| 0% | 2533 |
| 12.5% | 1270 ← 最速 |
| 25% | 1540 |
| 50% | 1549 |
結論
- 12.5%のIdentityが最速収束
- しかしGated方式と大きな差はない
Phase 7: 深いネットワーク(10層)でのIdentity効果検証
着想(ユーザー)
「10層ぐらいないと、Identityを使うメリットが無い気がします」
深いネットワークでこそIdentity経路が有効なはず。
実装(edla_deep.cpp)
- 可変深さのネットワーク
- Identity配置オプション追加
結果(MNIST、10層)
| 方式 | 最高精度 |
|---|---|
| Identity無し | 11.70%(学習崩壊) |
| Identity有り(全層) | 43.00% |
約31%の改善! 深いネットワークでIdentity経路が劇的に有効。
浅い vs 深い比較
| 深さ | Identity無し | Identity有り | 効果 |
|---|---|---|---|
| 3層 | 85.90% | 85.30% | -0.6%(効果なし) |
| 12層 | 11.70% | 43.00% | +31.3% |
Phase 8: Identity配置の最適化
着想(ユーザー)
「9層と10層を繋ぐ箇所では勾配消失しても問題なさそう」 「出力に近い層はIdentity不要では?」
実験: Identity配置の比較
| Identity範囲 | 最高精度 | 解釈 |
|---|---|---|
| 無し | 11.70% | 学習崩壊 |
| 全層(1-10) | 43.00% | 基準 |
| 前半のみ(1-5) | 18.50% | 部分的効果 |
| 後半のみ(6-10) | 11.70% | 効果なし |
追加実験: 最終層を除外
| Identity範囲 | 最高精度 |
|---|---|
| 層1-8 | 30.90% |
| 層1-9 | 73.65% ← 最良! |
| 層1-10(全層) | 43.00% |
重要な発見
- 出力側の層(6-10)にIdentityは効果なし
- 入力側の層(1-5)にこそIdentityが必要
- 最終層を除外した方が性能が向上(73.65% > 43.00%)
- 最終層はIdentityがあると「素通り情報」が出力を汚染
基本アルゴリズム
ED法の特徴
- P/Nニューロン対: 正(Positive)と負(Negative)のニューロンをペアで持つ
- 符号制約付き重み: weights_pp ≥ 0, weights_pn ≤ 0, weights_np ≤ 0, weights_nn ≥ 0
- sign(w)更新: 勾配ではなく重みの符号方向に更新
- 活性化関数: tanh(a/5) をスケーリングして [0,1] に正規化
更新式
d = target - output (誤差)
if d > 0:
Δw_pp = lr * d * g'(a) * x * sign(w_pp)
Δw_np = lr * d * g'(a) * x * sign(w_np)
else:
Δw_nn = lr * |d| * g'(a) * x * sign(w_nn)
Δw_pn = lr * |d| * g'(a) * x * sign(w_pn)
実験1: Identity経路の導入
背景
- Logic Gate Networks (arXiv:2411.04732) の「Residual Initialization」概念を参考
- 深いネットワークで情報が途切れる問題への対策
Identity経路の実装
各層の構成:
75% = Compute neurons (通常のED計算)
25% = Identity neurons (入力平均をそのまま通す)
結果
| 設定 | 精度 | 備考 |
|---|---|---|
| Identity無し(10層) | 11.70% | 学習崩壊 |
| Identity全層 | 43.00% | 改善あり |
| Identity層1-9 | 79.90% | 最良 |
| Identity層1-5のみ | 18.50% | 効果不足 |
| Identity層6-10のみ | 11.70% | 効果なし |
結論
- Identity経路は深いネットワークに必須
- 最終層(層10)にはIdentity不要(出力に直接情報が必要)
- 前半〜中盤の層でIdentityが効果的
実験2: ネットワーク幅の検討
比較設定
- 定幅: 128 → 128 → 128 → ... → 128
- 縮小幅: 128 → 96 → 72 → 54 → 41 → 30 → 30 → 30 → 30 → 30
結果
| 構成 | 精度 |
|---|---|
| 定幅(128固定) | 約70% |
| 縮小幅 | 79.90% |
結論
- 幅を徐々に縮小する方が良い
- 後半の層は情報が集約されるため、少ないニューロンで十分
実験3: 学習率と安定性
問題
- lr=1.0: Epoch 3で崩壊(73.65%→30%)
- lr=0.5: Epoch 6で崩壊
解決策: 学習率減衰
lr = max(0.05, 0.3 * 0.95^(epoch-1))
結果
| 設定 | 最高精度 | 安定性 |
|---|---|---|
| lr=1.0 固定 | 73.65% | ❌ Epoch 3で崩壊 |
| lr=0.5→decay | 74.35% | ❌ Epoch 6で崩壊 |
| lr=0.3→decay(0.95) | 79.90% | ✅ 安定 |
学習曲線(lr=0.3, decay=0.95)
Epoch 1: 48.90%
Epoch 5: 72.30%
Epoch 10: 78.20%
Epoch 15: 79.90% ← ピーク
Epoch 17: 79.35%
Epoch 18: 78.85% ← プラトー開始
実験4: ED + BP ハイブリッド
アイデア
- 前半8層: ED法で学習(粗い特徴抽出)
- 後半2層: BP法で学習(精密な分類)
実装
edla_hybrid.cppを作成- ED層とBP層を直列接続
結果
- うまく機能しなかった
原因分析
重みの構造が異なる
- ED法: 4つの符号制約付き重み行列(pp, pn, np, nn)
- BP法: 1つの制約なし重み行列
出力の意味が異なる
- ED層: 正負を分離した表現
- BP層: 通常の実数値特徴を期待
更新方向が競合
- ED法: sign(w)方向に押す
- BP法: 勾配方向に引く
- 互いに干渉する可能性
結論
ED法とBP法のパラメータは「意味が違いすぎる」ため、 同一ネットワーク内での直接結合は困難(「油と水」)
他手法との比較
MNIST精度ランキング
| 手法 | 精度 | 備考 |
|---|---|---|
| SOTA (CNN + Ensemble) | 99.87% | 最先端 |
| CNN (LeNet-5) | 99.0% | 古典的 |
| Forward-Forward | ~98.5% | BP不使用 |
| MLP (BP) | 98.4% | 3層1000ニューロン |
| SVM | 98.6% | 非NN |
| ED法(本実験) | 79.90% | - |
| ランダム | 10% | ベースライン |
位置づけ
- ED法は精度では他手法に遠く及ばない(約20%の差)
- しかし、計算の単純さ・メモリ効率では優位性あり
学習率微調整の見込み
予測
| 改善項目 | 見込み精度 |
|---|---|
| 学習率微調整のみ | 80.5% ~ 82.0% (+0.6~2.1%) |
| +データ増加(60k) | 82% ~ 85% |
| +ネットワーク拡大 | 84% ~ 87% |
| 全部合わせて | 85% ~ 88% |
試すべきパラメータ
- 初期学習率: 0.25, 0.35
- 減衰率: 0.93, 0.97
- 最小学習率: 0.08, 0.10
- ウォームアップ: 3エポック
実装ファイル一覧
| ファイル | 用途 | Phase |
|---|---|---|
ed_entropy.py |
Python版EDLA(エントロピー調整) | 1 |
ed_mnist.py |
MNIST用Python実装 | 1 |
ed_network.cpp |
C++版基本実装 | 1 |
edla_paper.cpp |
論文準拠実装(複数活性化関数対応) | 2, 3 |
edla_residual.cpp |
Gated EDLA実験 | 5 |
edla_residual2.cpp |
Gated EDLA改良版 | 5 |
edla_identity.cpp |
Identity経路導入版 | 6 |
edla_deep.cpp |
深層ネットワーク + Identity配置実験 | 7, 8 |
cifar10_compare.cpp |
CIFAR-10比較実験(EDLA vs LGN) | 4 |
edla_hybrid.cpp |
ED+BPハイブリッド(失敗) | - |
今後の方向性
ED法を続ける場合
- データ量増加: 10,000 → 60,000枚
- ネットワーク幅拡大: 1.5倍(192→144→108→...)
- 学習率スケジュール: Cosine Annealing, Cyclic LR
別アプローチ
- 蒸留方式: ED出力を教師としてBPネットを別に学習
- アンサンブル: ED分類器とBP分類器を投票で統合
- 別タスク: 異常検知、強化学習など精度が絶対でない領域
主な知見
時系列で得られた知見
sign(w)の重要性(Phase 2)
- 公式実装に
delta *= sign(w)がある - これなしでは収束が不安定
- 公式実装に
活性化関数の選択(Phase 3)
- tanh(a/5) が最良(勾配2.3倍)
- softmaxはP/N構造と相性悪い
深いネットワークとIdentity(Phase 6-8)
- 3層ではIdentity不要
- 10層以上ではIdentity必須
- 最終層はIdentity除外が最適
Identity配置の原則
- 入力側の層(1-5): 必須
- 中間層(6-9): あった方が良い
- 最終層(10): 不要(むしろ有害)
学習率減衰が安定性の鍵
- lr=0.3, decay=0.95 が最適
- 高すぎると崩壊、低すぎると学習しない
ED法とBP法の直接結合は困難
- パラメータの意味が根本的に異なる
- ハイブリッドは別の工夫が必要
ED法の限界と利点
- 精度ではBP系手法に劣る(~20%差)
- 計算効率・メモリ効率では優位
実験環境
- OS: macOS
- コンパイラ: g++ (C++17)
- 最適化: -O3
- データセット: MNIST (10,000訓練 / 2,000テスト)
- 乱数シード: 42
最終更新: 2026年1月4日