OpenAIのWhisper APIの25MB制限に合うような調整を検討する

長い会議データを書き起こしたい皆様へ(※約6.5時間まで、音質無保証)
2023.03.05

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんちには。

データアナリティクス事業本部 インテグレーション部 機械学習チームの中村です。

OpenAIからChatGPTとWhisperに関するAPIがリリースされ、先日その紹介記事を書きました。

またその他にも様々な関連記事が弊社のブログからも出ています。

この記事では更なる活用のために、前回書いた以下の部分ついてフォーカスします。

  • Whisper API
    • 入力は25MBまでのため、長さによっては音声のみ、圧縮フォーマットを使用するなどの工夫が必要

どんな時間のデータでも25MB以下に調整することで、Whisperで処理可能にする方法を見ていきます。

変換方法の検討

ファイルサイズの事前チェック

そもそも25MBを超過していない場合は、ビットレートを上げても再変換が走るためかえって劣化します。

そのため、事前にファイルサイズをチェックします。

入力が動画ファイルの場合、音声部分だけを取り出し、そのデータが25MB以下であれば、

元データから劣化せずに処理できます。

以降は、25MBを超えた場合の話となります。

採用する符号化方式

Whisper APIは以下の入力ファイルタイプに対応しています。

  • MP3、MP4、MPEG、MPGA、M4A、WAV、WebM

ひとつひとつのフォーマットについてもう少し詳細を確認すると以下のような感じです。

拡張子 説明
WAV 非圧縮フォーマット
MP3 音声フォーマット。1993年が初版で歴史が長い。
MPGA MP3と同じで、非標準な拡張子。
M4A AACで圧縮された音声フォーマット
WebM Googleが提供しているオープンな動画ファイル形式。
音声フォーマットとしてはVorbisとOpusに対応。
MPEG こちらも動画や音声を記録するファイル形式。MP4の前身。
音声フォーマットのカバー範囲はMP3と同様。
MP4 マルチメディアフォーマット。動画・音声に加え字幕・静止画なども格納可能。
音声フォーマットとしてはHE-AAC, AAC, MP3も格納可能。

一般的にはAACはMP3より後継ですので、AACの方が高効率で圧縮できると考えられます。

(同等ビットレートで高音質)

AACとOpus, Vorbisは比較が難しそうですが、音源ファイルの特性やビットレート設定によっても優劣は変わってきそうです。

今回はffmpegやPydubで安定動作しそうなAAC-LC(M4A)を採用したいと思います。

(ffmpegのOpus対応はexperimentalのようで、設定がうまく反映されないケースがありました)

  • フォーマット : M4A (AAC-LC)

なお、HE-AACはSBRありのため原音に無い成分が生成される可能性があるため、今回は検討しないこととします。

設定するビットレート

今回はデータを25MB以下に調整することで目標を達成したいため、以下の流れでビットレート(kbps)を計算します。

  • データの時間長X [sec]を計算
  • 使えるデータ量は25MB = 25,000,000 [byte]でビットにすると25,000,000*8 [bit]
  • よって理想的なビットレートは25,000,000*8 / Xとなる
  • 理想的なビットレートに対してさらに0.95掛けをする
    • CBR(固定ビットレート)であっても必ず理想的なレート制御ができるとは限らないため、0.95掛けする
  • 最後1000で除算し切り捨てることで、kbps単位に変換する

例えば1時間のデータの場合、以下のようになります。

  • データの時間長は1 * 60 * 60 = 3600[sec]
  • 目標のビットレートは25,000,000 * 8 / 3600 * 0.95 = 52777.77
  • 切り捨てにより52kbpsとなる

また下限のビットレートを8kbpsに設定しておき、これより小さい場合はassertします。

(計算すると、8kbpsだと6.5時間くらいが限界となります)

実際は、ビットレートが下がると音質が劣化しますので、音質が保証できなくなってきます。

その他の設定

WhisperはOSSのときは、内部的にサンプリングレートが 16,000 [Hz]に変換され、チャンネルもモノラルで扱われていました。

今回もその設定に合わせておけば無駄が少ないと予想して調整します。

  • サンプリングレート : 16,000
  • チャンネル数 : 1

実装してみた

フォーマット変換が決まったので、上記の方針に従って実装してみます。

まずはモジュールをインストールします。

環境はGoogle Colabで実施します。ローカル環境の場合、ffmpegのバイナリにPATHを通す必要があります。

準備

!pip install pydub

以下をインポートします

import pathlib
import subprocess
import math

from pydub import AudioSegment

元データを以下のように与えます。

original_file = pathlib.Path("sample.mp4")

今回はクラスメソッド公式の以下の動画を使用しました。

音声のみ抽出

pydubでの無変換での抽出のやり方が分からなかったため、ffmpegをsubprocessで実行します。

audio_file = pathlib.Path("./audio").with_suffix(original_file.suffix)

subprocess.run(["ffmpeg", "-i", str(original_file)
    , "-codec:a", "copy", "-vn", str(audio_file)])

25MB以上かどうかを確認します。

TARGET_FILE_SIZE = 25000000

print(f"{audio_file.stat().st_size=}")
if audio_file.stat().st_size > TARGET_FILE_SIZE:
    print("This file needs to be converted.")
audio_file.stat().st_size=42383482
This file needs to be converted.

こちらは、42MB程度となっているようです。

目標フォーマットに変換

時間長をみるためにpydubを使います。変換には先ほどと同様にffmpegを使用します。

