Qwen3-ASR 音声文字起こしツール

プログラムの動作

transcribe_qwen3_asr.py は、Qwen3-ASRモデルを利用して音声ファイルをテキストに文字起こしするためのコマンドラインツールです。このプログラムは、指定された入力音声ファイルを解析し、以下の3種類の出力を生成します。

  1. タイムスタンプ付きテキストファイル: 文字起こしされたテキストに、各セグメントの開始・終了時刻情報が付与されます。

  2. プレーンテキストファイル: 純粋な文字起こしテキストのみが含まれます。

  3. 情報ファイル (JSON形式): 実行時の環境情報、モデル設定、入力ファイルのメタデータ、および文字起こし結果の詳細な統計が含まれます。

このツールは、ASR(自動音声認識)エンジンを ASRBackend という抽象化されたインターフェースの背後に配置することで、将来的に他のASRエンジン(例: Faster Whisper、OpenAI Whisperなど)を容易に追加できるように設計されています。長時間音声ファイルに対しては、ffmpeg を用いた自動チャンク分割処理をサポートしており、タイムスタンプ付きの正確な文字起こしを実現します。

原理

transcribe_qwen3_asr.py は、以下の主要な原理とアルゴリズムに基づいて動作します。

ASRバックエンドの抽象化

プログラムは ASRBackend という抽象基底クラスを定義し、ASRエンジンの共通インターフェースを提供します。現在の実装では Qwen3ASRBackend がこのインターフェースを実装しており、Qwen3-ASRモデルとのやり取りをカプセル化しています。この設計により、コアロジック(CLI引数の解析、出力処理、環境レポートなど)を変更することなく、異なるASRモデルをプラグインとして追加することが可能です。

Qwen3-ASRモデルの利用

Qwen3ASRBackend は qwen_asr ライブラリを内部で使用し、Hugging Face Transformersエコシステムを通じてQwen3-ASRモデルをロードして推論を実行します。

  • モデルロード: Qwen3ASRModel.from_pretrained() メソッドを使用して、Hugging Face Hubから指定されたモデル(例: Qwen/Qwen3-ASR-0.6B)をロードします。

  • デバイスとデータ型の自動選択: --device および --dtype オプションが auto に設定されている場合、プログラムは利用可能なGPU (CUDA) とそのサポート状況(例: bfloat16 がサポートされているか)に基づいて最適なデバイスとデータ型を自動的に選択します。

  • タイムスタンプの付与: --timestamps 1 が指定された場合、Qwen3-ASRモデルの forced_aligner 機能を利用して、文字起こしテキストに対応する正確な開始・終了時刻を推定します。これには Qwen/Qwen3-ForcedAligner-0.6B などのアライナーモデルが使用されます。

  • Attention実装の選択: --attention オプションを通じて、PyTorchのAttention実装(sdpa, eager, flash_attention_2)を選択できます。これにより、パフォーマンスやメモリ使用量を最適化できます。

長時間音声のチャンク分割処理

タイムスタンプ機能が有効な場合、transcribe_with_optional_chunks 関数が長時間音声の処理を担当します。

  1. FFmpegによる分割: 入力音声ファイルの長さが --chunk-seconds で指定された閾値を超える場合、ffmpeg コマンドラインツールを使用して音声を小さなチャンク(部分)に分割します。各チャンクは一時ファイルとして .wav 形式で保存されます。

  2. 重複と結合: チャンク分割の際には、チャンクの境界付近で --chunk-overlap で指定された秒数だけ重複を持たせます。これにより、チャンク境界での文字起こし品質の低下を防ぎます。各チャンクの文字起こし結果は、元の音声ファイルの時間軸に合わせてタイムスタンプが調整され、連結されます。

  3. 境界マーカー: 連結されたテキストには、チャンクの開始、終了、およびチャンク間の境界を示す特殊なマーカー(例: [[ASR_CHUNK]], [[ASR_BOUNDARY]])が挿入されます。これにより、後続のLLM(大規模言語モデル)などによるテキストの後処理において、チャンク境界での重複や不整合を調整するヒントを提供します。

  4. 部分的な結果の保存: 長時間音声の文字起こし中に定期的に部分的な結果をディスクに保存するため、中断された場合でも中間結果が失われることを防ぎます。

