AI聽曲識歌!哼曲、口哨吹,都能秒識! ⛵

💡 作者:韓信子@ShowMeAI
📘 深度學習實戰系列://www.showmeai.tech/tutorials/42
📘 自然語言處理實戰系列://www.showmeai.tech/tutorials/45
📘 本文地址://www.showmeai.tech/article-detail/311
📢 聲明:版權所有,轉載請聯繫平台與作者並註明出處
📢 收藏ShowMeAI查看更多精彩內容

音樂是我們日常生活娛樂必不可少的部分,我們會收聽電台、欣賞音樂、我們能通過旋律和音色快速分辨歌曲和歌手。

大家都對 QQ 音樂、網易雲音樂等 App 中的『聽曲識歌』『哼唱識別』功能並不陌生,但是它是怎麼樣快速從海量歌曲庫中找到匹配的這一首的呢?

今天 ShowMeAI 就來和大家聊一聊音頻檢索的技術,實際上音頻檢索技術有非常廣泛的應用場景,除了識歌辨曲,基於實時檢索、審查和監控還可以很有效地保護版權。

💡 核心技術

音頻檢索的核心流程如圖所示,我們會對已知歌曲抽取特徵並構建特徵向量庫,而對於待檢索的歌曲音頻,同樣做特徵抽取後進行比對和匹配。其中最核心的技術就是『特徵提取』和『海量向量數據匹配檢索』。

📌 音頻特徵提取

我們在上述過程里也可以看到,要經過音頻內容特徵提取後才能進行後續的相似度檢索。而特徵提取的品質好壞,直接影響最終的效果。有2大類提取音頻特徵的方法:

  • 傳統統計模型:經典的高斯混合模型 (GMM) 和隱馬爾可夫模型 (HMM) 等。
  • 深度學習模型:循環神經網路、長短期記憶 (LSTM)、編碼-解碼框架和注意力機制模型等。

隨著深度學習神經網路技術的不斷革新突破,在音頻的表徵能力上優於傳統方法,基於深度學習的音頻特徵提取技術正逐漸成為音頻處理領域的核心技術。

在本篇內容中,特徵提取的部分使用的是基於深度學習網路的 📘PANNs (Large-Scale Pretrained Audio Neural Networks for Audio Pattern Recognition) 模型提取音頻的特徵向量。PANNs 模型的平均準確率 (mAP) 0.439 高於 Google 的0.317。

而提取音頻數據的特徵向量表徵後,我們可以通過 Milvus 實現高性能的特徵向量比對檢索,關於 Milvus 的介紹可以參考 ShowMeAI 的文章 📘使用Milvus向量資料庫進行可擴展的快速相似性搜索。

📌 向量檢索引擎

在眾多海量數據的場景下進行向量檢索,都會採用Milvus這款開源的向量相似度搜索引擎,它具備高效的檢索速度和精準的檢索精度。

實際上,非結構化的數據,基於深度學習等模型進行特徵表徵後,都可以藉助 Milvus 搭建檢索系統,它的整體工作流程如下:

典型的步驟為以下3步:

① 基於深度學習模型,將非結構化數據(影像、影片、語音、文本)轉化為表徵特徵向量。
② 將特徵向量存儲到 Milvus 並對特徵向量構建索引。
③ 對檢索數據提取特徵並進行向量相似性檢索,返回結果。

💡 系統搭建

下面我們搭建基本的音頻檢索系統,總體包含2個核心板塊:

  • 音頻特徵抽取與索引構建(下圖黑線所示)。
  • 音頻數據檢索(下圖紅線所示)。

對應的項目在 Milvus 的官方項目中已開源,地址為 📘Audio Similarity Search,其中使用到的示例數據為開源遊戲聲音數據。

📌 第一步:特徵抽取&索引構建

在 Google drive 中下載示例數據(也可以通過 ShowMeAI 的百度網盤地址下載),

🏆 實戰數據集下載(百度網盤):公眾號『ShowMeAI研究中心』回復『實戰』,或者點擊 這裡 獲取本文 [20]基於深度學習的音頻檢索技術與系統搭建 『音頻檢索示例數據集』

