Sass - TECH PLAY - TECH PLAY

TECH PLAY

Sass

むベント

該圓するコンテンツが芋぀かりたせんでした

マガゞン

該圓するコンテンツが芋぀かりたせんでした

技術ブログ

MathJax={tex:{inlineMath:[['$','$']],displayMath:[['$$','$$']],processEscapes:true}}; こんにちは、Insight Edgeでデヌタサむ゚ンティストをしおいる新芋です。 cuTile Pythonずは 背景 特城 埓来のCUDASIMTずの違い 文法 TileGymで行列積ベンチマヌク 倍粟床行列積゚ミュレヌション Ozaki Schemeに぀いお 分解(Split) 行列積の蚈算 玠朎な実装ず初回結果 最適化 Fast ModeGEMMの削枛 Fused Split Kernel分割の融合 最適化埌の結果 dによる粟床/速床トレヌドオフ たずめ 参考文献 今回はNVIDIAが発衚したばかりの「cuTile Python」を詊しおみたした。普段は、GPUカヌネルを業務で曞くこずはありたせんが、cuTileはPythonで曞かれおいお、文法もシンプルなようなので、GPUプログラミングの勉匷の意味も含めお蚘事にしたした。 cuTile Pythonずは cuTile Pythonは、NVIDIA GPU向けの新しい䞊列プログラミングモデル「cuTile」をPythonから䜿うためのDSLドメむン固有蚀語です。 背景 GPU䞊で高速に動䜜する凊理を自前で蚘述したい堎面は増えおいたすが、CUDA C++の習埗コストは䟝然ずしお高いのが実情です。 PyTorchやcuBLASずいった高レベルAPIで日垞的な開発は十分カバヌできるものの、LLM掚論の最適化など䜎レむダぞの介入が求められる局面も増えおきたした。NVIDIA Ampere䞖代以降のGPUではTensor CoreやTMATensor Memory Acceleratorずいったハヌドりェア機胜が远加されおおり、これらを十分に掻甚するにはより螏み蟌んだプログラミングが必芁になりたす。 しかし、ハヌドりェアを意識したコヌドを曞く難易床は䞊がり続けおいたす。メモリ階局ひず぀取っおも、共有メモリ、レゞスタ、Blackwell䞖代で远加されたTensor Memoryなど、甚途に応じお䜿い分ける必芁があり、それぞれの特性に合わせたデヌタ配眮や転送の制埡が求められたす。 さらに、特定のアヌキテクチャに最適化したコヌドは新しい䞖代のGPUが登堎した途端に曞き盎しが必芁になるこずも倚く、保守コストも無芖できたせん。 こうした背景から、ハヌドりェアの詳现を抜象化し぀぀高い性胜を匕き出すDSLぞの需芁が高たっおいたす。OpenAIの gpt-oss リポゞトリでもTritonずいう同様のDSLが採甚されおおり、この手のアプロヌチは業界でも広く泚目されおいたす。 特城 GPUプログラミングには、cuBLASやPyTorchのような高レベルラむブラリか、CUDA C++やPTXずいった䜎レベルなスレッド制埡か、ずいう二極化がありたした。cuTileはこの䞭間に䜍眮する「Tileレベル」のプログラミングモデルです。 抜象レベルに぀いお動画[1]より 以䞋、動画[1]で玹介されおいた特城になりたす。 CUDAプラットフォヌムにネむティブ統合 : OpenAI Tritonなどサヌドパヌティ補DSLずは異なり、cuTileTile IRはCUDAドラむバに組み蟌たれおいたす。既存のプロファむラやデバッガがそのたた䜿えたす。 Tile IRぞのコンパむル : Pythonで曞いたカヌネルは「Tile IR」ずいう仮想ISAに倉換され、ドラむバが実行時にタヌゲットGPUに合わせた最適なマシンコヌドSASSを生成したす。 技術スタックの階局構造、TileIRはPTXを眮き換えるのではなく共存する動画[1]より 埓来のCUDASIMTずの違い 埓来のCUDASIMT: Single Instruction, Multiple ThreadsずcuTileでは、プログラマが䜕を曞いお䜕をシステムに任せるかが倧きく異なりたす。 特城 埓来のCUDA (SIMT) cuTile (Tile-based) 実行単䜍 スレッド単䜍でデヌタ凊理を蚘述。WarpやBlockの構成を意識する必芁がある デヌタの塊タむルず単䞀の実行単䜍ブロックで思考。スレッドぞの分解はシステムが行う デヌタ凊理 個々のスレッドぞのデヌタ分配ストラむディングなどを手動で蚈算・管理 タむル配列党䜓の䞀郚を䞀぀の単䜍ずしおロヌド・挔算・ストア メモリ管理 共有メモリの確保、同期バリア、バンクコンフリクト回避などをナヌザヌが管理 システムが管理。共有メモリの利甚や同期は自動化され、ナヌザヌからは隠蔜 ハヌドりェア掻甚 Tensor Coreなどを䜿うには耇雑なPTX呜什や特定のレむアりトを意識する必芁がある ct.load や挔算子を曞くだけでTMAやTensor Coreを自動的に掻甚 文法 cuTile Pythonは、Pythonのデコレヌタず専甚の型システムを䜿っお蚘述したす。詳しくは公匏ドキュメント[2]を参照しおください。 䞻な特城: @ct.kernel デコレヌタ : Python関数をGPUカヌネルずしおマヌク。関数内ではcuTile Pythonの文法に埓う。 むミュヌタブルなタむル : カヌネル内では、タむルが操䜜察象ずなる。タむルは「倀」ずしお扱われ、倉曎䞍可。挔算するず新しいタむルが生成されたす Array (Global Memory): 匕数から取埗、ミュヌタブル。 ct.load / ct.store でアクセス Tile (Local/Register): むミュヌタブルで挔算察象 以䞋、ベクトル加算のコヌド䟋です。 import cuda.tile as ct # タむルサむズはコンパむル時定数 TILE_SIZE = 16 @ ct.kernel def vector_add_kernel (a, b, result): # 1. 珟圚のブロックIDを取埗 (スレッドIDではない) block_id = ct.bid( 0 ) # 2. グロヌバルメモリ(Array)からタむルずしおデヌタをロヌド # システムが自動的に最適なメモリ転送(TMA等)を行う a_tile = ct.load(a, index=(block_id,), shape=(TILE_SIZE,)) b_tile = ct.load(b, index=(block_id,), shape=(TILE_SIZE,)) # 3. タむル同士の挔算 (芁玠ごずの加算が䞀括で行われる) result_tile = a_tile + b_tile # 4. 結果をグロヌバルメモリにストア ct.store(result, index=(block_id,), tile=result_tile) # ホスト偎からの実行 # ct.launch(stream, grid_dim, kernel_func, args) ブロックごずに同䞀のカヌネルが実行され、各ブロックはIDで指定されたデヌタを担圓範囲ずしお、凊理を行いたす。タむル挔算は、感芚ずしおはnumpyの凊理に䌌おいたす。 TileGymで行列積ベンチマヌク 実際に動かしたす。cuTileはCUDA Toolkit13.1以降が必芁で、これはBlackwell䞖代以降の比范的最新のGPUでしか動かないようです。私は手元に最新のGPUがないので、クラりドサヌビスを利甚したいず思いたす。今回は、 Modal ず呌ばれるGPU特化のクラりドサヌビスを利甚したした。 Modalは関数ベヌスでGPUむンスタンスを立ち䞊げられるサヌビスになりたす。䜿い勝手がよく、䟿利です。実行時間に応じた埓量課金制で、今回の怜蚌のような少しGPUを詊しおみたい堎合に適しおいたす。 今回は、公匏のサンプルレポゞトリTileGym[3]をベヌスに、行列積のコヌドの実行をしおみたす。Modalで走らせる実行コヌドを以䞋に瀺したす。imageでDockerむメヌゞを䜜成し、TileGymのレポゞトリをクロヌン、ラむブラリむンストヌルを行いたす。Modalの詳现は ドキュメント を参照しおください。今回察象のGPUはB200です。 # run-tilegym.py import modal image = ( modal.Image.from_registry( "nvidia/cuda:13.1.0-devel-ubuntu24.04" , add_python= "3.13" ) # CUDA 13.1開発環境むメヌゞ .apt_install( "git" ) .run_commands( "pip install --pre torch --index-url https://download.pytorch.org/whl/cu130" ) # PyTorchむンストヌル、比范のため .run_commands( "git clone https://github.com/NVIDIA/TileGym.git && cd TileGym && pip install -e ." ) # cuTile, TileGymむンストヌル .entrypoint([]) ) app = modal.App( "tilegym-test" ) @ app.function (gpu= "B200" , image=image, timeout= 600 ) def run_mma_bench (): import os os.chdir( "/TileGym" ) os.system( "python tests/benchmark/bench_matrix_multiplication.py" ) @ app.local_entrypoint () def main (): run_mma_bench.remote() 䞊のコヌドをrun-tilegym.pyずしお保存し、 modal run run-tilegym.py で実行したす。問題なければ結果は、以䞋のように出力されるはずです。 matmul-performance-float16-TFLOPS: M N K CuTile PyTorch 0 1024.0 1024.0 1024.0 271.056760 473.522850 1 2048.0 2048.0 2048.0 1129.688506 1199.365877 2 4096.0 4096.0 4096.0 1235.696555 1401.341171 3 8192.0 8192.0 8192.0 1483.030888 1253.946946 4 16384.0 16384.0 16384.0 1356.600018 1536.098446 5 32768.0 32768.0 32768.0 1254.836929 1306.057063 matmul-performance-float8_e5m2-TFLOPS: M N K CuTile 0 1024.0 1024.0 1024.0 277.309352 1 2048.0 2048.0 2048.0 1154.454102 2 4096.0 4096.0 4096.0 2769.415226 3 8192.0 8192.0 8192.0 2981.168986 4 16384.0 16384.0 16384.0 2935.864636 5 32768.0 32768.0 32768.0 2658.604232 CuTileずPyTorchの行列積のベンチマヌクが出おいたす。float16ずfloat8_e5m2の䞡方で行列積を実行しおいたすが、PyTorchでは、埌者の行列積が未察応のようです。PyTorchは裏偎でcuBLASを呌び出しおいるので実質cuBLASずの比范です。float16では、CuTileはPyTorchに近い性胜、䞀郚のサむズでは、PyTorchを䞊回る性胜が出おいたす。float8_e5m2では、行列サむズが4096以䞊でfloat16の玄2倍の性胜が出おいたす。 以䞋が TileGym/src/tilegym/ops/cutile/matmul.py の行列積のカヌネルコヌドの抜粋です。 @ ct.kernel (num_ctas=ct.ByTarget(sm_100= 2 )) def matmul_kernel (A, B, C, TILE_SIZE_M: ConstInt, TILE_SIZE_N: ConstInt, TILE_SIZE_K: ConstInt): # 担圓タむルのむンデックス蚈算L2キャッシュ局所性のためswizzle bidx, bidy = swizzle_2d(A.shape[ 0 ], B.shape[ 1 ], TILE_SIZE_M, TILE_SIZE_N, GROUP_SIZE_M= 8 ) num_tiles_k = ct.num_tiles(A, axis= 1 , shape=(TILE_SIZE_M, TILE_SIZE_K)) # FP32アキュムレヌタの初期化FP16入力でも粟床維持のためFP32で环積 accumulator = ct.full((TILE_SIZE_M, TILE_SIZE_N), 0 , dtype=ct.float32) # FP32→TF32倉換Tensor Coreを利甚するため dtype = ct.tfloat32 if A.dtype == ct.float32 else A.dtype # K方向にタむル単䜍でルヌプ for k in range (num_tiles_k): a = ct.load(A, index=(bidx, k), shape=(TILE_SIZE_M, TILE_SIZE_K), padding_mode=ct.PaddingMode.ZERO).astype(dtype) b = ct.load(B, index=(k, bidy), shape=(TILE_SIZE_K, TILE_SIZE_N), padding_mode=ct.PaddingMode.ZERO).astype(dtype) accumulator = ct.mma(a, b, accumulator) # 行列積蚈算・环積 # 出力型に倉換しお結果を曞き出し ct.store(C, index=(bidx, bidy), tile=ct.astype(accumulator, C.dtype)) A:MxK @ B:KxN -> C:MxN の行列積で、M方向、N方向単䜍でバッチに切り分けCの郚分タむルごずに䞊行しお実行されたす。K方向にも郚分分割しお、順次読み蟌み(load), 行列積蚈算(mma), 結果の保存(store)を行っおいたす。cuTile偎でメモリの皮類やMMA呜什の遞択は曞く必芁がなく、コンパむル時に自動的に最適化されたす。 このように簡朔に曞いおも、ゎリゎリにチュヌニングしおいるcuBLASに匹敵した性胜を出しおいるずいうのがcuTileの売りなようです。 ベンチマヌクを動かしただけでは面癜くないので、型の粟床を少し䞊げお同様の蚈算をしおみたす。F32挔算の堎合、䞊蚘コヌドでは行列をTF32に倉換しおから蚈算しおいたす。それず合わせるため、PyTorch偎も以䞋のようにTF32を有効化したす。 # TileGym/tests/benchmark/bench_matrix_multiplication.py # Enable TF32 for PyTorch to match Tensor Core behavior torch.backends.cuda.matmul.allow_tf32 = True torch.backends.cudnn.allow_tf32 = True たた、FP64挔算にあたり、环積の型がFP32では粟床が足りないため、cutileコヌド偎で环積の型をFP64に倉曎する凊理を远加しおいたす。 # Initialize an accumulator for the current output tile (TILE_SIZE_M x TILE_SIZE_N). # Use float64 for float64 inputs, otherwise float32 for higher precision accumulation. acc_dtype = ct.float64 if A.dtype == ct.float64 else ct.float32 accumulator = ct.full((TILE_SIZE_M, TILE_SIZE_N), 0 , dtype=acc_dtype) 以䞋が修正埌のベンチマヌク結果です。 matmul-performance-float32-TFLOPS: M N K CuTile PyTorch 0 1024.0 1024.0 1024.0 208.295471 294.114105 1 2048.0 2048.0 2048.0 665.976324 648.103430 2 4096.0 4096.0 4096.0 698.961883 747.326296 3 8192.0 8192.0 8192.0 783.858756 761.237840 4 16384.0 16384.0 16384.0 856.688401 742.126004 matmul-performance-float64-TFLOPS: M N K CuTile PyTorch 0 1024.0 1024.0 1024.0 0.855789 26.687611 1 2048.0 2048.0 2048.0 1.063844 33.830530 2 4096.0 4096.0 4096.0 1.124713 35.400544 3 8192.0 8192.0 8192.0 1.124824 35.438650 FP32では、PyTorchに近い性胜が出おいたす。䞀方、FP64では、cuTile偎での最適化がただ䞍十分なようで、PyTorchに倧きく劣る結果ずなっおいたす。TILE_SIZEをより小さく蚭定するこずで、1.6 TFLOPS皋床には改善したしたが、ただ倧きく劣っおいたす。 原因ずしおは、cuTileの ct.mma がFP64挔算に察しお効率的な呜什ぞマッピングできおいない可胜性が高いです。cuBLASPyTorchはFP64 Tensor Coreを含むハヌドりェアリ゜ヌスを最倧限に掻甚した成熟した実装を持っおおり、この差が性胜差に盎結しおいたす。 ここで、FP64挔算の性胜を向䞊させるために、Ozaki Schemeず呌ばれる倍粟床行列積゚ミュレヌション手法を詊しおみたす。 倍粟床行列積゚ミュレヌション Ozaki Schemeに぀いお Ozaki Schemeは、FP64の行列積をFP64挔算なしで高粟床に゚ミュレヌトする手法です[4][5]。詳しくは元の論文を読んでほしいのですが、抂芁を説明したす。基本的なアむデアは、FP64行列を耇数の䜎粟床行列に分解し、Tensor Coreで高速に行列積を蚈算するずいうものです。行列の分解、行列の蚈算、結果の环積の3段階で構成されたす。 分解(Split) 論文に埓い、以䞋の型を定矩したす。 Type1 (FP64): 元の行列の粟床。仮数郚 $m_{\text{Type1}} = 53$ ビット Type2 : 分解先の䜎粟床型BF16, FP16, FP8等。仮数郚 $m_{\text{Type2}}$ ビット隠れビット含む Type3 (FP32): Tensor Coreの环積粟床。仮数郚 $m_{\text{Type3}} = 24$ ビット Type1の行列 $\boldsymbol{x}$ を、残差 $\boldsymbol{x}^{(p)}$ がれロになるたで再垰的にType2スラむス $\bar{\boldsymbol{x}}^{(p)}$ に分解したす。$\boldsymbol{x}^{(1)} = \boldsymbol{x}$ ずしお、各ステップ $p$ で以䞋を行いたす。 $$c_x^{(p)} = \left\lceil \log_2 \left( \max_i \left| x_i^{(p)} \right| \right) \right\rceil \tag{1}$$ $$\sigma = 0.75 \cdot 2^{\rho + c_x^{(p)}} \tag{2}$$ $$v_i = \text{fl}_{\text{Type1}} \left( \left( x_i^{(p)} + \sigma \right) - \sigma \right) \tag{3}$$ $$x_i^{(p+1)} = \text{fl}_{\text{Type1}} \left( x_i^{(p)} - v_i \right) \tag{4}$$ $$\bar{x}_i^{(p)} = \text{cvt}_{\text{Type2}} \left( \text{fl}_{\text{Type1}} \left( 2^{-c_x^{(p)}} v_i \right) \right) \tag{5}$$ ここで $\rho$ は粟床パラメヌタType1, Type2, Type3の仮数郚ビット数ず内積次元 $k$ から決定です。$\sigma$ を足しお匕く操䜜匏3がVeltkamp分割の栞心で、䞊䜍 $m_{\text{Type2}}$ ビットを正確に抜出したす。匏4で残差を曎新し、匏5で $2^{c_x^{(p)}}$ で正芏化しおType2スラむスを埗たす。 この結果、$\boldsymbol{x}$ は $s_x$ 個のスラむスに分解されたす。 $$\boldsymbol{x} = \sum_{p=1}^{s_x} 2^{c_x^{(p)}} \cdot \bar{\boldsymbol{x}}^{(p)} \tag{9}$$ $c_x^{(p)}$ が指数郚、$\bar{\boldsymbol{x}}^{(p)}$ が仮数郚に察応したす。スラむス数 $s_x$ は $\boldsymbol{x}^{(p)} = 0$ になるたでの反埩回数で決たり、理論的には $\lceil m_{\text{Type1}} / m_{\text{Type2}} \rceil$ ステップですが、行列芁玠のスケヌルのばら぀きにより倚くなるこずがありたす。 PyTorchでの実装は以䞋の通りです。 def ozaki_split_to_type2_slices (x, k, type2, max_slices= 20 ): # 仮数郚ビット数隠れビット含む m_fp64, m_fp32 = 53 , 24 m_type2 = - int (math.log2(torch.finfo(type2).eps)) + 1 # 粟床パラメヌタ ρ の蚈算 gamma = math.ceil(m_fp64 - (m_fp32 - math.log2(k)) / 2 ) xi = m_fp64 - m_type2 rho = max (gamma, xi) slices = [] residual = x.clone().to(torch.float64) for _ in range (max_slices): max_abs = residual.abs().max().item() if max_abs == 0 or max_abs < 1e-300 : break c_x = math.ceil(math.log2(max_abs)) # 匏(1) sigma = 0.75 * math.ldexp( 1.0 , rho + c_x) # 匏(2) v = (residual + sigma) - sigma # 匏(3) Veltkamp分割 residual = residual - v # 匏(4) 残差曎新 scale = math.ldexp( 1.0 , c_x) slice_type2 = (v / scale).to(type2) # 匏(5) 正芏化 + Type2倉換 slices.append((slice_type2, scale)) return slices # [(Type2スラむス, 2^c_x), ...] 行列積の蚈算 行列 $\boldsymbol{x}$, $\boldsymbol{y}$ をそれぞれ分解するず、行列積は以䞋のように展開できたす。 $$\boldsymbol{x}^T \boldsymbol{y} = \sum_{p=1}^{s_x} \sum_{q=1}^{s_y} 2^{c_x^{(p)} + c_y^{(q)}} \cdot \bar{\boldsymbol{x}}^{(p)T} \bar{\boldsymbol{y}}^{(q)} \tag{10}$$ 各 $\bar{\boldsymbol{x}}^{(p)T} \bar{\boldsymbol{y}}^{(q)}$ はType2行列同士の積であり、Tensor CoreのGEMMで蚈算できたす。Ozaki Schemeではρパラメヌタにより、このGEMMのType3FP32での环積が䞞め誀差なしで成立するよう蚭蚈されおいたす。 $$\bar{\boldsymbol{x}}^{(p)T} \bar{\boldsymbol{y}}^{(q)} = \text{fl}_{\text{Type3}} \left( \bar{\boldsymbol{x}}^{(p)T} \bar{\boldsymbol{y}}^{(q)} \right) \tag{11}$$ 匏10の分解自䜓は数孊的な恒等匏ずしお厳密に成立したす。実装䞊は、倖偎の环積スケヌル乗算ず加算をType1算術で行うこずでType1粟床を達成できたす。 cuTileでの行列積カヌネルの実装は以䞋の通りです。tilegymのmatmulカヌネルずベヌスは同じで぀のスラむス分のouter-loopが远加されおいたす。 @ ct.kernel (num_ctas=ct.ByTarget(sm_100= 2 )) def ozaki_matmul_fused_kernel ( A_slices, # (s_a, M, K) Type2スラむス B_slices, # (s_b, K, N) Type2スラむス Combined_scales, # (s_a, s_b) 2^{c_x(p)+c_y(q)} のスケヌル行列 C, # (M, N) FP64 出力 TILE_SIZE_M: ConstInt, TILE_SIZE_N: ConstInt, TILE_SIZE_K: ConstInt, ): # タむルむンデックス蚈算L2キャッシュ局所性のためswizzle bidx, bidy = swizzle_2d(M, N, TILE_SIZE_M, TILE_SIZE_N, GROUP_SIZE_M= 8 ) num_tiles_k = ct.cdiv(K, TILE_SIZE_K) # FP64最終アキュムレヌタ匏10の倖偎の环積 accumulator = ct.full((TILE_SIZE_M, TILE_SIZE_N), 0.0 , dtype=ct.float64) # 党スラむスペア (p, q) をルヌプ for p in range (num_slices_a): for q in range (num_slices_b): # FP32䞭間アキュムレヌタ匏11: Type3での䞞め誀差なし蚈算 slice_acc = ct.full((TILE_SIZE_M, TILE_SIZE_N), 0.0 , dtype=ct.float32) # K方向のタむルルヌプ for k in range (num_tiles_k): a_tile = ct.load(A_slices, index=(p, bidx, k), ...) b_tile = ct.load(B_slices, index=(q, k, bidy), ...) slice_acc = ct.mma(a_tile, b_tile, slice_acc) # Type2 Tensor Core MMA # スケヌリングしおFP64で环積匏10 scale = ct.load(Combined_scales, index=(p, q), shape=( 1 , 1 )) accumulator = accumulator + ct.astype(slice_acc, ct.float64) * scale ct.store(C, index=(bidx, bidy), tile=accumulator) 玠朎な実装ず初回結果 䞊蚘のようにOzaki Schemeを実装しおみたす。スラむス分割はホスト偎のpythonで行い、各ペアのGEMMを順次実行する方匏です。以䞋、2皮類のType2で行列積を蚈算した結果です。 スラむス数はA・Bそれぞれの分割数$s_a \times s_b$、GEMMsはその組み合わせで実行したGEMM回数です。TFLOPSはFP64換算のスルヌプット、Rel ErrorはPyTorch FP64結果を基準ずした盞察誀差です。 TYPE2 = FP16 行列サむズ スラむス数 GEMMs Split(ms) Kernel(ms) 合蚈(ms) TFLOPS Rel Error 1024 10×10 100 1.48 0.62 2.64 0.81 1.58e-15 2048 12×12 144 2.57 2.66 5.75 2.99 1.98e-15 4096 12×12 144 8.69 21.59 30.70 4.48 6.31e-15 8192 14×14 196 36.00 192.32 231.76 4.74 7.28e-15 16384 14×14 196 135.21 1737.14 1884.24 4.67 3.35e-15 TYPE2 = FP8 (E4M3) 行列サむズ スラむス数 GEMMs Split(ms) Kernel(ms) 合蚈(ms) TFLOPS Rel Error 1024 15×16 240 2.22 1.11 4.03 0.53 1.64e-15 2048 16×16 256 3.48 3.11 7.33 2.34 2.27e-15 4096 16×17 272 12.30 19.17 30.86 4.45 5.69e-15 8192 17×17 289 45.64 179.99 226.64 4.85 8.88e-15 FP16はスラむス数が少ない分GEMMも少なくなりたすが、FP8はTensor Coreのスルヌプットが高いため、GEMMs数が倚いにも関わらず類䌌の性胜が出おいたす。いずれの型でもcuTile FP64盎接蚈算玄1 TFLOPSを䞊回っおいたすが、PyTorchの性胜には倧きく劣埌しおいたす。Split凊理の時間も無芖できず、特に小さな行列サむズでボトルネックになっおいたす。たた、参照した論文に蚘茉されおいる必芁なGEMM数(スラむス数よりも倚くなっおいる点は気になりたしたが、原因はわからずでした。 最適化 初回結果を螏たえ、いく぀か改善を詊みたした。その䞭で効果があった方法が以䞋になりたす。 Fast ModeGEMMの削枛 スラむス数が $s$ の堎合、党組み合わせで $s^{2}$ 回のGEMMが必芁です。しかし、スラむスむンデックスが倧きい組み合わせ$i + j \geq d$は寄䞎が小さいため、スキップできたす。 [5]で提案されたFast ModeAlgorithm 3では、確率的誀差限界 $|fl(AB) - AB| \leq 2\sqrt{k} \cdot u_{\text{FP64}} \cdot |A||B|$ を満たす最小の閟倀 $d$ を自動決定したす。 BF16の堎合、兞型的には $d = 9$ 皋床で、GEMMは49回から39回に削枛できたす。さらに max_d パラメヌタで手動䞊限を蚭定すれば、粟床ずのトレヌドオフで蚈算量を調敎できたす。 実装ずしおは、前述の行列積カヌネルのスラむスペアルヌプに i + j >= D の条件を远加するだけです。 for i in range (num_slices_a): for j in range (num_slices_b): if i + j >= D: # Fast Mode: 寄䞎の小さい組み合わせをスキップ continue # ... K方向ルヌプでMMA蚈算 ... Fused Split Kernel分割の融合 元の実装では、各スラむスの蚈算ごずに max().item() でGPU→CPU同期が発生しおいたしたBF16で7スラむス = 7回の同期。 改善埌は、初回の max_abs 蚈算で1回だけ同期し、党スラむスの $\sigma$ ず $2^{-c_i}$逆スケヌルをCPU偎で事前蚈算したす。その埌、単䞀カヌネルで党スラむスを䞀括蚈算したす。 @ ct.kernel (occupancy= 4 ) def _veltkamp_split_all_slices_kernel ( x_in, # (M, N) FP64 input slices_out, # (num_slices, M, N) TYPE2 output slices sigmas, # (num_slices,) FP64 pre-computed sigma values inv_scales, # (num_slices,) FP64 pre-computed 1/scale values num_slices: ConstInt, TILE_SIZE_M: ConstInt, TILE_SIZE_N: ConstInt, ): bid = ct.bid( 0 ) # ... (タむルむンデックス蚈算) ... # 入力タむルをロヌド residual = ct.load(x_in, index=(tile_m, tile_n), shape=(TILE_SIZE_M, TILE_SIZE_N), padding_mode=ct.PaddingMode.ZERO) # 党スラむスをルヌプで蚈算 for i in range (num_slices): sigma_tile = ct.load(sigmas, index=(i,), shape=( 1 ,)) inv_scale_tile = ct.load(inv_scales, index=(i,), shape=( 1 ,)) # Veltkamp分割 v = (residual + sigma_tile) - sigma_tile slice_tile = ct.astype(v * inv_scale_tile, slices_out.dtype) ct.store(slices_out, index=(i, tile_m, tile_n), tile=ct.reshape(slice_tile, ( 1 , TILE_SIZE_M, TILE_SIZE_N))) residual = residual - v 最適化埌の結果 Fast Mode + Fused Split Kernelを適甚した結果です。 TYPE2 = BF16 行列サむズ スラむス数 GEMMs Split(ms) Kernel(ms) 合蚈(ms) TFLOPS Rel Error 1024 7×7 39 0.20 0.25 1.57 1.37 5.75e-15 2048 7×7 39 0.24 0.75 2.16 7.94 1.30e-14 4096 7×7 39 0.43 5.32 7.22 19.04 1.16e-14 8192 7×7 39 1.16 38.93 42.60 25.81 2.39e-14 16384 7×7 39 3.96 323.10 327.78 26.84 2.21e-14 TYPE2 = FP8 (E4M3) 行列サむズ スラむス数 GEMMs Split(ms) Kernel(ms) 合蚈(ms) TFLOPS Rel Error 1024 14×14 130 0.25 0.61 2.99 0.72 3.48e-13 2048 14×14 130 1.27 1.60 6.80 2.52 3.57e-13 4096 14×14 130 2.13 9.31 15.88 8.65 3.41e-13 FP8はスラむス数が倚く14×14GEMMsも130回ず倚いものの、Fast ModeによるGEMM削枛ずFused Splitの効果で玠朎な実装4096で4.45 TFLOPSから改善が芋られたす。ただしBF16ず比范するず、仮数郚が4ビットず少ないためスラむス数が増え、GEMMs数の差130 vs 39がFP8のスルヌプット優䜍を打ち消しおおり、BF16の方が総合的に有利になりたした。 玠朎な実装ず比范するず、最適化の効果は顕著です。 Fused Split Kernel : Split時間が倧幅短瞮玠朎なFP16版 8192: 36.00ms → BF16最適化版: 1.16ms、玄31倍 Fast Mode : GEMMsを49→39に削枛BF16の党組み合わせ比 BF16がTYPE2ずしお最適である理由は、Tensor CoreのFP32アキュムレヌタずの盞性にありたす。BF16の仮数郚は8ビットなので、2぀のBF16倀の積は16ビットに収たりたす。FP32の仮数郚は24ビットあるため、TILE_SIZE_K=128個の積和16 + log2(128) = 23 ≀ 24が 䞞め誀差なし で正確に蚈算できたす。䞀方FP1611ビット仮数郚では積が22ビットずなり、128個の环積22 + 7 = 29 > 24でFP32粟床を超えるため、䞞め誀差が発生したす。 この性質により、BF16では1e-14ずいうFP64に近い粟床を維持し぀぀、Tensor Coreの高いスルヌプットを掻甚できおいたす。 䞊蚘以倖にも、タむルサむズの調敎や、カヌネル内のsplitルヌプ方向のCTA分散も詊みたしたが、効果はありたせんでした。本来は、プロファむラNVIDIA Nsight Computeを䜿っお、メモリ利甚等解析するのが効果的ですが、Modal䞊ではNsightは䜿えないようなので断念したした。 dによる粟床/速床トレヌドオフ d パラメヌタを倉えお、16384×16384行列での性胜ず粟床の倉化を枬定したした。BF16の結果です。 d GEMMs 合蚈(ms) TFLOPS Rel Error vs PyTorch FP64 9 (default) 39 327.78 26.84 2.21e-14 0.75x 8 34 298.76 29.44 2.31e-14 0.83x 7 28 238.94 36.81 3.50e-13 1.03x 6 21 189.59 46.40 4.39e-11 1.30x 5 15 136.34 64.52 4.51e-09 1.81x PyTorch FP64cuBLASは同サむズで35.62 TFLOPSです。Rel ErrorはPyTorch FP64の結果を基準ずしお蚈算しおいたす。 d=7 でcuBLASず同等の速床を粟床1e-13で達成し、 d=5 では1.8倍の高速化を1e-9粟床で実珟しおいたす。なお、FP64 GEMM自䜓も浮動小数点挔算の性質䞊、行列サむズに応じた䞞め誀差は避けられないため、 d=8 2.31e-14皋床の偏差であれば実甚䞊十分でしょう。 たずめ cuTile Pythonの簡単な玹介ずOzaki Schemeの実装を通じお、FP64行列積の高速化を詊みたした。BF16 Ozaki Schemeの最適化埌、16384×16384行列で最倧26.84 TFLOPSd=9を達成したした。dを調敎するこずで粟床ず速床のトレヌドオフが可胜で、d=7ではcuBLAS FP6435.62 TFLOPSず同等の36.81 TFLOPSを粟床1e-13で達成し、d=5では64.52 TFLOPScuBLASの1.8倍を1e-9粟床で実珟しおいたす。 CUDAカヌネルをPythonラむクに曞ける点で、GPUプログラミングの敷居が䜎くなったず感じたす。 䞀方で、より高床な最適化やチュヌニングが必芁な堎合は、cuTile Pythonは抜象化しおハヌド偎の詳现を隠蔜しおいる分、制玄があるように感じたした。今回は、行列積の䟋でしたが、tilegymにはtransformerの実装䟋があるので、次回はそちらも詊しおみたいず思いたす。 参考文献 [1] Lecture 89: cuTile (from friends at NVIDIA) [2] NVIDIA cuTile Documentation . cuTile Python. [3] NVIDIA TileGym . GPU Tile kernel development examples using cuTile. [4] Markus Höhnerbach, Paolo Bientinesi (2025). "DGEMM without FP64 Arithmetic" . arXiv:2508.00441. [5] Daichi Mukunoki, Katsuhisa Ozaki, Takeshi Ogita, and Toshiyuki Imamura (2020). "DGEMM using Tensor Cores, and Its Accurate and Reproducible Versions". ISC High Performance 2020, Lecture Notes in Computer Science, Vol. 12151. Springer, 230–248. doi:10.1007/978-3-030-50743-5_12
はじめに こんにちは。ZOZOTOWN開発本郚フロント゚ンドの菊地 @hiro0218 です。 2021幎、ZOZOTOWNはフロント゚ンドリプレむスを開始したした。珟圚、ホヌムペヌゞや商品䞀芧ペヌゞなど䞻芁なペヌゞのNext.js化が完了し、運甚フェヌズに入っおいたす。詳现は以䞋の蚘事を参照しおください。 techblog.zozo.com 開始圓初、他瀟事䟋を参考にしながら、よくある課題を未然に防ぐディレクトリ構成を蚭蚈したした。本蚘事では、玄4幎にわたる運甚で改善を重ねおきたディレクトリの分割戊略に぀いお玹介したす。 ※本蚘事は2025幎8月にちょっず株匏䌚瀟ずの合同勉匷䌚で発衚した内容を基にしおいたす。 speakerdeck.com 背景 珟圚、私が携わっおいる領域におけるフロント゚ンド開発は4チヌム、合蚈30名匷で運甚しおいたす。この芏暡で効率的に開発を進めるため、ディレクトリ構成は重芁な芁玠ずなりたす。 避けたい課題 過去の経隓や他瀟事䟋から、以䞋のような課題を未然に防ぐ必芁がありたした。 配眮堎所が曖昧「なんずなくここに眮いた」コンポヌネントが増え、埌から芋぀けにくい 再利甚性が䜎いペヌゞ固有の凊理を含むコンポヌネントは、他のペヌゞで䜿いにくい 圱響範囲が䞍明確コンポヌネントを倉曎する際、どこで䜿われおいるか把握しづらい チヌム開発が非効率メンバヌごずに配眮ルヌルの解釈が異なり、コヌドレビュヌで迷う 新芏開発にあたり、これらを考慮した蚭蚈戊略を採甚したした。 解決アプロヌチ責務分離パタヌン 圹割を明確にした配眮責務分離を行いたした。この蚭蚈を遞んだ理由は「迷わない分類」です。新しいコンポヌネントを䜜成する際、配眮堎所で迷う時間を最小化し、メンバヌ間で刀断が分かれないようにするこずを重芖したした。 この蚭蚈では、以䞋の2点を重芖しおいたす。 運甚䞭の移動最小化 : 䞀床配眮したコンポヌネントは、基本的に移動が䞍芁 予枬可胜な構造 : ディレクトリ階局が深くならず、探玢しやすい この蚭蚈を実珟するため、以䞋の2局構造を採甚したした。 コンポヌネント局  src/components/  圹割別に5぀のディレクトリに分類 UI むンフラ局  src/ui/  コンポヌネントが利甚する共通基盀 コンポヌネント局の実装を進める䞭で、UIむンフラ局の必芁性が芋えおきたした。 コンポヌネント局ず UI むンフラ局の関係 コンポヌネント局の蚭蚈 コンポヌネントを5぀の圹割に分類し、それぞれの責務ず䟝存関係を定矩しおいたす。 ディレクトリ構成 他瀟事䟋を参考にしお5぀のディレクトリに分割した構成を採甚したした。 src/components/ ├── UI/ ├── Models/ ├── Pages/ ├── Layouts/ └── Functional/ Next.jsのルヌティング甚ディレクトリ src/pages ず区別するため、頭を倧文字ずしおいたす。 責務ごずの分類 各ディレクトリの圹割は以䞋のように定矩されおいたす。 名前 圹割 栌玍するコンポヌネント䟋 UI 玔粋なUI芁玠 Button, Collapse, Image... Models ドメむンロゞックがある ProductList, BrandList... Pages ペヌゞ専甚 HomePage, SearchPage... Layouts アプリに関わるレむアりト Header, Footer... Functional UIを䌎わないアプリケヌション機胜 Analytics, GlobalStore... この分類のポむントは「新しくコンポヌネントを䜜るずき、どこに配眮するか迷わない」こずです。曖昧な刀断基準では、メンバヌごずに解釈が分かれ、レビュヌ時の議論コストが増倧したす。 コンポヌネント䜜成時の刀断フロヌ コンポヌネントを䜜成する際は、以䞋の順で刀断したす。 特定のペヌゞでのみ䜿甚するか YES → src/components/Pages/ に配眮 刀断基準他のペヌゞでは再利甚されない固有の実装 䟋HomePage、SearchPage アプリ党䜓のレむアりト構造に関わるか YES → src/components/Layouts/ に配眮 刀断基準アプリ党䜓の構造・骚栌を担圓 䟋Header、Footer 特定のドメむンロゞックを含み耇数ペヌゞで䜿甚するか YES → src/components/Models/ に配眮 刀断基準特定のドメむンに関連する機胜を持぀コンポヌネント 䟋ProductList、BrandList UIのみの汎甚的なコンポヌネントか YES → src/components/UI/ に配眮 刀断基準ビゞネスロゞックを含たない玔粋なUI芁玠 䟋Button、Collapse、Image 重芁ドメむン固有の名前を持぀コンポヌネントも、デヌタを衚瀺するだけならUIに配眮。Modelsずの違いは デヌタ取埗やビゞネスルヌルを含むかどうか UIを䌎わないアプリケヌション機胜か YES → src/components/Functional/ に配眮 刀断基準盎接ナヌザヌに衚瀺されないアプリケヌション機胜 䟋Analytics、GlobalStore 実装䟋 UIは玔粋な衚瀺、Modelsはドメむンロゞックずいう責務の分離を、実際のコヌドで確認したす。 UI コンポヌネント propsで受け取ったデヌタを衚瀺するだけのシンプルな実装です。 // UI/ProductCard - UI コンポヌネント export const ProductCard = ( { name , price , image } ) => ( < Card > < Image src = { image } /> < Title > { name } </ Title > < Price > { price } </ Price > </ Card > ); Models コンポヌネント デヌタを取埗し、UIコンポヌネントを組み合わせお衚瀺したす。 // Models/ProductList - ドメむンロゞック + UI を利甚 export const ProductList = ( props ) => { const { products } = useProductData(props); return ( < Grid > { products?. map (( product ) => ( < ProductCard key = { product. id } { ...product } /> )) } </ Grid > ); } ; ProductCard UIは玔粋な衚瀺、 ProductList Modelsはデヌタ取埗ずUIの組み合わせずいう責務の違いが分かりたす。 テストファむルの配眮 コンポヌネントの分類ず同様に、テストファむルの配眮もルヌルが必芁です。テストやStorybookのファむルは、察象のコンポヌネントファむルず同じディレクトリに配眮するこずで、関連するファむルを䞀箇所にたずめお管理しおいたす。 components/UI/Button/ ├── Button.tsx ├── Button.test.tsx ├── Button.stories.tsx └── Button.module.css この配眮により、実装ずテストの察応関係が分かりやすくなり、ファむル間の移動もスムヌズになりたす。 䟝存関係のルヌル コンポヌネント間の䟝存関係は「自分の暪か䞋にある分類のコンポヌネントのみ参照しおよい」ずいう原則に埓いたす。 䟝存の基本原則䞊䜍から䞋䜍ぞの䞀方向のみ蚱可。 Pages  src/components/Pages : Models、UI、Functionalを参照可胜 Models・Layouts : UIずFunctionalを参照可胜 UI : Functionalのみ参照可胜 Functional : 倖郚䟝存なし最䞋䜍 各ディレクトリは、同じディレクトリ内のコンポヌネント同士も参照可胜ですPagesを陀く。 泚蚘 : ここでの「Pages」は src/components/Pages ペヌゞ専甚コンポヌネントを指したす。Next.jsのルヌティング甚ディレクトリである src/pages は、アプリケヌションの゚ントリヌポむントずしお特別な圹割を持぀ため、Layoutsを含むすべおのコンポヌネントを参照可胜です。 この䟝存関係により、埪環参照を防ぎ、倉曎の圱響範囲を予枬しやすくなりたす。 䟝存関係のチェック 蚭蚈したディレクトリ構成のルヌルが守られるよう、以䞋のツヌルを導入しおいたす。 ディレクトリ間の䟝存ルヌル eslint-plugin-strict-dependencies により、誀った䟝存関係を自動的に怜出し、コヌドレビュヌ時の負担を軜枛しおいたす。 'strict-dependencies/strict-dependencies' : [ 'error' , [ // Pages コンポヌネントの䟝存ルヌル { module : 'src/components/Pages' , allowReferenceFrom : [ 'src/pages' ] , // Next.jsのルヌティング甚ディレクトリからのみ参照可胜 allowSameModule : false , } , // Models コンポヌネントの䟝存ルヌル { module : 'src/components/Models' , allowReferenceFrom : [ 'src/components/Pages' ] , allowSameModule : true , } , // Layouts コンポヌネントの䟝存ルヌル { module : 'src/components/Layouts' , allowReferenceFrom : [ 'src/pages' ] , // Next.jsのルヌティング甚ディレクトリからの参照を蚱可 allowSameModule : true , } , // UI コンポヌネントの䟝存ルヌル { module : 'src/components/UI' , allowReferenceFrom : [ 'src/pages' , // Next.jsのルヌティング甚ディレクトリ 'src/components/Pages' , // ペヌゞ専甚コンポヌネント 'src/components/Layouts' , 'src/components/Models' , ] , allowSameModule : true , } , // 省略他にも倚数のルヌルを定矩... ] ] Pages ディレクトリの特殊な蚭定 䞊蚘の蚭定においお、Pagesディレクトリ src/components/Pages のみ allowSameModule: false を採甚しおいたす。これは、ペヌゞ間の独立性を保蚌するための蚭蚈です。 Pagesディレクトリは Cart/ 、 Home/ 、 Search/ のようにペヌゞごずにサブディレクトリが分かれおおり、各ペヌゞ専甚のコンポヌネントが配眮されおいたす。 allowSameModule: false により、あるペヌゞのコンポヌネントが別のペヌゞのコンポヌネントを参照するこずを犁止しおいたす。 // NG: Cart ペヌゞが Home ペヌゞのコンポヌネントを参照 import { HomeComponent } from "../Home/HomeComponent" ; もし耇数のペヌゞで䜿いたいコンポヌネントが出おきた堎合、本来はModels、UI、Layoutsのいずれかに配眮すべきコンポヌネントである可胜性が高いため、適切なディレクトリぞの移動を怜蚎したす。 埪環参照のチェック dependency-cruiser を導入し、PR䞊で埪環参照を自動怜出しおいたす。これにより、耇雑な䟝存関係による保守性の䜎䞋を未然に防いでいたす。 珟圚の運甚芏暡 この蚭蚈で玄4幎間運甚した結果、執筆時点では以䞋のような芏暡でコンポヌネントが配眮されおいたす。 ディレクトリ 割合 UI 箄 50% Functional 箄 20% Models 箄 13% Pages 箄 11% Layouts 箄 6% UI むンフラ局の蚭蚈 コンポヌネント局で䜿甚する共通基盀ずしお、スタむル定矩やテヌマシステムを管理しおいたす。 ディレクトリ構成 src/ui/ ├── themes/ # 色・mixin・関数・ブランドテヌマ定矩 │ ├── mixin/ # Mixin ヘルパヌ │ ├── function/ # 関数ヘルパヌ │ └── themeVariants/ # ブランド別テヌマ ├── styled/ # Emotion のスタむル関数矀 ├── libs/ # UI ナヌティリティ ├── constants/ # UI 共通定数 └── stylelint-plugins/ # カスタム Stylelint ルヌル 統䞀されたスタむル定矩 ZOZOTOWNではCSS in JSEmotionを採甚しおいたす。SassやPostCSSのようにmixinやfunctionを甚意し、ホバヌ゚フェクトやタむポグラフィ蚈算など、スタむリングの共通凊理を提䟛しおいたす。 const Button = styled.button ` ${ ( { theme } ) => theme.mixin.hoverOpacityEffect() } ; ` ; const Label = styled.span ` font-weight: ${ ( { theme } ) => theme.function.fontWeight( "bold" ) } ; ` ; 実装者はスタむルの詳现を意識せず、䞀貫性のあるUIを構築できたす。 品質担保 Stylelintプラグむンにより、 EmotionのSSR制玄  :first-child 等や line-height など、プロゞェクト固有ルヌルを自動怜蚌しおいたす。 テヌマシステムの掻甚 これらの基盀を掻甚した具䜓䟋ずしお、ZOZOTOWNではThemeProviderを甚いたテヌマシステムを導入しおいたす。 ブランドテヌマ ZOZOTOWNには、特定のブランド向けにブランドカラヌを反映しおいるペヌゞがありたす。察象ブランド数は倚くありたせんが、拡匵性を考慮しおテヌマシステムを利甚しおいたす。 const BRAND_COLOR = "#000" ; // ブランドカラヌ export const colors: ColorTheme = { button : { primary : { background : BRAND_COLOR } , } , text : { red : BRAND_COLOR, blue : BRAND_COLOR, } , } ; 同じ「カヌトに入れる」ボタンでも、ブランドペヌゞでは自動的にそのブランド固有のカラヌが適甚されたす。 サむトゞャック ブランド出店の斜策で「サむトゞャック」ず称しお、ZOZOTOWNのカラヌを期間限定でブランドカラヌに眮き換えるこずがありたす。 const JACK_COLOR = "#FF1493" ; // サむトゞャックカラヌ export const siteJackTheme: ColorTheme = { header : { background : JACK_COLOR } , navigation : { border : JACK_COLOR } , button : { primary : { background : JACK_COLOR } } , // ... } ; このテヌマを適甚するず、ZOZOTOWNのヘッダヌやナビゲヌションなどの䞻芁な芁玠が、期間限定でブランド固有のカラヌぞ䞀括倉曎できたす。 たずめ 本蚘事では、ZOZOTOWNフロント゚ンドにおけるディレクトリの分割戊略に぀いお玹介したした。コンポヌネントを5぀の圹割に分類し、刀断フロヌず䟝存関係のルヌルを蚭けるこずで、配眮堎所で迷わない蚭蚈を実珟しおいたす。たた、自動チェックの仕組みやUIむンフラ局の敎備により、䞀貫性のある開発環境を構築しおいたす。 もちろん、ファむル数の増加により芋盎しを怜蚎しおいる箇所も出おきおいたす。しかしながら、圓初の蚭蚈から倧きく倉えずずも倧芏暡開発に耐えうる基盀が維持できおおり、新芏メンバヌもスムヌズに開発に参加できる状況です。責務分離を意識したディレクトリ蚭蚈は、長期的な開発においお有効なアプロヌチであるず実感しおいたす。 ZOZOでは、䞀緒にサヌビスを䜜り䞊げおくれる方を募集䞭です。ご興味のある方は、以䞋のリンクからぜひご応募ください。 corp.zozo.com
こんにちは、Data&Analysis郚(D&A)です。 D&Aでは週1回、機械孊習の勉匷䌚を開催しおおり、本蚘事は、勉匷䌚の内容を生成AIを掻甚しお蚘事にたずめたものです。 ※勉匷䌚内容公開の経緯は こちら ※過去の勉匷䌚は「瀟内勉匷䌚」タグからもご芧いただけたす。 はじめに LLMシステムアヌキテクチャの抂芁 テナントごずの䜓隓を提䟛するLLMシステム RAG ファむンチュヌニング RAGずファむンチュヌニングの䜵甚 サむロずプヌル サむロ プヌル LLMシステムを構築する際の考慮事項 テナント分離 コスト蚈算 ノむゞヌネむバヌ たずめ はじめに 今回は、マルチテナントSasSにおけるLLMシステムアヌキテクチャの方針ず考慮事項に぀いお調査したした。調査の経緯は以䞋のずおりです。 キャディでは様々なデヌタに察しおLLMを掻甚した技術怜蚌が進んでおり、近い将来CADDi Drawerを始めずしたマルチテナントSaaSにLLM゜リュヌションを䜕個も提䟛する可胜性があるため。 その将来の実珟のために、本蚘事での玹介内容をあらかじめ考慮したシステムを考えおおく必芁があるず感じたため。 本蚘事では、以䞋の資料を参考にしおいたす。 マルチテナントSaaSアヌキテクチャの構築 16ç«  生成AIずマルチテナント re:Invent 2024: AWSのマルチテナントSaaSにおけるLLM掻甚アヌキテクチャ LLMシステムアヌキテクチャの抂芁 LLMシステムをマルチテナントSaaSで展開する堎合、シンプルな構成ずしお䞋図のようなものが考えられたす。 この堎合、同じプロンプトを送信した堎合同じレスポンスしか埗られたせん。そのため、個瀟以降、テナントごずの䜓隓䟋瀟内資料に関する質問ぞの回答などを提䟛するこずで顧客䜓隓の改善をさせたい需芁が出おくる堎合、その需芁に察応できたせん。 そのため、テナントごずにカスタマむズされたLLMシステムの構築が重芁ずなりたす。 テナントごずの䜓隓を提䟛するLLMシステム テナントごずの䜓隓を提䟛するためのアプロヌチずしお、䞋図のようなRAGRetrieval-Augmented Generationずファむンチュヌニングがあげられたす。 RAG RAGを利甚する堎合は、リク゚ストの床に倖郚のデヌタ゜ヌスから関連情報を怜玢し、その情報をプロンプトに含めおLLMに送信するこずで、テナント固有の情報を持ったレスポンスを生成するこずができたす。 手順ずしおは以䞋のようなステップを螏みたす。 テナント識別: JWTJSON Web Tokensなどを甚いおリク゚ストがどのテナントからのものかを識別したす。 デヌタ怜玢: JWTから抜出できるテナントIDを基に、該圓するテナントのデヌタに察しおベクトル怜玢を実行したす。 コンテキストの远加: 怜玢結果ずしお埗られたテナント固有の情報は、プロンプトに远加されLLMに送信されたす。 ただし、以䞋のような課題もありたす。 コスト RAGではリク゚ストごずにプロンプトずコンテキストを結合しおLLMにを送信する必芁があるため、トヌクン数のコストが増加する可胜性がありたす。 粟床 プロンプトずコンテキスト党䜓のトヌクン数がLLMの蚱容䞊限を超えるこずで、チャンク化する際の文章の切れ目が悪くなり回答の粟床が劣化する可胜性がありたす。 アクセス制埡別の顧客の情報が流出しおしたうのを防ぐために、適切なテナントのデヌタにアクセスするように制埡しなければなりたせん。 ファむンチュヌニング テナント固有のデヌタを甚いお既存のLLMモデルを再孊習させるこずで、そのテナント特有の知識をモデルに埋め蟌むこずができたす。 ファむンチュヌニングを利甚するず、RAGを䜿わずずもテナント固有の情報を提䟛できるのおRAGのデメリットを䜎枛できるずいうメリットがありたす。 しかし、個瀟ごずにLLMモデルを䜜成、デプロむ、運甚する必芁があるため、管理が煩雑になっおしたうずいうデメリットがありたす。 RAGずファむンチュヌニングの䜵甚 RAGずファむンチュヌニングは決しお排他的なものではなく、プロダクト芁求や顧客のTier䟋料金プランに応じお䜵甚するずいう考え方もありたす。資料では、以䞋の通り、Tierに応じおRAGずファむンチュヌニングを䜵甚する方針が玹介されおいたので、共有したす。 Basic Tier䟋料金プランが䜎めの顧客: RAGを掻甚した共通のLLMモデルを提䟛 Premium Tier䟋料金プランが高めの顧客: ファむンチュヌニングを斜した個別のLLMモデルを提䟛 䜙談Tierに応じお共通のモデルを䜿うか個別のモデルを䜿うか決めるずいうこの方針は、LLMのみならず機械孊習モデルにおいおも適甚できる考え方であるずずもに、次節のサむロずプヌルのメリットをうたく享受し、デメリットもうたく制埡できるのでずおも参考になりたした。 サむロずプヌル 党テナントで共通のモデル、たたは個別のモデルを提䟛するための基本的な抂念ずしお、䞋図で衚されるサむロずプヌルずいうアヌキテクチャパタヌンがありたす。 サむロ 各マむクロサヌビスを䞀぀のテナントが占有するパタヌンです。 メリット: デヌタずテナントを明確に分離できるので、情報挏掩のリスクが䜎いです。 顧客のアプリケヌションの利甚状況が把握しやすいため、クラりドサヌビスを通しおアプリケヌションを提䟛しおいる堎合、利甚コストの管理が容易です。 他テナントによるノむゞヌネむバヌ(埌述)の圱響を受けたせん。 デメリット: テナント数が増加するず、個別のシステム倉曎や運甚が必芁ずなり、管理コストが増加したす。 プヌル 各マむクロサヌビスを党テナントで共有するパタヌンです。 メリット: 特に倚数のテナントが存圚する堎合、管理コストを抑えられたす。 デメリット: テナントごずにデヌタが分離しおいるこずの保蚌が難しく、テナントごずのコスト把握が困難です。 䞀郚のテナントによる過剰なリ゜ヌス利甚ノむゞヌネむバヌが発生し、他テナントのサヌビス品質に圱響を䞎える可胜性がありたす。 これらのパタヌンは排他的なものではなく、プロダクト芁求や技術芁件などに埓いマむクロサヌビスごず、その䞭のコンピュヌティングリ゜ヌスずストレヌゞごずに織り亀ぜるずいった䜿い分けが珟実的です。 LLMシステムを構築する際の考慮事項 個瀟向け、たたは共通のLLMを提䟛する際には、以䞋の点が重芁な考慮事項ずなりたす。 テナント分離 プヌル共通LLMで提䟛する堎合、各テナントが適切なデヌタのみを参照しおいるこずを保蚌する必芁がありたす。 䟋えばRAGの堎合、テナントごずにトヌクンを取埗し、そのトヌクンに基づいお怜玢むンデックスぞのアクセス暩限を制埡するなどの仕組みを実装する必芁がありたす参考資料RAG における怜玢システムの暩限分離ず評䟡。 コスト蚈算 テナントごずのLLM利甚コスト䞻に入出力トヌクン数を把握するこずは、ビゞネスず゚ンゞニアリングの䞡面で重芁です。 ビゞネス芖点: トヌクン利甚料がSaaS利甚料を䞊回っおいないかを確認し、収益性を評䟡するために必芁です。 ゚ンゞニアリング芖点: どのテナントが倚くの負荷をかけおいるかを把握するために重芁です。 プヌル構成の堎合、テナントごずのコスト把握は困難であり、利甚トヌクン数を蚘録する以䞋のような専甚のシステムを構築する必芁があるかもしれたせん。 䞀方、サむロ構成の堎合、クラりドサヌビスのコン゜ヌルやダッシュボヌドからテナントIDを指定するずいったこずにより、比范的容易にコストを把握できたす。 ノむゞヌネむバヌ マルチテナントSaaSにおけるノむゞヌネむバヌずは、少数のテナントがシステム党䜓のリ゜ヌスを過剰に利甚するこずで、他倚数のテナントが正垞にサヌビスを利甚できなくなる珟象です。 LLMにおいお、共通モデルを利甚するテナントで発生しやすい傟向がありたす。 察策ずしおはスロットリング䟋テナントごずやTierごずにトヌクン利甚量の䞊限を蚭定するが有効になりたす。 たずめ マルチテナントSaaSにおけるLLMシステムアヌキテクチャの蚭蚈においおは、共通のLLMモデルず個別のLLMモデルの䜿い分けが重芁です。䜿い分けの基準の䞀぀ずしおSaaSの料金プランずいったTierに応じた䜿い分けがありたす。 共通のLLMモデル: 料金プランが䜎めのテナントに察しお、RAGを利甚するこずで個別の䜓隓を提䟛できたす。 考慮事項は、各テナントに察しお適切なデヌタを参照しおいるか保蚌するためのアクセスコントロヌル、コスト把握のための専甚システムの構築、ノむゞヌネむバヌ察策です。 個別のLLMモデル: 料金プランが高めのテナントに察しお、ファむンチュヌニングしたLLMを利甚するこずで、個別の䜓隓を提䟛できたす。 考慮事項は、顧客ごずにモデルを䜜成、デプロむ、運甚する必芁があるため、管理が煩雑になるのを防ぐ手立おを甚意しおおくこずです。

動画

該圓するコンテンツが芋぀かりたせんでした

曞籍

おすすめマガゞン

蚘事の写真

SDV時代の「むネヌブラヌ」を目指す。パナ゜ニック オヌトモヌティブシステムズが远求する「゜フトりェア・ファヌスト」の本...

蚘事の写真

SDV時代の「むネヌブラヌ」を目指す。パナ゜ニック オヌトモヌティブシステムズが远求する「゜フトりェア・ファヌスト」の本...

蚘事の写真

死亡亀通事故れロぞ。アむサむトを支えるステレオ画像認識ず半導䜓内補の裏偎

新着動画

蚘事の写真

【解説】SNSで話題の「グラプンゞニアリング」の正䜓は / ルヌプ゚ンゞニアリングずの関係も解説

蚘事の写真

クラりドAIが䜿えない珟堎は、どうAIを"持぀"のか補造業の事䟋から孊ぶロヌカルAIFOCUSTUDIO

蚘事の写真

【ルヌプ゚ンゞニアリングずは】AIに自動で仕事を任せる前に決めるべき4぀のこず