環境情報の収集

プログラムは、collect_environment 関数を通じて、OS、Pythonバージョン、インストールされている主要なPythonパッケージ(qwen-asr, torch, transformers など)のバージョン、CUDAの利用可能性とGPU情報、ffmpeg のバージョンなどの詳細な実行環境情報を収集します。この情報は、出力されるJSON形式の情報ファイルに含まれ、デバッグや結果の再現性検証に役立ちます。

必要な非標準ライブラリとインストール方法

transcribe_qwen3_asr.py を実行するには、以下のPythonライブラリと外部コマンドラインツールが必要です。

Pythonライブラリ

以下のライブラリは pip コマンドでインストールできます。

pip install qwen-asr torch transformers accelerate huggingface-hub soundfile librosa
  • qwen-asr: Qwen3-ASRモデルを使用するための公式ライブラリ。

  • torch: PyTorch。深層学習モデルの実行に必須です。CUDA (GPU) を利用する場合は、お使いの環境に合わせたPyTorch (cuda版) をインストールする必要があります。詳細は PyTorch公式ウェブサイト を参照してください。

  • transformers: Hugging Face Transformersライブラリ。Qwen3-ASRが依存しています。

  • accelerate: Hugging Face Accelerateライブラリ。モデルの分散・高速化に使用されます。

  • huggingface-hub: Hugging Face Hubとのインタラクションに使用されます。

  • soundfile: 音声ファイルの読み書きに必要です。

  • librosa: 音声処理ユーティリティを提供します。

外部コマンドラインツール

  • ffmpeg: 音声ファイルのフォーマット変換、トリミング、メタデータ取得などに使用されます。特に、長時間音声のチャンク分割機能を使用する場合に必須となります。

    ffmpeg のインストール方法はOSによって異なります。

    • Ubuntu/Debian:

      sudo apt update
      sudo apt install ffmpeg
      
    • macOS (Homebrew):

      brew install ffmpeg
      
    • Windows: ffmpeg.org からバイナリをダウンロードし、PATH環境変数に追加してください。

必要な入力ファイル

プログラムは1つ以上の音声ファイルを処理できます。

  • ファイル形式: ffmpeg がサポートする任意の音声ファイル形式(例: .wav, .mp3, .flac, .m4a など)。

  • 指定方法: コマンドライン引数 infile でパスを指定します。globパターン(例: *.wav)を使用して複数のファイルを一括で指定することも可能です。

  • データ構造: 特殊なデータ構造は必要ありません。標準的な音声ファイルであれば問題ありません。

生成される出力ファイル

