方言聽不懂,手把手教你用 Milvus 搭建方言翻譯器!

坐在上海的公交車上,我有時會遇到這樣的煩惱:稍一分神,沒能聽見普通話報站,支棱起耳朵,卻聽不懂滬語報站。爲了解決這個問題,我決定——學習滬語?No, 作爲一名數據工程師,我索性搭建了一個方言翻譯器,幫助大家輕鬆聽懂地方方言,再也不會錯過公交車站。

在本次的項目中,我會手把手教你使用 Milvus 搭建方言翻譯器。通過這個項目,你能收穫:

  • 熟悉開源數據集,在日常的模型訓練中應用這些數據集

  • 親自動手搭建 Demo,真正解決實際生活場景中問題

  • 學會使用 Milvus 後,還有更多的可以結合 Milvus 的應用場景等着你去發現

如果你是初次瞭解 Milvus 和 MagicHub 的小夥伴,我們爲你準備了一個簡短的介紹:

Milvus

Milvus 是基於 FAISS、Annoy、HNSW 等向量搜索庫構建,核心是解決稠密向量相似度檢索的問題。最近, Milvus 2.0 版本已經發布了,在向量檢索庫的基礎上,Milvus 支持了數據分區分片、持久化、增量數據攝取、標量向量混合查詢、Time Travel 等功能,同時大幅優化了向量檢索的性能。推薦用戶使用 Kubernetes 部署 Milvus ,以獲得最佳的可用性和彈性。

MagicHub

MagicHub.com 是愛數智慧發佈的一個開源社區。愛數智慧爲從事語音識別、語音合成、自然語言理解等人工智能領域研發與應用研究的企業、科研機構提供數據服務。MagicHub 開源數據覆蓋多個場景、行業、語種。自 2021 年 4 月 15 日正式發佈以來,已經覆蓋 3000+ 全球開發者,累計下載超過 15 萬小時數據集。目前開源 50 多種用於人工智能訓練/測試的數據集,包括方言和小語種。數據集種類包含 NLP、ASR、TTS 數據集和 LEX 發音詞典等。MagicHub 幫助 AI 開發者快速找到適合自己模型的數據集,用開源數據加速創新。

1. 數據準備

本項目中,我們選擇了 MagicHub 社區中提供的上海話數據集(來源詳見文末鏈接[1]),你也可以根據自己的需要使用其他方言的數據集。

下載數據集,解壓完成後可以看到這幾個文件:WAV - 音頻文件夾,README.txt - 數據集版權介紹文件,SPKINFO.txt - 每個音頻的錄音設備,性別,年齡,區域,錄音頻道的介紹文件,UTTRANSINFO.txt - 音頻的文本內容,包含普通話和上海話。這裏我們主要用到的是音頻文本內容普通話部分。這裏將 UTTRANSINFO.txt 文件轉成了 CSV 的形式,有利於我們後續數據處理。

def loadDataSet(test_dir):
    f = open(test_dir,'r',encoding='utf-8')
    fname ='ts.csv'
    with open(fname,'w') as fine:
        for line in f.readlines():
            line1 =line.split()
            PROMPT=line1[3]
            linew = PROMPT+"\n"
            fine.write(linew)


2. 音頻檢索

音頻搜索項目中,首先,將音頻文件用 Panns-Inference 模型轉成特徵向量存儲到 Milvus 2.0,並返回對應的 ID;接着,在 MySQL 數據庫中存儲 ID 、音頻文件的路徑 ,以及文本內容對應關係;隨後,在 Milvus 2.0 中檢索得出與其相似的音頻文件,並返回最相似的前 N 個結果;最後,根據返回的 ID 結果,在數據庫中搜索到對應的音頻文件和文本內容。

使用 Milvus 2.0 最新音頻檢索項目,只需要修改少量代碼,就可以對上海話音頻進行檢索,返回上海話的音頻和音頻內容。

下面是音頻檢索項目中需要修改的代碼,在 load.py 中讀取 CSV 的數據

def do_load(table_name, audio_dir,text_dir, model, milvus_client, mysql_cli):
    if not table_name:
        table_name = DEFAULT_TABLE
    vectors, names = extract_features(audio_dir, model)
    ids = milvus_client.insert(table_name, vectors)
    loadDataSet(text_dir)
    data = pd.read_csv("ts.csv")
    text = data['PROMPT'].tolist()
    milvus_client.create_index(table_name)
    mysql_cli.create_mysql_table(table_name)
    mysql_cli.load_data_to_mysql(table_name, format_data(ids, names,text))
    return len(ids)


在 search.py 中需要修改以下的代碼部分:

def do_search(host,table_name, audio_path, model, milvus_client, mysql_cli):
    try:
        if not table_name:
            table_name = DEFAULT_TABLE
        feat = get_audio_embedding(audio_path)
        vectors = milvus_client.search_vectors(table_name, [feat], TOP_K)
        vids = [str(x.id) for x in vectors[0]]
        paths,text = mysql_cli.search_by_milvus_ids(vids, table_name)
        distances = [x.distance for x in vectors[0]]
        for i in range(len(paths)):
             tmp = "http://" + str(host) + "/data?audio_path=" + str(paths[i])
             paths[i] = tmp
        return vids, paths, distances,text
    except Exception as e:
        LOGGER.error(" Error with search : {}".format(e))
        sys.exit(1)


