3 ポイント 投稿者 GN⁺ 2023-11-13 | 1件のコメント | WhatsAppで共有
  • AI開発では、もはやCPU的な逐次実行だけでは十分ではなく、GPUの大規模並列処理モデルを理解してこそ、学習・推論性能を適切に扱える
  • CPUは一般的な消費者向けでは2〜16個のコアを備え、単一スレッドや条件分岐を伴う処理に強く、GPUは数千個の小さなコアにより、行列演算・画像処理・ディープラーニングに有利
  • AWSはP3/P4、P5/Inf1、G4、Amazon SageMakerのようなGPU実行環境を提供しており、p3.2xlargeは1時間あたり$3.06、p5.48xlargeは$98.32、g4dn.xlargeは$0.526程度
  • NVIDIA CUDAは、GPUメモリ割り当て、データコピー、カーネル実行、コンパイルまで続く並列実行フローを開発者が直接扱えるようにする
  • 配列加算、Mandelbrot生成、猫・犬分類CNNの例は、逐次ループをGPUスレッドに分割する方法を示しており、MandelbrotはCPUの4.07秒からGPUの0.0046秒へ短縮される

CPUの知識だけでは不十分な理由

  • 多くの開発者は学習と問題解決をCPU中心の方法で身につけてきたが、CPUは基本的に逐次アーキテクチャに依存して動作する
  • 従来のCPUは命令を線形に実行し、強力な少数のコアを単一スレッド性能に合わせて最適化する
  • 複数の作業を同時に処理しなければならない状況では、逐次実行方式のため、各作業を順番に処理するコストが大きくなる
  • マルチスレッディングで性能を高めることはできるが、CPUの基本的な設計思想はいまなお逐次実行に近い

AIモデルと並列処理

  • Transformerのような現代のAIアーキテクチャは並列処理を活用して学習性能を高める
  • RNNは逐次的に動作するが、GPTのようなTransformerは複数の単語を同時に処理できるため、学習効率とモデルの能力を高められる
  • 並列学習はより大きなモデルを可能にし、より大きなモデルはより良い出力を生み出す基盤となる
  • 並列性は自然言語処理だけでなく画像認識にも適用される
    • AlexNetは、画像の複数の部分を同時に処理してパターンを識別する例である
  • CPUは単一スレッド性能中心の設計のため、複雑なAIモデルに必要な大量の並列計算を効率よく分散・実行するのが難しい

GPUがボトルネックを減らす仕組み

  • GPUはCPUの大きく強力なコアの代わりに、小さく特化したコアを多数使う構造で設計されている
  • グラフィックスレンダリングや複雑な数学計算のように、同種の演算を大量に繰り返すワークロードでGPUの並列性がよく発揮される
  • TensorFlowのようなディープラーニングフレームワークは、GPU性能を活用してモデルの学習と推論を高速化するよう最適化されている
  • ニューラルネットワークの学習には多くの行列演算が含まれ、GPUは多数のコアでこうした演算を並列化するのに強い

CPUとGPUの役割の違い

  • CPU

    • CPUは逐次処理に重点を置いて設計されており、1つの命令フローを線形に実行する作業に強い
    • 汎用コンピューティング、システム処理、条件分岐を含む複雑なアルゴリズム処理に適している
    • 消費者向けCPUは通常、2〜16個のコアという比較的少ないコア数を持つ
    • 各コアは自身の命令セットを独立して処理できる
  • GPU

    • GPUは並列アーキテクチャとして設計されており、多くのサブタスクを同時に処理するのに効率的である
    • グラフィックスレンダリング、複雑な数学計算、並列化可能なアルゴリズム実行に有利である
    • 作業をより小さな並列単位に分け、複数の演算を同時に処理する
    • GPUコアは数千個に達することが多く、streaming multiprocessors(SMs)または類似の構造で構成される
    • 画像・動画処理、ディープラーニング、科学シミュレーションのように大量のデータを同時に扱う作業に適している

