Skip to main content

DeviceParamStore

Struct DeviceParamStore 

Source
pub struct DeviceParamStore { /* private fields */ }
Expand description

デバイス常駐パラメータ更新の状態機械本体(モジュール冒頭コメント 参照)。単一デバイス固定(new() 時に tape.ops().device() から 決定し、以後変更不可)。Debug は unwrap_err()(テストコード)が Result<DeviceParamStore, _> を要求するため導出する(フィールドは いずれも Debug 実装済み: Device/DeviceBuffer<f32>(tensor-core 側で導出済み)/ParamLayout/PendingForward〈上記〉/ AtomicBool/DispatchFailureCell)。

poisoned は AtomicBool(Cell<bool> ではない)とする: &self メソッド(sync_to_host/snapshot_resident_params)からも check_not_poisoned が「遅延失敗トークンを検出して自己 poison する」ために書き込みが必要であり、&self からの内部可変性を 要求するため(モジュール冒頭「遅延失敗トークン経由の poison」参照)。

Implementations§

Source§

impl DeviceParamStore

Source

pub fn step_amp( &mut self, tape: &Tape, grads: &Gradients, config: &SgdConfig, scaler: &mut GradScaler, ) -> Result<bool, AutodiffError>

super::DeviceParamStore::step(SGD)の AMP 版。1 step の使い方: scaler.scale_loss(&loss) → tape.backward/DeviceParamStore:: backward → 本メソッド(内部で unscale・非有限検出・ scaler.update まで完結する)。

戻り値 Ok(true) はこの step が非有限勾配により skip された ことを示す(crate::nn::optim::amp::UnscaleResult:: should_skip_step と同じ極性)。skip 時はどのパラメータも 更新されず、forward 登録(pending)のみが消費される(モジュール doc「skip 時の状態遷移契約」参照)。

CUDA/Metal はデバイス側 unscale カーネルを持たないため、 param_grads_to_host によるホスト計算フォールバック(D2H → ホスト unscale → 必要なら H2D)を経由する(実装計画 §4.1 「新規の BackendOps を追加しない理由」)。性能目標は置かない。

§Errors

勾配読み出し・unscale・step() 本体・scaler.update のいずれかが 失敗した場合(AutodiffError::Backend でラップされた fandhe_ai_tensor_core::device::BackendError を含む)。

Source

pub fn step_adam_amp( &mut self, tape: &Tape, grads: &Gradients, config: &AdamConfig, scaler: &mut GradScaler, ) -> Result<bool, AutodiffError>

super::DeviceParamStore::step_adam の AMP 版。意味論・ エラー・戻り値の極性は Self::step_amp と同一([super:: DeviceParamStore::step] を呼ぶか [super::DeviceParamStore:: step_adam] を呼ぶかのみが異なる)。

Source

pub fn step_adamw_amp( &mut self, tape: &Tape, grads: &Gradients, config: &AdamWConfig, scaler: &mut GradScaler, ) -> Result<bool, AutodiffError>

super::DeviceParamStore::step_adamw の AMP 版。意味論・ エラー・戻り値の極性は Self::step_amp と同一。

Source§

impl DeviceParamStore

Source

pub fn train_step_device_chain<'t>( &mut self, tape: &'t Tape, x: &ResidentInput, y: &ResidentInput, steps: &[(&ResidentLeaf<'t>, Option<&ResidentLeaf<'t>>, Activation)], config: &SgdConfig, ) -> Result<TrainStepLoss, BackendError>

forward・MSE(mean)・backward(dW・bias 勾配・ReLU マスク・L2 以降の d_input)・ SGD を encode-only で 1 区間に積み、loss ハンドルを返す。この区間に同期は無い (モジュール doc 参照)。

x・y は Self::upload_resident_input が窓の外で upload したハンドル。 steps は predict_device_chain と同じ (weight, bias, act) の列。

