Intel Arcで「Qwen3-TTS」を使って音声を生成しよう

Ubuntu
スポンサーリンク

Amazonのアソシエイトとして、当ブログは適格販売により収入を得ています。

日本語を含む10言語に対応した音声生成モデル「Qwen3-TTS」ファミリーがオープンソース化
Alibaba CloudのQwenチームが、音声合成モデル「Qwen3-TTS」ファミリーをオープンソースとして公開しました。Qwen3-TTSはテキストから自然で人間らしい音声を生成するだけでなく、説明文から新しい声を作るボイスデザイン...

上のリンクの記事をみて「Qwen3-TTS」に興味を持ったので記事にしますね。
調べていると、

Qwen3-TTSってなんだ?〜3秒の音声でボイスクローンできる最新AIを日本語環境で完全攻略〜 - Qiita
この記事の対象読者 Pythonの基本文法を理解している方 音声合成(TTS)に興味があるが、まだ試したことがない方 ローカルでAI音声生成を動かしてみたい方 MacからWindowsに移行して、GPU環境を構築したばかりの方 この記事で得...

こちらの記事で「Qwen3-TTS」の公式UIをすべて日本語化したのみならず、文字起こしなど便利な機能を追加しgithubに公開されている方がおられました。
是非使わせていただこうと思います。

ただ、こちらのリポジトリではcudaのみ対応(Radeonでも動く?)のようで、そのままではIntel Arcでは動きませんので、いろいろと手を加えてみました。

かんたんにIntel Arcでの動作確認はしましたので、とりあえず記事にします。

まずは、uvのインストール

今回はuv環境を使います。
uvの導入は

sudo apt install curl

curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env

となります。

Qwen3-TTS-JPのインストール

上で紹介させていただいた、リポジトリからQwen3-TTS-JPを導入します。

#!/bin/bash

mkdir -p ~/install/Qwen3-TTS-for-xpu
git clone https://github.com/hiroki-abe-58/Qwen3-TTS-JP.git ~/install/Qwen3-TTS-for-xpu
cd ~/install/Qwen3-TTS-for-xpu

# 1.仮想環境の作成と有効化
uv venv --python 3.12 --seed
source .venv/bin/activate

# 2.torch.xpuのインストール
# ※ 最新の安定版を入れます。バージョンは環境に合わせて調整してください
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/xpu


# 3. faster-whisper代わりのTransformersと高速化ライブラリを入れる
# insanely-fast-whisperのコア技術であるtransformers pipelineとaccelerateを入れます
uv pip install transformers==4.57.3 accelerate optimum librosa soundfile onnxruntime sox

# 4. リポジトリ本体のインストール
# ※ --no-deps を付けて、さっき入れたtorch.xpuが上書きされないようにします
uv pip install --no-deps -e .

# 5. 足りない依存関係だけを手動で追加
# setup.py/pyproject.tomlの中身に基づき、TTS動作に必要なものを入れます
uv pip install gradio numpy scipy tqdm pyyaml tensorboard einops

文字起こしに使われている「faster-whisper」はIntel Arcでは動きません(自分が動かし方を知らないだけかも)。
なので、代わりに「insanely-fast-whisper」を使います。

Intel Arcで動かすために「run_arc.py」を追加

Qwen3-TTS-JPはソースコードにいたるところでtorch.cudaを呼び出していますが、これではIntel Arcでは動きません。
そこで、いつものようにGeminiにお願いして「run_arc.py」を作ってもらいました。

import sys
import types
import torch
from transformers import pipeline
import functools

print("=== initializing Qwen3-TTS for Intel Arc (XPU) [Final Patch] ===")

# ==========================================
# 0. 互換性パッチ: Allocator Warmup無効化
# ==========================================
try:
    import transformers.modeling_utils
    transformers.modeling_utils.caching_allocator_warmup = lambda *args, **kwargs: None
except:
    pass