AWSで選べるGPU環境

  • AWSは機械学習のような作業に使えるさまざまなGPUインスタンスを提供している
  • 汎用GPUインスタンス

    • P3P4は汎用GPUインスタンスで、さまざまなワークロードに適している
    • 機械学習の学習・推論、画像処理、動画エンコーディングに使える
    • p3.2xlargeは1時間あたり**$3.06**で、16GBのGPUメモリを持つNVIDIA Tesla V100 GPUを1基提供する
  • 推論最適化インスタンス

    • 推論とは、学習済みAIモデルにリアルタイムデータを入力して予測したりタスクを解決したりする過程である
    • P5Inf1は、低レイテンシとコスト効率が重要な機械学習推論向けに調整されている
    • p5.48xlargeは1時間あたり**$98.32**で、それぞれ80GBメモリを持つNVIDIA H100 GPUを8基、合計640GBのビデオメモリを提供する
  • グラフィックス最適化インスタンス

    • G4 instancesは、グラフィックス負荷の高い作業を処理するよう設計されている
    • ビデオゲーム開発者はG4インスタンスでゲーム向け3Dグラフィックスをレンダリングできる
    • g4dn.xlargeは1時間あたり**$0.526**で、16GBメモリのNVIDIA T4 GPUを1基使用する
  • マネージド機械学習サービス

    • Amazon SageMakerは機械学習向けのマネージドサービスで、P3、P4、P5のようなGPUベースインスタンスへのアクセスを提供する
    • SageMakerは、基盤インフラを直接管理せずに機械学習を始めたい組織に適している
    • Amazon SageMaker料金ドキュメントが別途提供されている

NVIDIA CUDAの基本的な使い方

  • CUDAはNVIDIAが開発した並列コンピューティングプラットフォーム兼プログラミングモデルであり、GPUアクセラレータを活用してアプリケーションを高速に実行できるようにする
  • 例では、GPUメモリ割り当て、データコピー、カーネル実行、結果取得へと続くCUDA開発フローを示している
  • インストールの流れ

    • CUDAからbase installerとdriver installerをダウンロードする
    • ホームフォルダの.bashrcに次の環境変数を追加する
      • export PATH="/usr/local/cuda-12.3/bin:$PATH"
      • export LD_LIBRARY_PATH="/usr/local/cuda-12.3/lib64:$LD_LIBRARY_PATH"
    • 次のコマンドを実行する
      • sudo apt-get install cuda-toolkit
      • sudo apt-get install nvidia-gds
    • 変更を適用するためにシステムを再起動する
  • 便利な確認コマンド

    • lspci | grep VGA: システムのGPUを識別して一覧表示する
    • nvidia-smi: NVIDIA GPUの使用率、温度、メモリ使用量などの詳細情報を提供する
    • sudo lshw -C display: グラフィックスカードなどのディスプレイコントローラ情報を提供する
    • inxi -G: GPUとディスプレイを含むグラフィックスサブシステム情報を表示する
    • sudo hwinfo --gfxcard: システムのグラフィックスカードの詳細情報を確認するために使う

CUDAで配列加算を並列化する

  • 配列加算はGPU並列化を説明するのに適した問題である
  • 例の配列はA = [1,2,3,4,5,6]B = [7,8,9,10,11,12]で、結果はC = [8,10,12,14,16,18]である
  • CPU方式では、配列の要素を1つずつ巡回しながら加算を行う
  • データが増えると逐次方式の時間が増え、GPUは1+72+83+9のような演算を同時に実行できる
  • CUDAの例では.cuカーネルファイルを使用する
    • __global__はGPUで呼び出されるカーネル関数を表す
    • vectorAddabcの3つの整数ポインタを受け取り、ベクトル加算を行う
    • threadIdx.xは現在のスレッドのインデックスを取得する
    • 各スレッドは対応する要素の和をc[i]に保存する
  • main関数はGPUメモリ割り当て、データコピー、カーネル実行、結果コピーの順で進む
    • cudaMalloccudaAcudaBcudaCのメモリをGPUに割り当てる
    • cudaMemcpyabをhostからGPUへコピーする
    • vectorAdd <<<1, sizeof(a) / sizeof(a[0])>>>でカーネルを実行する
    • 結果ベクトルcudaCをGPUからhostへコピーする
  • コンパイルと実行にはnvccコマンドを使用する
  • 全コードが提供されている