在 mysql_helpers.py 文件中修改以下代碼:

            LOGGER.debug("MYSQL create table: {} with sql: {}".format(table_name, sql))
        except Exception as e:
            LOGGER.error("MYSQL ERROR: {} with sql: {}".format(e, sql))
            sys.exit(1)

def load_data_to_mysql(self, table_name, data):
        sql = "insert into " + table_name + " (milvus_id,audio_path,text) values (%s,%s,%s);"
        try:
            self.cursor.executemany(sql, data)
            self.conn.commit()
            LOGGER.debug("MYSQL loads data to table: {} successfully".format(table_name))
        except Exception as e:
            LOGGER.error("MYSQL ERROR: {} with sql: {}".format(e, sql))
            sys.exit(1)


def search_by_milvus_ids(self, ids, table_name):
        str_ids = str(ids).replace('[', '').replace(']', '')
        sql = "select * from " + table_name + " where milvus_id in (" + str_ids + ") order by field (milvus_id," + str_ids + ");"
        try:
            self.cursor.execute(sql)
            results = self.cursor.fetchall()
            results_path=[res[1] for res in results]
            results_text=[res[2] for res in results]
            LOGGER.debug("MYSQL search by milvus id.")
            return results_path,results_text
        except Exception as e:
            LOGGER.error("MYSQL ERROR: {} with sql: {}".format(e, sql))
            sys.exit(1)


以及修改相關的接口,在 main.py 中修改以下代碼:

class Item(BaseModel):
    Table: Optional[str] = None
    File:str
    Text:str

@app.post('/audio/load')
async def load_audios(item: Item):
    # Insert all the audio files under the file path to Milvus/MySQL
    try:
        total_num = do_load(item.Table, item.File,item.Text,MODEL, MILVUS_CLI, MYSQL_CLI)
        LOGGER.info("Successfully loaded data, total count: {}".format(total_num))
        return {'status': True, 'msg': "Successfully loaded data!"}
    except Exception as e:
        LOGGER.error(e)
        return {'status': False, 'msg': e}, 400

@app.post('/audio/search')
async def search_audio(request: Request,Table: str = None, audio: UploadFile = File(...)):
    # Search the uploaded audio in Milvus/MySQL
    try:
        # Save the upload data to server.
        content = await audio.read()
        audio_path = os.path.join(UPLOAD_PATH, audio.filename)
        with open(audio_path, "wb+") as f:
            f.write(content)
        host = request.headers['host']
        ids, paths,text, distances= do_search(host,Table, audio_path, MODEL, MILVUS_CLI, MYSQL_CLI)
        names=[]
        names = text
        res = dict(zip(paths, zip(names, distances)))
        #res = sorted(res.items(), key=lambda item: item[1][1])
        LOGGER.info("Successfully searched similar audio!")
        return res
    except Exception as e:
        LOGGER.error(e)
        return {'status': False, 'msg': e}, 400


3. 測試運行

現在,修改完上述代碼以後,參考 Github 中 Audio_similar_search 的 Readme 文檔(來源詳見文末鏈接[2])啓動 FastAPI ,從 FastAPI 中驗證代碼是否成功運行,在瀏覽器中輸入 localhost:8002/docs 可以看到如圖所示 FastAPI 的頁面, 在 Load API 中分別輸入 Table 的名稱,音頻文件的路徑,音頻對應的文本的路徑,然後點擊 Excute 的按鈕,圖中顯示數據插入成功。

然後,在 Search API 中輸入對應的 Table 名稱和需要檢索的音頻路徑,點擊 Excute 按鈕進行檢索。如下圖所示,就可以看到相應的音頻和其對應的文本內容了。

最後,感謝愛數智慧 MagicHub 提供的開源數據集,讓我們更好地結合模型與 Milvus 進行多個領域的向量檢索。

在這個音頻檢索項目中,我們也可以使用其他的方言數據集,將數據集經過 AI 模型轉成特徵向量,結合 Milvus 進行相似檢索,就可以把任何你聽不懂的方言翻譯成普通話啦!

動手玩一把?

源碼鏈接就在下方


[1] 愛數智慧 MagicHub 開源社區:

https://magichub.com/cn/category/datasets/

[2] 音頻檢索:

https://github.com/milvus-io/bootcamp/tree/master/solutions/audio_similarity_search


作者  |賈晶晶

Zilliz 數據工程師,畢業於西安交通大學計算機系。加入Zilliz後,主要工作內容爲數據預處理、AI模型部署、Milvus 相關技術研究,以及幫助社區用戶實現應用場景落地。資深動漫粉,對社區溝通超級有耐心,平時比較關注自然語言處理領域的研究。


Zilliz 以重新定義數據科學爲願景,致力於打造一家全球領先的開源技術創新公司,並通過開源和雲原生解決方案爲企業解鎖非結構化數據的隱藏價值。

Zilliz 構建了 Milvus 向量數據庫,以加快下一代數據平臺的發展。Milvus 目前是 LF AI & Data 基金會的畢業項目,能夠管理大量非結構化數據集。我們的技術在新藥發現、計算機視覺、推薦引擎、聊天機器人等方面具有廣泛的應用。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章