ディープラーニングモデルの安全な並列推論とパフォーマンス最適化

ディープラーニングモデルの安全な並列推論とパフォーマンス最適化
Photo by Amy Chen / Unsplash

こんにちは!

今日は、よく聞かれる質問の1つである「単一のモデルインスタンスで安全に並列推論を行えるか?」に関する内容です!

evalモードでの並列推論の安全性

PyTorchモデルがmodel.eval()を使用してevalモードに設定されている場合、一般的に並列推論に対して安全になります。

(ここでいう「並列」はマルチスレッドによる処理ととらえてください。バッチ推論については後述します。)

その理由は、

  1. パラメータの不変性
    evalモードでは、順伝播(forward pass)中にモデルのパラメータが更新されません。
  2. 学習特有レイヤーの非活性化
    BatchNormなどのレイヤーは、バッチ統計の計算ではなく、実行時統計(running statistics)を使用するモードに切り替わります。
  3. 入力データの独立性
    各スレッドやプロセスは独自の入力データで動作し、それぞれ別のメモリ領域に存在します。

以下は、evalモードでの安全な並列推論の基本的な例です:

import torch
import threading

def safe_inference(model, data):
    with torch.no_grad():
        return model(data)

model = YourModel()
model.eval()  # 重要: evalモードに設定

# 複数スレッドで推論を実行
threads = []
for i in range(10):
    t = threading.Thread(target=safe_inference, args=(model, your_data[i]))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

注意が必要な場合

しかし、以下のような状況では注意が必要です:

  1. カスタムレイヤーの存在
    独自に実装したレイヤーがある場合、その並列実行時の挙動を慎重に確認する必要があります。