入力ファイルごとに以下の3種類のファイルが生成されます(または --outfile1, --outfile2, --outfile3 で指定されたパス)。ファイル名は、指定がない場合、入力ファイルの基本名(拡張子なし)にサフィックスが付加されます。

  1. <入力ファイル名>-time.txt または --outfile1 で指定されたファイル:

    • 内容: タイムスタンプ付きの文字起こしテキスト。各行は [開始時刻 - 終了時刻] テキスト の形式で出力されます。

    • 例:

      [00:00:00.00 - 00:00:03.50] こんにちは。
      [00:00:03.50 - 00:00:06.15] これはQwen3-ASRのテストです。
      [[ASR_CHUNK 0001 ACTUAL=00:00:00.00..00:00:15.00 CORE=00:00:00.00..00:00:10.00 OVERLAP=10.0s]]
      ...
      [[ASR_BOUNDARY 0001|0002 OVERLAP=10.0s; LLM: reconcile duplicated or incomplete text across this boundary]]
      ...
      
    • 補足: --timestamps 0 を指定すると、[timestamps unavailable] と表示された後にプレーンテキストが出力されます。長時間音声がチャンク分割された場合、チャンク境界を示すマーカーも含まれます。

  2. <入力ファイル名>.txt または --outfile2 で指定されたファイル:

    • 内容: プレーンな文字起こしテキスト。タイムスタンプやチャンク境界マーカーは含まれません。

    • 例:

      こんにちは。
      これはQwen3-ASRのテストです。
      
  3. <入力ファイル名>-info.txt または --outfile3 で指定されたファイル:

    • 内容: JSON形式で、実行に関する詳細なメタデータが含まれます。

      • environment: OS、Python、パッケージバージョン、CUDA/GPU情報、ffmpegバージョンなど。

      • backend: 使用したASRバックエンド(例: qwen3-asr)とモデル設定(モデル名、デバイス、dtype、アライナーなど)。

      • input: 入力ファイルのパス、サイズ、長さ、リクエストされた言語。

      • result: 検出された言語、文字数、セグメント数、処理時間、リアルタイムファクターなど。

      • outputs: 生成された出力ファイルの絶対パス。

      • model_load_seconds: モデルのロードにかかった時間。

    • 例:

      {
        "environment": {
          "timestamp_utc": "2023-10-27T12:34:56.789000+00:00",
          "platform": "Linux-6.x.y-z-generic-x86_64-with-glibc2.31",
          "os": "Linux",
          // ... (その他の環境情報)
          "packages": {
            "qwen-asr": "0.1.0",
            "torch": "2.1.0",
            // ...
          },
          "cuda": {
            "available": true,
            "torch_cuda_version": "12.1",
            "cudnn_version": 8902,
            "device_count": 1,
            "devices": [
              {
                "index": 0,
                "name": "NVIDIA GeForce RTX 3090",
                "total_memory_gib": 24.0,
                "compute_capability": "8.6"
              }
            ]
          },
          "ffmpeg": "ffmpeg version n5.1.2-1+buntu22.04"
        },
        "backend": {
          "backend": "qwen3-asr",
          "model": "Qwen/Qwen3-ASR-0.6B",
          "device": "cuda:0",
          "dtype": "bfloat16",
          "timestamps": true,
          "aligner": "Qwen/Qwen3-ForcedAligner-0.6B",
          "attention": "auto",
          "max_inference_batch_size": 1,
          "max_new_tokens": 4096
        },
        "input": {
          "path": "/home/user/audio.wav",
          "size_bytes": 1234567,
          "duration_seconds": 60.5,
          "requested_language": "Japanese"
        },
        "result": {
          "detected_language": "Japanese",
          "characters": 120,
          "segments": 5,
          "elapsed_seconds": 15.23,
          "realtime_factor": 0.2517,
          "timestamp_items": 5,
          "audio_chunks": 1,
          "chunk_seconds": 240.0,
          "chunk_overlap_seconds": 10.0,
          "boundary_markers": false
        },
        "outputs": {
          "timestamped": "/home/user/audio-time.txt",
          "plain": "/home/user/audio.txt",
          "info": "/home/user/audio-info.txt"
        },
        "model_load_seconds": 10.5
      }
      

コマンドラインでの使用例 (Usage)

python transcribe_qwen3_asr.py [-h] [--backend {qwen3-asr}]
                                [-m {0.6B,1.7B,Qwen/Qwen3-ASR-0.6B,Qwen/Qwen3-ASR-1.7B}]
                                [-l LANG] [-d DEVICE]
                                [--dtype {auto,bfloat16,float16,float32}]
                                [--timestamps {0,1}] [--aligner ALIGNER]
                                [--attention {auto,sdpa,eager,flash_attention_2}]
                                [--max-inference-batch-size MAX_INFERENCE_BATCH_SIZE]
                                [--max-new-tokens MAX_NEW_TOKENS]
                                [--chunk-seconds CHUNK_SECONDS]
                                [--chunk-overlap CHUNK_OVERLAP]
                                [--outfile1 OUTFILE1] [--outfile2 OUTFILE2]
                                [--outfile3 OUTFILE3] [--pause {0,1}]
                                infile

