🙄
Whisper-Atをgoogle colabで試してみた
Whisper-Atとは
Whisper-ATは、音声タグ付けと音声認識の両方を可能にした音声文字起こしモデルです。
リンク
準備
Google Colabを開き、メニューから「ランタイム→ランタイムのタイプを変更」でランタイムを「GPU」に変更します。
環境構築
インストール手順です。
!pip install whisper-at
推論
(1)デモデータの準備
!pip -q install wget
import wget,IPython
wget.download('https://www.dropbox.com/s/7eznyazmc1pmw9h/case_closed.wav?dl=1', '/content/sample_audio.flac')
IPython.display.Audio('/content/sample_audio.flac')
(2)文字起こし実行
import whisper_at as whisper
# the only new thing in whisper-at
# specify the temporal resolution for audio tagging, 10 means Whisper-AT predict audio event every 10 seconds (hop and window=10s).
audio_tagging_time_resolution = 10
model = whisper.load_model("large-v1")
# for large, medium, small models, we provide low-dim proj AT models to save compute.
# model = whisper.load_model("large-v1", at_low_compute=Ture)
result = model.transcribe("/content/sample_audio.flac", at_time_res=audio_tagging_time_resolution)
for segment in result['segments']:
print(segment['start'], 's-', segment['end'], 's', segment['text'])
output
0.0 s- 5.0 s My name's Jimmy Kudo, and I've always wanted to be a great detective.
5.0 s- 10.0 s Over the years I've worked at perfecting the craft, impressing almost everyone, except maybe Rachel.
10.0 s- 14.0 s But then some bad guys ambushed me, slipping me some kind of poison.
14.0 s- 16.0 s Now what's gonna happen?
16.0 s- 30.0 s It was the first new century in one hundred years.
30.0 s- 36.0 s And when I felt like I should cry, I laughed away my tears.
36.0 s- 48.0 s At the end of a millennium, we waited a long, long time,
48.0 s- 54.0 s To see the brave new world, and the mountains we would climb.
54.0 s- 60.0 s Things I tried to comprehend as a child were made of mystery.
60.0 s- 67.0 s There's nothing I need to defend, there's nothing great about me.
67.0 s- 73.0 s All I will ever believe is the pounding of my heart, though.
73.0 s- 79.0 s It doesn't answer questions, that's just the way it goes.
79.0 s- 84.0 s All I will ever have bacon is the beating in my heart.
90.0 s- 95.0 s Thanks for watching!
驚異的にすごいんですが、なんか意味の区切りまで理解している感じがする。。
(3)Audio Tagづけの結果を取得
import torchaudio
audio, sr = torchaudio.load('/content/sample_audio.flac')
audio_len = audio.shape[1] / sr
audio_tag_result = whisper.parse_at_label(result, language='follow_asr', top_k=5, p_threshold=-2, include_class_list=list(range(527)))
for segment in audio_tag_result:
print("time: ", segment['time'], 'Audio Tag Dict: ', segment['audio tags'])
output
time: {'start': 0, 'end': 10} Audio Tag Dict: [('Music', 1.8221180438995361), ('Speech', 0.932380735874176)]
time: {'start': 10, 'end': 20} Audio Tag Dict: [('Music', 1.3558011054992676), ('Grunge', -1.350265622138977), ('Progressive rock', -1.424497127532959), ('Punk rock', -1.5711394548416138)]
time: {'start': 20, 'end': 30} Audio Tag Dict: [('Music', 0.8049014806747437)]
time: {'start': 30, 'end': 40} Audio Tag Dict: [('Music', 1.323777437210083), ('Grunge', -1.3895658254623413), ('Progressive rock', -1.614871859550476), ('Punk rock', -1.6720657348632812), ('Independent music', -1.8473705053329468)]
time: {'start': 40, 'end': 50} Audio Tag Dict: [('Music', 0.7121016383171082), ('Singing', -1.492790699005127)]
time: {'start': 50, 'end': 60} Audio Tag Dict: [('Music', -1.4463484287261963)]
time: {'start': 60, 'end': 70} Audio Tag Dict: [('Music', 1.2629746198654175), ('Grunge', -0.9662912487983704), ('Pop music', -1.6864861249923706), ('Independent music', -1.7853952646255493)]
time: {'start': 70, 'end': 80} Audio Tag Dict: [('Music', 0.7769227623939514), ('Grunge', -1.5903935432434082), ('Singing', -1.6665356159210205)]
time: {'start': 80, 'end': 90} Audio Tag Dict: [('Speech', -1.0284314155578613), ('Silence', -1.3325611352920532), ('Music', -1.5024266242980957)]
time: {'start': 90, 'end': 100} Audio Tag Dict: [('Silence', 0.9160257577896118)]
(4)Videoのタグづけ
from IPython.display import HTML
from base64 import b64encode
# Replace this URL to play with your own video
wget.download('https://www.dropbox.com/s/pzc72c59xtluuc0/case_closed.mp4?dl=1', '/content/sample_video.mp4')
!pip install -q ffmpeg-python
import os,ffmpeg,cv2
def dubbing_video(video_path, out_video_path, text_info, font_size=0.5, font_v_pos=0.95, font_color=(0, 0, 255)):
extract_audio(video_path, './temp_audio.wav')
video = cv2.VideoCapture(video_path)
# Get video properties
frame_width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = video.get(cv2.CAP_PROP_FPS)
# Create output video writer
output_video = cv2.VideoWriter('./temp_video.mp4', cv2.VideoWriter_fourcc(*"mp4v"), fps,
(frame_width, frame_height))
# Process each frame of the video
current_frame = 0
while video.isOpened():
ret, frame = video.read()
if not ret:
break
# Calculate current time in seconds
current_time = current_frame / fps
# Iterate through text information and add text if within the time interval
for text_start, text_end, text in text_info:
if text_start <= current_time <= text_end:
text_position = (int(frame_width * 0.0), int(frame_height * font_v_pos))
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = font_size
font_color = font_color
line_type = 1
cv2.putText(frame, text, text_position, font, font_scale, font_color, line_type, cv2.LINE_AA)
# Write the frame to the output video
output_video.write(frame)
current_frame += 1
# Release video resources
video.release()
output_video.release()
combine_audio_video('./temp_video.mp4', './temp_audio.wav', out_video_path)
os.remove('./temp_video.mp4')
os.remove('./temp_audio.wav')
def combine_audio_video(video_path, audio_path, output_path):
video = ffmpeg.input(video_path)
audio = ffmpeg.input(audio_path)
output_file = ffmpeg.output(video, audio, output_path)
output_file.overwrite_output().run()
def extract_audio(video_path, output_path):
video = ffmpeg.input(video_path)
audio = video.audio
output_file = ffmpeg.output(audio, output_path)
output_file.overwrite_output().run()
extract_audio('/content/sample_video.mp4', '/content/sample_audio_from_video.wav')
result = model.transcribe("/content/sample_audio_from_video.wav", at_time_res=audio_tagging_time_resolution)
# ASR Output
text_segments = result['segments']
text_annotation = [(x['start'], x['end'], x['text']) for x in text_segments]
# Audio Tagging Output
audio_tag_result = whisper.parse_at_label(result, language='follow_asr', top_k=5, p_threshold=-2, include_class_list=list(range(527)))
all_seg = []
for segment in audio_tag_result:
cur_start = segment['time']['start']
cur_end = segment['time']['end']
cur_tags = segment['audio tags']
cur_tags = [x[0] for x in cur_tags]
cur_tags = '; '.join(cur_tags)
all_seg.append((cur_start, cur_end, cur_tags))
dubbing_video('/content/sample_video.mp4', '/content/sample_video_at.mp4', all_seg)
dubbing_video('/content/sample_video_at.mp4', '/content/sample_video_at_text.mp4', text_annotation, font_color=(0,255,0), font_v_pos=0.85)
os.remove('/content/sample_video.mp4')
os.remove('/content/sample_video_at.mp4')
mp4 = open('/content/sample_video_at_text.mp4','rb').read()
data_url = "data:video/mp4;base64," + b64encode(mp4).decode()
HTML(f"""
<video width="100%" height="100%" controls>
<source src="{data_url}" type="video/mp4">
</video>""")
動画の中に文字起こしされていますが、本当に完璧ですね。
Advanced Application
audio_tag_result = whisper.parse_at_label(result, language='ja', top_k=5, p_threshold=-2, include_class_list=list(range(527)))
for segment in audio_tag_result:
print(segment)
Audio Tagの結果を日本語にも変更できます。
output
{'time': {'start': 0, 'end': 2}, 'audio tags': [('サウンド・オブ・ミュージック', -0.4525575637817383), ('スピーチの音', -0.8882830739021301), ('静寂の音', -1.8616548776626587)]}
{'time': {'start': 2, 'end': 4}, 'audio tags': [('サウンド・オブ・ミュージック', 0.9328102469444275), ('スピーチの音', -0.158194437623024)]}
{'time': {'start': 4, 'end': 6}, 'audio tags': [('サウンド・オブ・ミュージック', 0.7153851389884949), ('スピーチの音', 0.38911065459251404)]}
{'time': {'start': 6, 'end': 8}, 'audio tags': [('サウンド・オブ・ミュージック', 0.40575844049453735), ('スピーチの音', -0.6977154612541199)]}
{'time': {'start': 8, 'end': 10}, 'audio tags': [('サウンド・オブ・ミュージック', 1.6714180707931519), ('スピーチの音', 0.5128814578056335), ('ドラムキットの音', -1.7371801137924194), ('太鼓の音', -1.9375439882278442)]}
{'time': {'start': 10, 'end': 12}, 'audio tags': [('サウンド・オブ・ミュージック', 1.3964262008666992), ('スピーチの音', -0.23263752460479736)]}
{'time': {'start': 12, 'end': 14}, 'audio tags': [('サウンド・オブ・ミュージック', 0.7910271883010864), ('スピーチの音', -1.9267847537994385)]}
{'time': {'start': 14, 'end': 16}, 'audio tags': [('サウンド・オブ・ミュージック', 1.018101692199707), ('スピーチの音', -1.863593339920044)]}
{'time': {'start': 16, 'end': 18}, 'audio tags': [('サウンド・オブ・ミュージック', 1.2444162368774414), ('ロックンロールの音', -1.106768012046814)]}
{'time': {'start': 18, 'end': 20}, 'audio tags': [('サウンド・オブ・ミュージック', 1.1749851703643799), ('ロックンロールの音', -1.696586012840271)]}
{'time': {'start': 20, 'end': 22}, 'audio tags': [('サウンド・オブ・ミュージック', 0.884811282157898)]}
{'time': {'start': 22, 'end': 24}, 'audio tags': [('サウンド・オブ・ミュージック', 1.3546898365020752), ('ロックンロールの音', -1.7012099027633667), ('スピーチの音', -1.882798671722412)]}
{'time': {'start': 24, 'end': 26}, 'audio tags': [('サウンド・オブ・ミュージック', 1.7713080644607544), ('ロックンロールの音', -1.4794251918792725), ('グランジの音', -1.6708897352218628), ('ロックミュージックの音', -1.7350000143051147), ('サウンド・オブ・パンクロック', -1.7468372583389282)]}
{'time': {'start': 26, 'end': 28}, 'audio tags': [('サウンド・オブ・ミュージック', 1.2942352294921875), ('サウンド・オブ・パンクロック', -1.5345808267593384), ('プログレッシブ・ロックのサウンド', -1.5366796255111694), ('ロックンロールの音', -1.795093059539795), ('ギターの音', -1.9063055515289307)]}
{'time': {'start': 28, 'end': 30}, 'audio tags': [('サウンド・オブ・ミュージック', 1.0816413164138794), ('サウンド・オブ・パンクロック', -1.1613421440124512), ('グランジの音', -1.1674290895462036), ('プログレッシブ・ロックのサウンド', -1.6921743154525757), ('ロックミュージックの音', -1.8889744281768799)]}
{'time': {'start': 30, 'end': 32}, 'audio tags': [('サウンド・オブ・ミュージック', 0.7130565047264099), ('グランジの音', -1.7496439218521118), ('サイケデリックロックの音', -1.9967429637908936)]}
{'time': {'start': 32, 'end': 34}, 'audio tags': [('サウンド・オブ・ミュージック', 0.9006908535957336)]}
{'time': {'start': 34, 'end': 36}, 'audio tags': [('サウンド・オブ・ミュージック', 1.1229232549667358)]}
{'time': {'start': 36, 'end': 38}, 'audio tags': [('サウンド・オブ・ミュージック', 1.5627844333648682), ('ロックンロールの音', -1.616320013999939), ('ポップミュージックの音', -1.860297441482544)]}
{'time': {'start': 38, 'end': 40}, 'audio tags': [('サウンド・オブ・ミュージック', 1.4832371473312378), ('ロックンロールの音', -1.5093891620635986)]}
{'time': {'start': 40, 'end': 42}, 'audio tags': [('サウンド・オブ・ミュージック', 1.1807818412780762), ('ロックンロールの音', -1.8162614107131958)]}
{'time': {'start': 42, 'end': 44}, 'audio tags': [('サウンド・オブ・ミュージック', 1.5886766910552979), ('ロックンロールの音', -1.6210857629776)]}
{'time': {'start': 44, 'end': 46}, 'audio tags': [('サウンド・オブ・ミュージック', 1.3883097171783447), ('サウンド・オブ・パンクロック', -1.4467766284942627), ('ロックンロールの音', -1.6486458778381348), ('グランジの音', -1.8386918306350708)]}
{'time': {'start': 46, 'end': 48}, 'audio tags': [('サウンド・オブ・ミュージック', 1.3570588827133179), ('グランジの音', -1.6415327787399292), ('インディペンデント音楽のサウンド', -1.6770530939102173)]}
{'time': {'start': 48, 'end': 50}, 'audio tags': [('サウンド・オブ・ミュージック', 1.2322897911071777), ('プログレッシブ・ロックのサウンド', -1.670889973640442), ('サウンド・オブ・パンクロック', -1.7552521228790283), ('グランジの音', -1.9851617813110352)]}
{'time': {'start': 50, 'end': 52}, 'audio tags': [('サウンド・オブ・ミュージック', 0.9578625559806824), ('楽器の音', -1.7584046125411987), ('グランジの音', -1.7898246049880981), ('ギターの音', -1.9311943054199219)]}
{'time': {'start': 52, 'end': 54}, 'audio tags': [('サウンド・オブ・ミュージック', 0.40247398614883423)]}
{'time': {'start': 54, 'end': 56}, 'audio tags': [('サウンド・オブ・ミュージック', 0.35136619210243225)]}
{'time': {'start': 56, 'end': 58}, 'audio tags': [('サウンド・オブ・ミュージック', 1.121218204498291), ('歌の音', -0.7474337220191956), ('ギターの音', -1.1709648370742798), ('楽器の音', -1.8700003623962402), ('撥弦楽器の音', -1.8718571662902832)]}
{'time': {'start': 58, 'end': 60}, 'audio tags': [('サウンド・オブ・ミュージック', 0.48927149176597595), ('歌の音', -1.516997218132019)]}
{'time': {'start': 60, 'end': 62}, 'audio tags': [('サウンド・オブ・ミュージック', 1.4061903953552246), ('グランジの音', -1.6520559787750244), ('ポップミュージックの音', -1.7633814811706543), ('歌の音', -1.8479968309402466)]}
{'time': {'start': 62, 'end': 64}, 'audio tags': [('サウンド・オブ・ミュージック', 1.0178853273391724), ('ポップミュージックの音', -1.6401900053024292), ('リズムとブルースの音', -1.9780902862548828)]}
{'time': {'start': 64, 'end': 66}, 'audio tags': [('サウンド・オブ・ミュージック', 1.2572810649871826), ('グランジの音', -1.1667473316192627)]}
{'time': {'start': 66, 'end': 68}, 'audio tags': [('サウンド・オブ・ミュージック', 1.0675106048583984), ('グランジの音', -1.7898226976394653)]}
{'time': {'start': 68, 'end': 70}, 'audio tags': [('サウンド・オブ・ミュージック', 1.1966230869293213), ('グランジの音', -1.2361091375350952), ('インディペンデント音楽のサウンド', -1.3939752578735352)]}
{'time': {'start': 70, 'end': 72}, 'audio tags': [('サウンド・オブ・ミュージック', 1.193831205368042), ('歌の音', -1.9588038921356201)]}
{'time': {'start': 72, 'end': 74}, 'audio tags': [('サウンド・オブ・ミュージック', 0.8933382034301758), ('グランジの音', -1.828943133354187)]}
{'time': {'start': 74, 'end': 76}, 'audio tags': [('サウンド・オブ・ミュージック', 1.2897837162017822), ('歌の音', -1.9028337001800537)]}
{'time': {'start': 76, 'end': 78}, 'audio tags': [('サウンド・オブ・ミュージック', 0.4346665143966675)]}
{'time': {'start': 78, 'end': 80}, 'audio tags': [('サウンド・オブ・ミュージック', 0.6879321932792664), ('グランジの音', -1.932247281074524)]}
{'time': {'start': 80, 'end': 82}, 'audio tags': [('サウンド・オブ・ミュージック', 0.5806633830070496), ('歌の音', -1.524978518486023)]}
{'time': {'start': 82, 'end': 84}, 'audio tags': [('サウンド・オブ・ミュージック', 0.3592168986797333), ('スピーチの音', -1.9439775943756104)]}
{'time': {'start': 84, 'end': 86}, 'audio tags': [('静寂の音', 0.6775252819061279), ('スピーチの音', -1.3987550735473633)]}
{'time': {'start': 86, 'end': 88}, 'audio tags': [('静寂の音', -0.42543643712997437), ('スピーチの音', -0.682219386100769)]}
{'time': {'start': 88, 'end': 90}, 'audio tags': [('スピーチの音', -0.7888064980506897), ('静寂の音', -1.000313401222229), ('ため息の音', -1.4150739908218384), ('サウンド・オブ・ミュージック', -1.4370006322860718), ('胃のゴロゴロという音', -1.5969691276550293)]}
{'time': {'start': 90, 'end': 92}, 'audio tags': [('静寂の音', 1.4236705303192139)]}
最後に
今回は新しい文字認識モデルであるwhisper-ATをgoogle colabで試してみました。なんかすごい飛躍を遂げたのではと思うくらい精度がすごい。音声の意味的な部分までしっかりと含めて音節に区切れているところとか驚きましたし、基本的に間違いもないです。人間の耳よりいいのでは?
今後ともLLM, Diffusion model, Image Analysis, 3Dに関連する試した記事を投稿していく予定なのでよろしくお願いします。
Discussion