CLAPを使ってMusicCapsの楽曲を検索してみる
概要
以前の記事でLAION/CLAPを使った効果音の検索をやりました。今回は楽曲の検索をやってみます。今回の検索は「楽曲」で「楽曲」を検索します。最後におまけで「テキスト」で「楽曲」を検索しています。
MusicCapsのダウンロード
今回は検索用のデータセットとしてMusicCapsを使います。過去記事で紹介したやり方でMusicCapsの楽曲をwav形式でダウンロードします。
全部落とす必要はありませんが、500曲ぐらいはあったほうが結果がわかりやすいと思います。今回はmusic_caps_dataというフォルダにダウンロードしています。
$ ls music_caps_data/
00M9FhCet6s.wav 0TV9zvfwFhs.wav 1ToIyrmWFjw.wav 2uvHgwAljPA.wav 3TO4C7SiC7I.wav 4sD0Bvt3FKk.wav 5s0yPPrQWxs.wav 6u1ckcErgcQ.wav 7YtKrL6ScXA.wav
01hjVJN9xCg.wav 0u1sk49gAU0.wav 1TyOPtg0Yfk.wav 2UY_-oF1vqo.wav 3TP1itJqv-E.wav -4SYC2YgzL8.wav 5tNOauvQWQQ.wav 6uIOGE36tWo.wav 7YWMPBHKdyY.wav
01PzcPKT3_E.wav 0u4gY1bBUwQ.wav 1tz4xNRRR4M.wav 2VFVe0RCn7g.wav 3TQmts_MxyQ.wav 4T2KBwRxi_g.wav 5Tq56BN8PCQ.wav 6UJhTZgnVro.wav 7ZW8xO37bA4.wav
0298WjE3_tk.wav 0u5-WiBKam8.wav 1uHF1-8TcEk.wav 2_Vk3tmqz-0.wav 3tSPMzvuQpk.wav 4T_5clu_0OM.wav 5tRNPTLRZqI.wav 6VJ_auuKzss.wav 7ZXz3Xa7APs.wav
02Qntw26enM.wav 0Ubu4BqSWmU.wav -1UWSisR2zo.wav 2vQTq4QLP8U.wav 3tyb0cXoX2g.wav 4TDtUHo5cSE.wav 5tt_GKV13G0.wav 6vM7Kv42Uv0.wav -88me9bBzrk.wav
...
MusicCapsのキャプションを取得
MusicCapsをload_dataset()で読み込みます。ytidにYoutubeのIDが入っています。captionが楽曲の説明文です。今回はこちらをdictionaryに突っ込んでJSONで保存しておきます。
import os
import json
from datasets import load_dataset
ds = load_dataset('google/MusicCaps', split='train')
filename_to_caption_dic = {}
for d in ds:
ytid = d['ytid'] # YoutubeのID
filename_to_caption_dic[ytid] = d['caption'] # キャプション
with open('filename_to_caption.json', 'w') as f:
json.dump(filename_to_caption_dic, f)
楽曲用のCLAPの学習済みモデルをダウンロード
楽曲用の学習済みモデルが music_audioset_epoch_15_esc_90.14.pt です。こちらをhuggingfaceからダウンロードします。下のリンク先のdownloadからダウンロードします。
今回はこちらをmodelsフォルダに入れておきます。
学習済みモデルをロード
サンプルコードのままではロード時にエラーになります。githubのissuesに回避策が書いてありました。
まずtransformersのバージョンを4.30.2にします。
transformers==4.30.2
次にこちらで書いてあるようにlaion_clap.CLAP_Module()でamodel='HTSAT-base'を指定する必要があります
import numpy as np
import librosa
import torch
import laion_clap
import glob
# quantization
def int16_to_float32(x):
return (x / 32767.0).astype(np.float32)
def float32_to_int16(x):
x = np.clip(x, a_min=-1., a_max=1.)
return (x * 32767.).astype(np.int16)
model = laion_clap.CLAP_Module(enable_fusion=False, amodel= 'HTSAT-base')
model.load_ckpt('models/music_audioset_epoch_15_esc_90.14.pt')
楽曲をベクトルに変換
ここは以前の効果音の検索とほぼ同じです。MusicCapsのキャプションは英語なので、ここでdeep_translatorを使って日本語に変換しています。このほうが結果比較がやりやすいです。
import os
import json
from tqdm import tqdm
from deep_translator import GoogleTranslator
def translate(text):
return GoogleTranslator(source='auto',target='ja').translate(text)
input_dir = 'music_caps_data/*.wav'
file_list = [p for p in glob.glob(input_dir, recursive=True) if os.path.isfile(p)]
with open('filename_to_caption.json','r') as f:
filename_to_caption_dic = json.load(f)
info_list = []
for file in tqdm(file_list):
try:
audio_embed = model.get_audio_embedding_from_filelist(x=[file], use_tensor=False)
key = os.path.basename(file).replace('.wav', '')
caption = filename_to_caption_dic[key]
info = {}
info['file'] = file
info['caption'] = translate(caption)
info['embed'] = audio_embed[0]
info_list.append(info)
except Exception as e:
print('error:', e)
continue
指定した楽曲に近い順番でソートする
ランダムで1曲選んで、それに近い順番にソートして、日本語のキャプションを表示してみます。
import numpy as np
import random
# ソートしてみる
find_index = random.randint(0, len(info_list)-1)
embed_list = [info['embed'] for info in info_list]
dot_product_list = []
find_embed = embed_list[find_index]
nrm = np.linalg.norm(find_embed)
find_embed = find_embed / nrm
for embed in embed_list:
nrm = np.linalg.norm(embed)
embed = embed / nrm
dot_product_list.append(np.dot(find_embed, embed))
sorted_index_list = list(np.argsort(dot_product_list))
sorted_index_list.reverse()
print('find index caption:', info_list[find_index]['caption'])
print('-------------------------')
for i in sorted_index_list[:10]:
print(info_list[i]['caption'], ' : ', dot_product_list[i])
print('---')
結果
結果その1
最初のfind index captionが検索対象の楽曲のキャプションです。検索結果の1番目に同じ曲が出ているので結果は正しいと言えそうです。今回は「幻想的、アンビエント、悲しい」曲のようです。検索結果の上位に似たような傾向の曲が来ていることがわかります。
find index caption: 女性の声が主旋律を歌うスローバラードです。これにピアノのメロディーが繰り返されます。ベースはコードのルート音を 8 分音符パターンでスタッカート スタイルで演奏します。シンセホーンがさまざまなピッチでバックグラウンドで演奏されます。この曲にはアンビエントで幻想的な雰囲気があります。曲の雰囲気が忘れられない。映画の悲しいシーンで流れるこの曲。
-------------------------
女性の声が主旋律を歌うスローバラードです。これにピアノのメロディーが繰り返されます。ベースはコードのルート音を 8 分音符パターンでスタッカート スタイルで演奏します。シンセホーンがさまざまなピッチでバックグラウンドで演奏されます。この曲にはアンビエントで幻想的な雰囲気があります。曲の雰囲気が忘れられない。映画の悲しいシーンで流れるこの曲。 : 1.0
---
この音楽は心安らぐインストゥルメンタルです。ゆっくりとしたテンポで、美しいヴァイオリンの交響曲、ロマンチックなピアノの伴奏、ハープの旋律、管楽器、シェイカーが響きます。その音楽は穏やかで、優しく、物思いにふけり、ノスタルジックで、心を痛め、メランコリックで、
ロマンチックで、魅惑的で、謎めいていて、夢のような、穏やかで、幻想的です。 : 0.7005424
---
これは新時代の音楽作品です。この作品には歌手は登場しません。アコースティックギターが主旋律を奏でています。ピアノが曲の和音を演奏しており、背景ではかすかなシンセストリングスの音が聞こえます。雰囲気はリラックスして癒されます。この曲は瞑想ビデオのBGMに最適です。スパやウェルネスセンターのバックグラウンドで再生されることもあります。 : 0.67039245
---
曲はインストゥルメンタルです。テンポはゆっくりで、感動的なヴァイオリンのソロ、キーボードの伴奏、パーカッションのドラム、力強いベースライン、ギターの伴奏が含まれます。この曲は感情的であり、悲しみと畏怖の念を持っています。この曲はドキュメンタリーのサウンドトラックです。 : 0.6660481
---
この曲は、言葉を使わずに音声だけを使ってオペラ風に歌う女性の声が特徴です。これには、演奏されているコードに応じて変化する 8 分音符のパターンを演奏するヴァイオリンが伴奏されます。ベースはコードのルート音に従います。ミュートされたギターまたは弦楽器がアルペジオ和音を演奏します。この曲はファンタジーゲームでプレイできます。 : 0.64572895
---
この曲はフルートが主旋律を奏でます。これに、遊牧的なビートを演奏するパーカッションが伴います。弦楽器がバックグラウンドで音を弾きます。アンビエントなシンセサウンドが演奏され、曲に厚みを与えます。この曲には中東の影響があり、夢のような雰囲気があります。ゲームのイントロロビーでプレイできます。 : 0.6444316
---
この音楽はまろやかで贅沢なインストゥルメンタルです。ゆっくりとしたテンポで、美しいヴァイオリンのハーモニー、ピアノ伴奏、シンセサイザーアレンジによる安定したベースラインが響きます。音楽は穏やかで、心を落ち着かせ、心地よく、感傷的で、感情的で、切なく、切なく、メランコリックで、幸福感に満ちています。この曲は絶妙な中東のインストゥルメンタルです。 : 0.6429268
結果その2
別の結果も見てみます。今度は激しいリズミカルな曲が上位に来ているようです。こちらも合っていますね。
find index caption: リードエレキギターがメロディーを奏で、リズムエレキギターがコードをかき鳴らすインストゥルメンタルサーフロック。ミックスではライド シンバルが大音量で、スプリング リバーブがエフェクトとして使用されています。エレキベースがウォーキングパターンを演奏しています。
-------------------------
リードエレキギターがメロディーを奏で、リズムエレキギターがコードをかき鳴らすインストゥルメンタルサーフロック。ミックスではライド シンバルが大音量で、スプリング リバーブがエフェクトとして使用されています。エレキベースがウォーキングパターンを演奏しています。 : 1.0
---
ブルース曲の生演奏です。楽器演奏です。リードのエレキギターがブルースのソロを演奏し、別のエレキギターとベースギターがバックグラウンドで演奏しています。リズミカルな背景は、スローテンポのブルースのアコースティック ドラムのビートで構成されています。この演奏にはグルーヴィーな雰囲気が漂っている。この曲はロックバーのバックグラウンドで流れているかもしれない。 : 0.60694575
---
これはパンクロックの音楽作品です。男性ヴォーカルがうなり声のような歌い方をしている。メロディーはエレキギターで演奏され、ベースギターがバックグラウンドで演奏されます。リズムはやや速めのロックなアコースティックドラムのビートで構成されています。アグレッシブな雰囲気を持った作品です。アクション満載のビデオ ゲームのサウンドトラックに使用できます。 : 0.5868683
---
これはサイケデリックなロック音楽です。男性ボーカリストがリードしてメロディックに歌います。エレキギターとベースギターをバックにキーボードで主旋律を奏でます。リズミカルな背景は、ロックのアコースティック ドラムのビートで構成されています。雰囲気は冷たくて奇抜です。この作品は、幻覚旅行のシーンが含まれるドラマ映画や TV シリーズのサウンドトラックに使用できます。ヒッピーコーヒーショップのバックグラウンドで再生されている可能性もあります。 : 0.57881033
---
このアマチュア録音にはクラシックな曲が含まれています。ヴァイオリンソロをフィーチャーしたインスト曲です。これに、シンプルなビートを演奏するパーカッションが伴います。キーボードがバックグラウンドでコードを演奏し、小節の間にフィルが入ります。ベースはルート音とコードの下5度を演奏します。この曲には声がありません。音質が低いため、他の楽器は不明瞭です。この曲はクラシック映画でも流れます。 : 0.56185186
---
低品質の録音には、ロック曲のカバーが含まれており、バックグラウンドでロック楽器の再生が再生され、その上でエレキギターのソロのメロディーが再生されます。おそらく低品質のマイクで録音されたため、くぐもってうるさく聞こえますが、それでも情熱的で感情的です。 : 0.5446205
指定したテキストで楽曲を検索してみる
今度はテキストで検索してみます。
model.get_text_embedding()でテキストをベクトルに変換します。こちらの関数が要素を2つ渡さないとエラーになってしまうようです。2つ渡して最初だけ使います。
text_data = ['cheerful', 'dummy']
text_embed = model.get_text_embedding(text_data)[0]
print(text_embed.shape)
embed_list = [info['embed'] for info in info_list]
dot_product_list = []
nrm = np.linalg.norm(text_embed)
text_embed = text_embed / nrm
for embed in embed_list:
nrm = np.linalg.norm(embed)
embed = embed / nrm
dot_product_list.append(np.dot(text_embed, embed))
sorted_index_list = list(np.argsort(dot_product_list))
sorted_index_list.reverse()
print('find index caption:', text_data[0])
print('-------------------------')
for i in sorted_index_list[:10]:
print(info_list[i]['caption'], ' : ', dot_product_list[i])
print('---')
結果
「cheerful(陽気な)」というテキストで検索してみます。cosine類似度は低いですが、陽気な曲が上位にきているのではないでしょうか。
find index caption: ['cheerful', 'dummy']
-------------------------
男性ボーカリストがこのメロウなラップを歌います。テンポはミディアムで、グルーヴィーなベースライン、キーボードのハーモニー、滑らかなドラム演奏、ボーカルのバックアップが特徴です。この曲は若々しく、物語性があり、情熱的で、インパクトがあり、説得力があり、魅力的です。この曲は現代的なヒップホップ/ラップです。 : 0.39054695
---
男性ボーカリストが外国語でこの甘いアニメーションソングを歌います。テンポが速く、同様に生き生きとした陽気なピアノ伴奏が伴います。この曲は、シンプルで、甘く、愛らしく、キャッチーで、愛らしく、キャッチーで、陽気で、キュートで、魅力的で、魅力的で、魅力的です。この曲はアニメシリーズの童謡です。 : 0.3703621
---
男性ボーカルがしっとりとしたラブソングを歌います。テンポはゆっくりで、ロマンチックなピアノ伴奏、グルーヴィーなベースライン、安定したドラム演奏、アンビエントなサックスハーモニーが響きます。この曲はロマンチックで、感情的で、穏やかで、感傷的な、プロポーズやウェディングソングです。この曲はR&B/ソウルの曲です。 : 0.35007432
---
この曲には2本のアコースティックギターがメロディーを弾いています。男性の声がバックボーカルとともに高音域で歌い始めると、デジタルドラムがシンプルなグルーヴを奏でます。するとメロディーが1オクターブ下がります。ギターはスピーカーの左右にパンされます。この曲は友達との旅行中に流れているかもしれません。 : 0.35001284
---
録音の品質が悪いです。スピーカーから聞こえてくるようなバックの楽器に合わせて、男性の声がソウルフルに歌っています。ピアノの演奏があり、電子ドラムの音が聞こえます。この曲が家で歌の練習中に流れているかもしれません。 : 0.34857455
---
これは、陽気で陽気で活気に満ちたジャズ風のインストゥルメンタルです。これはスイングダンスに適しています。リックを演奏するエレクトリック・ギタリスト、パンチの効いたピアノ、そしてグルーヴィーで複雑なドラム・パターンが特徴です。この曲は4つ打ちの4拍子です。 : 0.34316605
---
このオーディオには、アコースティック ドラム セットが高速のスネア ロールを演奏し、各ビートにキックといくつかのクラッシュ ヒットが追加されています。シンセサイザーが高音域の速いリードメロディーを演奏しています。その後、曲は次のパートに突入し、ブラス/ストリングスのセクションがキックとともにビートごとにメロディーを変化させる音を演奏します。この曲はペースの速いビデオゲームで流れているのかもしれません。 : 0.34108448
---
このヒップホップ ソングは、反復的でエコーするピアノのメロディー、手拍子、パンチの効いたキック ヒットの上でラップするフラットな男性ボーカルを特徴としています。ループの最初で、たどたどしいハイハット、持続的なシンセベース、フィルターをかけられたピッチアップした女性の聖歌の演奏があります。ラッパーのラップの仕方のおかげで、グルーヴィーで中毒性のあるサウンドに聞こえます。 : 0.3331912
Discussion