引数の説明

  • infile:

    • 説明: 入力音声ファイル名。globパターン(例: audio/*.wav)が使用可能です。

    • 必須: はい

  • --backend {qwen3-asr}:

    • 説明: 使用するASRバックエンド。現在サポートされているのは qwen3-asr のみです。

    • デフォルト: qwen3-asr

  • -m {0.6B,1.7B,Qwen/Qwen3-ASR-0.6B,Qwen/Qwen3-ASR-1.7B}, --model:

    • 説明: 使用するQwen3-ASRモデル。エイリアス(0.6B や 1.7B)または完全なHugging FaceモデルIDを指定できます。

    • デフォルト: 0.6B

  • -l LANG, --lang:

    • 説明: 文字起こしに使用する言語コードまたは名称(例: ja または Japanese, en または English)。auto または空文字列を指定すると自動で言語を判定します。

    • デフォルト: ja

  • -d DEVICE, --device:

    • 説明: 推論に使用するデバイス。auto (自動選択), cpu, cuda, cuda:0 などを指定できます。

    • デフォルト: auto

  • --dtype {auto,bfloat16,float16,float32}:

    • 説明: 推論に使用するデータ型(精度)。auto (自動選択), bfloat16, float16 (FP16), float32 (FP32) から選択します。

    • デフォルト: auto

  • --timestamps {0,1}:

    • 説明: ForcedAlignerを使用して文字起こし結果にタイムスタンプを付与するかどうか。1 で付与、0 で付与しません。

    • デフォルト: 1

  • --aligner ALIGNER:

    • 説明: タイムスタンプを付与する際に使用するForcedAlignerモデル。

    • デフォルト: Qwen/Qwen3-ForcedAligner-0.6B

  • --attention {auto,sdpa,eager,flash_attention_2}:

    • 説明: Attention層の実装方式。auto (自動選択), sdpa (Scaled Dot Product Attention), eager, flash_attention_2 から選択します。

    • デフォルト: auto

  • --max-inference-batch-size MAX_INFERENCE_BATCH_SIZE:

    • 説明: 推論時のバッチサイズの最大値。小さい値はVRAMの使用量を節約できます。

    • デフォルト: 1

  • --max-new-tokens MAX_NEW_TOKENS:

    • 説明: モデルが生成できる新しいトークンの最大数。長時間音声の文字起こしでは、この値を大きく設定する必要がある場合があります。

    • デフォルト: 4096

  • --chunk-seconds CHUNK_SECONDS:

    • 説明: 長時間音声ファイルをチャンクに分割する際の1チャンクの秒数。0 を指定すると分割を行いません。

    • デフォルト: 240.0

  • --chunk-overlap CHUNK_OVERLAP:

    • 説明: 長時間音声ファイルをチャンクに分割する際に、隣接するチャンク間の重複秒数。チャンク境界での文字起こし品質向上に役立ちます。

    • デフォルト: 10.0

  • --outfile1 OUTFILE1:

    • 説明: タイムスタンプ付きの文字起こし結果を保存するファイル名。指定しない場合、入力ファイル名から自動生成されます。

    • デフォルト: 空文字列 (自動生成)

  • --outfile2 OUTFILE2:

    • 説明: プレーンな文字起こし結果を保存するファイル名。指定しない場合、入力ファイル名から自動生成されます。

    • デフォルト: 空文字列 (自動生成)

  • --outfile3 OUTFILE3:

    • 説明: 環境・設定情報を含むJSONファイルを保存するファイル名。指定しない場合、入力ファイル名から自動生成されます。

    • デフォルト: 空文字列 (自動生成)

  • --pause {0,1}:

    • 説明: プログラム終了時にユーザーがEnterキーを押すまで待機するかどうか。1 で待機、0 で待機しません。

    • デフォルト: 0

コマンドラインでの具体的な使用例

1. 基本的な文字起こし(日本語、自動デバイス選択)

sample.wav という音声ファイルを日本語として文字起こしし、デフォルトのファイル名で出力を生成します。

python transcribe_qwen3_asr.py sample.wav

出力ファイル:

  • sample-time.txt

  • sample.txt

  • sample-info.txt

2. 英語で文字起こしし、出力ファイル名を指定(GPU使用)

my_audio.mp3 を英語として文字起こしし、出力ファイルを明示的に指定します。デバイスはCUDAを使用します。

python transcribe_qwen3_asr.py my_audio.mp3 -l en -d cuda \
    --outfile1 output_en-time.txt --outfile2 output_en.txt --outfile3 output_en-info.json

出力ファイル:

  • output_en-time.txt

  • output_en.txt

  • output_en-info.json

3. タイムスタンプなしで文字起こし

speech.flac をタイムスタンプなしで文字起こしします。

python transcribe_qwen3_asr.py speech.flac --timestamps 0

出力ファイル:

  • speech-time.txt (タイムスタンプなしの形式でプレーンテキストが出力されます)

  • speech.txt

  • speech-info.txt

4. より大きなモデル (1.7B) と bfloat16 精度で文字起こし

long_speech.wav を 1.7B モデルと bfloat16 精度で文字起こしします。GPUが bfloat16 をサポートしている必要があります。

python transcribe_qwen3_asr.py long_speech.wav -m 1.7B --dtype bfloat16

5. 長時間音声のチャンク分割設定を調整

非常に長い音声ファイル very_long_audio.wav を、チャンクサイズを60秒、チャンク重複を5秒に設定して文字起こしします。

python transcribe_qwen3_asr.py very_long_audio.wav --chunk-seconds 60 --chunk-overlap 5

実行中のコンソール出力例 (チャンク処理の場合):

Loading ASR model : Qwen/Qwen3-ASR-0.6B
Loading aligner   : Qwen/Qwen3-ForcedAligner-0.6B
Device / dtype   : cuda:0 / bfloat16
Model load time : 10.25 s

=== Transcription ===
Input           : very_long_audio.wav
Audio duration  : 00:05:00.00
Language        : auto
Output 1 (time) : very_long_audio-time.txt
Output 2 (text) : very_long_audio.txt
Output 3 (info) : very_long_audio-info.txt
Chunk 1: actual 00:00:00.00 - 00:00:60.00, core 00:00:00.00 - 00:00:60.00

=== Chunk 1 completed: 20.0% (00:01:00.00 / 00:05:00.00) ===
Chunk elapsed: 15.34 s
[text from chunk 1]
=== End of chunk result ===

Partial results saved: chunk 1 (20.0%) -> very_long_audio-time.txt, very_long_audio.txt
Chunk 2: actual 00:00:50.00 - 00:01:50.00, core 00:01:00.00 - 00:01:20.00

=== Chunk 2 completed: 40.0% (00:02:00.00 / 00:05:00.00) ===
Chunk elapsed: 16.12 s
[text from chunk 2]
=== End of chunk result ===

Partial results saved: chunk 2 (40.0%) -> very_long_audio-time.txt, very_long_audio.txt
...
Detected language: Japanese
Elapsed          : 80.50 s
Realtime factor  : 0.2683x

=== Transcribed text ===
[Full transcribed text with chunk markers]

6. 複数ファイルの文字起こし(globパターン)

audio_files ディレクトリ内のすべての .m4a ファイルを文字起こしします。出力ファイル名は各入力ファイルに基づいて自動生成されます。

python transcribe_qwen3_asr.py 'audio_files/*.m4a'