別スレッドの Graph capture と衝突した場合(DeviceContextCaptureInProgress。書き込み前、 または SGD 段の衝突で params は未変更)は、待ち上限(TRAIN_CAPTURE_WAIT_TIMEOUT)の範囲で capture の終了を待って step 全体をやり直す(predict_device_chain と同型。イシュー #3260・ 決定記録 docs/backend-cuda-graph-step-capture-design.md §8.5)。やり直しで部分結果は 漏れない(勾配バッファと loss は次の試行が全要素を上書きする)。capture が 1 つも無ければ このエラーは起きず、ループは 1 回で抜ける。

Source

pub fn validate_train_step_device_chain<'t>( &self, tape: &'t Tape, x: &ResidentInput, y: &ResidentInput, steps: &[(&ResidentLeaf<'t>, Option<&ResidentLeaf<'t>>, Activation)], config: &SgdConfig, ) -> Result<(), BackendError>

Self::train_step_device_chain の事前検証だけを行う(副作用なし。イシュー #3254)。

facade の Sequential::train_step_resident が「モデル構成・損失・最適化が範囲外(型付き エラーで止める)」と「バックエンドが部品を持たない(Tape 経路へ全体フォールバックしてよい)」を 判別するために、チェーンを積む前に呼ぶ。ここを通った後にチェーンが返す Unsupported は 後者(最初の dW の前の失敗は store を変えない。モジュール doc「失敗の境界」)に限られる。 生の &Tape を取るため facade の利用者からは到達できない。

Source

pub fn download_resident_input( &self, tape: &Tape, input: &ResidentInput, ) -> Result<Tensor<f32>, BackendError>

常駐入力をホストへ download する(イシュー #3254。Tape 経路フォールバック専用。D2H が入る ため通常のチェーン経路では呼ばない)。別 store・別デバイスのハンドルは拒否する。

Source

pub fn record_host_train_step_loss( &mut self, tape: &Tape, loss: f32, ) -> Result<TrainStepLoss, BackendError>

Tape 経路へフォールバックした step の loss(ホスト f32)を記録し、新しい世代の ハンドルを返す(イシュー #3254)。世代を進めるため、それ以前のハンドル(チェーン・ フォールバックのどちらのものも)は InvalidArgument になる。読み出し (Self::read_train_step_loss)は同期なしでこの値を返す。

Source

pub fn wait_device(&self, tape: &Tape) -> Result<(), BackendError>

このバックエンドへ積まれた仕事の完了を D2H なしで待つ(イシュー #3254 P7。facade の Tape::wait_device_param_store の実体)。poison 済み・別デバイスは拒否し、待機後に失敗 トークンを再検査してセット済みなら poison して StorePoisoned(A08)。ops が同期の部品を 持たない(Unsupported)場合は store の状態を変えずにそのまま返す。待機自体が失敗した 場合は積んだ GPU 仕事の失敗が表面化したとみなして poison する。

Source

pub fn read_train_step_loss( &self, tape: &Tape, loss: &TrainStepLoss, ) -> Result<f32, BackendError>

Self::train_step_device_chain が積んだ step の loss を f32 で読む。D2H と同期は ここ 1 回だけ。ハンドルが別 store・古い世代なら InvalidArgument。download の後に 失敗トークンを再検査し、セット済みなら poison して StorePoisoned。

Source§

impl DeviceParamStore

Source

pub fn new( tape: &Tape, params: &[&Tensor<f32>], ) -> Result<DeviceParamStore, BackendError>

params(呼び出し元の位置対応契約に従うホスト常駐パラメータ列。 典型的には fandhe_ai::compat::Sequential::trainable_parameters() の戻り値)を 1 本の連結バッファへまとめ、tape のバックエンドへ 1 回だけ アップロードして DeviceParamStore を構築する (#1023)。

tape.ops().memory_ops() が None(MemoryOps 未実装バックエンド) の場合は BackendError::Unsupported を返す(memory_ops() を 呼ぶフォールバック合成は設けない。設計文書 §3.2 改訂)。momentum の velocity バッファはここでは確保しない(初回 step() で遅延確保。 PyTorch torch.optim.SGD の state['momentum_buffer'] 初期化 タイミングと同じ。fandhe_ai_autodiff::optim::sgd::Sgd の velocity フィールド doc 参照)。

Source

pub fn device(&self) -> Device

このストアが常駐するデバイス。

Source

pub fn len(&self) -> usize

このストアが保持するパラメータ件数(連結バッファの要素数 total_numel ではなく layout の登録件数。#1023)。

Source

pub fn is_empty(&self) -> bool

パラメータ件数が 0 か判定する(clippy::len_without_is_empty 対応)。

Source

pub fn register_resident_params<'t>( &mut self, tape: &'t Tape, ) -> Result<Vec<ResidentLeaf<'t>>, BackendError>

forward 用: 現在デバイス上にある各パラメータを tape の Op::ResidentLeaf ノードとして毎回新規登録し(tape. push_resident_leaf(...)。ホストへの download を伴わない。本 イシュー #1022 の中核)、step() が消費するまで BackendError::PendingForwardUnconsumed で以後の再登録を拒否する (モジュール冒頭「状態機械」参照)。

#1022 による変更: 旧実装(register_resident_params。現在は #[deprecated])は mem.download(buf) でホストへ落としてから tape.var(&tensor)(Op::Leaf)に登録していた(設計文書 §3.3b が 「本段階で残る転送」と明記していたもの)。本メソッドはこの download を排除し、代わりに Op::ResidentLeaf(ホスト値を持たない テープノード)を登録して不透明型 ResidentLeaf を返す(Var を 返さない理由は同型の doc 参照)。呼び出し元は返った ResidentLeaf を Self::linear_forward へ渡して forward する。

#1023「R3」による変更: DeviceParamStore はパラメータを 個別の DeviceBuffer としてではなく単一の連結バッファ (self.params)として保持するため、各パラメータは self.layout の添字(slot)で識別する。shape は layout[slot].shape から 取得し、実際のバッファ範囲(オフセット)へのアクセスは forward 時(Self::linear_forward)に Self::checked_resident_buffer が解決する。

命名(codex-review PR #1059 P1 是正): DeviceParamStore は facade の公開 API(crates.io fandhe-ai 0.4.0 で公開済み。 crates/facade/src/lib.rs の再エクスポート)であり、旧 register_resident_params(Result<Vec<Var<'t>>, _> を返す)の 戻り型を本メソッドへ直接差し替えると SemVer 破壊的変更になる。 そのため常駐 forward(D2H を伴わない)経路は新規メソッド名 register_resident_params として追加し、旧名はホスト download を伴う旧挙動のまま #[deprecated] として維持する (下記 Self::register_resident_params 参照)。

Source

pub fn snapshot_resident_params<'t>( &self, tape: &'t Tape, ) -> Result<Vec<ResidentLeaf<'t>>, BackendError>

推論用の読み取り専用版(Self::register_resident_params と 異なり pending 状態を変化させない。step() で消費する必要が ないため)。D2H を伴わず ResidentLeaf を返す(Self:: register_resident_params と同じ理由・命名判断。上記 doc 参照)。

Source

pub fn register_resident_leaves<'t>( &mut self, tape: &'t Tape, ) -> Result<Vec<Var<'t>>, BackendError>

👎Deprecated since 0.5.0:

毎 step の D2H(ホスト download)を伴う。D2H を排除した register_resident_params を使うこと

forward 用(非推奨・互換維持版): 現在デバイス上にある各 パラメータをホストへ download してから(D2H を伴う) tape.var(&tensor)(Op::Leaf)へ登録し、step() が消費するまで BackendError::PendingForwardUnconsumed で以後の再登録を拒否する (モジュール冒頭「状態機械」参照。イシュー #1022 以前の挙動を そのまま維持する)。

非推奨の理由(codex-review PR #1059 P1 是正): DeviceParamStore は facade の公開 API(crates.io fandhe-ai 0.4.0 で公開済み) であり、本メソッドの戻り型 Result<Vec<Var<'t>>, BackendError> は SemVer 契約の一部である。イシュー #1022 の D2H 排除(forward の たびに weight/bias をホストへ download しない)を導入する際、 戻り型を非破壊に変更できなかったため(Var<'t> と ResidentLeaf<'t> は異なる型)、D2H を伴わない新経路は Self::register_resident_params という別名で追加し、本メソッド は旧シグネチャ・旧挙動(download を伴う)のまま維持して既存 呼び出し元の互換性を壊さない。新規コードは Self::register_resident_params(ResidentLeaf を Self::linear_forward へ渡す設計)を使うこと。

Source

pub fn snapshot_resident_leaves<'t>( &self, tape: &'t Tape, ) -> Result<Vec<Var<'t>>, BackendError>

👎Deprecated since 0.5.0:

毎回の D2H(ホスト download)を伴う。D2H を排除した snapshot_resident_params を使うこと

推論用の読み取り専用版(非推奨・互換維持版)。 Self::register_resident_leaves(非推奨版)と異なり pending 状態を変化させない。非推奨の理由・移行先は同メソッドの doc を 参照(D2H を伴わない新経路は Self::snapshot_resident_params)。

Source

pub fn linear_forward<'t>( &self, tape: &'t Tape, input: &Var<'t>, weight: &ResidentLeaf<'t>, bias: Option<&ResidentLeaf<'t>>, ) -> Result<Var<'t>, BackendError>

forward 用: weight(・bias)をデバイス常駐のまま BackendOps::gemm_resident_rhs(tensor-core)へ渡し、 y = input.matmul(weight) (+ bias) を計算してテープへ Op::LinearResident として記録する(イシュー #1022 の中核・ #1023「R3」で連結バッファ内のオフセットビュー経由に変更)。

input(活性化値)はホスト常駐のまま渡してよい(本イシューが 排除する D2H は weight/bias のものに限る。§1.2 の解釈)。 weight/bias はいずれも self(同一 DeviceParamStore)が 同じ tape に対して Self::register_resident_params/ Self::snapshot_resident_params で返した ResidentLeaf で なければならない(Self::checked_resident_buffer が store_id/slot を検証し、本メソッドが tape_id を検証する。 イシュー #1022 P1 是正: ライフタイム 't のみでは Tape の 同一性を保証しないため、store_id/slot の検証だけでは 「別の Tape 上で発行された同じストアの葉」を通してしまう 抜け穴があった。grad::vjp の Op::LinearResident 分岐が nodes[weight.0] を当該 tape の nodes に対して引くため、 別テープのノード ID が混入すると範囲外添字・無関係ノード誤読の 余地がある。ここで fail-closed に拒否することで、grad.rs 側の nodes.get(...) 検査と合わせた縦深防御とする)。

bias は Some の場合 [n](weight の列数)への厳密一致のみ 対応する(BackendOps::gemm_resident_rhs の融合カーネル契約と 同じ。ブロードキャスト全般は非対応のため、この形状検査はカーネル 本体へ触れる前にここで行う。REQ-8・OWASP A03)。

Source

pub fn linear_forward_with_activation<'t>( &self, tape: &'t Tape, input: &Var<'t>, weight: &ResidentLeaf<'t>, bias: Option<&ResidentLeaf<'t>>, act: Activation, ) -> Result<Var<'t>, BackendError>

Self::linear_forward の activation 融合版(イシュー #1044・ docs/kernel-fusion.md §2.2「学習経路への結線」)。次層が ReLU の場合、呼び出し元(fandhe_ai_facade::compat::sequential:: Sequential::forward_from_flat_leaves)が act: Activation::Relu を渡し、ReLU 層自体のノード追加をスキップする。層あたりの カーネル起動数を「gemm+bias(Op::LinearResident)→ 別ノードの relu」の 2 起動から「gemm+bias+act」の 1 起動へ減らす。

act 以外の契約(ResidentLeaf の tape 一致検査・bias shape 厳密一致・D2H 排除)は Self::linear_forward と同一。

Source

pub fn predict_device_chain<'t>( &self, tape: &'t Tape, input: &Tensor<f32>, steps: &[(&ResidentLeaf<'t>, Option<&ResidentLeaf<'t>>, Activation)], ) -> Result<Tensor<f32>, BackendError>

推論 forward チェーン(Linear〈+ReLU 融合〉の連なり)を、 入力側 upload 1 回・出力側 download 1 回のみに同期点を集約して 計算する(docs/inference-chain-single-sync-design.md。イシュー #1688・親 #1581/#1580)。層ごとに BackendOps:: linear_forward_device_tracked(a/w/bias/戻り値すべて DeviceBuffer 常駐)を呼び、層境界ごとの D2H/H2D を発生させ ない(linear_forward_with_activation はホスト Tensor を 返すため層ごとに同期点が生じる。本メソッドはその固定費を 除去する経路)。

steps の各要素は (weight, bias, act) で、weight/bias は self が同じ tape に対して発行した ResidentLeaf でなければ ならない(checked_resident_buffer が store_id/slot を、 本メソッドが tape_id を検証する。linear_forward_with_activation と同じ縦深防御)。

バックエンドが linear_forward_device_tracked を実装しない場合 (既定委譲経由で linear_forward_device の既定実装が返す) BackendError::Unsupported をそのまま伝播する。呼び出し元 (fandhe_ai_facade::compat::sequential::Sequential:: predict_resident)はこれを検出して現行の per-layer 経路へ全体 フォールバックする契約とする(部分的にチェーンを進めた結果を 使わない。設計文書決定 7)。

§poison(失敗トークン)契約

Metal のコマンドバッファ共有下では、download 自体が Ok を 返した後でも、他スレッドが検出したバッチエラーが self.failure_token へ遅れて反映される可能性がある (sgd_step_device_tracked doc の 4 状態機械エントリと同型の レース)。本メソッドは download 完了後に failure_token. is_set() を再検査し、セット済みなら self.poisoned を立てて BackendError::StorePoisoned を返す(register_resident_leaves の「事後再検査」パターンと同じ)。

Source

pub fn predict_device_chain_resident<'t>( &self, tape: &'t Tape, input: &ResidentInput, steps: &[(&ResidentLeaf<'t>, Option<&ResidentLeaf<'t>>, Activation)], ) -> Result<Tensor<f32>, BackendError>

Self::predict_device_chain の常駐入力版(イシュー #3250 P3)。入力は ResidentInput(upload_resident_input が窓の外で 1 回 upload 済み)で、 本メソッドは入力の H2D を行わず、出力の D2H 1 回だけを同期点に持つ。 チェーン本体(層ループ・scratch 再利用・失敗トークンの事後再検査・ capture 衝突の待機再試行)はホスト入力版と同一の predict_device_chain_once を共有する(bit 一致を構造で保つ)。

追加検査(チェーンを積む前): 別 store のハンドルは BackendError::InvalidArgument、別デバイスは BackendError::DeviceMismatch、 rank が 2 でない場合は BackendError::InvalidArgument、第 1 層 weight の行数と 列数が合わない場合は BackendError::ShapeMismatch。世代切れ (CUDA の invalidate 後)はバックエンドの BackendError::StaleDeviceGeneration をそのまま伝える。Graph capture 経路(linear_chain_forward_captured)は ホスト入力の API のため通らない(常駐入力の capture 対応は #3258 の課題)。 ホスト経路へは落とさず、Unsupported はそのまま返す。

Source

pub fn upload_resident_input( &self, tape: &Tape, x: &Tensor<f32>, ) -> Result<ResidentInput, BackendError>

入力 x を 1 回だけ デバイスへ upload し、常駐入力ハンドルとして返す (イシュー #3250 P2。計測窓の外で呼ぶ想定)。ハンドルは self(store)と tape のデバイスに束縛され、別 store・別デバイスでの利用は型付きエラーになる。 非 contiguous の x は upload の契約どおり実体化される。

Source

pub fn backward( &self, tape: &Tape, loss: &Var<'_>, ) -> Result<Gradients, AutodiffError>

loss から逆伝播し、常駐 weight/bias(Op::ResidentLeaf・ Op::LinearResident)を含むグラフの勾配を計算する(イシュー #1022)。self を ResidentResolver として tape. backward_with_resident へ渡す薄いラッパー。

素の tape.backward(loss) との違い: Op::LinearResident の VJP は weight のデバイスバッファ範囲を解決する手段 (ResidentResolver)を要求するため、素の backward は AutodiffError::InvalidArgument で拒否する(tape::Op:: LinearResident doc 参照)。Sequential::forward_resident で forward したグラフは必ず本メソッドで backward すること。

イシュー #3246: 入力が requires_grad=false(Tape::var_no_grad・ Var::detach と、それらだけを祖先に持つ view・elementwise)の Op::LinearResident は d_input の GEMM を実行しない。その入力に対する Gradients::get は従来どおり Err(GradientTrackingDisabled)。 Tape::var で登録した入力は従来どおり d_input を計算する (docs/autodiff-nograd-leaf-dinput-skip-decision.md)。

イシュー #1212: 走査開始前に backward_serial をインクリメント する(GradStaging::filled の鮮度検査の基準値。fill_resident_ weight_grad が今回の走査中に書き込む値と、後続 step() が 期待する値を一致させるため、逆伝播の副作用より前に確定させる)。

Source

pub fn abandon_pending_forward(&mut self) -> bool

pending(未消費の forward 登録)を副作用なくクリアする冪等 メソッド。呼び出し元が forward の結果を使わずに中断する場合 (例: 例外的なバッチスキップ)に呼ぶ。poisoned は解除しない (モジュール冒頭「状態機械」参照)。戻り値はクリア前に pending が存在したか(冪等性の可視化。2 回目以降の呼び出しは false)。

Source

pub fn step( &mut self, tape: &Tape, grads: &Gradients, config: &SgdConfig, ) -> Result<(), BackendError>

grads(tape.backward(...) の結果)を使って SGD の 1 ステップを デバイス上で in-place に適用する(本イシューの受け入れ条件の 本体)。

処理は「①TapeId 一致検査 → ②事前検証(勾配存在・shape)→ ③更新(grad を連結して 1 回 upload → sgd_step_device_tracked を 1 回起動)」の順(設計文書 §3.3a・#1023 で③をパラメータ横断の 単一カーネル起動へバッチ化)。②で 1 件でも失敗すればどの パラメータも更新せずに Err を返す(fail-closed。 .claude/rules/security.md A03)。③の実行時エラー(GPU 起動失敗 等)は最初のエラーを返しつつ poisoned へ遷移する(モジュール 冒頭「状態機械」参照。連結バッファは単一カーネル起動で更新される ため「一部だけ更新された」状態は構造的に発生しないが、起動失敗時の バッファ内容は不定になりうるため隔離する)。

Source

pub fn step_adam( &mut self, tape: &Tape, grads: &Gradients, config: &AdamConfig, ) -> Result<(), BackendError>

AdamConfig(coupled L2 weight decay。crate::nn::optim:: adam::Adam と同一の演算列)を使い、デバイス常駐パラメータへ 1 step を適用する(イシュー #1959・docs/device-resident-update- design.md)。

step()(SGD)とは独立の状態(adam_m/adam_v/ adam_state)を使うため、同一ストア上で SGD と Adam 系を混在 させることはできない(内部実装 step_adam_impl の「状態種別 ガード」参照)。CUDA Graph capture の対象外 (BackendOps::captured_segment_key を一切呼ばない。常に BackendOps::adam_step_device_tracked の直接実行。スコープ外 として実装計画で明記済み)。

Source

pub fn step_adamw( &mut self, tape: &Tape, grads: &Gradients, config: &AdamWConfig, ) -> Result<(), BackendError>

AdamWConfig(decoupled weight decay。crate::nn::optim:: adamw::AdamW と同一の演算列)版の Self::step_adam。

Source

pub fn step_rmsprop( &mut self, tape: &Tape, grads: &Gradients, config: &RmsPropConfig, ) -> Result<(), BackendError>

デバイス常駐パラメータへ RmsProp の 1 step を適用する(イシュー #2175・docs/device-resident-update-design.md)。step_adam/ step_adamw と同じ「①事前検証フェーズ→②更新フェーズ」構造を 踏襲する。

§状態種別ガード

初回呼び出しで alpha/eps/weight_decay/momentum/ centered を確定し、以後の呼び出しでの変更を拒否する(lr の みが可変)。このストアが一度でも step()(SGD)・step_adam/ step_adamw・step_adagrad/step_lamb で使われたことがある 場合は、以後の RmsProp 呼び出しを常に拒否する(step_adam_impl の同種ガードと対称。stale な square_avg/grad_avg/ momentum_buf の再利用を防ぐ)。

Source

pub fn step_adagrad( &mut self, tape: &Tape, grads: &Gradients, config: &AdagradConfig, ) -> Result<(), BackendError>

デバイス常駐パラメータへ Adagrad の 1 step を適用する(イシュー #2175)。step_rmsprop と同じ構造を踏襲する。

§状態種別ガード

初回呼び出しで lr_decay/weight_decay/ initial_accumulator_value/eps を確定し、以後の変更を拒否 する(lr のみ可変)。SGD/Adam 系/RmsProp/LAMB のいずれかで 使用済みのストアに対する呼び出しは常に拒否する。

Source

pub fn step_lamb( &mut self, tape: &Tape, grads: &Gradients, config: &LambConfig, ) -> Result<(), BackendError>

デバイス常駐パラメータへ LAMB の 1 step を適用する(イシュー #2175)。step_adam_impl と同じ構造を踏襲するが、layer-wise trust ratio のため segment_numels(self.layout から導出)を カーネルへ渡す点が異なる。

§非有限検出時の扱い

ops.lamb_step_device_tracked が返す [BackendError:: InvalidArgument](非有限な m/v/norm/trust ratio の検出。 LambStepConfig doc 参照)は param/m/v を一切変更しない no-op 失敗であり、DeviceContextCaptureInProgress/ Unsupported と同列に扱う(pending を復元し poisoned へ 遷移させない。beta_pow_t/step_count もコミットしない。 nn::optim::lamb モジュール doc「非有限 norm の扱い (fail-closed)」節と同じ理由: poison すると sync_to_host まで 塞いでしまい、再試行可能性を失う)。

§状態種別ガード

初回呼び出しで beta1/beta2/eps/weight_decay を確定し、 以後の変更を拒否する(lr のみ可変)。SGD/Adam 系/RmsProp/ Adagrad のいずれかで使用済みのストアに対する呼び出しは常に 拒否する。

Source

pub fn sync_to_host( &self, tape: &Tape, ) -> Result<Vec<Tensor<f32>>, BackendError>

現在のデバイス上パラメータをホストへダウンロードする(明示同期 点。fandhe_ai::compat::Sequential::apply_parameters へそのまま 渡せる並び順で返す)。#1023 により連結バッファの download も 1 回(download_split)へ縮退した。

Source

pub fn resident_grads_to_host( &self, tape: &Tape, grads: &Gradients, ) -> Result<Vec<Option<Tensor<f32>>>, BackendError>

resident 経路(ResidentResolver::fill_resident_weight_grad)で GradStaging(内部の grad 永続 staging バッファ)へ新鮮に充填 済みの重み勾配を、step() を呼ばずにホストへ読み出す公開 API (イシュー #1479・docs/device-resident- update-design.md 追補)。

由来: Op::LinearResident の weight 勾配は CPU(#1212)・ Metal(#1555)・CUDA(#1559。NT/TN 形状限定)の resident 経路 では Gradients へ寄与を残さず、GradStaging へ直接書き込まれる (docs/perf/train-resident-grad-device-update.md §4)。した がって resident 経由の重み勾配は、#1479 以前はホストから一切 観測できなかった(PR #1390 codex-review P2「対象外」・ crates/facade/tests/cuda_graph_step_common/mod.rs doc 参照)。 bias 勾配は Metal(#1566 以降)・CUDA(#3204 以降)が同様に resident 経由で GradStaging へ直接書き込む(CPU は bias 縮約が gemm_fp32_strict_into_with_bias_reduce_tracked の trait 既定 実装〈bias を無視〉のまま残るため引き続き Gradients 経由。 イシュー #1898 参照)。

呼び出し窓: tape.backward_device_param_store(...)(backward 実行)の後、step()(pending を消費)の前に限る。step() 消費 後に呼ぶと BackendError::InvalidArgument を返す。

契約: &self・読み出し専用(pending/backward_serial/ grad_staging を一切変更しない)。判定ロジックは step() と Self::resident_filled_slots を共有するため由来検証(鮮度+ 同一性)に抜け穴はない(.claude/rules/security.md A08)。 Gradients::get の意味論(Ok(None) は「loss へ未到達」)は 変更しない——本メソッドは Gradients を一切呼ばない別経路。

戻り値: pending の登録順(sync_to_host と同じ並び)で slot ごとに Some(Tensor<f32>)(今回の backward で resident 経由 により新鮮に充填された slot)または None(resident 未充填の slot。CPU の bias slot は常にこちら。Metal〈#1566 以降〉・CUDA 〈#3204 以降〉の bias slot は resident 経由のため Some。呼び出し元は grads.get(...) へフォールバックする。[Self:: param_grads_to_host] がその統合版)。

バックエンド差異(AC-R2): resident_grad_capability が Some(false)(gemm_fp32_strict_into が Unsupported と確定 済み。CPU・CUDA〈#1559〉・Metal〈#1555〉いずれも通常は到達せず、 gemm_fp32_strict_into 未実装のモック等が対象)の場合は panic せず BackendError::Unsupported を返す。この capability 判定 は weight 側のみを見ており、bias 縮約が resident 経由か (Metal〈#1566 以降〉のみ)ホスト経由か(CPU・CUDA)は独立の 契約である(戻り値の bias slot は前者のみ Some)。 grad_staging.is_some() を 判定に使わない理由: CUDA Graph capture 経路は step() 内で any_resident == false のまま grad_staging を確保することが ある(step() の graph capture 分岐参照)ため、staging の有無 だけでは capability を誤判定しうる。

Source

pub fn param_grads_to_host( &self, tape: &Tape, grads: &Gradients, ) -> Result<Vec<Tensor<f32>>, BackendError>

Self::resident_grads_to_host の統合版(イシュー #1479・ #1480 が利用する)。resident 経由で充填済みの slot は staging から、それ以外(bias 等のホスト計算勾配)は grads.get(...) (step() の非 resident フォールバックと同一経路)から取得し、 pending の登録順(sync_to_host と同じ並び)で全パラメータ 勾配を返す。

strict 版と分ける理由: bias 縮約は CPU では常に Gradients 側(通常の ResidentLeaf ではなく、backward が Op::LinearResident の VJP から生成した寄与)に載り、strict 版 (GradStaging 限定)は bias slot を None のまま返す (Metal〈#1566 以降〉・CUDA〈#3204 以降〉は bias も resident 経由で Some)。 また resident 対応可否がバックエンド構成によって非対応 (gemm_fp32_strict_into 未実装)でありうるため、strict 版 単独では「各 step の全パラメータ勾配を読む」ことがバックエンド 横断で保証できない。本メソッドは内部経路(resident_filled_ slots/download_staging_slots)を strict 版と共有しつつ、 未充填 slot を grads からのフォールバックで埋めることで 3 バックエンド共通の読み出し窓を提供する。

契約: 呼び出し窓・非破壊性は strict 版と同じ。grads.get が Err(クロステープ)を返した slot は [BackendError:: TapeMismatch]、Ok(None)(loss 未到達)は [BackendError:: MissingGradient] で fail-closed に拒否する(SequentialVars:: trainable_grads と同じ方針。一部 slot だけの部分成功を返さない)。 shape 不一致は BackendError::InvalidArgument。

Trait Implementations§

Source§

impl Debug for DeviceParamStore

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V