方針(ユーザー、2026-08-26)「op の GPU 化は E2E の本丸。他プロジェクトの土台としても効く」。 計画的・セッション横断で進めるための正本。GPU 実行 = loco venv(torch cu128 / RTX 5090)。 詳細所見 = docs/HIGHSPEED_VISION.md「op の GPU 化 = E2E の本丸」/ docs/GPU_OPTIMIZATION_PATTERNS.md。
shapematch_gpu.py。accel.run_pipeline: 転送1回で op 連鎖。5-op で per-op 比 4.9x、
CPU 比 12.6x。run_batch 逐次適用とビット一致。accel_bridge.py 完了: 進化 champion(genome/pipeline)を GPU 常駐区間
(accel 対応)+ CPU 区間(未対応)へ自動分割して実行。連続 accel op は 1 転送に償却。
honest metric 検証: GPU ルーティングは denoise champion の PSNR を ±0.01 dB で保存
(holdout −0.006 / locked −0.011 dB)。pixel は median 端差 → 後段 sk_tv(全域 TV)伝播で
~0.06 ずれるが、タスク指標は不変 = GPU 化は champion を壊さない。tests/test_accel_bridge.py。現状 champion 実 op のうち GPU 稼働は 4/38 段のみ(threshold×2 / median / percentile)。 残りは全て CPU。ランダムに op を足すのでなく、進化が実際に選ぶ op を頻度順で GPU 化する:
| 未対応 op(群) | 登場 champion | GPU 化の効き | 難度 |
|---|---|---|---|
| vol_count 5/5・vol_denoise 4/4(100% GPU、~64x) | 済 | 済(accel_vol.py) |
|
| edge, locate, locate_rot | 済(bit-exact) | 済(accel.py symmetric conv) |
|
| locate, locate_rot(100% GPU、4-6x) | 済(位置 Δ=0) | 済(accel_match.py) |
|
| binarize/count 5/6 GPU(3-5x、Δ=0) | 済(bit-exact) | 済(accel.py conv2d 二値) |
|
| backend 固有 sk_tv/cv_sharpen/simulate_defocus/xsitk_/xcv_/sk_scharr/gdilate | 各 1 | 低 | 高 |
| projective_trans_region(幾何) | binarize, count | 5/6→6/6 の最後の 1 | wave2(order3 spline でブロック中) |
| decode_barcode / xcv2_lap_var / xsitk_closing_by_recon | 各 1(barcode/classify) | 低(feature 終端) | 中〜高 |
教訓(honest): 「champion 頻度」≠「E2E レバレッジ」。pipeline を丸ごと GPU にできる塊(volume / locate / binarize-count 一族)が高レバレッジ。illuminate は edge では CPU op 島で低レバレッジだった。高レバレッジな塊はほぼ回収済。残りは (a) projective_trans_region(幾何=wave2 の order3 spline を解けば binarize/count が 6/6)、(b) backend 固有 op(各 1 champion=低レバレッジ・高難度)、(c) fullseye API device 引数(公開層で GPU 経路を通す=横展開)。次の実質前進は (c) or (a)。
_sep_conv/_conv/_unfold_reflect/
_std_filter が torch reflect(端非複製)のままで、symmetric 修正が gaussian 系に
しか当たっていなかった → 全て _pad_sym 化。sobel/laplace/prewitt/unsharp/median/
percentile/std が full-image 一致になり、diff_of_gauss の「faithful 不可」判定は
誤りだったと確定(真因は _norm でなく _sep_conv の padding。sym 化で full 1e-5 級)。PARITY_AB 5 点
スイープ + カーネル半径連動マージン(a>=0.75 の k=9 の穴を塞いだ)。同日の敵対的検証(3 視点並列)が Batch 0〜3 に残る欠陥を発見 → 全て修正済み:
_norm_b/_signed01_b が clamp_min で必ず除算し、平坦画像の
f32 丸め残差(~3e-8)をフルスケール 1.0 に増幅 → sobel/canny/dog/std 等 13 op が
定数入力で全面破綻(canny は全面前景化して後段 region 区間ごと破壊)。
→ core と同じ素通し分岐 + 閾値を f32 雑音床より上の 1e-6 へ。grad_dir は
勾配 <1e-6 を core の atan2(0,0)=0.5 に合わせる。std は分散の桁落ち床
(実測 2.4e-7)未満を 0 に_fp は skimage 不在時に disk→cross へ暗黙フォールバックする
ため、素の install では core 自体が別物になる(accel 側の検出は将来課題)backends_kornia.py(torch GPU)を device=cuda で使う。core と近似一致を確認。accel_bridge.py): champion(genome/pipeline)を
accel.run_pipeline の steps へ写像。accel 未対応 op が混ざる列は CPU 区間として併用、
連続 accel op は 1 転送に償却。metric 保存(±0.01 dB)を検証済。未対応 op 頻度が上の
wave 優先度を出す(report_champions)。bridge は image(accel)/ volume(accel_vol)/
CPU の 3 種区間を自動分割。accel_vol.py、2026-08-26): vol_median/vol_gaussian/vol_erode/
vol_dilate/vol_threshold の 3D 版(conv3d/max_pool3d/reflect)。core と 5/5 faithful
(interior<5e-3、gaussian は端からカーネル半径内側)。vol_count 5/5・vol_denoise 4/4 段が
単一 GPU 常駐区間に。RTX 5090 実測 対 CPU ~64x(32³B32:549→8.5ms / 128³B4:4547→70.7ms)、
常駐は per-op の 2.8x(4段で転送 4→1 償却)。指標保存 = vol_count 完全一致・vol_denoise ±0.15 dB。
tests/test_accel_vol.py(10 tests)。_sym_idx/_pad_sym/_sep_conv_sym(index_select、r>n も可)で symmetric conv を実装し、
大 σ gaussian が全サイズ bit 一致(illuminate=大 σ unsharp は exact、gauss_filter/
vol_gaussian も端まで faithful 化)。illuminate は edge/locate/locate_rot(3 champion)頻出。accel_match.py、2026-08-26): normxcorr2 =
correlate(mean-free T)+ uniform_filter(box)= conv2d/avg で GPU 化(shapematch_gpu と同機構)。
core と score |Δ|~1e-6・argmax 位置は完全一致。bridge に MATCH 終端区間を追加し、
locate/locate_rot が 100% GPU(illuminate+ncc)。RTX 5090 実測 対 CPU 4-6x
(256²B8:38→6.2ms)、タスク指標(位置誤差)は Δ=0 で完全一致。tests/test_accel_match.py(5)。_mean
流用(_mean を symmetric padding に修正=box も bit 一致に)。sk_tv=Chambolle TV を skimage
denoise_tv_chambolle 忠実移植(tau=1/(2ndim)、勾配/発散、E 停止)。★バッチは per-image freeze
(収束画像を凍結、全反復回すと早期停止画像を過剰平滑化する非faithful を回避)→ bit-exact。
→ denoise が median>sk_tv>simulate_defocus>cv_sharpen の 4/4 単一常駐区間、PSNR Δ~0.01 dB。
sk_tv は計算重(~200 反復)= GPU の本領(CPU-torch 比 5.9×)。bench_vs_opencv.py → docs/BENCH_VS_OPENCV.md、2026-08-26):
★honest な結論 = 単発の軽量 2D フィルタは cv2 CPU が速い(GPU は転送律速: 512²×32 で転送
40ms vs gaussian 実計算 0.51ms = 約 79 倍差)。GPU が cv2 に勝つのは 3 条件: (1) NCC マッチング
1.7-1.9×、(2) 多 op 常駐チェーン(3op で交差、20op で 5.1×)、(3) 3D(cv2 に無い→scipy 比
65-71×)。以前の「64x/3-5x」は scipy 比。cv2 は SIMD で極限最適化。imgevolve の常駐設計は (2) を突く
= 進化 champion を丸ごと GPU に載せる時に効く。_to_batch を float32 直積み(float64 中間を除去)。42→40ms(残りは実 PCIe +
from_batch の float64 出力変換)。parity 不変。api.run_pipeline(..., device="cuda") /
api.apply(..., device="cuda") を追加。device!=”cpu” は accel_bridge の GPU 常駐経路(未対応 op
は CPU、torch/GPU 不在は静かに CPU フォールバック)。既定 device=”cpu” は挙動不変(回帰テスト)。
CUDA vs CPU-torch 実結果照合(loco venv): region/volume は bit 一致(0.0)、illuminate/ncc は
float32 epsilon(5.96e-08)、ncc 位置は完全一致 → GPU が正しく計算していることを確認。
tests/test_api_device.py(4)。これで公開層から GPU 経路が通り、他プロジェクトの土台になる。py -3.11 accel.py(CPU parity)+ loco accel.py --device cuda(GPU parity)で faithful 数を確認。bench.py --device cuda で新 op のスループットを記録(honest: CPU 比、負ける op も明記)。