audio_segment = AudioSegment.from_file(str(audio_file))

audio_length_sec = len(audio_segment)/1000

target_kbps = int(math.floor(TARGET_FILE_SIZE * 8 / audio_length_sec / 1000 * 0.95))

if target_kbps < 8:
    assert f"{target_kbps=} is not supported."

converted_file = pathlib.Path("./converted").with_suffix(".mp4")

subprocess.run(["ffmpeg", "-i", str(audio_file)
    , "-codec:a", "aac", "-ar", "16000", "-ac", "1", "-b:a", f"{target_kbps}k"
    , str(converted_file)])

念のため、ファイルサイズを見ておきましょう。

print(f"{converted_file.stat().st_size=}")
converted_file.stat().st_size=23811550

25MB以下となっていることが確認できました。

Whisper APIによる認識

最後にWhisper APIを使って認識させます。

!pip install openai

句読点は欲しいので、promptに句読点ありの文章を入れておきます。

import openai

with open(str(converted_file), "rb") as f:
    response = openai.Audio.transcribe("whisper-1", f
    , prompt="こんにちは。今日は、いいお天気ですね。")
transcription = str(response["text"])

with open("transcription.txt", "wt", encoding="utf-8") as f:
    f.writelines([transcription])

以下が書き起こしされた結果の抜粋です。

はい、みなさんこんばんは。 クラスメソッドがですね、ラスベガスからリインベントの様子をお届けします。 Developers IEO in Las Vegas 2022ということで始めさせていただきます。 どうぞよろしくお願いします。 日本は今ですね、12月1日のお昼12時の時間帯だと思いますけれども、 こちらはですね、まだ11月30日の夜7時ということで、 ちょっと夜でですね、お疲れもあってちょっと変な感じになるんですけれども、 暖かく聞いていただければと思います。 はい、ちなみに今何人くらい入ってらっしゃるんですか?視聴者の方は。 104名です。 素晴らしいですね。 ありがとうございます。 この配信ではですね、 AWS Re-Invent 2022でですね、たくさんのアップデートだったりとかですね、 セッション、キーノート等ありましたので、ここまでで出ている情報をもとにですね、 クラスメソッドのエンジニアが注目した内容とか、 そういったものをですね、エンジニアメンバーから聞いていきたいと思います。 今回ですね、人数の都合上ですね、二部制となっておりまして、 今回今出ているのが前半のメンバーということで、 大体30分くらい目途でですね、後半のメンバーにチェンジしてお送りしていきたいと思います。 じゃあまずですね、今出ている前半メンバーの自己紹介をしたいと思いますので、 順によろしくお願いします。 はい、ARXジオン本部のコンサルティング部で働いてます。 門別と申します。 WebIOとかTwitterとかはMOKOという名前でやってます。よろしくお願いします。 イェーイ。 クラスメソッドのPRISMATICS事業部というところでエンジニアをしています。 エラオーカーと申します。 インターネットではトバシという名前で存在しています。よろしくお願いします。 おぉー。 クラスメソッドのCXジオ本部というところにいます。 主にサーバーサイドエンジニアとかバックエンドのエンジニアをやっています。 あと普段の活動としてはJawsUGのCDK支部みたいなところで運営とかをやったりしています。 今回CDKのアップデートとか気になってきていたりします。よろしくお願いします。 おぉー。 AWS事業本部コンサルティング部内ソリューションアーキテクトをやってます。 高倉と申します。 私はコンテナを覚え続けてここに来ています。よろしくお願いします。 よろしくお願いします。 前半はコンテナサーバーとかインフラやセキュリティにフォーカスしているメンバーを中心にお送りしていきたいと思います。 申し遅れました。私はAWS事業本部の菊池です。よろしくお願いします。 早速聞いていきたいと思いますが、まずは門別さん。 今回のリインベント、今見ている中でこれは熱いぞという事があれば。 そうですね。 初日のマンデーナイトライブで出たNITRO V5とHURAGATE 3E、それに伴うC7GNインスタンスの登場が今のところ僕の中ではポイントなトピックです。 それどの辺が注目ポイントですか? そうですね。GRAVITONシリーズってこれまでメモリーサイティックなインスタンスみたいなところはあったはずなんですけど、 ネットワークにサイティック化されているファミリーというのがなくて、それがGRAVITON 3Eが出てものすごく速くなって、 確か上限で200Gbpsくらい出るみたいな話が出ていたので、 すごいGRAVITONシリーズでもHPCであって、トラフィッククール用がワークロードに使えるようになったというのが、すごいアプレダムかなと思っています。 そうですね。V5とかGRAVITON 3Eですね。 今までN系のインスタンスタイプの後にNとか5、Nとか付いているのがあって、 ネットワークというのはありましたけれども、さらにそれがパワーアップして出るという感じですかね。 そうですね。 はい、ありがとうございます。 じゃあ続いて、トバチさんはどうですか? そうですね。僕が今のところ注目しているのは2つありまして、 1つは昨日のKeynoteで発表されたAmazonオープンサーチサービスのサーバーレス対応が1つと、 もう1つはこれは確か直前の日曜日くらいに発表されたと思うんですけど、 ...

まとめ

いかがでしたでしょうか。

Whisper APIの25MB制限について今回は細かく触れ、その対応方法を見ていきました。

この方法ではビットレートが低くなりすぎるケースも発生しますので、その場合は1時間単位などの区間に区切って使用するのが実用的と考えますので、ご留意ください。

今後APIをお使いになられる方の参考になれば幸いです。