LLM 学習チェックポイントの設定をどう決めるか
はじめに
チェックポイントは、学習を中断した地点から再開するために、モデルとオプティマイザの状態をストレージに書き出したものです。1 回に書く量、保存の間隔、書き込みにかけてよい時間が、ストレージに必要な容量と書き込みスループットを決めます。この記事では、これらを決めるための数字を公開資料から整理し、予算内でできるだけ安い FSx for Lustre を見積もる流れを示します。例には、NVIDIA Nemotron 3.5 Super 120B-A12B(以下 Nemotron 3.5 Super)を 32 ノードで学習する場合を使います。
!
実際に大規模な学習を運用していて、チェックポイントの設定やストレージの選び方について現場の知見をお持ちの方がいたら、ぜひコメントで教えてください。とても喜びます。
!
この記事が扱うのは、チェックポイントの書き込みです。Physical AI のように動画を大量に読む学習では、ストレージへの要求は読み込みが中心になり、話が変わります。たとえば Turing の記事は、7 台の車載カメラの動画を PB 級の規模で S3 から直接読むために、Range GET で必要な部分だけを取り、先読みで S3 のレイテンシーを隠しています。デコードの置き場所も設計の対象で、NVIDIA DALI の動画リーダーは GPU のハードウェアデコーダーで動画をデコードします。読み込みの設計は、この記事とは別に検討が必要です。
保存時の書き込み
ZeRO-3 や FSDP、テンソル並列、パイプライン並列、エキスパート並列で学習する場合、モデルとオプティマイザの状態は全ノードに分割されて置かれています。これを PyTorch の Distributed Checkpoint や Megatron-LM の分散チェックポイントで共有ファイルシステムに保存すると、全ノードが同じタイミングで、それぞれが持つ分割をシャードとして書き込みます。データ並列で同じ値を持つ部分は、どれか 1 つのランクだけが書くように重複が除かれます。一方、DDP のように全ランクが同じ状態を持ち、1 つのランクだけがファイルに書く方式では、書き込みスループットの上限はそのノード 1 台で決まります。書き込み先には、EC2 のインスタンスストアとしてノードに付いたローカルの NVMe、全ノードが同じファイルシステムをマウントする FSx for Lustre、オブジェクトストレージの S3 があります。ただし、書き込み先によって必要な仕組みが違います。FSx for Lustre にはファイルシステム向けの書き込みでそのまま書けますが、S3 に直接書くには S3 向けの書き込みの実装が要り、ノードごとのローカル NVMe から再開するには、後の節で扱うローカルチェックポイントの仕組みが要ります。
ローカルの NVMe は、ノードごとに独立しているので、全体の書き込みスループットはノード数に比例して増えます。その代わり、そのノードが使えなくなると、書いたシャードも読めなくなります。FSx for Lustre は全ノードで共有され、ノードを失ってもデータは残ります。全体の書き込みスループットの基準値は、確保したストレージ容量と、作成時に選ぶ容量 1 TiB あたりのスループットの積で決まります。後者を、コンソールではストレージ単位あたりのスループット、API では PerUnitStorageThroughput と呼びます。S3 は容量を事前に確保する必要がなく、ノードを失ってもデータは残ります。
保存の方式には、同期と非同期があります。同期では、ストレージへの書き込みが終わるまで学習を止めます。非同期では、状態を GPU のメモリからホストのメモリへコピーする間だけ学習を止め、ストレージへの書き込みは学習と並行して進めます。どちらの方式でも、書き込みが完了するまでそのチェックポイントは再開に使えず、その間にジョブが中断すると、直近の書き込みが完了したチェックポイントから再開します。
非同期で短くなるのは学習が止まる時間 C です。中断したときに失う学習の時間は、保存の開始から書き込みの完了までの時間 t で決まり、同じ書き込みスループットなら同期と非同期で t はほぼ同じです。非同期で書き込みにかける時間を長くとるほど t は延び、失う学習の時間は長くなります。
設定を決める量
この記事で決める設定は、保存の間隔、同期か非同期か、ストレージの書き込みスループットと容量です。保存の回数を増やすほど学習が止まる時間の合計が増え、減らすほど中断したときに失う学習が増えるので、これらは次の量の関係で決まります。
記号
意味
S
全ノードを合計した、1 回のチェックポイントの大きさ
C
1 回の保存で学習が止まる時間。同期では書き込みの完了まで、非同期ではホストのメモリへのコピーの間
t_a
非同期で、学習を再開してから書き込みが完了するまでの時間。同期では 0
t
保存の開始から書き込みの完了までの時間で、t = C + t_a
t_w
ストレージへの書き込みにかける時間。同期では C、非同期では t_a
T
保存の開始から次の保存の開始までの間隔
M
ジョブの平均中断間隔。故障を含め、チェックポイントからの再開が必要になる中断の平均間隔
R
中断してから学習を再開するまでの時間
\eta
学習時間のうち、保存で止まる時間と中断で失う時間を合わせて無駄になる割合
T^{*}
\eta が最も小さくなる保存間隔
図の下段に並べた 2 つの式は、\eta の近似式と、そこから求めた T^{*} です。どちらも「保存間隔の決め方」の節で導きます。
S を t_w の間に書き終えるには、ストレージが 1 秒あたり S/t_w 以上を書ける必要があります。これが必要な書き込みスループット W の最小値です。t_w は測る値ではなく、同期なら学習を止めてよい時間、非同期なら次の保存までに書き終える時間として、設計する側が決める値です。実際には、書き込みの効率やほかの I/O との競合を見込んで、これより大きく確保します。
W = \frac{S}{t_w}
チェックポイントの大きさ
重みのバイト数
2026 年 11 月に Hugging Face の API で取得した Nemotron 3.5 Super の BF16 版の重みのファイルサイズの合計は約 248.9 GB で、総パラメータ数の約 124.5B で割ると 1 パラメータあたり 2.0 バイトです。
MoE(Mixture of Experts)は、expert と呼ぶ複数の部分ネットワークのうち、トークンごとに一部だけを使うモデルです。1 トークンの計算に使うパラメータを活性パラメータと呼び、モデル名の 120B-A12B は総パラメータ約 120B、活性パラメータ約 12B を表します。保存では使われなかった expert の重みも書き出すので、チェックポイントの大きさは活性パラメータ数ではなく総パラメータ数に比例します。
再開に必要な状態
故障による中断や手動での一時停止で学習を止めたあと、止めた地点から同じように学習を再開するには、重みに加えて、オプティマイザの状態も保存します。混合精度の学習では、計算用の bf16 の重みに加えて、更新の丸め誤差をためないための fp32 の重みを持ちます。この fp32 の重みを master weight と呼びます。オプティマイザに Adam を使う場合、1 パラメータあたりのバイト数は次のとおりです。
状態
バイト数
bf16 の重み
2
fp32 の master weight
4
fp32 の Adam の 1 次と 2 次のモーメント
8
合計
14
この内訳は、Megatron-LM の distributed optimizer のように、bf16 の重みと fp32 の master weight を別々に持つ構成の値です。ZeRO の論文は、fp16 の重みと勾配で同じバイト数の内訳を示していて、勾配の 2 バイトを含めると 16 バイトです。FSDP2 を使う TorchTitan のように、分割して持つ重み自体が fp32 で、bf16 の重みは計算の間だけ作る構成では、保存するのは fp32 の重みとモーメントの 4 + 8 = 12 バイトです。モーメントを bf16 で持つ構成では 2 + 4 + 4 = 10 バイトになります。DeepSeek-V3 の技術報告は、AdamW の 1 次と 2 次のモーメントを bf16 で持ち、master weight を fp32 で持つと書いています。bf16 の重みと bf16 のモーメントだけを持ち、fp32 の重みを持たない構成では 2 + 4 = 6 バイトです。どの値になるかはフレームワークと設定で決まるので、実際に 1 回保存して確かめます。再開には、学習率のスケジューラ、ステップ数、乱数生成器、データの読み取り位置などの状態も必要ですが、これらは重みとオプティマイザの状態に比べて小さいので、大きさの計算では数えていません。
Nemotron 3.5 Super の大きさ
試算に使う Nemotron 3.5 Super の総パラメータ数は約 124.5B で、この値には画像エンコーダーのパラメータも含まれます。1 パラメータあたりのバイト数ごとに、チェックポイントの大きさ S と、32 ノードに均等に分けたときの 1 ノードあたりの大きさは次のとおりです。
保存する状態
1 パラメータあたり
S
1 ノードあたり
bf16 の重みだけ
2 バイト
約 0.25 TB
約 7.8 GB
重みとオプティマイザの状態
14 バイト
約 1.74 TB
約 54 GB
モーメントを bf16 にした場合
10 バイト
約 1.24 TB
約 39 GB
bf16 の重みと bf16 のモーメントだけの場合
6 バイト
約 0.75 TB
約 23 GB
画像エンコーダーを凍結して学習するなら、そのパラメータはオプティマイザの状態を持たないので、bf16 の重みの 2 バイトだけを保存すれば足ります。公開されている例では、awsome-distributed-ai の verl の例が、20B のモデルを GPU 12 枚で学習すると 1 つのチェックポイントが約 117 GB になると書いています。以降の試算では 14 バイトの約 1.74 TB を使い、最後に 6 バイトの場合の結果も示します。
公開事例の保存間隔
保存の間隔についての公開情報は乏しく、モデルの技術報告にはほとんど書かれていません。後の節で見るとおり、フレームワークに既定値がある場合も、時間ではなくステップ数で決まっています。時間で間隔を書いている公開事例は、次の表のように少数です。
出典
間隔
補足
BLOOM 176B
3 時間ごと。学習ログによると、計算機の保守の停止に備えて 100 ステップごとに変更
Hugging Face のブログによると 1 回が 2.3 TB、学習ログによると保存は 40 秒
DeepSeek の Fire-Flyer AI-HPC
5 分
保存と読み込みはどちらも数秒
Meta の信頼性の論文
大規模ジョブの典型は 1 時間
1,024 GPU のジョブの平均故障間隔は 7.9 時間
Unicron
30 分。再計算の時間を比べるために論文が置いた値
128 GPU のクラスターでの評価
ジョブの平均中断間隔
保存の間隔は、1 回の保存で止まる時間と、ジョブがどのくらいの頻度で中断するかの両方で決まります。次の表は、公開されている故障や中断の記録を、1 ノードに GPU 8 枚を積んだ 32 ノードのジョブの平均中断間隔に換算した値です。中断がノード数に比例して起きると仮定し、元の平均間隔を M_0、元のノード数を N_0 として M = M_0 N_0 / 32 で計算しました。ノード数は、論文の GPU 数を 1 ノード 8 GPU として割った値です。元の論文が数えた範囲、たとえば対象のクラスターや期間の取り方で値は変わるので、表の値は目安です。数えている事象は出典ごとに違い、GPU の故障、ハードウェアが原因の再起動、原因を問わない中断が混ざっているので、比べるときは注意が必要です。
出典
規模と期間
32 ノードに換算した平均中断間隔
Meta の信頼性の論文
128 ノード、1,024 GPU のジョブで 7.9 時間
約 32 時間
OPT-175B
124 ノード、60 日とみなした 2 か月で、ハードウェアの障害による手動の再起動が少なくとも 35 回、自動の再起動が 70 回以上
105 回で約 53 時間、35 回で約 159 時間
BLOOM
48 ノードで、GPU の故障が週 1〜2 回
約 126〜252 時間
Llama 3
2,048 ノード、54 日で 466 回の中断。うち想定外が 419 回で、その約 78%、約 327 回がハードウェアの問題と確認されたか、そう疑われた中断
466 回で約 178 時間、419 回で約 198 時間、327 回で約 254 時間
MegaScale
10,000 GPU を超える本番の学習で、3 週間とみなした数週間に 100 回を超える再起動。1,250 ノードとして計算
約 197 時間。GPU 数も回数も「超える」なので目安
Acme
588 ノード、182.5 日とみなした 6 か月で、ハードウェアが原因の故障が 103 件
約 781 時間
ネットワークの障害や、複数のノードがまとめて故障する場合があるので、ノード数に比例させる換算は目安です。ジョブの中断には GPU の故障のほかにネットワークやソフトウェアの障害も含まれるので、GPU の故障率だけからは M を決められません。参考として、NCSA Delta の研究は、GPU 1 枚あたりのメモリエラーの平均間隔を H100 で約 88,768 時間、A100 で約 283,271 時間と報告しています。B200 と B300 の故障率は公開されていません。
保存間隔の決め方
Young の式
保存間隔 T は、学習が止まる時間と、中断で失う学習の時間の合計が最も小さくなるように決めます。学習時間のうち無駄になる割合を \eta とすると、次の式で近似できます。
\eta \approx \frac{C}{T} + \frac{T/2 + t + R}{M}
第 1 項は、保存で学習が止まる分です。間隔 T ごとに C だけ止まるので、止まる割合は C/T です。
第 2 項は、中断で失う分です。1 回の中断で失う時間の期待値を T/2 + t + R とし、中断が平均 M に 1 回起きるので M で割ります。ここで t は、保存を始めてから書き込みが終わり、そのチェックポイントが再開に使えるようになるまでの時間です。
!
ここからの導出は、確率変数と期待値を使います。数理統計になじみがない方は、導出を飛ばして「1 回の中断で失う時間の平均は T/2 + t になる」という結論だけを眺めても、この先を読み進められます。内容は統計検定 2 級くらいなので、学んでおくと性能の見積もりなどいろいろな場面で役に立ちます。
T/2 + t は、次のように求まります。直近の保存を始めた時刻から中断までの経過時間を連続型の確率変数 X とし、中断は間隔のどこでも同じように起きる、つまり X が区間 [0, T) の連続一様分布に従うと仮定します。また、保存は予定どおり t < T で書き終わり、C は T より十分短いとします。
X \sim \mathrm{U}(0, T), \qquad E[X] = \frac{T}{2}, \qquad P(X < t) = \frac{t}{T}
X \ge t なら直近の保存は書き終わっているので、やり直すのは X だけです。X < t なら直近の保存はまだ使えないので、1 つ前の保存まで戻り、さらに間隔 1 つ分の T をやり直します。やり直す時間を L とすると、指示関数 \mathbf{1}{X < t} を使って次のように書けます。
L = X + T \cdot \mathbf{1}{X < t}
期待値をとると、次のようになります。
E[L] = E[X] + T \cdot P(X < t) = \frac{T}{2} + T \cdot \frac{t}{T} = \frac{T}{2} + t
最悪の場合は X が t の直前のときで、L は T + t に近づきます。
これに再開までの時間 R を足したものが、1 回の中断で失う時間です。たとえば T が 45 分、t が 5 分なら、学習のやり直しは平均 22.5 分 + 5 分 = 27.5 分、最悪で 45 分 + 5 分 = 50 分です。
t と R が T によらないとすると、右辺を T で微分して 0 と置いた -C/T^2 + 1/(2M) = 0 から、最適な間隔は次のようになります。
T^{*} \approx \sqrt{2\,C\,M}
この式は Young が 1974 年に示したもので、C \ll T \ll M のときに成り立ちます。C が M に比べて無視できない場合の補正は、Daly が 2006 年に加えています。
!
Young の式と Daly の補正は、HPC のチェックポイント研究で古くから使われてきた式です。もともとは、スーパーコンピューターで長時間の計算を故障に備えてどの間隔で保存するかを決めるためのものでした。大規模な LLM の学習でも同じ考え方が使われていて、Meta の信頼性の論文もこの形の式で保存の間隔を見積もっています。
M は、Llama 3 の換算値の約 178〜254 時間の範囲にある 200 時間とし、R は 15 分とします。
方式
M
C
t
T^{*}
\eta
同期
200 時間
5 秒
5 秒
約 45 分
約 0.50%
同期
200 時間
60 秒
60 秒
約 2.6 時間
約 1.42%
同期
200 時間
300 秒
300 秒
約 5.8 時間
約 3.05%
非同期
200 時間
5 秒
5 分 5 秒
約 45 分
約 0.54%
同期
約 32 時間
5 秒
5 秒
約 18 分
約 1.72%
同期
約 781 時間
5 秒
5 秒
約 88 分
約 0.22%
最後の 2 行は、M を前の節の表で最も短い Meta の換算値と、最も長い Acme の換算値にした場合で、T^{*} は M によって大きく変わります。
式の前提
この式は、故障が互いに独立で、故障の起きやすさが時間によらないこと、つまり故障間隔が指数分布に従うことを前提にしています。Aupy らの論文が引く Heien らの測定では、HPC システムの故障間隔は形状パラメータ 0.58〜0.71 の Weibull 分布に当てはまりました。Weibull 分布は、形状パラメータが 1 のとき指数分布と同じになり、1 より小さいほど故障の直後に次の故障が集中します。同じ論文は、形状パラメータ 0.5、2^{19} プロセスのシミュレーションで、Daly の式の間隔を使うと、論文が提案する間隔の場合より実行時間が約 61%、Young の式では約 50% 長くなったと報告しています。
平均中断間隔も一定ではないので、運用中に記録した中断から M を更新して、間隔を見直します。評価の節目、損失が急に悪化したときの巻き戻し、予約した計算資源の期限などでもチェックポイントから再開するので、これらの時刻に合わせて保存する場合もあります。
フレームワークの既定値
Megatron-LM、それを継承する Megatron Bridge、TorchTitan では、非同期の保存は既定で無効です。有効にしなければ同期で保存され、書き込みが終わるまで学習は止まります。次の表は、2026 年 10 月に取得したコミットのソースコードで確かめた既定値で、リンク先はそのコミットの該当行です。
フレームワーク
保存間隔の既定
非同期保存の既定
Megatron-LM
既定値はなしで、保存先を指定すると間隔の指定が必須
無効。分散チェックポイント形式で --use-persistent-ckpt-worker を指定しないと、有効にしても無効に戻される
Megatron Bridge
Megatron-LM の設定を継承
Megatron-LM の設定を継承するので無効。async_save で有効にする
TorchTitan
500 ステップ
無効
Hugging Face Trainer
500 ステップ
非同期保存の機能はなく、save_steps ごとに同期で保存
ローカル NVMe と複製
前の節の非同期保存を一歩進めると、チェックポイントを短い間隔で各ノードのローカル NVMe に書き、共有ストレージへは長い間隔で書く方法があります。ローカル NVMe は書き込みが速いので、学習が止まる時間と、共有ストレージに必要な書き込みスループットを小さくできます。弱点は、そのノードを失うとローカルに書いた分も失うことです。NVIDIA Resiliency Extension は、このローカルへの保存を提供するライブラリで、ほかのノードに複製を持って冗長性を高める仕組みも備えています。ローカルに書いたチェックポイントを共有ストレージへ移す処理は含まず、共有ストレージへの保存は、通常のチェックポイントとして別に行います。この節では、この方法で何を守れて何を守れないかを整理します。次の図は、保存先ごとに、プロセスの再起動、1 ノードの喪失、クラスター全体の停止のあとでデータが残るかを示しています。
NVIDIA B300 を 8 枚積んだ p6-b300.48xlarge には、3,800 GB の NVMe SSD が 8 本、合計 30,400 GB のインスタンスストアがあり、1 ノードあたり約 54 GB のシャードを何世代分も置けます。共有ストレージへの転送が終わるまでは、そのノードが使えなくなるとシャードを失います。
NVIDIA Resiliency Extension のローカルチェックポイントは、Megatron-LM などの学習ループに組み込んで使い、各ノードの SSD か RAM ディスクに保存し、ほかのノードにも複製を持つことで、1 ノードを失っても複製からシャードを復元します。複製の組み方は設定で決め、保存と再開で同じ設定にする必要があります。
NVIDIA Resiliency Extension は、GPU 1 枚を受け持つプロセスであるランクを組にして、組の中で複製を持ち合います。組の作り方は、組の大きさ F と、組の中のランクの間隔 J の 2 つの設定で決まり、それぞれ replication_factor と replication_jump です。J の既定値は 1 ノードの GPU 数なので、組のランクは別々のノードに置かれ、組の中の F ノードが互いの分の複製をすべて持ちます。複製は既定では無効で、Megatron-LM では --replication で有効にします。F の既定値は NVIDIA Resiliency Extension でも Megatron-LM でも 2 です。ランクの総数が J \times F で割り切れないと、組を作る処理が止まります。p6-b300.48xlarge 32 台ではランクの総数が 256、J が 8 なので、F に使えるのは 1、2、4、8、16、32 です。
組を持っていても、故障したノードの分の複製を作り直す前に、同じ組のほかのノードもすべて失われると、そのシャードは失われます。この確率を、組に固定する NVIDIA Resiliency Extension の置き方と、比較のために複製先をランダムに選ぶ置き方で比べます。前提は次のとおりです。
前提
内容
ノード数
32
組の大きさ F
既定値の 2。原本を含めて 2 か所に置く
最初の故障
ノード A が故障する
\Delta
A の分の複製を作り直すまでの時間。例では 1 時間
M_n
1 ノードが失われてインスタンスストアのデータが読めなくなる平均間隔。例では 6,400 時間で、ジョブの中断がすべてノードの喪失によるとした多めの見積もり
p
ほかの各ノードが \Delta の間に失われる確率で、p \approx \Delta / M_n。例では約 0.016%
独立性
ほかのノードは互いに独立に失われる
シャードの数
A が持つシャードは十分に多い
組に固定する場合
F = 2 では、A と組になるノード B が、A のシャードの複製をすべて持ちます。A のシャードを失うのは、B が \Delta の間に失われるときだけなので、確率は次のとおりです。
P_{\text{組}} = p
複製先をランダムに選ぶ場合
A の各シャードの複製を、ほかの 31 ノードからランダムに選んだ 1 台に置くとします。シャードが十分に多いと、31 ノードのどれにも A のどれかのシャードの複製があります。そのため、31 ノードのどれか 1 台が \Delta の間に失われれば、A のシャードのどれかを失います。31 台のどれも失われない確率は、各ノードが独立に確率 1 - p で残るので (1 - p)^{31} です。A のシャードを失う確率はその余事象なので、次のようになり、p が小さければ 31p で近似できます。
P_{\text{ランダム}} = 1 - (1 - p)^{31} \approx 31\, p
近似は、(1 - p)^{31} を二項定理で展開し、p が小さいときに p^2 以降の項を捨てたものです。
(1 - p)^{31} = 1 - 31p + \binom{31}{2}p^2 - \binom{31}{3}p^3 + \cdots \approx 1 - 31p
31p は、31 台それぞれが失われる確率 p を足した値です。2 台以上が同時に失われる場合を重ねて数えていますが、p が小さければその分は無視できます。前提の表の例の値では、正確な値が約 0.4832%、近似が約 0.4844% です。
前提の表の例の値を入れると、組に固定する場合は約 0.016%、ランダムに置く場合は約 0.48% で、ランダムに置くと約 31 倍になります。例の M_n は、ジョブの平均中断間隔 200 時間を 32 倍した値です。F を 4 にすると、組に固定する場合は組のほかの 3 台がすべて失われるときだけなので p^3、ランダムでは、シャードが十分に多く 3 台の組み合わせのどれにも複製があるとして、p が小さいときの近似で \binom{31}{3} p^3 = 4{,}495\, p^3 になり、どちらも桁違いに小さくなります。その代わり、各ノードが持つ複製の量は F に比例して増えます。
チェックポイントは、シャードが 1 つでも欠けると再開に使えません。そのため、ある世代のシャードを 1 つ失っても全部失っても、その世代は同じように使えなくなります。複数の世代を同じ組に置いている場合は、組を失えばそれらの世代をまとめて失い、共有ストレージにある世代まで戻ります。どちらの置き方でも失う世代の数は同じなので、確率が低い、組に固定する置き方のほうが有利です。置き方によってデータを失う組み合わせの数が変わることは、Copysets の論文が分散ストレージについて示しています。
この計算は故障が独立だという前提に立っているので、ラックや電源の障害で複数のノードがまとめて止まる場合や、クラスター全体が止まる場合には当てはまりません。その場合に備えて、FSx for Lustre か S3 にもコピーを置きます。
データが通る経路
チェックポイントのデータは、GPU のメモリからホストのメモリを経て、ローカル NVMe か、ネットワークインターフェースを通って共有ストレージへ書かれます。経路の途中にはそれぞれ上限があり、いちばん低い上限が書き込みスループットを決めます。
ローカル NVMe は PCIe でつながったノード内のディスクなので、ネットワークの帯域は効かず、ディスクの性能で決まります。S3、S3 Files、EFA を使わない FSx for Lustre は、ENA というネットワークインターフェースで TCP を使って通信します。EFA は、OS を通らずに SRD というプロトコルで通信するネットワークインターフェースで、EFA を有効にした FSx for Lustre との通信や、ノード間の集団通信に使います。
ネットワークインターフェースの帯域は、インスタンスの種類で大きく違います。
インスタンス
ネットワークインターフェースの帯域
c6in.2xlarge
最大 40 Gbps、基準値 12.5 Gbps
g6e.12xlarge
100 Gbps
p6-b300.48xlarge
1 枚目のネットワークカードが 350 Gbps、ほかに 400 Gbps のネットワークカードが 16 枚あり、16 枚の合計は 6,400 Gbps
TCP には、インスタンスの帯域とは別の上限もあります。EC2 の文書によると、同じクラスタープレイスメントグループにない相手との 1 本の TCP 接続は 5 Gbps までです。同じグループの中では 10 Gbps、同じ AZ で ENA Express を使えば 25 Gbps まで上がりますが、いずれにしても 1 本の接続には上限があります。S3 の性能のガイドラインも、多数の接続に分けて並列に送ることを勧めています。FSx for Lustre の文書は、クライアント 1 台あたりの最大スループットを、EFA を使わない場合は 100 Gbps、EFA では 700 Gbps、EFA と GPUDirect Storage では 1,200 Gbps としています。ENA で TCP を使う場合のもう 1 つの上限は、次の節で説明します。
FSx for Lustre の容量と書き込みスループット
FSx for Lustre の SSD を使う Persistent 2 では、ディスクのスループットの基準値は確保したストレージ容量とストレージ単位あたりのスループットの積で決まり、ストレージ単位あたりのスループットは 125、250、500、1,000 MB/s/TiB から選びます。料金は使用量ではなく確保した容量にかかり、ストレージ容量の文書にあるとおり、容量は増やせますが減らせません。
容量は GiB で指定し、EFA を使わない場合は 1,200 GiB も選べます。それより大きい容量の単位はストレージサーバー 1 台あたりの容量で決まります。EFA を使わない場合は 2,400 GiB、EFA を使う場合は 125 MB/s/TiB で 38,400 GiB、250 MB/s/TiB で 19,200 GiB、500 MB/s/TiB で 9,600 GiB、1,000 MB/s/TiB で 4,800 GiB です。スループットの計算では、AWS の文書の例に合わせて 1,000 GiB を 1 TiB として扱います。EFA を使うファイルシステムは、スループットが 10 GB/s を超える場合に推奨されていて、作成後に EFA の有無もストレージ単位あたりのスループットも変えられません。EFA を使わない SSD のファイルシステムは、作成後にストレージ単位あたりのスループットを変更できます。
ストレージ単位あたりのスループットは、ディスクのスループットの基準値です。性能の表によると、125 MB/s/TiB と 250 MB/s/TiB には、ディスクのスループットを一時的に 500 MB/s/TiB まで上げるバーストがあり、500 MB/s/TiB と 1,000 MB/s/TiB にはありません。また、ENA で TCP を使って通信する場合、クライアント 1 台とストレージサーバー 1 台の間のトラフィックは 5 Gbps が上限なので、1 台のクライアントが書けるのは、ストレージサーバーの台数に 5 Gbps を掛けた値までです。
Nemotron 3.5 Super の S を 1.74 TB とすると、ストレージへの書き込みにかける時間 t_w ごとに必要な書き込みスループット W = S / t_w は次のとおりです。
t_w
W
300 秒
約 5.8 GB/s
60 秒
約 29 GB/s
20 秒
約 87 GB/s
同期で保存するなら t_w がそのまま学習の止まる時間 C になるので、C を短くするほど確保する容量と料金が増えます。非同期なら C と t_w を別々に決められます。前回の書き込みが次の保存の開始までに終わっていない場合の動きは、フレームワークで違います。TorchTitan は前回の書き込みが終わるまで待つので、その分だけ学習が止まります。Megatron-LM と Megatron Bridge は警告を出して次の保存を始めるので、学習は止まりませんが、書き終わっていない書き込みが積み重なります。どちらでも重なりを避けるには W \ge S/(T - C) が必要で、T が約 45 分なら約 0.65 GB/s が下限です。t_w を長くすると W は小さくなりますが、t が延びるので中断で失う学習の時間 T + t と \eta は大きくなります。ローカルの NVMe を経由して共有ストレージへ転送する場合も、次の保存までに転送を終える必要があるので、平均で S/T 以上の書き込みスループットが要ります。
!
コラム: 保存で止まる GPU 時間と FSx for Lustre の料金のトレードオフ
同期で保存する場合、C を短くすると FSx for Lustre の料金は増えますが、保存で止まる GPU の時間は減ります。1 年間の学習で両者を比べると次のとおりです。前提は、S が 1.74 TB、p6-b300.48xlarge 32 台、M が 200 時間、T を Young の式で \sqrt{2CM} に置くことです。GPU の時間は、1 年の 8,760 時間に止まる割合 C/T を掛け、2026 年 11 月時点の p6-b300.48xlarge のオレゴンのオンデマンド料金、1 時間 142.416 ドルで金額にしました。FSx for Lustre は、各 C で最も安い構成の月額の 12 か月分で、必要な書き込みスループットが 10 GB/s を超える場合は EFA を使う構成にしています。
C
止まる GPU 時間/年
その金額/年
FSx for Lustre/年
合計/年
30 秒
約 10,200 GPU 時間
約 18.2 万ドル
約 44.9 万ドル
約 63.1 万ドル
60 秒
約 14,500 GPU 時間
約 25.8 万ドル
約 24.2 万ドル
約 50.0 万ドル
120 秒
約 20,500 GPU 時間
約 36.4 万ドル
約 13.8 万ドル
約 50.3 万ドル
300 秒
約 32,400 GPU 時間
約 57.6 万ドル
約 4.9 万ドル
約 62.5 万ドル
実際には GPU は年単位で確保していることが多く、保存で止まっても GPU の支払いは変わりません。その場合、止まる GPU 時間の金額は、その時間で行えたはずの追加の学習を金額に換算した機会費用として読みます。この考え方では、合計は C が 90 秒前後で最も小さく、年に約 46 万ドルです。この比較は保存で止まる時間だけを数えています。中断で失う学習も GPU 時間なので、それも足すと合計は年に約 76 万ドルになり、最も小さくなる C は 50 秒前後に移ります。C を短くしすぎると FSx for Lustre の料金が、長くしすぎると止まる GPU の時間が、合計を押し上げます。GPU の単価が予約や個別の価格で下がれば、最も小さくなる C は長い側へ動きます。非同期で保存できるなら、止まる時間はホストのメモリへのコピーの間だけになります。書き込みにかける時間は学習を止めずに長くとれるので、FSx for Lustre の料金と、中断で失う学習の時間の釣り合いだけで決められ、止まる GPU 時間の費用を小さくできます。Megatron-LM では分散チェックポイント形式と常駐の保存ワーカーが条件になるので、使っているフレームワークで有効にできるなら、非同期で保存するのがよいと考えます。
確保する容量は、残す世代数を k、ストレージ単位あたりのスループットを \tau、容量の単位を u として、次の式で決まります。容量は GiB で比べ、kS はバイト数を 2^{30} で割って GiB にし、W/\tau は MB/s を MB/s/TiB で割った値を 1,000 倍して GiB とします。
\text{確保する容量} = u \left\lceil \frac{\max\left(k S,\ W/\tau\right)}{u} \right\rceil
Nemotron 3.5 Super で FSx for Lustre を見積もる
見積もりは、チェックポイントの設定を決め、そこから FSx for Lustre に必要な書き込みスループットと容量を逆算し、最も安い構成の月額を求める順に進めます。式はこれまでの節で説明したとおりで、計算の過程はこの節の最後の折りたたみにまとめました。
見積もる人が決める値
次の値を決めれば、見積もりができます。既存の環境で測れる値は測り、測れない値は右の概算から始めます。
値
決め方
測れないときの概算
この例の値
総パラメータ数
モデルの定義から読む
なし
約 124.5B
1 パラメータあたりのバイト数
小さい構成で 1 回保存し、チェックポイントの大きさを総パラメータ数で割る
bf16 の重み、fp32 の master weight、fp32 のモーメントなら 14、fp32 の重みとモーメントなら 12、モーメントが bf16 なら 10
14
ノード数
学習の計画から決める
なし
32
同期か非同期か
使うフレームワークで非同期を有効にできるかで決める
なし
非同期
保存で止まる時間 C
1 回保存し、学習のステップが止まった時間を測る
非同期は 1 ノード分を GPU からホストへ写す時間で、MegaScale と Fire-Flyer はどちらも数秒と報告している。同期は t_w と同じ
5 秒程度
書き込みにかける時間 t_w
予算と、中断で失ってよい学習の時間から決める
なし
5 分または 20 分
平均中断間隔 M
既存のクラスターのジョブの中断を記録する
ジョブの平均中断間隔の節の表から選ぶ
200 時間
再開までの時間 R
中断から再開までを 1 回試して測る
10 分にチェックポイントの読み込み時間を足す
約 15 分。FSx for Lustre の構成で変わる
残す世代数 k
何世代前まで戻れればよいかで決める
完了した 3 世代と書き込み中の 1 世代
4
EFA を使うか
必要な書き込みスループットが 10 GB/s を超えるなら、AWS の推奨に合わせて使う
なし
使わない
料金
使うリージョンの料金ページで確かめる
なし
オレゴン
見積もりの結果
左のグラフは、書き込みにかける時間 t_w ごとに、FSx for Lustre の最も安い構成の月額を示します。右のグラフは、同じ t_w で、同期と非同期それぞれの無駄になる割合 \eta を示します。
t_w を延ばすほど必要な書き込みスループットが下がり、FSx for Lustre は安くなります。容量が残す世代を置く量で決まるところまで下がると、それ以上は安くなりません。
EFA を使う構成は容量の単位が大きいので、同じ書き込みスループットなら、EFA を使わない構成と同じか高くなります。10 GB/s を超える範囲では、AWS の推奨に合わせて EFA を使う構成で計算しています。
同期では t_w がそのまま学習の止まる時間になるので、\eta は t_w とともに急に増えます。非同期では止まる時間が数秒のままなので、t_w を延ばしても \eta はゆっくりしか増えません。
主な組み合わせの結果は次のとおりです。「最も安い構成」の列は、FSx for Lustre を作るときに選ぶ 2 つの値で、たとえば「250 MB/s/TiB、7,200 GiB」は、ストレージ単位あたりのスループットを 250 MB/s/TiB に、ストレージ容量を 7,200 GiB にすることを意味します。この構成の書き込みスループットの基準値は、7,200 GiB を 7.2 TiB として 250 MB/s/TiB を掛けた 1.8 GB/s です。250 MB/s/TiB 以下ではバーストで一時的にこれを超えられますが、見積もりでは基準値を使います。容量は、必要な書き込みスループットから出る容量と、残す世代を置く容量の大きいほうで決まるので、世代を置く容量で決まった場合は、基準値が必要な書き込みスループットより大きくなります。
チェックポイントの設定
必要な書き込みスループット
最も安い構成
書き込みスループットの基準値
容量を決めたもの
月額
\eta
14 バイト、非同期、20 分で書き終える
約 1.45 GB/s
250 MB/s/TiB、7,200 GiB
1.8 GB/s
世代を置く容量
約 1,500 ドル
約 0.76%
14 バイト、非同期、5 分で書き終える
約 5.8 GB/s
500 MB/s/TiB、12,000 GiB
6.0 GB/s
書き込みスループット
約 4,100 ドル
約 0.54%
6 バイト、非同期、5 分で書き終える
約 2.5 GB/s
500 MB/s/TiB、7,200 GiB
3.6 GB/s
書き込みスループット
約 2,400 ドル
約 0.53%
14 バイト、同期、60 秒で書き終える
約 29 GB/s
EFA あり、1,000 MB/s/TiB、33,600 GiB
33.6 GB/s
書き込みスループット
約 20,200 ドル
約 1.39%
この例では、非同期で 45 分ごとに保存し、20 分で書き終えればよいとすると、250 MB/s/TiB の 7,200 GiB、月額約 1,500 ドルで予算を見積もれます。中断で失う学習を減らしたい場合は、書き終える時間を 5 分に縮めて月額約 4,100 ドルで見積もります。
計算の過程: 14 バイト、非同期、5 分で書き終える場合
ノード数を N、総パラメータ数を P、1 パラメータあたりのバイト数を b とします。
チェックポイントの大きさと 1 ノードあたりの大きさ
S = P \times b = 124.45 \times 10^{9} \times 14 \approx 1.74\ \text{TB}, \qquad \frac{S}{N} = \frac{1.74\ \text{TB}}{32} \approx 54\ \text{GB}
保存で止まる時間 C を 5 秒にするのに必要な、1 ノードあたりの GPU からホストへの転送
\frac{S/N}{C} = \frac{54\ \text{GB}}{5\ \text{s}} \approx 11\ \text{GB/s}
保存間隔
T^{*} = \sqrt{2CM} = \sqrt{2 \times 5\ \text{s} \times 720{,}000\ \text{s}} \approx 2{,}683\ \text{s} \approx 45\ \text{min}
必要な書き込みスループット
W = \frac{S}{t_w} = \frac{1.74\ \text{TB}}{300\ \text{s}} \approx 5.8\ \text{GB/s}
確保する容量。kS を GiB にし、W/\tau は MB/s を MB/s/TiB で割った値を 1,000 倍して GiB にします。\tau = 500 MB/s/TiB、u = 2{,}400 GiB では次のとおりです。
kS = \frac{4 \times 1.742\ \text{TB}}{2^{30}} \approx 6{,}491\ \text{GiB}, \qquad \frac{W}{\tau} \times 1{,}000 = \frac{5{,}808}{500} \times 1{,}000 \approx 11{,}616\ \text{GiB}
u \left\lceil \frac{\max(6{,}491,\ 11{,}616)}{2{,}400} \right\rceil = 2{,}400 \times 5 = 12{,}000\ \text{GiB}
月額。オレゴンの 500 MB/s/TiB の料金は GiB 月あたり 0.340 ドルです。
12{,}000\ \text{GiB} \times 0.340\ \text{USD} = 4{,}080\ \text{USD/month}
再開までの時間と無駄になる割合。この構成のスループットの基準値は 12{,}000 / 1{,}000 \times 500 = 6{,}000 MB/s で、読み込みも同じ程度出ると仮定すると、約 290 秒です。
R = 600 + \frac{1.74\ \text{TB}}{6.0\ \text{GB/s}} \approx 890\ \text{s}, \qquad t = C + t_w = 305\ \text{s}
\eta = \frac{C}{T} + \frac{T/2 + t + R}{M} = \frac{5}{2{,}683} + \frac{1{,}341 + 305 + 890}{720{,}000} \approx 0.54\%
中断で失う学習の時間の上限は、T + t \approx 2{,}683 + 305 \approx 2{,}988 秒、約 50 分です。
ほかのストレージ単位あたりのスループットと EFA の有無で同じ計算をすると、次のようになります。
ストレージ単位あたりのスループット
EFA なし
EFA あり
125 MB/s/TiB
48,000 GiB、約 7,000 ドル/月
76,800 GiB、約 11,100 ドル/月
250 MB/s/TiB
24,000 GiB、約 5,000 ドル/月
38,400 GiB、約 8,100 ドル/月
500 MB/s/TiB
12,000 GiB、約 4,100 ドル/月
19,200 GiB、約 6,500 ドル/月
1,000 MB/s/TiB
7,200 GiB、約 4,300 ドル/月
9,600 GiB、約 5,800 ドル/月
まとめ
FSx for Lustre をできるだけ安く見積もるには、先にチェックポイントの大きさ、保存間隔、書き込みにかける時間を決め、そこから必要な書き込みスループットと容量を逆算します。Nemotron 3.5 Super を 32 ノードで学習する例では、非同期で 45 分ごとに保存し、20 分で書き終えればよいとすると、250 MB/s/TiB の 7,200 GiB、月額約 1,500 ドルで足ります。書き込みにかける時間を延ばすほど FSx for Lustre は安くなりますが、中断で失う学習と再開の時間は延びるので、その釣り合いで決めます。ここでの値はどれも試算なので、実際の構成で保存と再開の時間、中断の頻度、書き込みスループットを測って置き換えてください。
NVIDIAの『ループ型』4Bモデル Dory1.0-4B、標準ツールで動かそうとしたら2箇所で止まった
これは何を試した記事か
NVIDIAが公開したDory1.0-4Bという4Bパラメータのモデルを、公式のモデルカードが案内するとおりの手順で動かそうとした記事である。
Dory1.0-4Bは、1つの重み(チェックポイント)のまま「再帰ブロックを何回ループさせるか」を1〜4回の間で切り替えることで、再学習なしに推論時の計算量と精度をトレードオフできる「ループ型Transformer」である。
出典は論文(huggingface.co )とモデル重みコレクション(huggingface.co )で、ライセンスはOpenMDW License Agreement version 1.1。
Zenn・Qiita・noteを検索した範囲では、2026年11月4日時点で日本語の一次検証記事は0件だった。
結論を先に書くと、モデルカードのサンプルコードをそのままコピーして動かすという最もハードルの低い経路は、2つとも実際に動かなかった。
「GPUが無いから」ではなく、両方とも「モデルの推論エンジン側がまだdoryという新しいアーキテクチャに対応していない」というエラーで止まる。
このモデル自体は何も壊れていないので、どこで何のエラーが出たのかを実際のログで残す。
ライセンス確認
モデルを試す前に、ライセンス全文を取得して確認した。
$ curl -sS raw.githubusercontent.com
OpenMDW-1.1は、著作権・特許・データベース・トレードシークレット権を含めてモデルを無制限に扱うことを無償で許諾する、実質MIT相当のパーミッシブなライセンスだった。
コピーレフト(派生物も同ライセンスで公開する義務)は無く、再配布時にライセンス全文と著作権表示を残すことだけが条件になっている。
モデルの出力物(生成結果)の利用にも制限を課さないと明記されている。
2026年11月5日時点ではLinux Foundation管理下でOSI承認審議中であり、まだOSI承認済みライセンスにはなっていない。
アーキテクチャの実際の構成
config.jsonを直接取得して、backlog調査時点の情報(8層の入力ブロック・20層の共有再帰ブロック・8層の出力ブロック)を確認した。
$ curl -sS huggingface.co
model_typeは"dory"、architecturesは["DoryForCausalLM"]。
n_input_layers: 16 n_recurrent_layers: 40 n_output_layers: 16(合計72)という値が入っているが、これはAttention/MLPのサブレイヤーをそれぞれ1としてカウントした数で、2で割ると入力8ブロック・再帰20ブロック・出力8ブロックになり、事前に調べていた概要と一致した。
n_recurrent_loopsはこのBF16版のconfigでは既定2。
sliding_attention層(theta=10000)とfull_attention層(theta=10000000)を交互に使い分けており、256Kコンテキストに対応している。
1つ目: transformersのサンプルコードをそのまま動かす
モデルカードのtransformersサンプルは次のように書かれている。
pip install -U transformers accelerate
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"nvidia/NVIDIA-Nemotron-Labs-Dory1.0-4B-BF16", device_map="auto"
)
trust_remote_codeやカスタムコードの指定は書かれておらず、「pipでtransformersを更新するだけで動く」という体裁になっている。
2026年11月5日時点のPyPI最新安定版(transformers 5.22.1)を実際に入れて試した。
$ pip install "transformers>=4.57" accelerate
$ python3 -c "
from transformers import AutoConfig
AutoConfig.from_pretrained('nvidia/NVIDIA-Nemotron-Labs-Dory1.0-4B-BF16')
"
実際に出たエラーはこちらである。
ValueError: The checkpoint you are trying to load has model type dory but Transformers does not
recognize this architecture. This could be because of an issue with the checkpoint, or because
your version of Transformers is out of date.
You can update Transformers with the command pip install --upgrade transformers. If this does
not work, and the checkpoint is very new, then there may not be a release version that supports
this model yet. In this case, you can get the most up-to-date code by installing Transformers
from source with the command pip install git+https://github.com/huggingface/transformers.git
つまり、モデルカードのサンプルコードが前提にしているdoryアーキテクチャは、2026年11月5日時点のPyPI安定版にはまだ入っていない。
エラーメッセージ自体がGitHub mainからの再インストールを案内しているが、それが実際にdoryに対応しているかどうかは、この時点では未確認のままになった(後述)。
2つ目: llama.cpp(GGUF)をそのまま動かす
モデルカードはGGUF版について「ループ構造に対応したllama.cppのフォーク(PR ggml-org/llama.cpp#30306相当)が必要で、素のllama.cpp/Ollamaは未対応」と明記している。
この主張を、フォークをビルドせずに検証できる方法(PyPIで配布されているllama-cpp-pythonが内部にバンドルしている素のllama.cpp C++コード)で確認した。
$ pip install llama-cpp-python
ビルド成功: llama_cpp_python-0.3.36
$ curl -sS -L -o dory-q5_k_m.gguf \
"huggingface.co"
$ sha256sum dory-q5_k_m.gguf
96080be49ffd67b916018b7bdef8c484762576fb52780e10ab98ac4978a660e0
このSHA-256はモデルカード記載の値と完全に一致しており、公式配布物そのものをダウンロードできていることを確認した。
これを素のllama-cpp-pythonでロードしようとした。
$ python3 -c "
from llama_cpp import Llama
Llama(model_path='dory-q5_k_m.gguf', n_ctx=512, verbose=True)
"
GGUFのヘッダ(メタデータ)自体は正しく読み込まれ、dory.num_loops = 4やdory.recurrent_layer_count = 40といった値もログに表示された。
GGUFのファイル形式としては壊れていないということである。
しかし実際のモデルロードは次のエラーで止まった。
print_info: file format = GGUF V3 (latest)
print_info: file type = Q5_K - Medium
print_info: file size = 3.41 GiB (7.38 BPW)
llama_model_load: error loading model: unknown model architecture: 'dory'
llama_model_load_from_file_impl: failed to load model
モデルカードの記述(素のllama.cpp/Ollamaは未対応)は、実際に手元で動かしても確かにその通りだった。
ここまでの経路はどちらも、同じ理由で止まっている
transformersもllama.cppも、「ファイル自体は正しく読める」「しかしdoryという新しいアーキテクチャの実装がまだ入っていない」という同じ理由で止まった。
GPUが無いから遅い、メモリが足りない、といった計算資源の問題ではなく、推論エコシステム側の対応がまだ追いついていないという話である。
論文公開直後のモデルではよくあることだが、「モデルカードに書かれた手順をそのままコピーすれば動く」と思って試すと、現時点ではここで止まる。
モデルカードはこの先の回避策として、(1)transformersをGitHub本家リポジトリのmain branchから入れ直す、(2)専用フォークのllama.cpp(brianchmielNV/llama.cpp、特定コミットにpin)をビルドする、という2つの道を示している。
筆者の作業環境(Claude Code Routineのクラウド実行環境)では、外部ソースから取得した未レビューのコードをビルド・インストールする操作自体がセキュリティポリシーでブロックされており、この2つの回避策を実際に試すことができなかった。
ここは「動かした結果」ではなく「まだ試せていない」として正直に書く。
ローカルPCのGPU環境で両方を実際に試した結果を次節に書く。
ローカルPCで2つの回避策を実際に試した
transformersのGitHub mainは、まだdoryに対応していなかった
エラーメッセージが案内するとおり、GitHub本家のmain branchからtransformersを入れ直した。
$ pip install -U "git+huggingface/transformers"
インストール成功: transformers 5.23.0.dev0
$ python3 -c "
from transformers import AutoConfig
AutoConfig.from_pretrained('nvidia/NVIDIA-Nemotron-Labs-Dory1.0-4B-BF16')
"
結果は同じエラーだった。
KeyError: 'dory'
...
ValueError: The checkpoint you are trying to load has model type dory but Transformers does not
recognize this architecture. ...
つまり、エラーメッセージ自身が案内する回避策が、少なくとも2026年11月5日時点のmain branchではまだ機能していない。
doryアーキテクチャの実装はtransformers本体にはまだ入っていないということである。
専用フォーク版llama.cppはビルドでき、ループ回数1と4を実際に比較できた
もう一つの回避策、モデルカード記載の専用フォーク(brianchmielNV/llama.cpp、指定コミットにpin)をビルドした。
$ REV=98a74c97ea09ac72f6ceda1559808fc0a2f447ce
$ git clone brianchmielNV/llama.cpp llama.cpp-dory
$ git -C llama.cpp-dory checkout --detach "$REV"
$ cmake -S llama.cpp-dory -B llama.cpp-dory/build \
-DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON -DGGML_CUDA_GRAPHS=ON -DCMAKE_CUDA_ARCHITECTURES=120
$ cmake --build llama.cpp-dory/build --target llama-server --parallel
ビルドは成功し、素のllama.cppではunknown model architecture: 'dory'で止まっていた同じGGUFファイル(SHA-256一致済み)を、今度は問題なくロードできた。
ループ回数1と4のそれぞれでサーバーを起動し、--override-kv dory.num_loops=int:1,dory.recurrent_kv_cache_mode=str:per_loopで切り替えながら、同一の算数問題(「電車が120kmを2時間、続けて180kmを3時間走った。全体の平均速度は?」)をtemperature=0で投げて比較した。
num_loops=1
num_loops=4
応答
正解(60 km/h)
正解(60 km/h)
completion_tokens
1130
1157
所要時間(壁時計)
39.97秒
129.23秒
両方とも同じ正解(60 km/h)に到達したが、出力トークン数はほとんど変わらず(むしろ4ループの方が少し多い)、生成時間だけがループ回数4で約3.2倍に伸びた。
論文がSWE-bench VerifiedやGDPval-AAのような難しいタスクで報告している「ループを増やすほど出力トークン数が減る」という効果は、今回使ったような元々思考過程が短い単純な算数問題では現れず、単純にループ回数分だけ1トークンあたりの計算が増えて遅くなる、という素直な結果になった。
まとめ
OpenMDW-1.1ライセンスは実質MIT相当で、商用利用を含め問題なく使える。
config.jsonから、backlog調査時点の「8層入力+20層再帰+8層出力」という構成を実機で確認した。
モデルカードのtransformersサンプルコードは、2026年11月5日時点のPyPI安定版(5.22.1)ではdoryアーキテクチャ未対応のため実際に動かなかった。
モデルカードのGGUF版も、SHA-256まで一致する公式配布ファイルを使っても、素のllama-cpp-pythonではunknown model architecture: 'dory'で実際に動かなかった。
ローカルPCのGPU環境で確認したところ、GitHub mainから入れ直したtransformers(5.23.0.dev0)でもdoryはまだ実装されておらず、エラーメッセージが案内する回避策自体が機能しなかった。
一方、モデルカード記載の専用フォーク版llama.cppはビルド・ロードに成功し、ループ回数1と4のBefore/After比較まで実施できた。単純な算数問題では出力トークン数は減らず、生成時間が約3.2倍に伸びるだけだった。論文が報告する「出力トークン削減」効果は、より複雑な推論タスクでなければ現れないと考えられる。
Rust + CUDA are coming to @hf.co kernel-builder. We just landed support for cuda-oxide and cutile-rs is up next!
Some example Rust kernels, including a flash-attn2 port to Rust and cuda-oxide:
huggingface/kernels-community-rs
#rust #cuda #gpu #kernels
4 likes
学習なしでLLMの思考ループは直せるのか——重みを2か所編集する研究を、自宅のDGX Sparkで追試した
はじめに
株式会社DeploAIで代表取締役CTOをしている袖山剛です。
営業を科学するプロダクトの開発と、お客様の業務にAIを組み込む仕事をしています。手元では DGX Spark 2台でオープンウェイトのモデルを動かしていて、論文やブログの主張を自分の機材で確かめるようにしています。
この記事で確かめるのは、Weight-Space Programming という報告です。GPT-6 Astra が Qwen3.5-0.8B の重みを直接書き換え、思考(thinking)が同じ文の繰り返しで終わらなくなる癖を直したというものです。ファインチューニング(データと逆伝播で重みを学習し直すこと)をせず、15層と19層の MLP の重みの一部だけを変えています。
答え:再現しました。 公開された編集済みの重みは、元のモデルの正答率を MATH-500 で 8.5% → 55.0%、GSM8K で 16.0% → 68.5% に上げました(各200問、同じ問題どうし)。報告の値は 7.9% → 48.1%、13.8% → 67.1% です。報告の編集を使わずに同じ手順を自分でやり直した編集でも 50.5%・65.5% になりました。
Qwen3.5-0.8B、各200問・1問1回答。思考 ON は上限 32,768 トークン、思考 OFF は 8,192。「打ち切り」は上限に達した回答の割合
結論:効いているのは、重みの中の「繰り返しの方向」を引くこと
報告の結果は、報告と同じ設定で再現した。 元のモデルは、MATH-500 の 91.5%、GSM8K の 86.0% の問題で同じ文を繰り返し、上限で打ち切られていました。編集後に新しく解けた問題(MATH 93問、GSM8K 107問)は、ほぼすべてがこの打ち切られていた問題です。逆に解けなくなったのは、合わせて2問でした。
同じ手順を独立にやり直しても、同じ層と、ほぼ同じ方向が見つかった。 自分で書いた例文8組から分析すると、報告と同じ15層・19層が選ばれ、方向の向きは報告の編集とコサイン類似度 0.80・0.78 でそろいました。この編集の正答率と報告の編集との差は、誤差の範囲でした(MATH −4.5 ± 3.1、GSM8K −3.0 ± 3.5 ポイント)。
大きさが同じでも、方向がランダムなら +10 ポイントにとどまる。 設定を変えるだけ(思考 OFF、temperature 1.0)でも、編集には届きませんでした。
数字の読み方を補います。± は、同じ問題で2つの条件を比べたときの、正誤の差の標準誤差です。各問題1回答なので、1問の結果には偶然が入ります。
元の報告は何を主張しているのか
小さなモデルの「考えすぎて終わらない」失敗は、重みの中の1つの方向として表れていて、そこを引けば直る、という主張です。 Qwen3.5-0.8B は思考を ON にすると、数学の問題で「もう一度確かめよう」のような文を延々と繰り返し、上限の 32,768 トークンで打ち切られることが多いモデルです。報告では、元のモデルの MATH-500 の回答の93%が打ち切られていました。
報告では GPT-6 Astra が、モデルの推論を流して内部を調べ、採点し、編集を試す作業を50回繰り返して、次の編集にたどり着きました(ログと重みの差分)。
書き換えたのは、15層と19層の MLP の出力側の重み(down_proj、1024×3584)の、それぞれ64列だけ
各層で「繰り返しの方向」u の成分を、その64列から引く
式にすると、選んだ列の集合を S として、次のとおりです。
W' = W - \alpha \, u \, \big(u^\top W\big)_S
(u^\top W)_S は、u^\top W のうち S の列だけを残し、ほかを0にした行ベクトルです。層ごとに rank-1 の変更で、重み全体に対する相対的な変化は約8〜11%です。
どうやって確かめたのか
報告の評価のコード(evaluate.py)と同じ設定にそろえ、同じ200問で条件どうしを対にして比べました。
項目
条件
モデル
Qwen/Qwen3.5-0.8B(報告と同じ revision 2fc06364)。報告の編集は、公開の差分から作り直し、編集したテンソルの sha256 が報告の記録と一致することを確かめた
生成
vLLM v0.30.0 のオフライン生成、bf16、seed 0。思考 ON、temperature 0.6、top_p 0.95、top_k 20、presence penalty 1.5、上限 32,768 トークン
問題
MATH-500(500問)と GSM8K の test(1,319問)から、それぞれ無作為に200問。全条件で同じ問題、1問1回答
採点
最後の </think> より後の、最後の \boxed{} を math-verify で正解と照らす
機材
生成は DGX Spark。1つの条件は1台で回し、違う条件を2台に振り分けて並べた。重みの分析と編集の作成は、別マシンの EVO-X2 の CPU
報告は全問を、MATH-500 は4回答・GSM8K は2回答ずつで測っています。今回は時間の都合で200問・1回答にしました。
比べた条件は次の6つです。
条件
中身
元のモデル
編集なし
報告の編集
報告で GPT-6 Astra が作った編集(p50c)
自分の編集
報告の編集の値は使わず、同じ手順で作り直したもの(次の節)
対照
自分の編集と同じ列・同じ大きさで、方向だけランダムにしたもの
思考 OFF
元のモデル。モデルカードの思考 OFF の設定(temperature 1.0、top_p 1.0、presence penalty 2.0)、上限 8,192
temperature 1.0
元のモデル。思考 ON のまま temperature だけ 1.0 にしたもの(時間の都合で100問ずつ)
同じ手順を自分でやり直すと、同じ編集になるのか
なりました。報告の探索の文とは別に例文を書いて分析しても、同じ2つの層と、ほぼ同じ方向が選ばれました。 手順は次のとおりで、勾配は一度も使っていません。推論(前向き計算)だけです。
同じ問題・同じ書き出しの後に、正しく進む続きと、確認の文を4回繰り返す続きを手で書く(学習用の分割の問題から8組。確認用に別の問題で6組)
両者の各層の残差ストリーム(層をまたいで流れる内部の主経路)を、最後の36トークンで平均して差をとる。これを各層の「繰り返しの方向」u とする
この方向を MLP がいちばん多く書き込む層を2つ選ぶ
各ニューロン j に「(繰り返すときの活性 − 進むときの活性)×(u^\top W の j 列目)」の点数を付け、上位64列について上の式で u の成分を引く。\alpha は6
結果は次のとおりです。
項目
自分の分析
選ばれた層
15層と19層(MLP の書き込みが大きい順に19・15・21。最終層は正規化の後の値なので除いた)
報告の編集との方向の一致
コサイン類似度 15層 0.80、19層 0.78
64列の重なり
15層 48列、19層 29列
確認用の6組での変化(1トークンあたりの対数尤度)
繰り返す続き −0.117、正しく進む続き −0.004(報告は −0.103、−0.009)
繰り返す続きだけが選んで起こりにくくなり、正しく進む続きはほとんど変わりません。\alpha を 2・4・6・8 と大きくすると、繰り返す続きの変化は −0.032・−0.072・−0.117・−0.168 と強まりました。\alpha=6 は、この例文での効き方を見て決めた値で、問題の正答率を見て調整してはいません。
本当に「方向」が効いているのか
効き目の大部分は方向によるものでした。ただし、方向がランダムでも0ではありませんでした。 対照は、自分の編集と同じ64列を、選んだ方向と直交するランダムな方向で、同じ大きさだけ変えたものです。
比べたもの
MATH-500
GSM8K
対照 − 元のモデル
+10.0 ± 2.6
+10.0 ± 3.2
自分の編集 − 元のモデル
+42.0 ± 3.5
+49.5 ± 3.6
自分の編集 − 対照
+32.0 ± 3.5
+39.5 ± 3.7
報告の編集 − 元のモデル
+46.5 ± 3.5
+52.5 ± 3.7
自分の編集と対照の片方だけが解けた問題は、MATH-500 で67対3、GSM8K で83対4でした。
対照で10ポイント上がった理由は、元のモデルが9割の問題で繰り返しに入っているため、重みを少し揺らすだけでも抜け出す回答があるからだと考えています。これは確かめていません。ランダムな方向は1つしか試しておらず、seed も1つです。
設定を変えるだけでは駄目なのか
改善はしますが、編集には届きませんでした。 0.8B のモデルでは、思考 ON にすると繰り返しに入る損が大きく、思考を OFF にするだけで正答率はかなり上がります。
条件
MATH-500
GSM8K
元のモデル(思考 ON)
8.5%
16.0%
思考 OFF
34.0%
46.0%
自分の編集(思考 ON)
50.5%
65.5%
報告の編集(思考 ON)
55.0%
68.5%
temperature を 1.0 にした条件は100問ずつで測り、同じ100問で元のモデルの 6問・17問 から 19問・37問 に増えました。同じ100問で、報告の編集は55問・70問、自分の編集は50問・66問です。
思考 OFF で打ち切られた回答(MATH-500 の52%)は、同じ文の繰り返しではありませんでした。上限の 8,192 トークンまで、繰り返さずに書き続けていました。
ファインチューニングとは何が違うのか
学習(勾配による重みの更新)をせず、推論だけで見つけた方向を、決めた場所に式で1回書き込む点が違います。 この種の手法は、モデル編集(model editing)や、内部表現の方向を扱う表現工学(representation engineering)と呼ばれる分野に入ります。
ファインチューニング
今回の重みの編集
使うデータ
数千〜数十万件の学習データ
対にした例文が数組(報告では、採点できる練習問題)
データの使い方
誤差を計算し、逆伝播で重みを更新する
推論を流し、内部の活性の差を測る
変える場所
重み全体、または LoRA などの追加部分
決めた2層の64列ずつ
同じ系統に、拒否の方向を重みから引いて消す directional ablation(abliteration とも呼ばれる)があります。推論のたびに内部の値へ方向を足し込む activation steering とは違い、変更は重みに入ります。そのため、普通の推論エンジンでそのまま動きます。今回も、改造していない vLLM で評価しました。
ただし、「データが要らない」わけではありません。方向を見つけるための例文と、効いたかを確かめる問題は必要です。また、今回の改善は新しい知識や能力を足したものではありません。元のモデルが解けるのに、繰り返しで打ち切られていた問題を救ったものです。
どれくらいの時間がかかったのか
生成に、2台それぞれで約5.5時間と約6.2時間かかりました。0.8B のモデルでも、長い思考の評価は重い作業です。 重みと作業領域は合わせて5GBほどで、割り当てたメモリのほとんどは、同時に約200本の長い回答を作るためのキャッシュです。
条件
時間(Spark 1台)
元のモデル
212分
対照
189分
自分の編集
105分
報告の編集
91分
temperature 1.0(100問ずつ)
93分
思考 OFF
16分
短い入力での処理量は1台あたり毎秒約3,300トークンでしたが、実際の評価では平均で毎秒930〜1,150トークンでした。終わりの近くでは、長い回答だけが残って同時に処理する本数が減るからです。繰り返しで上限まで書き続ける元のモデルと対照が、いちばん時間を使いました。
作業は Claude Code に任せました。私は確かめる範囲と機材の使い方を決め、結果と記録を確認しました。
まとめ
公開された編集は、報告どおりの成績を出しました。同じ手順を独立にやり直しても同じ層とほぼ同じ方向が見つかり、同じくらい効きました。効き目の大部分は、方向がランダムな対照(+10ポイント)との差から、繰り返しの方向を引いたことによるものです。
この記事が扱っていない範囲は次のとおりです。
GPT-6 Astra が編集を見つける過程そのものは、再現していません。自分の編集は、報告の「2層・64列・方向を引く」という形を知ったうえで作りました。形を知らずに見つけられるかは、確かめていません。
数学以外の課題(報告にある IFEval・MMLU-Pro・GPQA)と、ほかの数学の集合(AIME・AMC など)は測っていません。
報告と同じ規模(全問・複数回答)では測っていません。採点も、報告のコードではなく、同じ規則を自分で実装したものです。
ファインチューニングとの性能の比較はしていません。どちらが良いかは、この記事からは言えません。
参考文献
Weight-Space Programming(元の報告)
RikiyaT/lm_understand-logs(元の報告のログ・重みの差分・評価コード。4d09ba6d を参照)
Qwen/Qwen3.5-0.8B(モデルカード。思考 ON・OFF の推奨設定)
Hendrycks, D. et al. Measuring Mathematical Problem Solving With the MATH Dataset. 2021
Lightman, H. et al. Let's Verify Step by Step. 2023(MATH-500 の500問)
Cobbe, K. et al. Training Verifiers to Solve Math Word Problems. 2021(GSM8K)
Meng, K. et al. Locating and Editing Factual Associations in GPT. 2022(モデル編集)
Zou, A. et al. Representation Engineering: A Top-Down Approach to AI Transparency. 2023
Arditi, A. et al. Refusal in Language Models Is Mediated by a Single Direction. 2024(directional ablation)
Turner, A. et al. Steering Language Models With Activation Engineering. 2023(activation steering)
huggingface/Math-Verify(採点)
営業の受注率を上げるAIネイティブなサービス Intelligent Sales を開発しています。
筆者:袖山剛(株式会社DeploAI CTO)
線形代数・微積分・最適化・統計・ベイズ統計を学び直した記録を書いています。
Why the downvotes? Are people completely oblivious to huggingface/tau ? That far removed from the fact that the harness is not the TUI?
FineDNA: the largest dataset to teach any LLM DNA (midtraining, SFT, RL)
Hi everyone, we're releasing FineDNA, all the data we used to turn Qwen3-14B into Carbon-X, the strongest open language model on DNA. It contains:
- Midtraining: 300B+ tokens of genomes and DNA-rich text
- SFT: ~200K conversations
- RL: ~98K verifiable prompts
Code and recipe are open too, so you can apply it to other LLMs.
Dataset: huggingface.co
Code: huggingface/carbon
65 points · 5 comments
Open data and code to teach LLMs to read DNA
3 points
OpenAI, Hugging Face, Google: Why They All Reach for Rust
OpenAI rewrote Codex CLI in Rust. Hugging Face's tokenizers, safetensors, uv and Ruff all run on Rust. Why does a Python world keep reaching for it? The problem Rust solves (speed or safety), where it already runs in AI, what it honestly costs, and the plan for this series: Rust from zero, one picture at a time.
Chapters
0:00 AI keeps reaching for Rust
0:46 The problem: speed or safety
1:34 What Rust does differently
2:03 Does it work? Android's numbers
2:40 Where Rust runs in AI today
4:04 Is Rust replacing Python?
4:29 The honest cost
4:59 The plan: two playlists
5:28 What would you build?
Next: Episode 1: Your first Rust program
The whole series, in order: Learn Rust from Zero (Beginners) · Rust You Can See (playlist)
Sources
- OpenAI Codex CLI rewrite: codex#1174
- Hugging Face tokenizers: huggingface/tokenizers
- safetensors joins the PyTorch Foundation: pytorch.org
- uv: astral-sh/uv · Ruff: astral-sh/ruff
- Astral agrees to join OpenAI: astral.sh
- Microsoft, ~70% of CVEs are memory safety: microsoft.com
- Chromium memory safety: chromium.org
- Android memory safety: security.googleblog.com · blog.google
- The Case for Memory Safe Roadmaps (2023): cisa.gov
- Linux 6.1 (Rust support): kernelnewbies.org
- Stack Overflow 2025 survey: survey.stackoverflow.co
- GitHub Octoverse 2025: github.blog
- TypeScript's native port in Go: devblogs.microsoft.com
- Rust compiler performance survey 2025: blog.rust-lang.org
- Pydantic core: pydantic/pydantic-core · Polars: pola.rs
Ferris the crab is the Rust community's mascot (public domain, rustacean.net).
Rust You Can See is an independent series, not affiliated with or endorsed by the Rust Project or the Rust Foundation. Rust is a trademark of the Rust Foundation.
Narration: AI-generated voices.
#rust #learnrust #programming
[es] Por qué la IA se está pasando a Rust
[fr] Pourquoi l'IA se tourne vers Rust
[hi] AI अब Rust पर क्यों शिफ्ट हो रहा है?
[ja] なぜAIはRustへ移行しているのか
[ko] AI가 Rust로 옮겨가는 이유
[pt-BR] Por que a IA está migrando para Rust
4 likes · 1 comment · 352 views
TRL has day-0 support to post-train Le Chonk on a single node 🤯
LoRA SFT on a 1T-parameter model, training adapters on top of FP8 weights:
⚡ 32.7k tokens per step in ~8 seconds
💾 142 GiB per GPU on 8× B300
🔀 Expert parallelism + FSDP
Recipe: github.com/huggingface/trl/blob/ea936f801deeea713…
Open weights = open training after all ;)
32 likes · 3 reposts · 1,425 views
SafeAgents: an open-source proxy that checks every tool call your coding agent makes before it runs
SafeAgents is a small local proxy that sits between a coding agent and its model server. It checks each tool call in the model's response before the harness receives it. A call it flags is replaced with a short text notice, so the harness gets a plain text reply and runs nothing.
You point the agent's base URL at the proxy instead of the model server. All checks run locally on your machine: the proxy only forwards traffic to the model server you already use, and doesn't send your prompts, code or tool calls anywhere else unless you point the optional judge at a remote server. Each tool call goes through up to three checks:
1. Two local checks that only need the request: whether the tool was declared by the harness, and whether the call reaches a host that appears nowhere in the conversation. The model's own earlier turns don't count as a source, so a URL the model came up with on its own is flagged.
2. atif-scan by u/evalstate, which runs about 110 deterministic detectors on the pending call, in-process, with no model or network call: sandbox side channels, proxy and network bypasses, namespace escapes and reward hacking. Examples are curl to the cloud metadata endpoint, curl --noproxy posting ~/.netrc somewhere, or reading /proc/1/environ.
3. Optionally, a judge model for milder findings. It can be any OpenAI-compatible server, including a small model on your own machine through llama.cpp, so this step can stay local too. It answers allow or block as JSON. It sees only the user's request, the call and the findings, not the agent's reasoning or tool outputs. It can add blocks but not remove them.
Catching reward hacking in RL and evals
The same detectors cover the tool calls a policy makes to game its reward instead of solving the task: writing its own reward file, editing the verifier's tests, or patching pytest so everything passes. Since safeagents is just a proxy in front of an OpenAI-compatible server, it can sit in front of the inference server used for rollouts or eval runs. In --log-only mode it records these attempts without changing the trajectories, which gives a measure of how often a model tries to cheat. In blocking mode, the call is replaced with a notice and never runs.
Some practical details:
- It handles OpenAI Chat Completions and Anthropic Messages, streamed or not. Text is forwarded as it arrives; a tool call is held until its arguments are complete.
- The local checks take around 10–20 ms per call on an M-series Mac. The judge is only called for calls that already raised a finding.
- --log-only checks every call without changing anything, which is the recommended way to start. Hosts you trust can be added with --allow-host.
- The repo has setup guides for 12 harnesses. Six of them (pi, Claude Code, OpenCode, Qwen Code, OpenHands, DeepSeek Harness) are tested end to end in CI: the real harness runs through the proxy against a scripted model, and the tests check that flagged calls don't execute and clean ones do.
Next steps are a small fine-tuned decision model for malicious tool calls and a public benchmark for it. Reports of interesting catches and of false positives are both useful.
Apache 2.0, runs locally: huggingface/safeagents
96 points · 22 comments
Mentions
LLM 学習チェックポイントの設定をどう決めるか はじめに チェックポイントは、学習を中断した地点から再開するために、モデルとオプティマイザの状態をストレージに書き出したものです。1 回に書く量、保存の間隔、書き込みにかけてよい時間が、ストレージに必要な容量と書き込みスループットを決めます。この記事では、これらを決めるための数字を公開資料から整理し、予算内でできるだけ安い FSx for Lustre を見積もる流れを示します。例には、NVIDIA Nemotron 3.5 Super 120B-A12B(以下 Nemotron 3.5 Super)を 32 ノードで学習する場合を使います。 ! 実際に大規模な学習を運用していて、チェックポイントの設定やストレージの選び方について現場の知見をお持ちの方がいたら、ぜひコメントで教えてください。とても喜びます。 ! この記事が扱うのは、チェックポイントの書き込みです。Physical AI のように動画を大量に読む学習では、ストレージへの要求は読み込みが中心になり、話が変わります。たとえば Turing の記事は、7 台の車載カメラの動画を PB 級の規模で S3 から直接読むために、Range GET で必要な部分だけを取り、先読みで S3 のレイテンシーを隠しています。デコードの置き場所も設計の対象で、NVIDIA DALI の動画リーダーは GPU のハードウェアデコーダーで動画をデコードします。読み込みの設計は、この記事とは別に検討が必要です。 保存時の書き込み ZeRO-3 や FSDP、テンソル並列、パイプライン並列、エキスパート並列で学習する場合、モデルとオプティマイザの状態は全ノードに分割されて置かれています。これを PyTorch の Distributed Checkpoint や Megatron-LM の分散チェックポイントで共有ファイルシステムに保存すると、全ノードが同じタイミングで、それぞれが持つ分割をシャードとして書き込みます。データ並列で同じ値を持つ部分は、どれか 1 つのランクだけが書くように重複が除かれます。一方、DDP のように全ランクが同じ状態を持ち、1 つのランクだけがファイルに書く方式では、書き込みスループットの上限はそのノード 1 台で決まります。書き込み先には、EC2 のインスタンスストアとしてノードに付いたローカルの NVMe、全ノードが同じファイルシステムをマウントする FSx for Lustre、オブジェクトストレージの S3 があります。ただし、書き込み先によって必要な仕組みが違います。FSx for Lustre にはファイルシステム向けの書き込みでそのまま書けますが、S3 に直接書くには S3 向けの書き込みの実装が要り、ノードごとのローカル NVMe から再開するには、後の節で扱うローカルチェックポイントの仕組みが要ります。 ローカルの NVMe は、ノードごとに独立しているので、全体の書き込みスループットはノード数に比例して増えます。その代わり、そのノードが使えなくなると、書いたシャードも読めなくなります。FSx for Lustre は全ノードで共有され、ノードを失ってもデータは残ります。全体の書き込みスループットの基準値は、確保したストレージ容量と、作成時に選ぶ容量 1 TiB あたりのスループットの積で決まります。後者を、コンソールではストレージ単位あたりのスループット、API では PerUnitStorageThroughput と呼びます。S3 は容量を事前に確保する必要がなく、ノードを失ってもデータは残ります。 保存の方式には、同期と非同期があります。同期では、ストレージへの書き込みが終わるまで学習を止めます。非同期では、状態を GPU のメモリからホストのメモリへコピーする間だけ学習を止め、ストレージへの書き込みは学習と並行して進めます。どちらの方式でも、書き込みが完了するまでそのチェックポイントは再開に使えず、その間にジョブが中断すると、直近の書き込みが完了したチェックポイントから再開します。 非同期で短くなるのは学習が止まる時間 C です。中断したときに失う学習の時間は、保存の開始から書き込みの完了までの時間 t で決まり、同じ書き込みスループットなら同期と非同期で t はほぼ同じです。非同期で書き込みにかける時間を長くとるほど t は延び、失う学習の時間は長くなります。 設定を決める量 この記事で決める設定は、保存の間隔、同期か非同期か、ストレージの書き込みスループットと容量です。保存の回数を増やすほど学習が止まる時間の合計が増え、減らすほど中断したときに失う学習が増えるので、これらは次の量の関係で決まります。 記号 意味 S 全ノードを合計した、1 回のチェックポイントの大きさ C 1 回の保存で学習が止まる時間。同期では書き込みの完了まで、非同期ではホストのメモリへのコピーの間 t_a 非同期で、学習を再開してから書き込みが完了するまでの時間。同期では 0 t 保存の開始から書き込みの完了までの時間で、t = C + t_a t_w ストレージへの書き込みにかける時間。同期では C、非同期では t_a T 保存の開始から次の保存の開始までの間隔 M ジョブの平均中断間隔。故障を含め、チェックポイントからの再開が必要になる中断の平均間隔 R 中断してから学習を再開するまでの時間 \eta 学習時間のうち、保存で止まる時間と中断で失う時間を合わせて無駄になる割合 T^{*} \eta が最も小さくなる保存間隔 図の下段に並べた 2 つの式は、\eta の近似式と、そこから求めた T^{*} です。どちらも「保存間隔の決め方」の節で導きます。 S を t_w の間に書き終えるには、ストレージが 1 秒あたり S/t_w 以上を書ける必要があります。これが必要な書き込みスループット W の最小値です。t_w は測る値ではなく、同期なら学習を止めてよい時間、非同期なら次の保存までに書き終える時間として、設計する側が決める値です。実際には、書き込みの効率やほかの I/O との競合を見込んで、これより大きく確保します。 W = \frac{S}{t_w} チェックポイントの大きさ 重みのバイト数 2026 年 11 月に Hugging Face の API で取得した Nemotron 3.5 Super の BF16 版の重みのファイルサイズの合計は約 248.9 GB で、総パラメータ数の約 124.5B で割ると 1 パラメータあたり 2.0 バイトです。 MoE(Mixture of Experts)は、expert と呼ぶ複数の部分ネットワークのうち、トークンごとに一部だけを使うモデルです。1 トークンの計算に使うパラメータを活性パラメータと呼び、モデル名の 120B-A12B は総パラメータ約 120B、活性パラメータ約 12B を表します。保存では使われなかった expert の重みも書き出すので、チェックポイントの大きさは活性パラメータ数ではなく総パラメータ数に比例します。 再開に必要な状態 故障による中断や手動での一時停止で学習を止めたあと、止めた地点から同じように学習を再開するには、重みに加えて、オプティマイザの状態も保存します。混合精度の学習では、計算用の bf16 の重みに加えて、更新の丸め誤差をためないための fp32 の重みを持ちます。この fp32 の重みを master weight と呼びます。オプティマイザに Adam を使う場合、1 パラメータあたりのバイト数は次のとおりです。 状態 バイト数 bf16 の重み 2 fp32 の master weight 4 fp32 の Adam の 1 次と 2 次のモーメント 8 合計 14 この内訳は、Megatron-LM の distributed optimizer のように、bf16 の重みと fp32 の master weight を別々に持つ構成の値です。ZeRO の論文は、fp16 の重みと勾配で同じバイト数の内訳を示していて、勾配の 2 バイトを含めると 16 バイトです。FSDP2 を使う TorchTitan のように、分割して持つ重み自体が fp32 で、bf16 の重みは計算の間だけ作る構成では、保存するのは fp32 の重みとモーメントの 4 + 8 = 12 バイトです。モーメントを bf16 で持つ構成では 2 + 4 + 4 = 10 バイトになります。DeepSeek-V3 の技術報告は、AdamW の 1 次と 2 次のモーメントを bf16 で持ち、master weight を fp32 で持つと書いています。bf16 の重みと bf16 のモーメントだけを持ち、fp32 の重みを持たない構成では 2 + 4 = 6 バイトです。どの値になるかはフレームワークと設定で決まるので、実際に 1 回保存して確かめます。再開には、学習率のスケジューラ、ステップ数、乱数生成器、データの読み取り位置などの状態も必要ですが、これらは重みとオプティマイザの状態に比べて小さいので、大きさの計算では数えていません。 Nemotron 3.5 Super の大きさ 試算に使う Nemotron 3.5 Super の総パラメータ数は約 124.5B で、この値には画像エンコーダーのパラメータも含まれます。1 パラメータあたりのバイト数ごとに、チェックポイントの大きさ S と、32 ノードに均等に分けたときの 1 ノードあたりの大きさは次のとおりです。 保存する状態 1 パラメータあたり S 1 ノードあたり bf16 の重みだけ 2 バイト 約 0.25 TB 約 7.8 GB 重みとオプティマイザの状態 14 バイト 約 1.74 TB 約 54 GB モーメントを bf16 にした場合 10 バイト 約 1.24 TB 約 39 GB bf16 の重みと bf16 のモーメントだけの場合 6 バイト 約 0.75 TB 約 23 GB 画像エンコーダーを凍結して学習するなら、そのパラメータはオプティマイザの状態を持たないので、bf16 の重みの 2 バイトだけを保存すれば足ります。公開されている例では、awsome-distributed-ai の verl の例が、20B のモデルを GPU 12 枚で学習すると 1 つのチェックポイントが約 117 GB になると書いています。以降の試算では 14 バイトの約 1.74 TB を使い、最後に 6 バイトの場合の結果も示します。 公開事例の保存間隔 保存の間隔についての公開情報は乏しく、モデルの技術報告にはほとんど書かれていません。後の節で見るとおり、フレームワークに既定値がある場合も、時間ではなくステップ数で決まっています。時間で間隔を書いている公開事例は、次の表のように少数です。 出典 間隔 補足 BLOOM 176B 3 時間ごと。学習ログによると、計算機の保守の停止に備えて 100 ステップごとに変更 Hugging Face のブログによると 1 回が 2.3 TB、学習ログによると保存は 40 秒 DeepSeek の Fire-Flyer AI-HPC 5 分 保存と読み込みはどちらも数秒 Meta の信頼性の論文 大規模ジョブの典型は 1 時間 1,024 GPU のジョブの平均故障間隔は 7.9 時間 Unicron 30 分。再計算の時間を比べるために論文が置いた値 128 GPU のクラスターでの評価 ジョブの平均中断間隔 保存の間隔は、1 回の保存で止まる時間と、ジョブがどのくらいの頻度で中断するかの両方で決まります。次の表は、公開されている故障や中断の記録を、1 ノードに GPU 8 枚を積んだ 32 ノードのジョブの平均中断間隔に換算した値です。中断がノード数に比例して起きると仮定し、元の平均間隔を M_0、元のノード数を N_0 として M = M_0 N_0 / 32 で計算しました。ノード数は、論文の GPU 数を 1 ノード 8 GPU として割った値です。元の論文が数えた範囲、たとえば対象のクラスターや期間の取り方で値は変わるので、表の値は目安です。数えている事象は出典ごとに違い、GPU の故障、ハードウェアが原因の再起動、原因を問わない中断が混ざっているので、比べるときは注意が必要です。 出典 規模と期間 32 ノードに換算した平均中断間隔 Meta の信頼性の論文 128 ノード、1,024 GPU のジョブで 7.9 時間 約 32 時間 OPT-175B 124 ノード、60 日とみなした 2 か月で、ハードウェアの障害による手動の再起動が少なくとも 35 回、自動の再起動が 70 回以上 105 回で約 53 時間、35 回で約 159 時間 BLOOM 48 ノードで、GPU の故障が週 1〜2 回 約 126〜252 時間 Llama 3 2,048 ノード、54 日で 466 回の中断。うち想定外が 419 回で、その約 78%、約 327 回がハードウェアの問題と確認されたか、そう疑われた中断 466 回で約 178 時間、419 回で約 198 時間、327 回で約 254 時間 MegaScale 10,000 GPU を超える本番の学習で、3 週間とみなした数週間に 100 回を超える再起動。1,250 ノードとして計算 約 197 時間。GPU 数も回数も「超える」なので目安 Acme 588 ノード、182.5 日とみなした 6 か月で、ハードウェアが原因の故障が 103 件 約 781 時間 ネットワークの障害や、複数のノードがまとめて故障する場合があるので、ノード数に比例させる換算は目安です。ジョブの中断には GPU の故障のほかにネットワークやソフトウェアの障害も含まれるので、GPU の故障率だけからは M を決められません。参考として、NCSA Delta の研究は、GPU 1 枚あたりのメモリエラーの平均間隔を H100 で約 88,768 時間、A100 で約 283,271 時間と報告しています。B200 と B300 の故障率は公開されていません。 保存間隔の決め方 Young の式 保存間隔 T は、学習が止まる時間と、中断で失う学習の時間の合計が最も小さくなるように決めます。学習時間のうち無駄になる割合を \eta とすると、次の式で近似できます。 \eta \approx \frac{C}{T} + \frac{T/2 + t + R}{M} 第 1 項は、保存で学習が止まる分です。間隔 T ごとに C だけ止まるので、止まる割合は C/T です。 第 2 項は、中断で失う分です。1 回の中断で失う時間の期待値を T/2 + t + R とし、中断が平均 M に 1 回起きるので M で割ります。ここで t は、保存を始めてから書き込みが終わり、そのチェックポイントが再開に使えるようになるまでの時間です。 ! ここからの導出は、確率変数と期待値を使います。数理統計になじみがない方は、導出を飛ばして「1 回の中断で失う時間の平均は T/2 + t になる」という結論だけを眺めても、この先を読み進められます。内容は統計検定 2 級くらいなので、学んでおくと性能の見積もりなどいろいろな場面で役に立ちます。 T/2 + t は、次のように求まります。直近の保存を始めた時刻から中断までの経過時間を連続型の確率変数 X とし、中断は間隔のどこでも同じように起きる、つまり X が区間 [0, T) の連続一様分布に従うと仮定します。また、保存は予定どおり t < T で書き終わり、C は T より十分短いとします。 X \sim \mathrm{U}(0, T), \qquad E[X] = \frac{T}{2}, \qquad P(X < t) = \frac{t}{T} X \ge t なら直近の保存は書き終わっているので、やり直すのは X だけです。X < t なら直近の保存はまだ使えないので、1 つ前の保存まで戻り、さらに間隔 1 つ分の T をやり直します。やり直す時間を L とすると、指示関数 \mathbf{1}{X < t} を使って次のように書けます。 L = X + T \cdot \mathbf{1}{X < t} 期待値をとると、次のようになります。 E[L] = E[X] + T \cdot P(X < t) = \frac{T}{2} + T \cdot \frac{t}{T} = \frac{T}{2} + t 最悪の場合は X が t の直前のときで、L は T + t に近づきます。 これに再開までの時間 R を足したものが、1 回の中断で失う時間です。たとえば T が 45 分、t が 5 分なら、学習のやり直しは平均 22.5 分 + 5 分 = 27.5 分、最悪で 45 分 + 5 分 = 50 分です。 t と R が T によらないとすると、右辺を T で微分して 0 と置いた -C/T^2 + 1/(2M) = 0 から、最適な間隔は次のようになります。 T^{*} \approx \sqrt{2\,C\,M} この式は Young が 1974 年に示したもので、C \ll T \ll M のときに成り立ちます。C が M に比べて無視できない場合の補正は、Daly が 2006 年に加えています。 ! Young の式と Daly の補正は、HPC のチェックポイント研究で古くから使われてきた式です。もともとは、スーパーコンピューターで長時間の計算を故障に備えてどの間隔で保存するかを決めるためのものでした。大規模な LLM の学習でも同じ考え方が使われていて、Meta の信頼性の論文もこの形の式で保存の間隔を見積もっています。 M は、Llama 3 の換算値の約 178〜254 時間の範囲にある 200 時間とし、R は 15 分とします。 方式 M C t T^{*} \eta 同期 200 時間 5 秒 5 秒 約 45 分 約 0.50% 同期 200 時間 60 秒 60 秒 約 2.6 時間 約 1.42% 同期 200 時間 300 秒 300 秒 約 5.8 時間 約 3.05% 非同期 200 時間 5 秒 5 分 5 秒 約 45 分 約 0.54% 同期 約 32 時間 5 秒 5 秒 約 18 分 約 1.72% 同期 約 781 時間 5 秒 5 秒 約 88 分 約 0.22% 最後の 2 行は、M を前の節の表で最も短い Meta の換算値と、最も長い Acme の換算値にした場合で、T^{*} は M によって大きく変わります。 式の前提 この式は、故障が互いに独立で、故障の起きやすさが時間によらないこと、つまり故障間隔が指数分布に従うことを前提にしています。Aupy らの論文が引く Heien らの測定では、HPC システムの故障間隔は形状パラメータ 0.58〜0.71 の Weibull 分布に当てはまりました。Weibull 分布は、形状パラメータが 1 のとき指数分布と同じになり、1 より小さいほど故障の直後に次の故障が集中します。同じ論文は、形状パラメータ 0.5、2^{19} プロセスのシミュレーションで、Daly の式の間隔を使うと、論文が提案する間隔の場合より実行時間が約 61%、Young の式では約 50% 長くなったと報告しています。 平均中断間隔も一定ではないので、運用中に記録した中断から M を更新して、間隔を見直します。評価の節目、損失が急に悪化したときの巻き戻し、予約した計算資源の期限などでもチェックポイントから再開するので、これらの時刻に合わせて保存する場合もあります。 フレームワークの既定値 Megatron-LM、それを継承する Megatron Bridge、TorchTitan では、非同期の保存は既定で無効です。有効にしなければ同期で保存され、書き込みが終わるまで学習は止まります。次の表は、2026 年 10 月に取得したコミットのソースコードで確かめた既定値で、リンク先はそのコミットの該当行です。 フレームワーク 保存間隔の既定 非同期保存の既定 Megatron-LM 既定値はなしで、保存先を指定すると間隔の指定が必須 無効。分散チェックポイント形式で --use-persistent-ckpt-worker を指定しないと、有効にしても無効に戻される Megatron Bridge Megatron-LM の設定を継承 Megatron-LM の設定を継承するので無効。async_save で有効にする TorchTitan 500 ステップ 無効 Hugging Face Trainer 500 ステップ 非同期保存の機能はなく、save_steps ごとに同期で保存 ローカル NVMe と複製 前の節の非同期保存を一歩進めると、チェックポイントを短い間隔で各ノードのローカル NVMe に書き、共有ストレージへは長い間隔で書く方法があります。ローカル NVMe は書き込みが速いので、学習が止まる時間と、共有ストレージに必要な書き込みスループットを小さくできます。弱点は、そのノードを失うとローカルに書いた分も失うことです。NVIDIA Resiliency Extension は、このローカルへの保存を提供するライブラリで、ほかのノードに複製を持って冗長性を高める仕組みも備えています。ローカルに書いたチェックポイントを共有ストレージへ移す処理は含まず、共有ストレージへの保存は、通常のチェックポイントとして別に行います。この節では、この方法で何を守れて何を守れないかを整理します。次の図は、保存先ごとに、プロセスの再起動、1 ノードの喪失、クラスター全体の停止のあとでデータが残るかを示しています。 NVIDIA B300 を 8 枚積んだ p6-b300.48xlarge には、3,800 GB の NVMe SSD が 8 本、合計 30,400 GB のインスタンスストアがあり、1 ノードあたり約 54 GB のシャードを何世代分も置けます。共有ストレージへの転送が終わるまでは、そのノードが使えなくなるとシャードを失います。 NVIDIA Resiliency Extension のローカルチェックポイントは、Megatron-LM などの学習ループに組み込んで使い、各ノードの SSD か RAM ディスクに保存し、ほかのノードにも複製を持つことで、1 ノードを失っても複製からシャードを復元します。複製の組み方は設定で決め、保存と再開で同じ設定にする必要があります。 NVIDIA Resiliency Extension は、GPU 1 枚を受け持つプロセスであるランクを組にして、組の中で複製を持ち合います。組の作り方は、組の大きさ F と、組の中のランクの間隔 J の 2 つの設定で決まり、それぞれ replication_factor と replication_jump です。J の既定値は 1 ノードの GPU 数なので、組のランクは別々のノードに置かれ、組の中の F ノードが互いの分の複製をすべて持ちます。複製は既定では無効で、Megatron-LM では --replication で有効にします。F の既定値は NVIDIA Resiliency Extension でも Megatron-LM でも 2 です。ランクの総数が J \times F で割り切れないと、組を作る処理が止まります。p6-b300.48xlarge 32 台ではランクの総数が 256、J が 8 なので、F に使えるのは 1、2、4、8、16、32 です。 組を持っていても、故障したノードの分の複製を作り直す前に、同じ組のほかのノードもすべて失われると、そのシャードは失われます。この確率を、組に固定する NVIDIA Resiliency Extension の置き方と、比較のために複製先をランダムに選ぶ置き方で比べます。前提は次のとおりです。 前提 内容 ノード数 32 組の大きさ F 既定値の 2。原本を含めて 2 か所に置く 最初の故障 ノード A が故障する \Delta A の分の複製を作り直すまでの時間。例では 1 時間 M_n 1 ノードが失われてインスタンスストアのデータが読めなくなる平均間隔。例では 6,400 時間で、ジョブの中断がすべてノードの喪失によるとした多めの見積もり p ほかの各ノードが \Delta の間に失われる確率で、p \approx \Delta / M_n。例では約 0.016% 独立性 ほかのノードは互いに独立に失われる シャードの数 A が持つシャードは十分に多い 組に固定する場合 F = 2 では、A と組になるノード B が、A のシャードの複製をすべて持ちます。A のシャードを失うのは、B が \Delta の間に失われるときだけなので、確率は次のとおりです。 P_{\text{組}} = p 複製先をランダムに選ぶ場合 A の各シャードの複製を、ほかの 31 ノードからランダムに選んだ 1 台に置くとします。シャードが十分に多いと、31 ノードのどれにも A のどれかのシャードの複製があります。そのため、31 ノードのどれか 1 台が \Delta の間に失われれば、A のシャードのどれかを失います。31 台のどれも失われない確率は、各ノードが独立に確率 1 - p で残るので (1 - p)^{31} です。A のシャードを失う確率はその余事象なので、次のようになり、p が小さければ 31p で近似できます。 P_{\text{ランダム}} = 1 - (1 - p)^{31} \approx 31\, p 近似は、(1 - p)^{31} を二項定理で展開し、p が小さいときに p^2 以降の項を捨てたものです。 (1 - p)^{31} = 1 - 31p + \binom{31}{2}p^2 - \binom{31}{3}p^3 + \cdots \approx 1 - 31p 31p は、31 台それぞれが失われる確率 p を足した値です。2 台以上が同時に失われる場合を重ねて数えていますが、p が小さければその分は無視できます。前提の表の例の値では、正確な値が約 0.4832%、近似が約 0.4844% です。 前提の表の例の値を入れると、組に固定する場合は約 0.016%、ランダムに置く場合は約 0.48% で、ランダムに置くと約 31 倍になります。例の M_n は、ジョブの平均中断間隔 200 時間を 32 倍した値です。F を 4 にすると、組に固定する場合は組のほかの 3 台がすべて失われるときだけなので p^3、ランダムでは、シャードが十分に多く 3 台の組み合わせのどれにも複製があるとして、p が小さいときの近似で \binom{31}{3} p^3 = 4{,}495\, p^3 になり、どちらも桁違いに小さくなります。その代わり、各ノードが持つ複製の量は F に比例して増えます。 チェックポイントは、シャードが 1 つでも欠けると再開に使えません。そのため、ある世代のシャードを 1 つ失っても全部失っても、その世代は同じように使えなくなります。複数の世代を同じ組に置いている場合は、組を失えばそれらの世代をまとめて失い、共有ストレージにある世代まで戻ります。どちらの置き方でも失う世代の数は同じなので、確率が低い、組に固定する置き方のほうが有利です。置き方によってデータを失う組み合わせの数が変わることは、Copysets の論文が分散ストレージについて示しています。 この計算は故障が独立だという前提に立っているので、ラックや電源の障害で複数のノードがまとめて止まる場合や、クラスター全体が止まる場合には当てはまりません。その場合に備えて、FSx for Lustre か S3 にもコピーを置きます。 データが通る経路 チェックポイントのデータは、GPU のメモリからホストのメモリを経て、ローカル NVMe か、ネットワークインターフェースを通って共有ストレージへ書かれます。経路の途中にはそれぞれ上限があり、いちばん低い上限が書き込みスループットを決めます。 ローカル NVMe は PCIe でつながったノード内のディスクなので、ネットワークの帯域は効かず、ディスクの性能で決まります。S3、S3 Files、EFA を使わない FSx for Lustre は、ENA というネットワークインターフェースで TCP を使って通信します。EFA は、OS を通らずに SRD というプロトコルで通信するネットワークインターフェースで、EFA を有効にした FSx for Lustre との通信や、ノード間の集団通信に使います。 ネットワークインターフェースの帯域は、インスタンスの種類で大きく違います。 インスタンス ネットワークインターフェースの帯域 c6in.2xlarge 最大 40 Gbps、基準値 12.5 Gbps g6e.12xlarge 100 Gbps p6-b300.48xlarge 1 枚目のネットワークカードが 350 Gbps、ほかに 400 Gbps のネットワークカードが 16 枚あり、16 枚の合計は 6,400 Gbps TCP には、インスタンスの帯域とは別の上限もあります。EC2 の文書によると、同じクラスタープレイスメントグループにない相手との 1 本の TCP 接続は 5 Gbps までです。同じグループの中では 10 Gbps、同じ AZ で ENA Express を使えば 25 Gbps まで上がりますが、いずれにしても 1 本の接続には上限があります。S3 の性能のガイドラインも、多数の接続に分けて並列に送ることを勧めています。FSx for Lustre の文書は、クライアント 1 台あたりの最大スループットを、EFA を使わない場合は 100 Gbps、EFA では 700 Gbps、EFA と GPUDirect Storage では 1,200 Gbps としています。ENA で TCP を使う場合のもう 1 つの上限は、次の節で説明します。 FSx for Lustre の容量と書き込みスループット FSx for Lustre の SSD を使う Persistent 2 では、ディスクのスループットの基準値は確保したストレージ容量とストレージ単位あたりのスループットの積で決まり、ストレージ単位あたりのスループットは 125、250、500、1,000 MB/s/TiB から選びます。料金は使用量ではなく確保した容量にかかり、ストレージ容量の文書にあるとおり、容量は増やせますが減らせません。 容量は GiB で指定し、EFA を使わない場合は 1,200 GiB も選べます。それより大きい容量の単位はストレージサーバー 1 台あたりの容量で決まります。EFA を使わない場合は 2,400 GiB、EFA を使う場合は 125 MB/s/TiB で 38,400 GiB、250 MB/s/TiB で 19,200 GiB、500 MB/s/TiB で 9,600 GiB、1,000 MB/s/TiB で 4,800 GiB です。スループットの計算では、AWS の文書の例に合わせて 1,000 GiB を 1 TiB として扱います。EFA を使うファイルシステムは、スループットが 10 GB/s を超える場合に推奨されていて、作成後に EFA の有無もストレージ単位あたりのスループットも変えられません。EFA を使わない SSD のファイルシステムは、作成後にストレージ単位あたりのスループットを変更できます。 ストレージ単位あたりのスループットは、ディスクのスループットの基準値です。性能の表によると、125 MB/s/TiB と 250 MB/s/TiB には、ディスクのスループットを一時的に 500 MB/s/TiB まで上げるバーストがあり、500 MB/s/TiB と 1,000 MB/s/TiB にはありません。また、ENA で TCP を使って通信する場合、クライアント 1 台とストレージサーバー 1 台の間のトラフィックは 5 Gbps が上限なので、1 台のクライアントが書けるのは、ストレージサーバーの台数に 5 Gbps を掛けた値までです。 Nemotron 3.5 Super の S を 1.74 TB とすると、ストレージへの書き込みにかける時間 t_w ごとに必要な書き込みスループット W = S / t_w は次のとおりです。 t_w W 300 秒 約 5.8 GB/s 60 秒 約 29 GB/s 20 秒 約 87 GB/s 同期で保存するなら t_w がそのまま学習の止まる時間 C になるので、C を短くするほど確保する容量と料金が増えます。非同期なら C と t_w を別々に決められます。前回の書き込みが次の保存の開始までに終わっていない場合の動きは、フレームワークで違います。TorchTitan は前回の書き込みが終わるまで待つので、その分だけ学習が止まります。Megatron-LM と Megatron Bridge は警告を出して次の保存を始めるので、学習は止まりませんが、書き終わっていない書き込みが積み重なります。どちらでも重なりを避けるには W \ge S/(T - C) が必要で、T が約 45 分なら約 0.65 GB/s が下限です。t_w を長くすると W は小さくなりますが、t が延びるので中断で失う学習の時間 T + t と \eta は大きくなります。ローカルの NVMe を経由して共有ストレージへ転送する場合も、次の保存までに転送を終える必要があるので、平均で S/T 以上の書き込みスループットが要ります。 ! コラム: 保存で止まる GPU 時間と FSx for Lustre の料金のトレードオフ 同期で保存する場合、C を短くすると FSx for Lustre の料金は増えますが、保存で止まる GPU の時間は減ります。1 年間の学習で両者を比べると次のとおりです。前提は、S が 1.74 TB、p6-b300.48xlarge 32 台、M が 200 時間、T を Young の式で \sqrt{2CM} に置くことです。GPU の時間は、1 年の 8,760 時間に止まる割合 C/T を掛け、2026 年 11 月時点の p6-b300.48xlarge のオレゴンのオンデマンド料金、1 時間 142.416 ドルで金額にしました。FSx for Lustre は、各 C で最も安い構成の月額の 12 か月分で、必要な書き込みスループットが 10 GB/s を超える場合は EFA を使う構成にしています。 C 止まる GPU 時間/年 その金額/年 FSx for Lustre/年 合計/年 30 秒 約 10,200 GPU 時間 約 18.2 万ドル 約 44.9 万ドル 約 63.1 万ドル 60 秒 約 14,500 GPU 時間 約 25.8 万ドル 約 24.2 万ドル 約 50.0 万ドル 120 秒 約 20,500 GPU 時間 約 36.4 万ドル 約 13.8 万ドル 約 50.3 万ドル 300 秒 約 32,400 GPU 時間 約 57.6 万ドル 約 4.9 万ドル 約 62.5 万ドル 実際には GPU は年単位で確保していることが多く、保存で止まっても GPU の支払いは変わりません。その場合、止まる GPU 時間の金額は、その時間で行えたはずの追加の学習を金額に換算した機会費用として読みます。この考え方では、合計は C が 90 秒前後で最も小さく、年に約 46 万ドルです。この比較は保存で止まる時間だけを数えています。中断で失う学習も GPU 時間なので、それも足すと合計は年に約 76 万ドルになり、最も小さくなる C は 50 秒前後に移ります。C を短くしすぎると FSx for Lustre の料金が、長くしすぎると止まる GPU の時間が、合計を押し上げます。GPU の単価が予約や個別の価格で下がれば、最も小さくなる C は長い側へ動きます。非同期で保存できるなら、止まる時間はホストのメモリへのコピーの間だけになります。書き込みにかける時間は学習を止めずに長くとれるので、FSx for Lustre の料金と、中断で失う学習の時間の釣り合いだけで決められ、止まる GPU 時間の費用を小さくできます。Megatron-LM では分散チェックポイント形式と常駐の保存ワーカーが条件になるので、使っているフレームワークで有効にできるなら、非同期で保存するのがよいと考えます。 確保する容量は、残す世代数を k、ストレージ単位あたりのスループットを \tau、容量の単位を u として、次の式で決まります。容量は GiB で比べ、kS はバイト数を 2^{30} で割って GiB にし、W/\tau は MB/s を MB/s/TiB で割った値を 1,000 倍して GiB とします。 \text{確保する容量} = u \left\lceil \frac{\max\left(k S,\ W/\tau\right)}{u} \right\rceil Nemotron 3.5 Super で FSx for Lustre を見積もる 見積もりは、チェックポイントの設定を決め、そこから FSx for Lustre に必要な書き込みスループットと容量を逆算し、最も安い構成の月額を求める順に進めます。式はこれまでの節で説明したとおりで、計算の過程はこの節の最後の折りたたみにまとめました。 見積もる人が決める値 次の値を決めれば、見積もりができます。既存の環境で測れる値は測り、測れない値は右の概算から始めます。 値 決め方 測れないときの概算 この例の値 総パラメータ数 モデルの定義から読む なし 約 124.5B 1 パラメータあたりのバイト数 小さい構成で 1 回保存し、チェックポイントの大きさを総パラメータ数で割る bf16 の重み、fp32 の master weight、fp32 のモーメントなら 14、fp32 の重みとモーメントなら 12、モーメントが bf16 なら 10 14 ノード数 学習の計画から決める なし 32 同期か非同期か 使うフレームワークで非同期を有効にできるかで決める なし 非同期 保存で止まる時間 C 1 回保存し、学習のステップが止まった時間を測る 非同期は 1 ノード分を GPU からホストへ写す時間で、MegaScale と Fire-Flyer はどちらも数秒と報告している。同期は t_w と同じ 5 秒程度 書き込みにかける時間 t_w 予算と、中断で失ってよい学習の時間から決める なし 5 分または 20 分 平均中断間隔 M 既存のクラスターのジョブの中断を記録する ジョブの平均中断間隔の節の表から選ぶ 200 時間 再開までの時間 R 中断から再開までを 1 回試して測る 10 分にチェックポイントの読み込み時間を足す 約 15 分。FSx for Lustre の構成で変わる 残す世代数 k 何世代前まで戻れればよいかで決める 完了した 3 世代と書き込み中の 1 世代 4 EFA を使うか 必要な書き込みスループットが 10 GB/s を超えるなら、AWS の推奨に合わせて使う なし 使わない 料金 使うリージョンの料金ページで確かめる なし オレゴン 見積もりの結果 左のグラフは、書き込みにかける時間 t_w ごとに、FSx for Lustre の最も安い構成の月額を示します。右のグラフは、同じ t_w で、同期と非同期それぞれの無駄になる割合 \eta を示します。 t_w を延ばすほど必要な書き込みスループットが下がり、FSx for Lustre は安くなります。容量が残す世代を置く量で決まるところまで下がると、それ以上は安くなりません。 EFA を使う構成は容量の単位が大きいので、同じ書き込みスループットなら、EFA を使わない構成と同じか高くなります。10 GB/s を超える範囲では、AWS の推奨に合わせて EFA を使う構成で計算しています。 同期では t_w がそのまま学習の止まる時間になるので、\eta は t_w とともに急に増えます。非同期では止まる時間が数秒のままなので、t_w を延ばしても \eta はゆっくりしか増えません。 主な組み合わせの結果は次のとおりです。「最も安い構成」の列は、FSx for Lustre を作るときに選ぶ 2 つの値で、たとえば「250 MB/s/TiB、7,200 GiB」は、ストレージ単位あたりのスループットを 250 MB/s/TiB に、ストレージ容量を 7,200 GiB にすることを意味します。この構成の書き込みスループットの基準値は、7,200 GiB を 7.2 TiB として 250 MB/s/TiB を掛けた 1.8 GB/s です。250 MB/s/TiB 以下ではバーストで一時的にこれを超えられますが、見積もりでは基準値を使います。容量は、必要な書き込みスループットから出る容量と、残す世代を置く容量の大きいほうで決まるので、世代を置く容量で決まった場合は、基準値が必要な書き込みスループットより大きくなります。 チェックポイントの設定 必要な書き込みスループット 最も安い構成 書き込みスループットの基準値 容量を決めたもの 月額 \eta 14 バイト、非同期、20 分で書き終える 約 1.45 GB/s 250 MB/s/TiB、7,200 GiB 1.8 GB/s 世代を置く容量 約 1,500 ドル 約 0.76% 14 バイト、非同期、5 分で書き終える 約 5.8 GB/s 500 MB/s/TiB、12,000 GiB 6.0 GB/s 書き込みスループット 約 4,100 ドル 約 0.54% 6 バイト、非同期、5 分で書き終える 約 2.5 GB/s 500 MB/s/TiB、7,200 GiB 3.6 GB/s 書き込みスループット 約 2,400 ドル 約 0.53% 14 バイト、同期、60 秒で書き終える 約 29 GB/s EFA あり、1,000 MB/s/TiB、33,600 GiB 33.6 GB/s 書き込みスループット 約 20,200 ドル 約 1.39% この例では、非同期で 45 分ごとに保存し、20 分で書き終えればよいとすると、250 MB/s/TiB の 7,200 GiB、月額約 1,500 ドルで予算を見積もれます。中断で失う学習を減らしたい場合は、書き終える時間を 5 分に縮めて月額約 4,100 ドルで見積もります。 計算の過程: 14 バイト、非同期、5 分で書き終える場合 ノード数を N、総パラメータ数を P、1 パラメータあたりのバイト数を b とします。 チェックポイントの大きさと 1 ノードあたりの大きさ S = P \times b = 124.45 \times 10^{9} \times 14 \approx 1.74\ \text{TB}, \qquad \frac{S}{N} = \frac{1.74\ \text{TB}}{32} \approx 54\ \text{GB} 保存で止まる時間 C を 5 秒にするのに必要な、1 ノードあたりの GPU からホストへの転送 \frac{S/N}{C} = \frac{54\ \text{GB}}{5\ \text{s}} \approx 11\ \text{GB/s} 保存間隔 T^{*} = \sqrt{2CM} = \sqrt{2 \times 5\ \text{s} \times 720{,}000\ \text{s}} \approx 2{,}683\ \text{s} \approx 45\ \text{min} 必要な書き込みスループット W = \frac{S}{t_w} = \frac{1.74\ \text{TB}}{300\ \text{s}} \approx 5.8\ \text{GB/s} 確保する容量。kS を GiB にし、W/\tau は MB/s を MB/s/TiB で割った値を 1,000 倍して GiB にします。\tau = 500 MB/s/TiB、u = 2{,}400 GiB では次のとおりです。 kS = \frac{4 \times 1.742\ \text{TB}}{2^{30}} \approx 6{,}491\ \text{GiB}, \qquad \frac{W}{\tau} \times 1{,}000 = \frac{5{,}808}{500} \times 1{,}000 \approx 11{,}616\ \text{GiB} u \left\lceil \frac{\max(6{,}491,\ 11{,}616)}{2{,}400} \right\rceil = 2{,}400 \times 5 = 12{,}000\ \text{GiB} 月額。オレゴンの 500 MB/s/TiB の料金は GiB 月あたり 0.340 ドルです。 12{,}000\ \text{GiB} \times 0.340\ \text{USD} = 4{,}080\ \text{USD/month} 再開までの時間と無駄になる割合。この構成のスループットの基準値は 12{,}000 / 1{,}000 \times 500 = 6{,}000 MB/s で、読み込みも同じ程度出ると仮定すると、約 290 秒です。 R = 600 + \frac{1.74\ \text{TB}}{6.0\ \text{GB/s}} \approx 890\ \text{s}, \qquad t = C + t_w = 305\ \text{s} \eta = \frac{C}{T} + \frac{T/2 + t + R}{M} = \frac{5}{2{,}683} + \frac{1{,}341 + 305 + 890}{720{,}000} \approx 0.54\% 中断で失う学習の時間の上限は、T + t \approx 2{,}683 + 305 \approx 2{,}988 秒、約 50 分です。 ほかのストレージ単位あたりのスループットと EFA の有無で同じ計算をすると、次のようになります。 ストレージ単位あたりのスループット EFA なし EFA あり 125 MB/s/TiB 48,000 GiB、約 7,000 ドル/月 76,800 GiB、約 11,100 ドル/月 250 MB/s/TiB 24,000 GiB、約 5,000 ドル/月 38,400 GiB、約 8,100 ドル/月 500 MB/s/TiB 12,000 GiB、約 4,100 ドル/月 19,200 GiB、約 6,500 ドル/月 1,000 MB/s/TiB 7,200 GiB、約 4,300 ドル/月 9,600 GiB、約 5,800 ドル/月 まとめ FSx for Lustre をできるだけ安く見積もるには、先にチェックポイントの大きさ、保存間隔、書き込みにかける時間を決め、そこから必要な書き込みスループットと容量を逆算します。Nemotron 3.5 Super を 32 ノードで学習する例では、非同期で 45 分ごとに保存し、20 分で書き終えればよいとすると、250 MB/s/TiB の 7,200 GiB、月額約 1,500 ドルで足ります。書き込みにかける時間を延ばすほど FSx for Lustre は安くなりますが、中断で失う学習と再開の時間は延びるので、その釣り合いで決めます。ここでの値はどれも試算なので、実際の構成で保存と再開の時間、中断の頻度、書き込みスループットを測って置き換えてください。
NVIDIAの『ループ型』4Bモデル Dory1.0-4B、標準ツールで動かそうとしたら2箇所で止まった これは何を試した記事か NVIDIAが公開したDory1.0-4Bという4Bパラメータのモデルを、公式のモデルカードが案内するとおりの手順で動かそうとした記事である。 Dory1.0-4Bは、1つの重み(チェックポイント)のまま「再帰ブロックを何回ループさせるか」を1〜4回の間で切り替えることで、再学習なしに推論時の計算量と精度をトレードオフできる「ループ型Transformer」である。 出典は論文(huggingface.co )とモデル重みコレクション(huggingface.co )で、ライセンスはOpenMDW License Agreement version 1.1。 Zenn・Qiita・noteを検索した範囲では、2026年11月4日時点で日本語の一次検証記事は0件だった。 結論を先に書くと、モデルカードのサンプルコードをそのままコピーして動かすという最もハードルの低い経路は、2つとも実際に動かなかった。 「GPUが無いから」ではなく、両方とも「モデルの推論エンジン側がまだdoryという新しいアーキテクチャに対応していない」というエラーで止まる。 このモデル自体は何も壊れていないので、どこで何のエラーが出たのかを実際のログで残す。 ライセンス確認 モデルを試す前に、ライセンス全文を取得して確認した。 $ curl -sS raw.githubusercontent.com OpenMDW-1.1は、著作権・特許・データベース・トレードシークレット権を含めてモデルを無制限に扱うことを無償で許諾する、実質MIT相当のパーミッシブなライセンスだった。 コピーレフト(派生物も同ライセンスで公開する義務)は無く、再配布時にライセンス全文と著作権表示を残すことだけが条件になっている。 モデルの出力物(生成結果)の利用にも制限を課さないと明記されている。 2026年11月5日時点ではLinux Foundation管理下でOSI承認審議中であり、まだOSI承認済みライセンスにはなっていない。 アーキテクチャの実際の構成 config.jsonを直接取得して、backlog調査時点の情報(8層の入力ブロック・20層の共有再帰ブロック・8層の出力ブロック)を確認した。 $ curl -sS huggingface.co model_typeは"dory"、architecturesは["DoryForCausalLM"]。 n_input_layers: 16 n_recurrent_layers: 40 n_output_layers: 16(合計72)という値が入っているが、これはAttention/MLPのサブレイヤーをそれぞれ1としてカウントした数で、2で割ると入力8ブロック・再帰20ブロック・出力8ブロックになり、事前に調べていた概要と一致した。 n_recurrent_loopsはこのBF16版のconfigでは既定2。 sliding_attention層(theta=10000)とfull_attention層(theta=10000000)を交互に使い分けており、256Kコンテキストに対応している。 1つ目: transformersのサンプルコードをそのまま動かす モデルカードのtransformersサンプルは次のように書かれている。 pip install -U transformers accelerate from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained( "nvidia/NVIDIA-Nemotron-Labs-Dory1.0-4B-BF16", device_map="auto" ) trust_remote_codeやカスタムコードの指定は書かれておらず、「pipでtransformersを更新するだけで動く」という体裁になっている。 2026年11月5日時点のPyPI最新安定版(transformers 5.22.1)を実際に入れて試した。 $ pip install "transformers>=4.57" accelerate $ python3 -c " from transformers import AutoConfig AutoConfig.from_pretrained('nvidia/NVIDIA-Nemotron-Labs-Dory1.0-4B-BF16') " 実際に出たエラーはこちらである。 ValueError: The checkpoint you are trying to load has model type dory but Transformers does not recognize this architecture. This could be because of an issue with the checkpoint, or because your version of Transformers is out of date. You can update Transformers with the command pip install --upgrade transformers. If this does not work, and the checkpoint is very new, then there may not be a release version that supports this model yet. In this case, you can get the most up-to-date code by installing Transformers from source with the command pip install git+https://github.com/huggingface/transformers.git つまり、モデルカードのサンプルコードが前提にしているdoryアーキテクチャは、2026年11月5日時点のPyPI安定版にはまだ入っていない。 エラーメッセージ自体がGitHub mainからの再インストールを案内しているが、それが実際にdoryに対応しているかどうかは、この時点では未確認のままになった(後述)。 2つ目: llama.cpp(GGUF)をそのまま動かす モデルカードはGGUF版について「ループ構造に対応したllama.cppのフォーク(PR ggml-org/llama.cpp#30306相当)が必要で、素のllama.cpp/Ollamaは未対応」と明記している。 この主張を、フォークをビルドせずに検証できる方法(PyPIで配布されているllama-cpp-pythonが内部にバンドルしている素のllama.cpp C++コード)で確認した。 $ pip install llama-cpp-python ビルド成功: llama_cpp_python-0.3.36 $ curl -sS -L -o dory-q5_k_m.gguf \ "huggingface.co" $ sha256sum dory-q5_k_m.gguf 96080be49ffd67b916018b7bdef8c484762576fb52780e10ab98ac4978a660e0 このSHA-256はモデルカード記載の値と完全に一致しており、公式配布物そのものをダウンロードできていることを確認した。 これを素のllama-cpp-pythonでロードしようとした。 $ python3 -c " from llama_cpp import Llama Llama(model_path='dory-q5_k_m.gguf', n_ctx=512, verbose=True) " GGUFのヘッダ(メタデータ)自体は正しく読み込まれ、dory.num_loops = 4やdory.recurrent_layer_count = 40といった値もログに表示された。 GGUFのファイル形式としては壊れていないということである。 しかし実際のモデルロードは次のエラーで止まった。 print_info: file format = GGUF V3 (latest) print_info: file type = Q5_K - Medium print_info: file size = 3.41 GiB (7.38 BPW) llama_model_load: error loading model: unknown model architecture: 'dory' llama_model_load_from_file_impl: failed to load model モデルカードの記述(素のllama.cpp/Ollamaは未対応)は、実際に手元で動かしても確かにその通りだった。 ここまでの経路はどちらも、同じ理由で止まっている transformersもllama.cppも、「ファイル自体は正しく読める」「しかしdoryという新しいアーキテクチャの実装がまだ入っていない」という同じ理由で止まった。 GPUが無いから遅い、メモリが足りない、といった計算資源の問題ではなく、推論エコシステム側の対応がまだ追いついていないという話である。 論文公開直後のモデルではよくあることだが、「モデルカードに書かれた手順をそのままコピーすれば動く」と思って試すと、現時点ではここで止まる。 モデルカードはこの先の回避策として、(1)transformersをGitHub本家リポジトリのmain branchから入れ直す、(2)専用フォークのllama.cpp(brianchmielNV/llama.cpp、特定コミットにpin)をビルドする、という2つの道を示している。 筆者の作業環境(Claude Code Routineのクラウド実行環境)では、外部ソースから取得した未レビューのコードをビルド・インストールする操作自体がセキュリティポリシーでブロックされており、この2つの回避策を実際に試すことができなかった。 ここは「動かした結果」ではなく「まだ試せていない」として正直に書く。 ローカルPCのGPU環境で両方を実際に試した結果を次節に書く。 ローカルPCで2つの回避策を実際に試した transformersのGitHub mainは、まだdoryに対応していなかった エラーメッセージが案内するとおり、GitHub本家のmain branchからtransformersを入れ直した。 $ pip install -U "git+huggingface/transformers" インストール成功: transformers 5.23.0.dev0 $ python3 -c " from transformers import AutoConfig AutoConfig.from_pretrained('nvidia/NVIDIA-Nemotron-Labs-Dory1.0-4B-BF16') " 結果は同じエラーだった。 KeyError: 'dory' ... ValueError: The checkpoint you are trying to load has model type dory but Transformers does not recognize this architecture. ... つまり、エラーメッセージ自身が案内する回避策が、少なくとも2026年11月5日時点のmain branchではまだ機能していない。 doryアーキテクチャの実装はtransformers本体にはまだ入っていないということである。 専用フォーク版llama.cppはビルドでき、ループ回数1と4を実際に比較できた もう一つの回避策、モデルカード記載の専用フォーク(brianchmielNV/llama.cpp、指定コミットにpin)をビルドした。 $ REV=98a74c97ea09ac72f6ceda1559808fc0a2f447ce $ git clone brianchmielNV/llama.cpp llama.cpp-dory $ git -C llama.cpp-dory checkout --detach "$REV" $ cmake -S llama.cpp-dory -B llama.cpp-dory/build \ -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON -DGGML_CUDA_GRAPHS=ON -DCMAKE_CUDA_ARCHITECTURES=120 $ cmake --build llama.cpp-dory/build --target llama-server --parallel ビルドは成功し、素のllama.cppではunknown model architecture: 'dory'で止まっていた同じGGUFファイル(SHA-256一致済み)を、今度は問題なくロードできた。 ループ回数1と4のそれぞれでサーバーを起動し、--override-kv dory.num_loops=int:1,dory.recurrent_kv_cache_mode=str:per_loopで切り替えながら、同一の算数問題(「電車が120kmを2時間、続けて180kmを3時間走った。全体の平均速度は?」)をtemperature=0で投げて比較した。 num_loops=1 num_loops=4 応答 正解(60 km/h) 正解(60 km/h) completion_tokens 1130 1157 所要時間(壁時計) 39.97秒 129.23秒 両方とも同じ正解(60 km/h)に到達したが、出力トークン数はほとんど変わらず(むしろ4ループの方が少し多い)、生成時間だけがループ回数4で約3.2倍に伸びた。 論文がSWE-bench VerifiedやGDPval-AAのような難しいタスクで報告している「ループを増やすほど出力トークン数が減る」という効果は、今回使ったような元々思考過程が短い単純な算数問題では現れず、単純にループ回数分だけ1トークンあたりの計算が増えて遅くなる、という素直な結果になった。 まとめ OpenMDW-1.1ライセンスは実質MIT相当で、商用利用を含め問題なく使える。 config.jsonから、backlog調査時点の「8層入力+20層再帰+8層出力」という構成を実機で確認した。 モデルカードのtransformersサンプルコードは、2026年11月5日時点のPyPI安定版(5.22.1)ではdoryアーキテクチャ未対応のため実際に動かなかった。 モデルカードのGGUF版も、SHA-256まで一致する公式配布ファイルを使っても、素のllama-cpp-pythonではunknown model architecture: 'dory'で実際に動かなかった。 ローカルPCのGPU環境で確認したところ、GitHub mainから入れ直したtransformers(5.23.0.dev0)でもdoryはまだ実装されておらず、エラーメッセージが案内する回避策自体が機能しなかった。 一方、モデルカード記載の専用フォーク版llama.cppはビルド・ロードに成功し、ループ回数1と4のBefore/After比較まで実施できた。単純な算数問題では出力トークン数は減らず、生成時間が約3.2倍に伸びるだけだった。論文が報告する「出力トークン削減」効果は、より複雑な推論タスクでなければ現れないと考えられる。
Rust + CUDA are coming to @hf.co kernel-builder. We just landed support for cuda-oxide and cutile-rs is up next! Some example Rust kernels, including a flash-attn2 port to Rust and cuda-oxide: huggingface/kernels-community-rs #rust #cuda #gpu #kernels
学習なしでLLMの思考ループは直せるのか——重みを2か所編集する研究を、自宅のDGX Sparkで追試した はじめに 株式会社DeploAIで代表取締役CTOをしている袖山剛です。 営業を科学するプロダクトの開発と、お客様の業務にAIを組み込む仕事をしています。手元では DGX Spark 2台でオープンウェイトのモデルを動かしていて、論文やブログの主張を自分の機材で確かめるようにしています。 この記事で確かめるのは、Weight-Space Programming という報告です。GPT-6 Astra が Qwen3.5-0.8B の重みを直接書き換え、思考(thinking)が同じ文の繰り返しで終わらなくなる癖を直したというものです。ファインチューニング(データと逆伝播で重みを学習し直すこと)をせず、15層と19層の MLP の重みの一部だけを変えています。 答え:再現しました。 公開された編集済みの重みは、元のモデルの正答率を MATH-500 で 8.5% → 55.0%、GSM8K で 16.0% → 68.5% に上げました(各200問、同じ問題どうし)。報告の値は 7.9% → 48.1%、13.8% → 67.1% です。報告の編集を使わずに同じ手順を自分でやり直した編集でも 50.5%・65.5% になりました。 Qwen3.5-0.8B、各200問・1問1回答。思考 ON は上限 32,768 トークン、思考 OFF は 8,192。「打ち切り」は上限に達した回答の割合 結論:効いているのは、重みの中の「繰り返しの方向」を引くこと 報告の結果は、報告と同じ設定で再現した。 元のモデルは、MATH-500 の 91.5%、GSM8K の 86.0% の問題で同じ文を繰り返し、上限で打ち切られていました。編集後に新しく解けた問題(MATH 93問、GSM8K 107問)は、ほぼすべてがこの打ち切られていた問題です。逆に解けなくなったのは、合わせて2問でした。 同じ手順を独立にやり直しても、同じ層と、ほぼ同じ方向が見つかった。 自分で書いた例文8組から分析すると、報告と同じ15層・19層が選ばれ、方向の向きは報告の編集とコサイン類似度 0.80・0.78 でそろいました。この編集の正答率と報告の編集との差は、誤差の範囲でした(MATH −4.5 ± 3.1、GSM8K −3.0 ± 3.5 ポイント)。 大きさが同じでも、方向がランダムなら +10 ポイントにとどまる。 設定を変えるだけ(思考 OFF、temperature 1.0)でも、編集には届きませんでした。 数字の読み方を補います。± は、同じ問題で2つの条件を比べたときの、正誤の差の標準誤差です。各問題1回答なので、1問の結果には偶然が入ります。 元の報告は何を主張しているのか 小さなモデルの「考えすぎて終わらない」失敗は、重みの中の1つの方向として表れていて、そこを引けば直る、という主張です。 Qwen3.5-0.8B は思考を ON にすると、数学の問題で「もう一度確かめよう」のような文を延々と繰り返し、上限の 32,768 トークンで打ち切られることが多いモデルです。報告では、元のモデルの MATH-500 の回答の93%が打ち切られていました。 報告では GPT-6 Astra が、モデルの推論を流して内部を調べ、採点し、編集を試す作業を50回繰り返して、次の編集にたどり着きました(ログと重みの差分)。 書き換えたのは、15層と19層の MLP の出力側の重み(down_proj、1024×3584)の、それぞれ64列だけ 各層で「繰り返しの方向」u の成分を、その64列から引く 式にすると、選んだ列の集合を S として、次のとおりです。 W' = W - \alpha \, u \, \big(u^\top W\big)_S (u^\top W)_S は、u^\top W のうち S の列だけを残し、ほかを0にした行ベクトルです。層ごとに rank-1 の変更で、重み全体に対する相対的な変化は約8〜11%です。 どうやって確かめたのか 報告の評価のコード(evaluate.py)と同じ設定にそろえ、同じ200問で条件どうしを対にして比べました。 項目 条件 モデル Qwen/Qwen3.5-0.8B(報告と同じ revision 2fc06364)。報告の編集は、公開の差分から作り直し、編集したテンソルの sha256 が報告の記録と一致することを確かめた 生成 vLLM v0.30.0 のオフライン生成、bf16、seed 0。思考 ON、temperature 0.6、top_p 0.95、top_k 20、presence penalty 1.5、上限 32,768 トークン 問題 MATH-500(500問)と GSM8K の test(1,319問)から、それぞれ無作為に200問。全条件で同じ問題、1問1回答 採点 最後の </think> より後の、最後の \boxed{} を math-verify で正解と照らす 機材 生成は DGX Spark。1つの条件は1台で回し、違う条件を2台に振り分けて並べた。重みの分析と編集の作成は、別マシンの EVO-X2 の CPU 報告は全問を、MATH-500 は4回答・GSM8K は2回答ずつで測っています。今回は時間の都合で200問・1回答にしました。 比べた条件は次の6つです。 条件 中身 元のモデル 編集なし 報告の編集 報告で GPT-6 Astra が作った編集(p50c) 自分の編集 報告の編集の値は使わず、同じ手順で作り直したもの(次の節) 対照 自分の編集と同じ列・同じ大きさで、方向だけランダムにしたもの 思考 OFF 元のモデル。モデルカードの思考 OFF の設定(temperature 1.0、top_p 1.0、presence penalty 2.0)、上限 8,192 temperature 1.0 元のモデル。思考 ON のまま temperature だけ 1.0 にしたもの(時間の都合で100問ずつ) 同じ手順を自分でやり直すと、同じ編集になるのか なりました。報告の探索の文とは別に例文を書いて分析しても、同じ2つの層と、ほぼ同じ方向が選ばれました。 手順は次のとおりで、勾配は一度も使っていません。推論(前向き計算)だけです。 同じ問題・同じ書き出しの後に、正しく進む続きと、確認の文を4回繰り返す続きを手で書く(学習用の分割の問題から8組。確認用に別の問題で6組) 両者の各層の残差ストリーム(層をまたいで流れる内部の主経路)を、最後の36トークンで平均して差をとる。これを各層の「繰り返しの方向」u とする この方向を MLP がいちばん多く書き込む層を2つ選ぶ 各ニューロン j に「(繰り返すときの活性 − 進むときの活性)×(u^\top W の j 列目)」の点数を付け、上位64列について上の式で u の成分を引く。\alpha は6 結果は次のとおりです。 項目 自分の分析 選ばれた層 15層と19層(MLP の書き込みが大きい順に19・15・21。最終層は正規化の後の値なので除いた) 報告の編集との方向の一致 コサイン類似度 15層 0.80、19層 0.78 64列の重なり 15層 48列、19層 29列 確認用の6組での変化(1トークンあたりの対数尤度) 繰り返す続き −0.117、正しく進む続き −0.004(報告は −0.103、−0.009) 繰り返す続きだけが選んで起こりにくくなり、正しく進む続きはほとんど変わりません。\alpha を 2・4・6・8 と大きくすると、繰り返す続きの変化は −0.032・−0.072・−0.117・−0.168 と強まりました。\alpha=6 は、この例文での効き方を見て決めた値で、問題の正答率を見て調整してはいません。 本当に「方向」が効いているのか 効き目の大部分は方向によるものでした。ただし、方向がランダムでも0ではありませんでした。 対照は、自分の編集と同じ64列を、選んだ方向と直交するランダムな方向で、同じ大きさだけ変えたものです。 比べたもの MATH-500 GSM8K 対照 − 元のモデル +10.0 ± 2.6 +10.0 ± 3.2 自分の編集 − 元のモデル +42.0 ± 3.5 +49.5 ± 3.6 自分の編集 − 対照 +32.0 ± 3.5 +39.5 ± 3.7 報告の編集 − 元のモデル +46.5 ± 3.5 +52.5 ± 3.7 自分の編集と対照の片方だけが解けた問題は、MATH-500 で67対3、GSM8K で83対4でした。 対照で10ポイント上がった理由は、元のモデルが9割の問題で繰り返しに入っているため、重みを少し揺らすだけでも抜け出す回答があるからだと考えています。これは確かめていません。ランダムな方向は1つしか試しておらず、seed も1つです。 設定を変えるだけでは駄目なのか 改善はしますが、編集には届きませんでした。 0.8B のモデルでは、思考 ON にすると繰り返しに入る損が大きく、思考を OFF にするだけで正答率はかなり上がります。 条件 MATH-500 GSM8K 元のモデル(思考 ON) 8.5% 16.0% 思考 OFF 34.0% 46.0% 自分の編集(思考 ON) 50.5% 65.5% 報告の編集(思考 ON) 55.0% 68.5% temperature を 1.0 にした条件は100問ずつで測り、同じ100問で元のモデルの 6問・17問 から 19問・37問 に増えました。同じ100問で、報告の編集は55問・70問、自分の編集は50問・66問です。 思考 OFF で打ち切られた回答(MATH-500 の52%)は、同じ文の繰り返しではありませんでした。上限の 8,192 トークンまで、繰り返さずに書き続けていました。 ファインチューニングとは何が違うのか 学習(勾配による重みの更新)をせず、推論だけで見つけた方向を、決めた場所に式で1回書き込む点が違います。 この種の手法は、モデル編集(model editing)や、内部表現の方向を扱う表現工学(representation engineering)と呼ばれる分野に入ります。 ファインチューニング 今回の重みの編集 使うデータ 数千〜数十万件の学習データ 対にした例文が数組(報告では、採点できる練習問題) データの使い方 誤差を計算し、逆伝播で重みを更新する 推論を流し、内部の活性の差を測る 変える場所 重み全体、または LoRA などの追加部分 決めた2層の64列ずつ 同じ系統に、拒否の方向を重みから引いて消す directional ablation(abliteration とも呼ばれる)があります。推論のたびに内部の値へ方向を足し込む activation steering とは違い、変更は重みに入ります。そのため、普通の推論エンジンでそのまま動きます。今回も、改造していない vLLM で評価しました。 ただし、「データが要らない」わけではありません。方向を見つけるための例文と、効いたかを確かめる問題は必要です。また、今回の改善は新しい知識や能力を足したものではありません。元のモデルが解けるのに、繰り返しで打ち切られていた問題を救ったものです。 どれくらいの時間がかかったのか 生成に、2台それぞれで約5.5時間と約6.2時間かかりました。0.8B のモデルでも、長い思考の評価は重い作業です。 重みと作業領域は合わせて5GBほどで、割り当てたメモリのほとんどは、同時に約200本の長い回答を作るためのキャッシュです。 条件 時間(Spark 1台) 元のモデル 212分 対照 189分 自分の編集 105分 報告の編集 91分 temperature 1.0(100問ずつ) 93分 思考 OFF 16分 短い入力での処理量は1台あたり毎秒約3,300トークンでしたが、実際の評価では平均で毎秒930〜1,150トークンでした。終わりの近くでは、長い回答だけが残って同時に処理する本数が減るからです。繰り返しで上限まで書き続ける元のモデルと対照が、いちばん時間を使いました。 作業は Claude Code に任せました。私は確かめる範囲と機材の使い方を決め、結果と記録を確認しました。 まとめ 公開された編集は、報告どおりの成績を出しました。同じ手順を独立にやり直しても同じ層とほぼ同じ方向が見つかり、同じくらい効きました。効き目の大部分は、方向がランダムな対照(+10ポイント)との差から、繰り返しの方向を引いたことによるものです。 この記事が扱っていない範囲は次のとおりです。 GPT-6 Astra が編集を見つける過程そのものは、再現していません。自分の編集は、報告の「2層・64列・方向を引く」という形を知ったうえで作りました。形を知らずに見つけられるかは、確かめていません。 数学以外の課題(報告にある IFEval・MMLU-Pro・GPQA)と、ほかの数学の集合(AIME・AMC など)は測っていません。 報告と同じ規模(全問・複数回答)では測っていません。採点も、報告のコードではなく、同じ規則を自分で実装したものです。 ファインチューニングとの性能の比較はしていません。どちらが良いかは、この記事からは言えません。 参考文献 Weight-Space Programming(元の報告) RikiyaT/lm_understand-logs(元の報告のログ・重みの差分・評価コード。4d09ba6d を参照) Qwen/Qwen3.5-0.8B(モデルカード。思考 ON・OFF の推奨設定) Hendrycks, D. et al. Measuring Mathematical Problem Solving With the MATH Dataset. 2021 Lightman, H. et al. Let's Verify Step by Step. 2023(MATH-500 の500問) Cobbe, K. et al. Training Verifiers to Solve Math Word Problems. 2021(GSM8K) Meng, K. et al. Locating and Editing Factual Associations in GPT. 2022(モデル編集) Zou, A. et al. Representation Engineering: A Top-Down Approach to AI Transparency. 2023 Arditi, A. et al. Refusal in Language Models Is Mediated by a Single Direction. 2024(directional ablation) Turner, A. et al. Steering Language Models With Activation Engineering. 2023(activation steering) huggingface/Math-Verify(採点) 営業の受注率を上げるAIネイティブなサービス Intelligent Sales を開発しています。 筆者:袖山剛(株式会社DeploAI CTO) 線形代数・微積分・最適化・統計・ベイズ統計を学び直した記録を書いています。
Why the downvotes? Are people completely oblivious to huggingface/tau ? That far removed from the fact that the harness is not the TUI?
FineDNA: the largest dataset to teach any LLM DNA (midtraining, SFT, RL) Hi everyone, we're releasing FineDNA, all the data we used to turn Qwen3-14B into Carbon-X, the strongest open language model on DNA. It contains: - Midtraining: 300B+ tokens of genomes and DNA-rich text - SFT: ~200K conversations - RL: ~98K verifiable prompts Code and recipe are open too, so you can apply it to other LLMs. Dataset: huggingface.co Code: huggingface/carbon
Open data and code to teach LLMs to read DNA
OpenAI, Hugging Face, Google: Why They All Reach for Rust OpenAI rewrote Codex CLI in Rust. Hugging Face's tokenizers, safetensors, uv and Ruff all run on Rust. Why does a Python world keep reaching for it? The problem Rust solves (speed or safety), where it already runs in AI, what it honestly costs, and the plan for this series: Rust from zero, one picture at a time. Chapters 0:00 AI keeps reaching for Rust 0:46 The problem: speed or safety 1:34 What Rust does differently 2:03 Does it work? Android's numbers 2:40 Where Rust runs in AI today 4:04 Is Rust replacing Python? 4:29 The honest cost 4:59 The plan: two playlists 5:28 What would you build? Next: Episode 1: Your first Rust program The whole series, in order: Learn Rust from Zero (Beginners) · Rust You Can See (playlist) Sources - OpenAI Codex CLI rewrite: codex#1174 - Hugging Face tokenizers: huggingface/tokenizers - safetensors joins the PyTorch Foundation: pytorch.org - uv: astral-sh/uv · Ruff: astral-sh/ruff - Astral agrees to join OpenAI: astral.sh - Microsoft, ~70% of CVEs are memory safety: microsoft.com - Chromium memory safety: chromium.org - Android memory safety: security.googleblog.com · blog.google - The Case for Memory Safe Roadmaps (2023): cisa.gov - Linux 6.1 (Rust support): kernelnewbies.org - Stack Overflow 2025 survey: survey.stackoverflow.co - GitHub Octoverse 2025: github.blog - TypeScript's native port in Go: devblogs.microsoft.com - Rust compiler performance survey 2025: blog.rust-lang.org - Pydantic core: pydantic/pydantic-core · Polars: pola.rs Ferris the crab is the Rust community's mascot (public domain, rustacean.net). Rust You Can See is an independent series, not affiliated with or endorsed by the Rust Project or the Rust Foundation. Rust is a trademark of the Rust Foundation. Narration: AI-generated voices. #rust #learnrust #programming [es] Por qué la IA se está pasando a Rust [fr] Pourquoi l'IA se tourne vers Rust [hi] AI अब Rust पर क्यों शिफ्ट हो रहा है? [ja] なぜAIはRustへ移行しているのか [ko] AI가 Rust로 옮겨가는 이유 [pt-BR] Por que a IA está migrando para Rust
TRL has day-0 support to post-train Le Chonk on a single node 🤯 LoRA SFT on a 1T-parameter model, training adapters on top of FP8 weights: ⚡ 32.7k tokens per step in ~8 seconds 💾 142 GiB per GPU on 8× B300 🔀 Expert parallelism + FSDP Recipe: github.com/huggingface/trl/blob/ea936f801deeea713… Open weights = open training after all ;)
SafeAgents: an open-source proxy that checks every tool call your coding agent makes before it runs SafeAgents is a small local proxy that sits between a coding agent and its model server. It checks each tool call in the model's response before the harness receives it. A call it flags is replaced with a short text notice, so the harness gets a plain text reply and runs nothing. You point the agent's base URL at the proxy instead of the model server. All checks run locally on your machine: the proxy only forwards traffic to the model server you already use, and doesn't send your prompts, code or tool calls anywhere else unless you point the optional judge at a remote server. Each tool call goes through up to three checks: 1. Two local checks that only need the request: whether the tool was declared by the harness, and whether the call reaches a host that appears nowhere in the conversation. The model's own earlier turns don't count as a source, so a URL the model came up with on its own is flagged. 2. atif-scan by u/evalstate, which runs about 110 deterministic detectors on the pending call, in-process, with no model or network call: sandbox side channels, proxy and network bypasses, namespace escapes and reward hacking. Examples are curl to the cloud metadata endpoint, curl --noproxy posting ~/.netrc somewhere, or reading /proc/1/environ. 3. Optionally, a judge model for milder findings. It can be any OpenAI-compatible server, including a small model on your own machine through llama.cpp, so this step can stay local too. It answers allow or block as JSON. It sees only the user's request, the call and the findings, not the agent's reasoning or tool outputs. It can add blocks but not remove them. Catching reward hacking in RL and evals The same detectors cover the tool calls a policy makes to game its reward instead of solving the task: writing its own reward file, editing the verifier's tests, or patching pytest so everything passes. Since safeagents is just a proxy in front of an OpenAI-compatible server, it can sit in front of the inference server used for rollouts or eval runs. In --log-only mode it records these attempts without changing the trajectories, which gives a measure of how often a model tries to cheat. In blocking mode, the call is replaced with a notice and never runs. Some practical details: - It handles OpenAI Chat Completions and Anthropic Messages, streamed or not. Text is forwarded as it arrives; a tool call is held until its arguments are complete. - The local checks take around 10–20 ms per call on an M-series Mac. The judge is only called for calls that already raised a finding. - --log-only checks every call without changing anything, which is the recommended way to start. Hosts you trust can be added with --allow-host. - The repo has setup guides for 12 harnesses. Six of them (pi, Claude Code, OpenCode, Qwen Code, OpenHands, DeepSeek Harness) are tested end to end in CI: the real harness runs through the proxy against a scripted model, and the tests check that flagged calls don't execute and clean ones do. Next steps are a small fine-tuned decision model for malicious tool calls and a public benchmark for it. Reports of interesting catches and of false positives are both useful. Apache 2.0, runs locally: huggingface/safeagents