class CustomLayer(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.counter = 0  # 潜在的な問題源

    def forward(self, x):
        self.counter += 1  # スレッドセーフではない
        return x + self.counter

# このようなカスタムレイヤーは並列実行時に問題を引き起こす可能性があります
  1. GPUメモリの制約
    複数スレッドが同時に大量のデータを処理する場合、GPUメモリ不足が発生する可能性があります。
  2. 複雑なモデル構造
    特定のタイプのAttentionメカニズムなど、一部の複雑なモデル構造では、並列実行時に予期せぬ挙動を示す可能性があります。

プールの使用

上記のような注意が必要な場合、モデルインスタンスのプールを使用することで問題を回避できる場合があります。
以下は簡単なモデルプールの実装例です

import torch
from queue import Queue

class ModelPool:
    def __init__(self, model_class, num_instances):
        self.pool = Queue()
        for _ in range(num_instances):
            model = model_class().to('cuda')
            model.eval()
            self.pool.put(model)

    def get_model(self):
        return self.pool.get()

    def return_model(self, model):
        self.pool.put(model)

def safe_pooled_inference(pool, data):
    model = pool.get_model()
    try:
        with torch.no_grad():
            result = model(data)
        return result
    finally:
        pool.return_model(model)

# 使用例
pool = ModelPool(YourModel, num_instances=3)
results = [safe_pooled_inference(pool, data) for data in your_data_list]

このアプローチでは、各推論タスクが独立したモデルインスタンスを使用するため、並列実行時の問題を回避できます。

パフォーマンスの最適化の基本はバッチ

並列推論は柔軟性を提供しますが、オーバーヘッドによりパフォーマンスが低下する可能性があります。ここでは、パフォーマンスを向上させるための重要なヒントを紹介します。

バッチ処理の活用

個別の並列推論よりも、バッチ処理を活用することで大幅なパフォーマンス向上が見込めます。GPUは大量のデータを同時に処理するのに適しているため、バッチ処理はGPUの能力を最大限に活用できます。

1. 静的バッチ処理

最も単純な方法は、固定サイズのバッチを使用することです:

def batch_inference(model, data_list, batch_size=32):
    results = []
    for i in range(0, len(data_list), batch_size):
        batch = torch.stack(data_list[i:i+batch_size])
        with torch.no_grad():
            batch_results = model(batch)
        results.extend(batch_results)
    return results

# 使用例
results = batch_inference(model, your_data_list)

ただし、都合よくバッチのタイミングでアクセスは来ない

Webサービスなのでオンデマンドな推論サービスをつくってるときには、GPUの単純な並列推論だけでは対処しきれません。

なぜなら、都合よく、同じタイミングでユーザーがアクセスしてこないからです。
むしろうまくバッチにのせられるタイミングのほうがマレです。

2. ダイナミックバッチング

リアルタイムで到着するデータを効率的に処理するために、ダイナミックバッチングを使用できます

import time
from collections import deque

class DynamicBatcher:
    def __init__(self, model, max_batch_size=32, max_wait_time=0.1):
        self.model = model
        self.max_batch_size = max_batch_size
        self.max_wait_time = max_wait_time
        self.queue = deque()
        self.results = {}

    def add_item(self, item_id, data):
        self.queue.append((item_id, data))
        if len(self.queue) >= self.max_batch_size:
            self.process_batch()

    def process_batch(self):
        batch_ids, batch_data = zip(*[self.queue.popleft() for _ in range(len(self.queue))])
        batch_tensor = torch.stack(batch_data)
        with torch.no_grad():
            batch_results = self.model(batch_tensor)
        for item_id, result in zip(batch_ids, batch_results):
            self.results[item_id] = result

    def get_result(self, item_id):
        start_time = time.time()
        while item_id not in self.results:
            if time.time() - start_time > self.max_wait_time:
                self.process_batch()
            time.sleep(0.01)
        return self.results.pop(item_id)

# 使用例
batcher = DynamicBatcher(model)

def process_item(item_id, data):
    batcher.add_item(item_id, data)
    return batcher.get_result(item_id)

# 複数スレッドからprocess_itemを呼び出す

このアプローチでは、データが到着次第バッチに追加され、バッチサイズが最大に達するか、最大待機時間を超えた場合に処理が実行されます。

3. 連続バッチ処理

また、連続的にデータが生成される場合、以下のような連続バッチ処理が効果的です

import torch
from torch.utils.data import DataLoader, IterableDataset

class ContinuousDataset(IterableDataset):
    def __iter__(self):
        while True:
            yield self.get_next_item()  # データ生成ロジックを実装

    def get_next_item(self):
        # 実際のデータ生成ロジックをここに実装
        pass

def continuous_batch_inference(model, dataset, batch_size=32):
    dataloader = DataLoader(dataset, batch_size=batch_size)
    for batch in dataloader:
        with torch.no_grad():
            yield model(batch)

# 使用例
dataset = ContinuousDataset()
for batch_results in continuous_batch_inference(model, dataset):
    process_results(batch_results)  # 結果の処理

この方法では、データが連続的に生成される場合でも、効率的にバッチ処理を行うことができます。

まとめ

今回は、とくに1台のGPUにおける並列化とパフォーマンスについて解説しました。
evalモードでの並列推論は多くの場合安全ですが、パフォーマンスを最大化するためにはバッチ処理が必須ですね。またディープラーニング、LLM系のサービスの推論シーンは多くの場合でダイナミックバッチング、連続バッチ処理などの技術が重要となります。当社でも、ダイナミックバッチ、連続バッチを当初から研究しており、LLMや動画生成、AIキャラクター応答にも応用しています。
これらのテクニックを適切に選択し、実装することで、推論のスループットを大幅に向上させることができます。

並列化とは別観点ではありますが、モデルの量子化、TorchScript の使用、GPU 最適化など、追加の手法を組み合わせることで、さらなるパフォーマンス向上が期待できます。

GPUはとても高額な機器なので、1台のGPUを「使い切る」という視点は非常に重要で当社Qualitegでも日々技術を磨いています。

さらに大規模なアクセスには「GPUクラスター」の導入を考えましょう

一方、大量の同時アクセスが想定されるシーンでは複数台のGPUを使用した負荷分散が必須となります。そちらのテクニックについてもまた別途ブログにて投稿させていただこうとおもいますが、以下の動画に LLM におけるGPUクラスターの構成方法について解説していますので、こちらもよろしければご覧くださいませ。

それでは、また次回お会いしましょう!

Read more

ディープラーニングにおけるEMA(Exponential Moving Average)

ディープラーニングにおけるEMA(Exponential Moving Average)

こんにちは! 本日は、画像生成、動画生成モデルなどで重要な役割を果たしている EMA ※について解説してみたいとおもいます! 当社のAIアバター動画生成サービス「MotionVox™」でも役立っています! といっても、画像生成のための専用技術というわけではなく、学習と推論(生成系も含む)というディープラーニングの運用の中で昨今かなり重宝されるテクニックとなっておりますので、基礎から実装までみていきたいとおもいます。 ※EMAの読み方は私はエマと呼んでますが、イーエムエーって言ってる人もいます。どっちでもいいでしょう。 EMA の基礎知識 EMA(Exponential Moving Average=指数移動平均)は、ざっくりいえばモデルの重みを平均化する手法です。 実は株価分析などでも使われている古くからある概念なのですが、ディープラーニングでは比較的最近になって「あ、これ結構使えるんじゃね?」と重要性が認識されるようになりました。 (”EMA”に限らず、理論の積み上げではなく「やってみたら、使えんじゃん」っていうのがかなり多いのがディープラーニング界隈のもはや常識でし

By Qualiteg 研究部
TOKYO DIGICONX 「MotionVox™」出展レポート

TOKYO DIGICONX 「MotionVox™」出展レポート

こんにちは! 2025年1月9日~11日に東京ビッグサイトにて開催された TOKYO DIGICONX に出展してまいりました。 開催中3日間の様子を簡単にレポートいたします! TOKYO DIGICONX TOKYO DIGICONX は東京ビッグサイト南3・4ホールにて開催で、正式名称は『TOKYO XR・メタバース&コンテンツ ビジネスワールド』ということで、xR・メタバース・コンテンツ・AIと先端テクノロジーが集まる展示会です 「Motion Vox™」のお披露目を行いました 当社からは、新サービス「Motion Vox™」を中心とした展示をさせていただきました MotionVox™は動画内の顔と声を簡単にAIアバター動画に変換できるAIアバター動画生成サービスです。 自分で撮影した動画をアップロードし、変換したい顔と声を選ぶだけの3ステップで完了。特別な機材は不要で、自然な表情とリップシンクを実現。 社内研修やYouTube配信、ドキュメンタリー制作など、幅広い用途で活用できます。 当社ブースの様子 「MotionVox™」の初出展とい

By Qualiteg ビジネス開発本部 | マーケティング部
【本日開催】TOKYO DIGICONX で「MotionVox」を出展~リアルを纏う、AIアバター~

【本日開催】TOKYO DIGICONX で「MotionVox」を出展~リアルを纏う、AIアバター~

こんにちは! 本日(2025年1月9日)より東京ビックサイトにて開催されている「TOKYO DIGICONX」に、フォトリアリスティック(Photorealistic Avater)な次世代アバター生成AI「MotionVox」を出展しています! XR・メタバース・AIと先端テクノロジーが集まる本展示会で、ビジネス向け次世代AI動画生成ツールとしてMotionVox™をご紹介させていただきます。 MotionVox™とは MotionVox™は、あなたの表情や発話を魅力的なアバターが完全再現する動画生成AIです。まるで本物の人間がそこにいるかのような自然な表情と圧倒的な存在感で、新しい表現の可能性を切り開きます。 主な特徴 * フォトリアリスティックな高品質アバター * 高再現度の表情同期 * プロフェッショナルなリップシンク * カスタマイズ可能なボイスチェンジ機能 * 簡単な操作性 * プライバシーの完全保護 多様な用途に対応 MotionVoxは、以下のようなさまざまなビジネスシーンで活用いただけます! * 動画配信やVTuber活動 * S

By Qualiteg ビジネス開発本部 | マーケティング部
[AI新規事業創出]Qualitegセレクション:ビジネスモデル設計①ビジネスモデル図

[AI新規事業創出]Qualitegセレクション:ビジネスモデル設計①ビジネスモデル図

Qualiteg blogを訪問してくださった皆様、こんにちは。Micheleです。AIを活用した新規事業やマーケティングを手がけている私には、クライアントからよく寄せられる質問があります。AIを用いた事業展開を検討されている方々が共通して直面するであろう課題に対して、このブログを通じて私なりの解答をご提供したいと思います。 「新規事業のビジネスモデル図の描き方 〜実践で活かせる具体的なコツ〜」 新規事業開発のコンサルティングをさせていただいておりますとクライアント企業様の現場で、「ビジネスモデル図をどう描けばいいの?」という質問をよく頂きます。 実は私も最初は悩んだのですが、数々の失敗と成功を経て、効果的なビジネスモデル図の描き方が分かってきました。今回は、その実践的なコツをお伝えしていきます。 なぜビジネスモデル図が重要なのか ビジネスモデル図は、単なる図解ではありません。これは、自分のビジネスアイデアを「検証可能な形」に落とし込むための重要なツールです。 上申の際にステークホルダーの説明をするのに使うこともできます。また、アイディア創出後のマネタイズ検討の場合も情報

By Join us, Michele on Qualiteg's adventure to innovation