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
impl DeviceParamStore
Sourcepub fn step_amp(
&mut self,
tape: &Tape,
grads: &Gradients,
config: &SgdConfig,
scaler: &mut GradScaler,
) -> Result<bool, AutodiffError>
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 を含む)。
Sourcepub fn step_adam_amp(
&mut self,
tape: &Tape,
grads: &Gradients,
config: &AdamConfig,
scaler: &mut GradScaler,
) -> Result<bool, AutodiffError>
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] を呼ぶかのみが異なる)。
Sourcepub fn step_adamw_amp(
&mut self,
tape: &Tape,
grads: &Gradients,
config: &AdamWConfig,
scaler: &mut GradScaler,
) -> Result<bool, AutodiffError>
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
impl DeviceParamStore
Sourcepub 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>
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 回で抜ける。
Sourcepub 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>
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 の利用者からは到達できない。
Sourcepub fn download_resident_input(
&self,
tape: &Tape,
input: &ResidentInput,
) -> Result<Tensor<f32>, BackendError>
pub fn download_resident_input( &self, tape: &Tape, input: &ResidentInput, ) -> Result<Tensor<f32>, BackendError>
常駐入力をホストへ download する(イシュー #3254。Tape 経路フォールバック専用。D2H が入る ため通常のチェーン経路では呼ばない)。別 store・別デバイスのハンドルは拒否する。
Sourcepub fn record_host_train_step_loss(
&mut self,
tape: &Tape,
loss: f32,
) -> Result<TrainStepLoss, BackendError>
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)は同期なしでこの値を返す。
Sourcepub fn wait_device(&self, tape: &Tape) -> Result<(), BackendError>
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 する。
Sourcepub fn read_train_step_loss(
&self,
tape: &Tape,
loss: &TrainStepLoss,
) -> Result<f32, BackendError>
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
impl DeviceParamStore
Sourcepub fn new(
tape: &Tape,
params: &[&Tensor<f32>],
) -> Result<DeviceParamStore, BackendError>
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 参照)。
Sourcepub fn register_resident_params<'t>(
&mut self,
tape: &'t Tape,
) -> Result<Vec<ResidentLeaf<'t>>, BackendError>
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 参照)。
Sourcepub fn snapshot_resident_params<'t>(
&self,
tape: &'t Tape,
) -> Result<Vec<ResidentLeaf<'t>>, BackendError>
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 参照)。
Sourcepub 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 を使うこと
pub fn register_resident_leaves<'t>( &mut self, tape: &'t Tape, ) -> Result<Vec<Var<'t>>, BackendError>
毎 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 へ渡す設計)を使うこと。
Sourcepub 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 を使うこと
pub fn snapshot_resident_leaves<'t>( &self, tape: &'t Tape, ) -> Result<Vec<Var<'t>>, BackendError>
毎回の D2H(ホスト download)を伴う。D2H を排除した snapshot_resident_params を使うこと
推論用の読み取り専用版(非推奨・互換維持版)。
Self::register_resident_leaves(非推奨版)と異なり pending
状態を変化させない。非推奨の理由・移行先は同メソッドの doc を
参照(D2H を伴わない新経路は Self::snapshot_resident_params)。
Sourcepub fn linear_forward<'t>(
&self,
tape: &'t Tape,
input: &Var<'t>,
weight: &ResidentLeaf<'t>,
bias: Option<&ResidentLeaf<'t>>,
) -> Result<Var<'t>, BackendError>
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)。
Sourcepub 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>
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 と同一。
Sourcepub fn predict_device_chain<'t>(
&self,
tape: &'t Tape,
input: &Tensor<f32>,
steps: &[(&ResidentLeaf<'t>, Option<&ResidentLeaf<'t>>, Activation)],
) -> Result<Tensor<f32>, BackendError>
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
の「事後再検査」パターンと同じ)。
Sourcepub fn predict_device_chain_resident<'t>(
&self,
tape: &'t Tape,
input: &ResidentInput,
steps: &[(&ResidentLeaf<'t>, Option<&ResidentLeaf<'t>>, Activation)],
) -> Result<Tensor<f32>, BackendError>
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 はそのまま返す。
Sourcepub fn upload_resident_input(
&self,
tape: &Tape,
x: &Tensor<f32>,
) -> Result<ResidentInput, BackendError>
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 の契約どおり実体化される。
Sourcepub fn backward(
&self,
tape: &Tape,
loss: &Var<'_>,
) -> Result<Gradients, AutodiffError>
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() が
期待する値を一致させるため、逆伝播の副作用より前に確定させる)。
Sourcepub fn abandon_pending_forward(&mut self) -> bool
pub fn abandon_pending_forward(&mut self) -> bool
pending(未消費の forward 登録)を副作用なくクリアする冪等
メソッド。呼び出し元が forward の結果を使わずに中断する場合
(例: 例外的なバッチスキップ)に呼ぶ。poisoned は解除しない
(モジュール冒頭「状態機械」参照)。戻り値はクリア前に pending
が存在したか(冪等性の可視化。2 回目以降の呼び出しは false)。
Sourcepub fn step(
&mut self,
tape: &Tape,
grads: &Gradients,
config: &SgdConfig,
) -> Result<(), BackendError>
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 へ遷移する(モジュール
冒頭「状態機械」参照。連結バッファは単一カーネル起動で更新される
ため「一部だけ更新された」状態は構造的に発生しないが、起動失敗時の
バッファ内容は不定になりうるため隔離する)。
Sourcepub fn step_adam(
&mut self,
tape: &Tape,
grads: &Gradients,
config: &AdamConfig,
) -> Result<(), BackendError>
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 の直接実行。スコープ外
として実装計画で明記済み)。
Sourcepub fn step_adamw(
&mut self,
tape: &Tape,
grads: &Gradients,
config: &AdamWConfig,
) -> Result<(), BackendError>
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。
Sourcepub fn step_rmsprop(
&mut self,
tape: &Tape,
grads: &Gradients,
config: &RmsPropConfig,
) -> Result<(), BackendError>
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 の再利用を防ぐ)。
Sourcepub fn step_adagrad(
&mut self,
tape: &Tape,
grads: &Gradients,
config: &AdagradConfig,
) -> Result<(), BackendError>
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 のいずれかで
使用済みのストアに対する呼び出しは常に拒否する。
Sourcepub fn step_lamb(
&mut self,
tape: &Tape,
grads: &Gradients,
config: &LambConfig,
) -> Result<(), BackendError>
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 のいずれかで使用済みのストアに対する呼び出しは常に
拒否する。
Sourcepub fn sync_to_host(
&self,
tape: &Tape,
) -> Result<Vec<Tensor<f32>>, BackendError>
pub fn sync_to_host( &self, tape: &Tape, ) -> Result<Vec<Tensor<f32>>, BackendError>
現在のデバイス上パラメータをホストへダウンロードする(明示同期
点。fandhe_ai::compat::Sequential::apply_parameters へそのまま
渡せる並び順で返す)。#1023 により連結バッファの download も
1 回(download_split)へ縮退した。
Sourcepub fn resident_grads_to_host(
&self,
tape: &Tape,
grads: &Gradients,
) -> Result<Vec<Option<Tensor<f32>>>, BackendError>
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 を誤判定しうる。
Sourcepub fn param_grads_to_host(
&self,
tape: &Tape,
grads: &Gradients,
) -> Result<Vec<Tensor<f32>>, BackendError>
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§
Auto Trait Implementations§
impl !Freeze for DeviceParamStore
impl !RefUnwindSafe for DeviceParamStore
impl !Send for DeviceParamStore
impl !Sync for DeviceParamStore
impl !UnwindSafe for DeviceParamStore
impl Unpin for DeviceParamStore
impl UnsafeUnpin for DeviceParamStore
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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