⭐ ShowMeAI官方GitHub://github.com/ShowMeAI-Hub

遍歷文件夾並調用 panns-inference 預訓練模型將音頻數據轉換為特徵向量,將得到的特徵向量導入到 Milvus 中,Milvus 將返迴向量對應的 ID。示例程式碼如下:

import os
import librosa
import gdown
import zipfile
import numpy as np
from panns_inference import SoundEventDetection, labels, AudioTagging

data_dir = './example_audio'
at = AudioTagging(checkpoint_path=None, device='cpu')

# 下載音頻文件
def download_audio_data():
    url = '//drive.google.com/uc?id=1bKu21JWBfcZBuEuzFEvPoAX6PmRrgnUp'
    gdown.download(url)
    with zipfile.ZipFile('example_audio.zip', 'r') as zip_ref:
        zip_ref.extractall(data_dir)

# 構建音頻特徵向量並存儲
def embed_and_save(path, at):
    
    audio, _ = librosa.core.load(path, sr=32000, mono=True)
    audio = audio[None, :]
    try:
        _, embedding = at.inference(audio)
        embedding = embedding/np.linalg.norm(embedding)
        embedding = embedding.tolist()[0]
        mr = collection.insert([[embedding]])
        ids = mr.primary_keys
        collection.load()
        red.set(str(ids[0]), path)
    except Exception as e:
        print("failed: " + path + "; error {}".format(e))

# 遍歷與操作
print("Starting Insert")
download_audio_data()
for subdir, dirs, files in os.walk(data_dir):
    for file in files:
        path = os.path.join(subdir, file)
        embed_and_save(path, at)
print("Insert Done")

📌 第二步:向量檢索&音頻匹配

在這一步中,我們會繼續使用 panns-inference 預訓練模型對待檢索音頻提取特徵向量,基於 Milvus 在此前導入 Milvus 庫的音頻數據特徵向量中進行檢索。根據檢索返回結果並輸出。示例程式碼如下:

# 對待檢索音頻批量抽取特徵,返回embedding
def get_embed(paths, at):
    embedding_list = []
    for x in paths:
        audio, _ = librosa.core.load(x, sr=32000, mono=True)
        audio = audio[None, :]
        try:
            _, embedding = at.inference(audio)
            embedding = embedding/np.linalg.norm(embedding)
            embedding_list.append(embedding)
        except:
            print("Embedding Failed: " + x)
    return np.array(embedding_list, dtype=np.float32).squeeze()

random_ids = [int(red.randomkey()) for x in range(2)]
search_clips = [x.decode("utf-8") for x in red.mget(random_ids)]
embeddings = get_embed(search_clips, at)
print(embeddings.shape)



import IPython.display as ipd
# 輸出結果
def show_results(query, results, distances):
    print("Query: ")
    ipd.display(ipd.Audio(query))
    print("Results: ")
    for x in range(len(results)):
        print("Distance: " + str(distances[x]))
        ipd.display(ipd.Audio(results[x]))
    print("-"*50)

embeddings_list = embeddings.tolist()

# 檢索參數配置
search_params = {"metric_type": "L2", "params": {"nprobe": 16}}

# 使用milvus進行向量檢索並返回結果
try:
    start = time.time()
    results = collection.search(embeddings_list, anns_field="embedding", param=search_params, limit=3)
    end = time.time() - start
    print("Search took a total of: ", end)
    for x in range(len(results)):
        query_file = search_clips[x]
        result_files = [red.get(y.id).decode('utf-8') for y in results[x]]
        distances = [y.distance for y in results[x]]
        show_results(query_file, result_files, distances)
except Exception as e:
    print("Failed to search vectors in Milvus: {}".format(e))

💡 系統展示

📌 介面展示

完整的音頻檢索系統基於FastAPI等搭建完成部署,主要介面功能為音頻數據插入與刪除。啟動服務後,在瀏覽器中輸入 127.0.0.1/docs 可查看所有 API。API 查詢頁面如下圖所示:

📌 系統演示

接下來大家就可以上傳自己的音頻數據,體驗基於深度學習與Milvus搜索引擎構建的音頻檢索系統了,部分系統截圖如下:

💡 參考文獻