Pythonの画像生成でGPUを活用する

  • Mandelbrot set生成は、特定の方程式における数値の挙動を基に複雑な視覚パターンを作る作業であり、リソース集約的である
  • CPUベースのPython例では各ピクセルを巡回しながらMandelbrot値を計算し、1024×1536画像の生成に4.07秒かかる
  • GPUアクセラレーション版はNumba libraryを使用する
    • @jitデコレータはPythonコードを機械語に変換するJust-In-Timeコンパイルを行う
    • cuda.jitmandel_gpuを作り、device=Trueを指定してGPU上で実行されるようにする
    • mandel_kernelはCUDA GPU上で実行され、GPUスレッドにMandelbrot生成作業を分割する
  • create_fractal_gpuはGPUメモリ割り当て、スレッド・ブロック設定、GPUカーネル実行、同期、結果コピーを行う
    • threadsperblock = (16, 16)を使用する
    • cuda.synchronize()でGPU処理の完了を待つ
    • d_image.copy_to_host(image)で結果をCPU側へコピーする
  • GPU実行時間は0.0046秒で、CPUベースのコードよりはるかに高速に実行される
  • 全コードが提供されている

GPUで猫・犬分類ニューラルネットワークを学習する

  • GPUがAIでどのように使われるかを示すため、猫と犬を区別するニューラルネットワークの例が使われている
  • 事前準備項目はCUDAとTensorFlowである
    • TensorFlowはpip install tensorflow[and-cuda]でインストールできる
    • データセットはKaggle Dogs vs. Catsを使用する
    • ダウンロード後、猫と犬の画像を学習フォルダ内の別々のサブフォルダに整理する
  • モデルは畳み込みニューラルネットワーク(CNN)を使用する
    • pandasとnumpyはデータ操作に使用する
    • Sequentialはニューラルネットワークのレイヤーを線形に積み重ねるために使う
    • Convolution2DMaxPooling2DDenseFlattenはCNN構成レイヤーである
    • ImageDataGeneratorは学習中のリアルタイムデータ拡張に活用される
  • 学習データはImageDataGeneratorでロードされる
    • 学習データにはrescale=1./255shear_range=0.2zoom_range=0.2horizontal_flip=Trueが適用される
    • 入力画像は(64, 64)サイズ、バッチサイズ32、二値分類モードに設定される
  • CNN構造は畳み込み、最大プーリング、フラット化、Denseレイヤー、sigmoid出力で構成される
  • モデルはadamオプティマイザ、binary_crossentropy損失、accuracy指標でコンパイルされる
  • 学習はepochs=25validation_steps=2000で実行され、classifier.save('trained_model.h5').h5ファイルに保存される
  • 推論コードはtrained_model.h5をロードして画像を(64, 64)に変換し、予測値が0.5以上ならdog、そうでなければcatと出力する
  • 全コードが提供されている

GPU活用の範囲

  • AI時代にはGPU機能を無視することは難しく、開発者はGPUの能力をよりよく理解する必要がある
  • 逐次アルゴリズムから並列化されたアルゴリズムへ移行するなかで、GPUは複雑な計算を高速化する道具になる
  • GPUの並列処理能力は、AIと機械学習タスクにおける大規模データセットや複雑なニューラルネットワークアーキテクチャの処理に特に有利である
  • GPUは従来の機械学習領域を超え、科学研究、シミュレーション、データ集約型作業にも使われる
  • 並列処理能力は、創薬、気候モデリング、金融シミュレーションのようなさまざまな分野の問題解決に活用される

