状態:実測(2026-10-31)。 24GBのGPUサーバー1台に gpu-unlock 2.0.0 を適用し、適用前と後を同じ使い捨てポッド・同じスクリプトで測定しました。 行列積はdtypeごとに7回、プロファイルは3回繰り返した中央値であり、遅延は600フレームのセッションを複数回実行した値です。記述のルール:実測データが 基本であり、測定できなかったものは「未実測」、原因を確認できなかった解釈は「推定」と表示します。この記事は使用を推奨するものではありません。
目次
- 1. 結論から
- 2. gpu-unlockの仕組み
- 3. 適用前に知っておくべきリスクとライセンス
- 4. 測定環境と方法
- 5. 適用前の上限から:テンソルコアの割合4.7%
- 6. 解除されたか:行列積は1.61倍、2倍にならない理由
- 7. 出力は同じか:対照群とのビット比較
- 8. リアルタイムスコアボード:上限内の−0.9%
- 9. エンドツーエンドの遅延 22.5 → 17.4ms はgpu-unlockの効果ではない
- 10. 元に戻す方法
- 11. まとめ
1. 結論から
「コンシューマー向けGPUのテンソルコアは半分の速度に制限されており、解除すれば2倍になる」という話を実際に検証してみました。結果は半分正しく、半分は ワークロードの性質に依存していました。
- 制限は解除されました。 カーネルログに
gpu_unlock: unlockedが記録され、速度選択レジスタSS0が0x43301046から0x88888888に変更されました。行列積8192³(FP32アキュュムレート)は、BF16が 70.1 → 113.0 TFLOPS(×1.61)、FP16が 68.4 → 108.9、TF32が 37.2 → 61.3 になりました。 テンソルコアを使用しないFP32は 23.8 → 23.8 のままでした(対照群)。 - 2倍ではなく1.6倍だった理由は、電力のためでした。 クロックあたりのスループットは約1.95倍に増加しましたが、カードが350Wの上限に達したため、SMクロックが 約1710MHzから1395MHzに低下しました。適用後のクロックは100ms間隔で、適用前のクロックは0.5秒間隔のサンプルで測定した近似値です。
- 出力は同じでした。 本番リアルタイムモデルの出力6種を決定論的設定でそれぞれ200フレーム比較し、sha256はいずれも一致しました。ただし、本番と
同じ設定(
cudnn.benchmark=True)では、解除後にcuDNNが別の畳み込みアルゴリズムを選択したため、その設定のビット一致は未実測です。 - リアルタイム卓球スコアボードのボール検出モデルは0.9%高速化しました。 フレームあたりのGPUカーネル時間が 9.09 → 9.00ms になりました。適用前にプロファイルで 計算しておいた上限−2.3%の範囲内に収まりました。このモデルのGPU時間においてテンソルコアが占める割合が4.7%しかなかったためです。
- エンドツーエンドの遅延 22.5 → 17.4ms はgpu-unlockの効果ではありません。 GPU側とワーカーのパスは同じであり、同じブート内で再計測したところ、 26.2msと17.2msが交互に出ました。サーバー側のCPU区間の違いであり、その原因は最後まで特定できませんでした(第9節)。
2. gpu-unlockの仕組み
テンソルコアは、小さな行列の乗算を一度に処理する専用の演算装置です。NVIDIAのコンシューマー向けカードは、FP16・BF16・TF32の入力を FP32でアキュュムレートするテンソルコア演算を、同じチップを使用するプロフェッショナル向けカードの半分の速度で実行します。学習や量子化されていない推論は大部分が このパスを通ります。FP16でアキュュムレートする演算、INT8、テンソルコアを使用しないFP32はこの制限とは無関係です。
gpu-unlockは、この速度を決定するレジスタを起動時に書き換えるLinuxカーネルモジュールです。リポジトリのREADMEの「How it works」および 「Boot flow and opt-in」セクションを要約すると以下の通りです。
- パッケージがモジュールとファームウェアをinitramfsに配置します。そのため、モジュールはNVIDIAドライバーがカードを認識する 前 に動作します。
- モジュールは、カーネルコマンドラインに
gpu_unlock.targets=がある場合のみ動作します。allまたはPCIアドレスを記述します。 - モジュールは、NVIDIAドライバーパッケージから抽出した署名付きブートファームウェア(GPUセキュリティプロセスが実行するbooter)を介して、保護されたレジスタに書き込む権限を取得し、速度選択レジスタSS0に
0x88888888、SS1に0x8を書き込みます。 - カードをリセット(FLR)した後に処理を終了します。その後、 変更されていないNVIDIAドライバーが通常通りカードを認識します。
ドライバーを改変したりVBIOSを書き換えたりする方式ではないため、ドライバーをアップデートしても再適用する必要がないとリポジトリに説明されています。起動が完了した 後に手動でモジュールをロードしても、すでにドライバーが認識しているカードに対しては何も行いません。
適用したサーバーのカーネルログは以下の通りでした(必要な部分のみ、アドレスは短縮しています)。
gpu_unlock: loading out-of-tree module taints kernel.
gpu_unlock: module verification failed: signature and/or required key missing - tainting kernel
gpu_unlock: stage=gfw plm=0xffffff8f ss0=0x43301046 ss1=0x6 ...
gpu_unlock: pass=1/2 attempt=1 ... ret=0
gpu_unlock: pass=2/2 attempt=1 ... ret=0
gpu_unlock: stage=host ss0=0x88888888 ss1=0x8 ...
gpu_unlock: stage=flr ... ss0=0x88888888 ss1=0x8 ...
gpu_unlock: unlocked
すべてのステップが同じ秒数以内に完了しました。適用後もドライバーバージョン(580.95.05)、最大クロック(2100MHz)、電力上限(350W)はそのまま維持されました。
3. 適用前に知っておくべきリスクとライセンス
このモジュールは、GPUセキュリティプロセスのブートパスに干渉する サードパーティ製 のコードです。NVIDIAが作成またはサポートしているものではありません。以下は、リポジトリの ドキュメントと今回の適用で実際に確認した内容です。
| 項目 | 内容 | 根拠 |
|---|---|---|
| カーネルのTaint | ツリー外モジュールのためカーネルが O(ツリー外)表示を付与し、DKMSが独自のキーで署名したもののそのキーが登録されていないため検証に失敗し、 E(署名なし)も付与された。 /proc/sys/kernel/tainted は12289(P·O·E の合計)。Taintされたカーネルのバグレポートはカーネル開発者から受け付けられない場合がある |
実測(カーネルログ) |
| Secure Boot | このサーバーではSecure Bootが無効になっており、適用スクリプトは有効な場合に停止するようになっている。有効にした状態で使用するには、モジュールに署名してそのキーをファームウェアに登録する必要があるが、今回は検証していない | 実測(適用スクリプト)、署名パスは未実測 |
| サポート範囲 | Ampere世代は安定、Ada・Turing世代は実験段階、Blackwellは非対応と記載されている | リポジトリのREADME |
| ノートPC用カード | 外部GPUが休止中に完全に電源が切れると、解除状態が静かに消える。リポジトリにも結果が混ざると記載されている。実験目的でのみ扱うべきである | リポジトリのREADME、未実測 |
| 省電力 | メモリサスペンド(suspend to RAM)から復帰する際に再度解除を行う。ハイバネーション(hibernation)については言及されていない | リポジトリのREADME、未実測 |
| 失敗時 | カードのファームウェアがハングアップしない場合、モジュールがDMAバッファを次の電源遮断まで保持し続ける。再試行するには電源を完全に切る | リポジトリのREADME、未実測 |
| 画面出力 | 画面出力を持つカードの場合、リセットからドライバーが認識するまで画面がブラックアウトする | リポジトリのREADME、今回のサーバーはヘッドレス運用 |
| 発熱・寿命 | リポジトリのFAQには害を及ぼす可能性は低いと記載されている。今回行列積を8秒間ずつ実行した際、電力は上限(350W)を超えることはなく、温度は最高67°Cだった | 短期的な値のみ実測、長期的な影響は未実測 |
ライセンス。 カーネルモジュールとパッケージングはGPL-2.0-onlyです。しかし、モジュールが使用するファームウェアはNVIDIAドライバーパッケージ(610.43.03)からバイト単位でそのまま抽出したものであり、 NVIDIAのファームウェアはNVIDIAのライセンス(ドライバー使用許諾契約)に準拠します。 リポジトリの firmware/NOTICE.md は、公開されているオープンなカーネルモジュールのソースコードのライセンスがこのファームウェアに適用されないこと、また再配布の許可を主張するものではなく、個人が自身のハードウェアでパッケージングすることを第一の目的としていることを明らかにしています。そのためビルドは毎回 download.nvidia.com からドライバー .run(344,190,507 B)とカーネルモジュールのソース(26,172,192 B)を直接取得し、その場でファームウェアを抽出します。今回の適用も同様にサーバー内でのみビルドを行い、生成されたファームウェアやパッケージを外部に配布することはありませんでした。この記事は法的判断を示すものではありません。商用環境や複数の機器へのデプロイにあたっては、NVIDIAの契約原文を事前に確認する必要があります。
再起動によって変更されたのは gpu-unlock だけではありませんでした。 update-grub が数ヶ月前に修正したものの反映していなかった /etc/default/grub の編集も同時に反映されたため、カーネルコマンドラインから quiet splash swapaccount=0 vt.handoff=7 が抜け、IOMMUの引数が二重に入っていました。前後比較の変数が一つ増えたような形であり、再起動前後の /proc/cmdline を並べて確認するまで気付きませんでした。適用する前に update-grub が何を生成するのかを事前に確認しておくことをおすすめします。
4. 測定環境と方法
| 項目 | 値 |
|---|---|
| GPU | Ampere世代(GA102)24GB コンシューマー向けカード、電力上限350W(設定の最大値も350W)、ドライバー 580.95.05 |
| サーバー | ハイブリッド(Pコア・Eコア)24スレッドデスクトップCPU、Ubuntu 25.04、カーネル 6.14.0-37-generic |
| gpu-unlock | 2.0.0、コミット 7eb51bc、DKMSパッケージ、対象はそのカードの1つのPCIアドレス |
| 測定用ポッド | 本番スコアボードワーカーと同一のイメージ(PyTorch 2.9.1+cu128、cuDNN 9.10)および同一の重み(読み取り専用)、GPUタイムスライス1スライス、CPU 4・メモリ 8Giの制限、終了時に破棄される使い捨て |
| 負荷 | 測定中の本番スコアボードセッションおよびバッチ処理は0件 |
測定項目は4つです。適用前と後に同じポッド、同じスクリプトで実行しました。
- 行列積。
torch.mmを使用して、8192³と4096³をdtypeごとに20回(4096は100回)連続で実行する7つのウィンドウの中央値。FP16・BF16の低精度アキュュムレートは無効化し、FP32アキュュムレートのみ測定しました。クロックと電力は同じ時間のnvidia-smiのサンプル(適用前は0.5秒、適用後は個別に8秒ずつ連続実行しながら100ms)です。 - カーネルプロファイル。
torch.profilerのトレースから、カーネル名でテンソルコアの行列積・畳み込み(s1688gemm,xmma,tensorop)とそれ以外を分類しました。ボール検出モデルBlurBall(HRNet系、1.49Mパラメータ、入力解像度9×288×512)をバッチ1・2・3で3回ずつ実行しました。 - ビット比較。 同じ200フレームを稼働中のモデル(BlurBall、EfficientTAM映像エンコーダー、卓球台セグメンテーションヘッド、卓球台頂点ヘッド)に通して得られた出力6種のフレーム別sha256。決定論的設定(
cudnn.benchmark=False,cudnn.deterministic=True,use_deterministic_algorithms,CUBLAS_WORKSPACE_CONFIG=:4096:8)であり、精度は本番環境と同じです。適用前に2回実行し、両者が一致することを確認しました。 - エンドツーエンド遅延。 本番ワーカーをPod内にそのまま起動し、ブラウザのように30fpsでJPEGを送信して「送信した時刻 → そのフレームの応答を受信した時刻」を測定しました。応答を受信できなかったフレームは3枚まで蓄積し、最初の2秒間は破棄します。ネットワークは除外されています。
5. 適用前の事前上限予測:テンソルコアの割合4.7%
gpu-unlockは テンソルコアカーネルのみ を高速化します。そのため、自社のモデルがどれくらい速くなるかは「GPU時間のうちテンソルコアカーネルが占める割合」によって上から制限されます。適用する前にまずこれを測定しました。
| ボール検出モデル(バッチ1、1フレームあたり) | 適用前の実測値 |
|---|---|
| GPUカーネル時間 | 9.09ms(カーネル427個) |
| そのうちテンソルコアカーネル | 0.42ms(TF32行列積カーネル2個)、 4.7% |
| 最大のカーネル | バッチ正規化(2.9ms)、clamp、加算などのメモリ律速な小さなカーネル |
| 畳み込み | TF32が有効になっているにもかかわらず(cudnn.allow_tf32=True デフォルト)、 cudnn.benchmark がFP32 winograd(テンソルコア非使用)を選択した |
小さな解像度と少ないチャンネル(16–128)を持つHRNetは、演算ではなくカーネル数とメモリ往復がボトルネックになります。テンソルコアカーネルが正確に半分になると仮定しても減少分は0.21msであり、これは 上限−2.3% になります。「FP32モデルだからTF32テンソルコアで動作するはずだ」と仮定していた場合、それは誤りでした。cuDNNはTF32を許可していてもベンチマーク結果に応じてテンソルコアを使用しないアルゴリズムを選択することがあるため、仮定に頼らずカーネル名を数える必要があります。
同様の測定で他の経路についても事前に確認しました。モデルをBF16 autocastで実行した場合(本番環境とは異なる変更であり、精度評価は行っていません)、カーネルは7.67ms、テンソルコアの割合は26%に上昇し、上限が大きくなります。卓球台検出(リクエスト時のみ実行されるセグメンテーションモデル)ではGPU時間49msのうちテンソルコアが約21msでしたが、ウォールクロック時間は1.4秒であり、その大部分はCPUでの後処理でした。どちらも「GPUが高速化されてもユーザーが体感する時間はほとんど変わらない」ことを事前に示す数値です。
6. どの程度高速化されたか:行列積は1.61倍、2倍にならない理由
| 8192³、FP32累積 | 適用前(TFLOPS) | 適用後 | 倍率 |
|---|---|---|---|
| BF16 | 70.1 | 113.0 | ×1.61 |
| FP16 | 68.4 | 108.9 | ×1.59 |
| TF32 | 37.2 | 61.3 | ×1.65 |
| FP32(テンソルコア非使用、対照群) | 23.75 | 23.83 | ×1.00 |
4096³でもBF16 ×1.68、FP16 ×1.65、TF32 ×1.65、FP32 ×1.00でした。リポジトリのREADMEにまとめられたユーザー報告によると、同等グレードのカードはBF16が75 → 125 TFLOPS(+65%)であり、近い数値となっています。
2倍にならない理由は電力に見出すことができます。行列積の実行中、 nvidia-smi のクロック制限理由はほぼ一貫して「ソフトウェアの電力上限」であり、電力は最大348.9Wと350Wの上限に張り付いていました。同時間のSMクロックで割ると次のようになります。
| 8192³ | 適用前のSMクロック | 適用前のクロックあたり | 適用後のSMクロック | 適用後のクロックあたり | クロックあたり倍率 |
|---|---|---|---|---|---|
| BF16 | 約1710MHz | 41.7 TFLOPS/GHz | 1395MHz | 81.3 | ×1.95 |
| FP16 | 約1680MHz | 41.3 | 1365MHz | 80.5 | ×1.95 |
| TF32 | 約1815MHz | 20.7 | 1485MHz | 40.9 | ×1.98 |
| FP32 | 約1470MHz | 16.3 | 1455MHz | 16.4 | ×1.01 |
クロックあたりの値は、同一区間のTFLOPSをその区間のSMクロックの中央値で割ったものです。GA102ホワイトペーパー(ドキュメント基準)におけるクロックあたりの最大値は、FP32累積のFP16・BF16が半精度で約41.9 TFLOPS/GHz、全精度でその2倍です。適用前の41.7は半精度の99%、適用後の81.3は全精度の97%にあたります。 クロックあたりではほぼ正確に2倍になっており、仕事量が2倍になる分だけ電力が先に上限に達し、クロックが18%低下したと読み取れます。1.95 × (1395 / 1710) ≈ 1.59 となり、実測値の1.61と一致します。
ただし、これは 推測です。適用前のクロックは0.5秒間隔のサンプルからdtype区間ごとに4〜8個を読み取った値であるため、近似値です。確認する方法は2つありますが、どちらも実施していません(未実測)。1つ目は電力上限を引き上げて倍率が2に近づくかを確認する方法ですが、このカードの設定可能な最大値が350Wであるため引き上げることができませんでした。2つ目は nvidia-smi -lgc を使用してSMクロックを電力上限下の同じ値に固定し、前後を測定することです。このサーバーは本番処理とGPUを共用しているため、クロック設定は変更していません。
7. 出力は同一か:対照群とのビット比較
速度が変化したという数値と同様に、「それ以外のものは変化していない」という数値も必要です。2つの検証を行いました。
- 対照群。 テンソルコアを使用しないFP32行列積は23.75 → 23.83 TFLOPS(×1.00)、TF32を無効化したボール検出モデルはカーネルが9.28 → 9.30ms(+0.2%)でした。制限に関係のない経路がそのまま維持されていることは、他の変動要因(クロック、ドライバー、熱)が結果に影響を与えていないことも示しています。
- ビット比較。 適用前に同じ比較を2回実行し、出力6種がすべて一致すること(測定方法自体が決定論的であること)を事前に確認しました。その上で、適用後の出力を適用前の基準と比較しました。
| 出力(決定論的設定) | 比較した数 | 異なる数 | 生テンソル最大絶対誤差 |
|---|---|---|---|
| ボール検出BlurBall | 198 | 0 | 0 |
| EfficientTAM映像埋め込み | 200 | 0 | |
| EfficientTAM高解像度特徴量 | 200 | 0 | |
| 卓球台セグメンテーション低解像度ロジット | 200 | 0 | 0 |
| 卓球台セグメンテーションIoU | 200 | 0 | |
| 卓球台頂点ヒートマップ | 200 | 0 | 0 |
これら6つは、フレームごとにsha256を個別に比較した結果です。卓球台検出の最終結果(複数のモデルと後処理を経た四角形)はまとめられたハッシュ1つのみを比較し、項目ごとに何個一致したかをカウントしていないため、「確認済み」から除外しています。
制限事項。 この一致は決定論的設定における話です。本番環境は cudnn.benchmark=True で実行されており、セクション8で見られるように適用後にcuDNNが一部の畳み込みをTF32テンソルコアカーネルに変更して選択しました。アルゴリズムが変更されると加算の順序が変わるため、本番設定の出力がビット単位で同一であるとは言えません。その比較は実施していません(未実測)。「出力がビット単位で同一である」という文言には、常にどのような設定であったかを明記する必要があります。
8. リアルタイムスコアボード:上限内の−0.9%
| ボール検出モデルGPUカーネル(フレームあたり、3回の中央値) | 適用前 | 適用後 | 変化 |
|---|---|---|---|
| 本番設定、バッチ1 | 9.087ms | 9.001ms | −0.9% |
| 本番設定、バッチ2 | 16.24ms | 16.00ms | −1.5% |
| 本番設定、バッチ3 | 23.28ms | 22.87ms | −1.8% |
| TF32無効(対照群)、バッチ1 | 9.284ms | 9.302ms | +0.2% |
| BF16 autocast、バッチ1(本番とは異なる変更) | 7.666ms | 7.357ms | −4.0% |
| FP16 autocast、バッチ1(本番とは異なる変更) | 7.219ms | 7.071ms | −2.0% |
バッチ1における−0.9%は、事前に計算した上限−2.3%の範囲内です。ワーカー内でのデコードから推論までの1フレームの経路も13.04 → 12.96ms(p50)と同程度でした。上限に達しなかったことは不自然ではありません。上限はテンソルコアカーネルが正確に半分になるという仮定に基づいている一方、実際にはテンソルコアカーネル時間が0.42 → 0.73msへと 増加したためです。 適用後にTF32畳み込みが高速化されると、 cudnn.benchmark が一部の畳み込みをFP32 winogradからTF32 implicit GEMMカーネルに変更して選択し、その代わりに残りのカーネルが8.67 → 8.27msに減少しました。合計では0.09ms減少しました。
テンソルコアをより多く使用する経路ほど、その恩恵は大きくなります。バッチが大きくなると−1.5%、−1.8%へと増加し、卓球台検出のflash attentionカーネルは6.97 → 4.75ms(−32%)、検出1回あたりのGPU時間は49.3 → 43.1msでした。それでも検出1回あたりのウォールクロック時間は1,399 → 1,412msと変化しませんでした。GPUではなくCPUの後処理が時間を消費しているためです。
9. エンドツーエンド遅延の22.5 → 17.4msはgpu-unlockの効果ではない
同じ測定において、エンドツーエンド遅延(30fpsセッション単体、p50)は22.5msから17.4msへ23%減少しました。表の数字だけを見ると、gpu-unlockによって遅延が5ms短縮されたと書きたくなるような結果です。しかし、GPUカーネルの短縮分は0.09msであり、ワーカーの経路も0.08ms短縮されたにすぎません。残りの5msは別の要因に由来しています。さらにいくつかの測定を行いました。
GPU側はそのまま変化ありませんでした。 セッションの実行中、GPUは前後ともにP2状態、SM 1695MHz、170W、使用率29–30%でした。3つのセッションを同時に実行した場合の遅延は26.5 → 26.3msと変化ありませんでした。ワーカーが報告するサーバー内時間(受信時刻 → 応答生成時刻)は20.3 → 15.9msに短縮されているため、その差はサーバー側にあります。各ステップを計測するラッパーを適用して適用後のサーバー内時間を分解したところ、GPU推論が11.7ms、その手前のCPU区間(JPEGデコード、卓球台のオプティカルフロー追跡、待機)が4.2msでした。GPU推論の前後は同じであるため、適用前のCPU区間は約8.6msであったと計算できます。
同一の起動内で再度測定したところ、数値が変動しました。 gpu-unlockを有効にしたまま、画像・スクリプト・設定を変更せずに20分間でさらに3回測定しました。
| 測定 | gpu-unlock | エンドツーエンドp50(セッション別) | サーバー内p50 | サーバーCPU使用量(全体) | 測定Pod CPU | 同一サーバーのCIビルド |
|---|---|---|---|---|---|---|
| 適用前 | なし | 23.6, 22.5, 22.3 | 20.3 | 7.2% | 0.90コア | なし |
| 適用後 | あり | 17.4, 19.1, 17.2 | 15.9 | 7.6% | 0.76コア | 1.46コア |
| 再測定1 | あり | 26.2, 26.2, 26.8 | 23.7 | 9.2% | 0.96コア | 0.04コア |
| 再測定2 | あり | 17.4, 17.2, 17.0 | 15.7 | 8.5% | 0.66コア | 0.99コア |
| 再測定3 | あり | 16.8–18.1(12セッション) | 15.4–16.4 | 約9% | 0.5–1.4コア | 1.0–1.4コア |
gpu-unlockを有効にした同一の起動内において、26.2msと17.2msが4分間隔で出現しました。22.5 → 17.4という数値はこの変動の範囲内収まっています。したがって、 gpu-unlockの効果ではないことは実測に基づいて断言でき、その原因が何であるかは次の段階の課題となります。
最初に立てた仮説は間違っていました。 再起動後に同じサーバーにあったCIサーバーとウェブポッドが別のサーバーに移動したため、「CPUの競合が減ったから」と 推測しました。しかし、適用前の測定時間にそれらのポッドが消費したCPUは合わせて約0.1コアであり、サーバー全体のCPU使用率は前後ともに7〜9%でした。 むしろ 遅かった2回はサーバー上のほかの処理がほとんどないときで、速かった3回は同じサーバーでCIビルドが1〜1.5コアを使用しているときでした。 遅いときは測定ポッドが同じ処理に多くのCPUを使っていました(0.90〜0.96コア対0.66〜0.76コア)。
この傾向はCPUの省電力機能を示唆しています。このサーバーは powersave ガバナで最も深いアイドル状態(C10、復帰に680µs)を使用しており、30fpsの1セッションは33msごとに約16ms動作して残りは休止します。サーバー全体が暇な場合、コアが深くスリープするかクロックが下がり、フレームごとに復帰するコストを払うという説明になります。これを検証するため、同じポッド内で1つのコアを回り続けさせるプロセス(nice 19)のオンオフを切り替えて交互に測定しましたが(上の表の「再び3」)、当時はCIビルドが動いていたため、オンでもオフでも17ms台でした。サーバーが暇になったら再び測定しようと30分待ちましたが、ビルドが連続して入ってきたためそのようなタイミングは訪れませんでした。遅い状態を再現できなかったため、 この説明は推測として残します。
確認するには、サーバーが暇な時間を選んで同じ交互測定を行うか、コア固定とCステートの制限をかけて測定する必要があります(未測定)。
この件から得られる教訓は、原因そのものよりも手順です。端から端までの数値が改善したときにすぐ理由を結びつけず、 同じ条件で再度測定して ブレの幅をまず確認し、部分的なパス(GPUカーネル、ワーカーパス、サーバー内の段階)に分けてどこが変わったのかを切り分けることです。今回は部分パスが同じだったため、gpu-unlockを原因から除外できました。
10. ロールバック方法
リポジトリのドキュメントと適用スクリプトに記載した方法です。今回はロールバックを行っていません(未実行)。
| 範囲 | 方法 |
|---|---|
| 1回だけ無効化 | 起動画面のGRUB編集で gpu_unlock.targets=... を削除して起動 |
| 永続的に無効化 | /etc/default/grub を適用前のバックアップに戻し、 sudo update-grub の後に再起動。モジュールが残っていてもこの引数がなければ何も動作しない |
| 完全に削除 | パッケージを削除する(Debian系 sudo apt-get remove gpu-unlock-dkms)。initramfsが再生成される |
| 確認 | 今回の起動のカーネルログ(journalctl -k -b)に gpu_unlock: unlocked がなく、行列積BF16が再び約70 TFLOPSになっているか |
設定は起動時にレジスタに書き込む値であるため、カードには残りません。電源が完全に切れると元に戻ります。
11. まとめ
| 確認項目 | 理由(本記事の実測値) |
|---|---|
| 適用前にGPU時間におけるTensorコアカーネルの割合を測定する | ボール探索モデルは4.7%であったため上限は−2.3%であり、実際は−0.9%であった |
| カーネル名で集計する | TF32を許可してもcuDNNはTensorコアを使用しない畳み込みを選択した |
| 電力制限とクロックを合わせて確認する | クロックあたり約1.95倍だったが、350Wに張り付いてクロックが18%低下し、1.61倍になった |
| 対照群を設ける | FP32行列積(×1.00)とTF32を無効化したモデル(+0.2%)に変化がなく、ほかの変更が混入していないと判断できた |
| ビット単位の比較には設定を付与する | 決定的設定では6種が一致したが、本番設定では解除後にアルゴリズムの選択が変わり未測定である |
| 端から端までの数値に直接原因を結びつけない | 22.5 → 17.4msは同一起動内のブレ(17〜26ms)の範囲内であり、部分パスは同じであった |
| 再起動によって何が一緒に変更されるかを確認する | 保留になっていたGRUBの編集が同時に反映され、カーネルのコマンドラインが追加で変更された |
要するに、このモジュールがコンシューマー向けカードのFP32累積Tensorコア速度をクロックあたり2倍にすることはこのサーバーで確認され、電力制限下では行列積がおよそ1.6倍になりました。大規模なBF16・FP16行列積が処理の大半を占めるワークロード(言語モデルのプロンプト処理や学習)であればこの数値に近づいて高速化し、小規模な畳み込みモデルのようにメモリやカーネル数にボトルネックがあるワークロードではほとんど変化しません。どちらに該当するかは、適用前にプロファイリングを1回行えば判明します。そしてその代償として、署名のないサードパーティ製モジュールがGPUのブートパスに介入し、NVIDIAファームウェアのライセンス条件を直接読み取らなければならないという負担を背負います。
Titiのひと言。 自転車のギアを1段上げたらペダル1回転で2倍進むようになりました。しかし足の力(350W)は同じなのでペダルがゆっくり回り、結局1.6倍速くなりました! そして私の卓球ボール探索は大部分が靴紐を結ぶ時間(メモリの往復)なので、ギアを変えてもほとんど変わりませんでした。ある日学校に早く着いたからといって、ギアのおかげだと言ってはいけません。その日は追い風が吹いていたかもしれないのですから。