# ==========================================
# 1. 互換性パッチ: Config pad_token_id
# ==========================================
try:
    from qwen_tts.core.models.modeling_qwen3_tts import Qwen3TTSTalkerConfig
    _original_config_init = Qwen3TTSTalkerConfig.__init__
    def _patched_config_init(self, *args, **kwargs):
        _original_config_init(self, *args, **kwargs)
        if not hasattr(self, "pad_token_id") or self.pad_token_id is None:
            self.pad_token_id = 0
    Qwen3TTSTalkerConfig.__init__ = _patched_config_init
except ImportError:
    pass

# ==========================================
# 2. CUDA偽装パッチ (Factory Functions)
# ==========================================
# device="cuda" を device="xpu" に書き換える処理
def _convert_device_arg(kwargs):
    if "device" in kwargs:
        dev = kwargs["device"]
        if (isinstance(dev, str) and "cuda" in dev) or \
           (isinstance(dev, torch.device) and dev.type == "cuda"):
            kwargs["device"] = "xpu"
    return kwargs

# クロージャの問題を回避するためのファクトリ関数
def create_patched_factory(original_func):
    @functools.wraps(original_func)
    def patched_factory(*args, **kwargs):
        # デバイス引数をXPUに置換
        kwargs = _convert_device_arg(kwargs)
        return original_func(*args, **kwargs)
    return patched_factory

_torch_factories = ["empty", "zeros", "ones", "full", "randn", "rand", "tensor", "arange", "linspace"]

count = 0
for func_name in _torch_factories:
    if hasattr(torch, func_name):
        original = getattr(torch, func_name)
        # ここで関数を作成してセットする(変数が上書きされないように分離)
        setattr(torch, func_name, create_patched_factory(original))
        count += 1

print(f"=== [Patch] Successfully redirected {count} torch factory functions to XPU. ===")

# ==========================================
# 3. CUDA偽装パッチ (API Level)
# ==========================================

# A. 有無チェック
torch.cuda.is_available = lambda: True
torch.cuda.device_count = lambda: 1
torch.cuda.current_device = lambda: 0
torch.cuda.get_device_name = lambda x=0: "Intel Arc Pro B60"
torch.cuda.set_device = lambda x: None

# B. メモリ情報
def patched_mem_get_info(device=None):
    try:
        return torch.xpu.mem_get_info(device)
    except:
        return (20 * 1024**3, 24 * 1024**3)
torch.cuda.mem_get_info = patched_mem_get_info

# C. デバイスプロパティ
class DummyDeviceProperties:
    def __init__(self):
        self.total_memory = 24 * 1024**3
        self.major = 8
        self.minor = 0
        self.name = "Intel Arc Pro B60"
        self.multi_processor_count = 128
torch.cuda.get_device_properties = lambda device: DummyDeviceProperties()
torch.cuda.get_device_capability = lambda device=None: (8, 0)

# D. 転送メソッド (.to, .cuda)
original_to = torch.Tensor.to
def patched_to(self, *args, **kwargs):
    new_args = list(args)
    if len(new_args) > 0:
        if isinstance(new_args[0], str) and "cuda" in new_args[0]:
            new_args[0] = new_args[0].replace("cuda", "xpu")
        elif isinstance(new_args[0], torch.device) and new_args[0].type == "cuda":
            new_args[0] = torch.device("xpu")
    
    if "device" in kwargs:
        dev = kwargs["device"]
        if isinstance(dev, str) and "cuda" in dev:
            kwargs["device"] = dev.replace("cuda", "xpu")
        elif isinstance(dev, torch.device) and dev.type == "cuda":
            kwargs["device"] = torch.device("xpu")
            
    return original_to(self, *new_args, **kwargs)

torch.Tensor.to = patched_to
torch.Tensor.cuda = lambda self, *args, **kwargs: self.to("xpu")

