(二十二)RASA的超參數(shù)優(yōu)化
作者簡(jiǎn)介
作者:孟繁中
原文:https://zhuanlan.zhihu.com/p/349000987
轉(zhuǎn)載者:楊夕
面筋地址:https://github.com/km1994/NLP-Interview-Notes
個(gè)人筆記:https://github.com/km1994/nlp_paper_study

這篇文章包含以下內(nèi)容:
如何用Rasa NLU進(jìn)行大規(guī)模參數(shù)優(yōu)化
哪個(gè)超參數(shù)在微調(diào)時(shí)對(duì)結(jié)果優(yōu)化最明顯
超參數(shù)優(yōu)化
選擇合適的組件是你的AI助手應(yīng)用成功的關(guān)鍵。但是,如果你想要進(jìn)一步充分利用組件,你必須要對(duì)單個(gè)組件的配置參數(shù)(叫做超參數(shù))進(jìn)行調(diào)優(yōu)。尋找最佳配置的方法是,用不同的配置參數(shù)進(jìn)行訓(xùn)練,然后分別在驗(yàn)證集上面進(jìn)行評(píng)估。通過(guò)超參數(shù)查找,可以找到評(píng)估分?jǐn)?shù)最高的超參數(shù)配置。由于組件有很多的超參數(shù),以及模型訓(xùn)練是時(shí)間密集型的,我們將展示如何使用Docker容器,幫助你將超參數(shù)查找更好的擴(kuò)展到多個(gè)機(jī)器上。
定義查找空間
在開(kāi)始之前,前克隆rasaHQ/nlu-hyperopt repository。為你的NLU管道定義模板,可以對(duì)data/template_config.yml進(jìn)行更改。并將參數(shù)替換成你想要優(yōu)化的參數(shù),使用大括號(hào)括起來(lái),如:
language: en
pipeline:
- name: "intent_featurizer_count_vectors"
- name: "intent_classifier_tensorflow_embedding"
epochs: {epochs}在上面的例子中,我們定義了NLU管道用于intent_classifier_tensorflow_embedding意圖識(shí)別。在超參數(shù)查找的時(shí)候,我們將試圖查找最佳的訓(xùn)練迭代次數(shù)。
下一個(gè)步驟是定義你的NLU模型中想要評(píng)估的參數(shù)的范圍。根據(jù)你想要評(píng)估的超參數(shù),調(diào)整nlu_hyperopt/space.py文件中的內(nèi)容,如:
from hyperopt import hp
search_space = {
'epochs': hp.uniform(“epochs”, 1, 10)
}針對(duì)查找空間,模型將被以不同的epochs數(shù)值進(jìn)行訓(xùn)練,epochs的取值范圍為從1到10。你可以從其他的分布中進(jìn)行選擇。參見(jiàn)hyperopt docs。
組件有很多的超參數(shù),那么我們?cè)搹氖裁吹胤介_(kāi)始呢?由于預(yù)訓(xùn)練詞嵌入intent_classifier_sklearn已經(jīng)在訓(xùn)練中執(zhí)行了網(wǎng)格搜索,當(dāng)你使用intent_classifier_tensorflow_embedding訓(xùn)練你自己的詞嵌入的時(shí)候,超參數(shù)優(yōu)化會(huì)更你更多的額外的好處。該組件的重要的超參數(shù)是來(lái)自?intent_featurizer_count_vectors組件和分類(lèi)器本身的。對(duì)于組件?intent_featurizer_count_vectors,我們建議考慮min_df,max_df,和max_features。更詳細(xì)介紹參見(jiàn):Sklearn documentation。
tensorflow classifier含有很多的參數(shù)。我們建議從調(diào)整embeddings的維度(embed_dim)和隱藏層的大?。?code style="margin-right: 2px;margin-left: 2px;padding: 3px 4px;border-radius: 3px;font-family: Menlo, Monaco, Consolas, "Andale Mono", "lucida console", "Courier New", monospace;font-size: 0.9em;background-color: rgb(246, 246, 246);">hidden_layers_sizes_a,hidden_layers_sizes_b)開(kāi)始。針對(duì)上面三個(gè)參數(shù),更大的值能夠獲得更高的精度,但是也可能會(huì)導(dǎo)致過(guò)擬合。
配置超參數(shù)搜索
最后,配置你的嘗試。這是通過(guò)環(huán)境變量的設(shè)置實(shí)現(xiàn)的。如果你想要順序的運(yùn)行超參數(shù)查找,或不適用Docker,那么你可以忽略mongo數(shù)據(jù)庫(kù)的設(shè)置。這個(gè)選項(xiàng)的詳細(xì)介紹見(jiàn)readme,因此為了簡(jiǎn)單起見(jiàn),我們將關(guān)注最重要的幾個(gè)參數(shù)。
MAX_EVALS
這個(gè)參數(shù)描述了你想要運(yùn)行多少次評(píng)估。如果參數(shù)的組合(查找空間)比較小,你也許需要選擇一個(gè)較小的值。如果查找空間很大,為了更好的覆蓋查找空間,必須要執(zhí)行更多的評(píng)估。
TARGET_METRIC
這個(gè)值定義了用于比較不同訓(xùn)練模型的評(píng)價(jià)指標(biāo)??晒┑倪x擇有:
f1_score:在評(píng)估數(shù)據(jù)集中查找f1分?jǐn)?shù)最高的模型accuracy:在評(píng)估數(shù)據(jù)集中查找準(zhǔn)確度最高的模型
precision:在評(píng)估數(shù)據(jù)集中查找精度最高的模型
threshold_loss:其他的度量方式會(huì)選擇出置信度最高的意圖作為正確的結(jié)果,該損失函數(shù)僅會(huì)選擇出預(yù)測(cè)結(jié)果是正確的,并且置信度值高于閾值的結(jié)果。這說(shuō)明了使用fallback策略來(lái)消除低置信度預(yù)測(cè)的歧義。你可以使用參數(shù)ABOVE_BELOW_WEIGHT來(lái)指定使用閾值之上還是閾值之下的預(yù)測(cè)作為不正確的預(yù)測(cè)。
然后添加訓(xùn)練集用于模型訓(xùn)練,評(píng)價(jià)集用于模型評(píng)估。通過(guò)將訓(xùn)練數(shù)據(jù)放到data/train.md,將評(píng)估數(shù)據(jù)放到data/validation.md進(jìn)行指定。
運(yùn)行
終于到了運(yùn)行參數(shù)搜索的時(shí)間了。你可以選擇不使用Docker或使用Docker容器來(lái)運(yùn)行超參數(shù)搜索。
如果你想要在本地運(yùn)行,通過(guò)命令pip install -r requirements.txt安裝依賴(lài),然后執(zhí)行python -m nlu_hyperopt.app。
如果想要通過(guò)Docker運(yùn)行,可以執(zhí)行命令:docker-compose up -d --scale hyperopt-work=。這個(gè)會(huì)構(gòu)建包含你的數(shù)據(jù)集,搜索空間,和模板配置的docker鏡像,接著使用mongo數(shù)據(jù)庫(kù)并行的運(yùn)行。當(dāng)然,你可以在集群運(yùn)行,將工作分發(fā)到不同的機(jī)器上。常見(jiàn)的集群編排工具,如Kubernetes,能夠處理生成的docker-compose文件。
當(dāng)評(píng)估結(jié)束之后,會(huì)在日志中輸出最佳的pipeline配置,如:
INFO:__main__:The best configuration is:
language: en
pipeline:
- name: "intent_featurizer_count_vectors"
- name: "intent_classifier_tensorflow_embedding"
epochs: 8.0如果你通過(guò)Docker和mongo數(shù)據(jù)庫(kù)進(jìn)行超參數(shù)搜索,所有的評(píng)估結(jié)果會(huì)存儲(chǔ)到mongo數(shù)據(jù)庫(kù)中。通過(guò)執(zhí)行docker-compose exec mongodb mongo進(jìn)入mongo容器查看評(píng)估結(jié)果。下面的命令會(huì)輸出對(duì)應(yīng)的結(jié)果:
db.jobs.find({"exp_key" : "default-experiment", "result.loss":{$exists: 1}}).sort({"result.loss": 1})