1件のコメント

 
GN⁺ 2023-11-13
Hacker Newsのコメント
  • この記事のコードは間違っている。CUDAカーネルがまったく呼び出されていない: https://github.com/RijulTP/GPUToolkit/blob/f17fec12e008d0d37...
    JITコンパイルされたコードでMandelbrot集合を「計算」する時間の90%は、実際の計算ではなく関数のコンパイルに使われている
    CUDAをきちんと学びたいなら、行列乗算の実装がよい練習になる。参考になるチュートリアルは https://cnugteren.github.io/tutorial/pages/page1.htmlhttps://siboehm.com/articles/22/CUDA-MMM

    • CUDAにおける並列数学コードの「Hello World」と呼ばれるSAXPYもある。SAXPYは「Single-Precision A·X Plus Y」の略で、標準的なBLAS関数であり、スカラー乗算とベクトル加算を組み合わせた非常に単純な演算
      32ビット浮動小数点ベクトルXとY、スカラーAを受け取り、各X[i]にAを掛けてからY[i]に加える: https://developer.nvidia.com/blog/six-ways-saxpy/
    • 指摘を受けた後、コードを修正し、ブログも更新した
  • 「すべての開発者が知るべき」と主張しているが、実際にはAIでGPUが使われる方法を扱った記事に近い。大半の開発者はAI開発者ではなく、AIと直接やり取りしたりGPUを直接使ったりもしない
    さらに、GPUが存在するようになった中核的な理由である3Dグラフィックスはほとんど扱っていない

    • 隣接分野の基礎を知っておくのは役に立つ。特に機械学習のように広く適用される分野ならなおさらで、来月担当するプロジェクトで機械学習を使うことになるかもしれないし、その部分を担当する同僚と協業する際にも有利になる
      基本知識があれば、マネージャーに売り込まれる「AI」の話もよりよく理解できる
      「隣接分野は必要ない」という態度は、学校でよく見かけたものだった。システム管理の側では同期たちがプログラミングを知らなくてもよいと言っていたが、実際にはスクリプティングが必要だったし、ソフトウェア開発の学校ではネットワークを知らなくてもよいと言っていたが、数年後には求人票にDevOpsが広く登場した
      記事がおよそ1500語なら、勉強するつもりで読んでも12分ほどで、コード例を実行してみて2時間ほど使ったとしても大きな投資ではない。もちろん、その記事がよい入門書であるという前提は必要だ
    • 伝統的な組み込み系企業からスタートアップに移ったとき、同僚がJSONリクエストをcurlで送る方法を知らないことを親しみを込めてからかっていたのを覚えている。今も組み込み開発者だが、その後バックエンド、フロントエンド、インフラをかなり学んだ。今後数年、業界全体でAIをめぐって似たような状況が起きる可能性は高そうだ
    • Mandelbrot集合のレンダリング例でさえ10倍の高速化しか出ていないが、これは浮動小数点演算量にほぼ完全に縛られる計算の代表例だ。個人的にはひどい記事に見える
    • 不正確な前提が多い。大半の開発者がAI開発者ではないという点には同意するし、原文の筆者は一般的な開発者集団から少し離れているか、自分の周囲の世界を基準に全体を推測しているように見える
    • 「すべての開発者が知るべき」と主張する記事を見るたびに、その主張はたいてい嘘だった。本当に全員が知るべき情報を含む記事もあり得るだろうが、遭遇するものの大半はクリックベイト
  • AIでPythonが支配的な理由は、Python-Cの関係CPU-GPUの関係に似ているからだと思う
    GPUは性能が非常に高いが直接コーディングするのが難しいため、人々はPyTorchのような高レベルAPI呼び出しでGPUを扱う
    Cも性能は高いがコーディングが難しいため、PythonをCの上の抽象化レイヤーとして使う
    人々がGPUをそこまで深く理解すべきかは明らかではない。AIの学習や運用の深部に入り込む場合でなければなおさらだし、Mooreの法則が終わってマルチスレッディングが速度向上の主な手段になれば、並列プログラミングのパラダイムに合わせた新しい言語が出てくる可能性は高い。Mojoがその出発点のように見える

    • どのハードウェア上で実行されても、見えないところで性能を最大化する新しい言語の余地があるのか気になっていた
      単純な反復計算から、すべての命令が裏側でインテリジェントにすべてのCPUコアを並列活用し、可能な作業はGPUに渡すように設計される、といった形だ
      こうした試みがすでにあったのか、そもそも可能なのか気になる
    • Mooreの法則はまだ終わったとは言いにくく、マルチスレッディングが答えでもない。ただし最初の文は正しい
    • GPUプログラミングはそれほど難しくない。CUDAは多くの作業でかなり直感的で、100行未満のコードで処理速度100倍の向上を得られる場合も多い
    • より現代的な言語を使えば、Pythonらしい表現力を保ちながらCレベルの性能をかなり簡単に得られる。むしろCは抽象化が不足しているせいで、遅いが単純なコードのほうが魅力的に見えるようにしていると思う
    • Cは生き方だ。ほぼ完全にCだけを使う人たちは、Pythonの「意味のある空白」という概念を受け入れにくい
  • 「CPUは複数のタスクに遭遇すると、各タスクを1つずつ処理するようにリソースを配分する」という説明は単純すぎる。CPUがまだその程度に単純だったらいいのに、と思ってしまうほどだ
    記事がプログラミングモデルに焦点を当てるのは妥当だが、性能の観点で「CPUは命令を順次実行する」というのは基本的に間違っている。パイプラインは命令を並列実行するし、SIMDもあり、複数のコアが同じ問題を一緒に処理することもできる

    • この記事は焦点を誤っているように思う。AVX-512を備えたCPUにも大規模なデータ並列性があり、CPUも同時に多数の命令を実行できる
      大きな違いは、CPUが1つのスレッドを効率的に実行するために制御フロー処理へ多くのシリコンと電力を使う一方で、GPUはそのリソースをより多くの計算ユニットに使い、多数のスレッドを実行して制御フローとメモリ遅延を隠す点にある
    • CPUもSIMD命令を複数同時に実行する
  • CPUはシリアルコードに向いていてGPUはパラレルコードに向いている、という言い方はある程度正しいものの、かなり粗い近似です。数百ワット程度の同じような電力予算を想定すると、CPUには独立したタスクを1つずつ、ハイパースレッドまで含めて実行する「コア」が約100個あり、分岐予測とパイプライン化でメモリ遅延を隠します
    GPUには「計算ユニット」が約100個あり、各ユニットは独立したタスク約80個を交互に実行し、別のタスクの次の命令を実行することでメモリ遅延を隠します
    用語はかなり混乱していますし、CPUには256ビット幅のベクトルユニットが、GPUには2048ビット幅のベクトルユニットがある可能性が高いですが、少し離れて見ると両アーキテクチャはかなり似て見えます

    • GPUはCPUよりメモリ帯域幅がおよそ10倍大きく、LLMではこの差が重要になります。最適にバッチ処理するなら、出力トークンを1つ生成するために実質的にメモリ全体を読む必要があり、そのメモリは重みやKVキャッシュに使われるためです
    • 低レイテンシのコアを少数、高スループットのコアを多数組み合わせようという動きがあまりないのが、いつも不思議です。IntelのPコア1つを複数のEコアで囲み、そのEコアにiGPUコアやAVX-512ユニットをたくさん付けるような形でよいはずです
      名前はXeon Chiと呼べばよさそうです
  • ほとんどのプログラミング言語がCPUのような逐次処理に合わせて設計されている一方で、Erlang/ElixirはGPUのように並列性に合わせて設計されていると見るなら、Nx / Axonが伸びるのか気になります: https://github.com/elixir-nx/

    • Erlangは計算量の多い並列処理ではなく、並行性の高い分散システムのために設計されています
    • ElixirとNxが、高性能コンピューティングクラスタの計算集約的なワークロードでどれほどうまく動くのか、本当に気になります。構造的にはこの分野でよく使われるMPIと大きくは違わず、numpyや科学技術向けPythonエコシステムのように、はるかに手に取りやすくなる可能性があります
    • ElixirとNx/Axonの組み合わせが、CPUとGPUが混在するNVIDIA Grace Hopperのようなアーキテクチャにうまく合うかを調べているところです
    • それがGPU上で実行されるのか気になります。将来は両方とも必要になると思います。逐次プログラミングは、依然として、膨大な並列実行を必要としない大半の作業にとって最良の抽象化です
  • 購入ガイドが必要です。最低いくら必要なのか、予算帯ごとの最善の選択肢は何なのか知りたいです。問題は、その情報が時々変わることで、継続的に最新化されている資料があるのか分かりません

  • また「すべての開発者が知っておくべき」系のクリックベイト記事に戻ってきたのか

    • そういう形式の記事はChatGPTに置き換えられそうですが、よく書かれた記事なら実際かなり価値があります
      複雑さに正面から向き合うのが好きですし、コンピュータハードウェアのような分野における定量的な方法と定性的な細部の両方をある程度知っているので、ある分野の細部をきちんと教えてくれる記事は歓迎です
      例えば「What every programmer should know about memory」をすべてのプログラマーが知るべきかは別として、優れたプログラマーならコンピュータが実際にどう動くのかについて感覚を持っているべきです。その記事から得られる核心である局所性は、速く、追いやすく、問題に合った良いコードの中で、しばしば自然に現れます
    • そんな感じです。この記事の主張は割り引いて見るべきです
  • 良い記事ですが、AWS P5インスタンスはP4d、P4deと同様、推論ではなく学習向けに明確に最適化されています。推論により適したインスタンスタイプは、それぞれT4とA10G GPUを使うG4dnG5です

    • 原文はG5を抜かしています
  • GPUプログラミングはほぼ初めてですが、この記事は面白く読めました。簡単な「犬か猫か」のニューラルネットワークを、これほど簡単に学習できるようになるまで進歩したことに驚きます