# ==========================================
# 4. Whisper アダプター (Transformers Pipeline化)
# ==========================================
class ArcWhisperAdapter:
    def __init__(self, model_size_or_path, device="xpu", compute_type="float16", **kwargs):
        if "/" not in model_size_or_path:
            model_id = f"openai/whisper-{model_size_or_path}"
        else:
            model_id = model_size_or_path
        
        print(f"=== [Arc Wrapper] Loading Whisper model '{model_id}'... ===")
        self.pipe = pipeline(
            "automatic-speech-recognition",
            model=model_id,
            device="xpu",
            torch_dtype=torch.float16,
            chunk_length_s=30,
        )

    def transcribe(self, audio, language=None, beam_size=5, **kwargs):
        generate_kwargs = {}
        if language:
            generate_kwargs["language"] = language
        
        outputs = self.pipe(
            audio, 
            batch_size=16, 
            return_timestamps=True,
            generate_kwargs=generate_kwargs
        )
        
        class DummySegment:
            def __init__(self, text):
                self.text = text
                self.start = 0.0
                self.end = 0.0

        return [DummySegment(outputs["text"])], None

dummy_fw = types.ModuleType("faster_whisper")
dummy_fw.WhisperModel = ArcWhisperAdapter
sys.modules["faster_whisper"] = dummy_fw

# ==========================================
# 5. メインプロセスの起動
# ==========================================
if __name__ == "__main__":
    from qwen_tts.cli.demo import main
    
    if "--no-flash-attn" not in sys.argv:
        sys.argv.append("--no-flash-attn")
    
    model_arg_exists = any("Qwen/Qwen3-TTS" in arg for arg in sys.argv)
    if not model_arg_exists:
        sys.argv.append("Qwen/Qwen3-TTS-12Hz-1.7B-Base")
        
    if "--port" not in sys.argv:
        sys.argv.extend(["--port", "7860"])
    
    if "--ip" not in sys.argv:
        sys.argv.extend(["--ip", "0.0.0.0"])

    print("=== Launching Qwen3-TTS Main Loop ===")
    main()

実は自分は中身について全くわかっていません。
なので、この記事を見ている人で動かしてみようと思っている方は、自己責任でお願いします。

上のスクリプトを「run_arc.py」として保存します。
そうしたら、これを「Qwen3-TTS-for-xpu」のフォルダの中に移動します。

では起動してみましょう。

source .venv/bin/activate
python ./run_arc.py

簡単にテスト

それでは簡単にテストしてみましょう。

ちょっと読み間違いがあるのと、抑揚が不自然な点が気になります。
「Qwen3-TTS」はまだ発表されたばかりなので、これからでしょう。
以前の記事で紹介した、GPT-SoVITSと比べどのように発展するのか楽しみです。

今回は以上です。


相変わらず表記がおかしいですが、「Arc Pro B60」らしきものがAmazonにあるみたいです。

Amazon | SPARKLE Intel Arc A60 搭載 グラフィックボード ロープロファイル 対応 【国内正規代理店品】 SBP60W-24G | スパークル(Sparkle) | グラフィックボード 通販
SPARKLE Intel Arc A60 搭載 グラフィックボード ロープロファイル 対応 【国内正規代理店品】 SBP60W-24Gがグラフィックボードストアでいつでもお買い得。当日お急ぎ便対象商品は、当日お届け可能です。アマゾン配送商...

B580も在庫が復活しているみたい。

Amazon | SPARKLE Intel Arc B580 グラフィックカードOC版 トリプルファン「TITAN」シリーズ [ B580 TITAN OC 12GB ] | Sparkle Computer | グラフィックボード 通販
SPARKLE Intel Arc B580 グラフィックカードOC版 トリプルファン「TITAN」シリーズ がグラフィックボードストアでいつでもお買い得。当日お急ぎ便対象商品は、当日お届け可能です。アマゾン配送商品は、通常配送無料(一部除...

コメント

タイトルとURLをコピーしました