Hugging Face 分詞器新增聊天模板屬性

一個(gè)幽靈,格式不正確的幽靈,在聊天模型中游蕩!
太長(zhǎng)不看版
現(xiàn)存的聊天模型使用的訓(xùn)練數(shù)據(jù)格式各各不同,我們需要用這些格式將對(duì)話轉(zhuǎn)換為單個(gè)字符串并傳給分詞器。如果我們?cè)谖⒄{(diào)或推理時(shí)使用的格式與模型訓(xùn)練時(shí)使用的格式不同,通常會(huì)導(dǎo)致嚴(yán)重的、無(wú)聲的性能下降,因此匹配訓(xùn)練期間使用的格式極其重要!Hugging Face 分詞器新增了?chat_template
?屬性,可用于保存模型訓(xùn)練時(shí)使用的聊天格式。此屬性包含一個(gè) Jinja 模板,可將對(duì)話歷史記錄格式化為正確的字符串。請(qǐng)參閱 技術(shù)文檔,以了解有關(guān)如何在代碼中編寫和應(yīng)用聊天模板。
引言
如果你熟悉 ?? transformers 庫(kù),你可能寫過(guò)如下代碼:
通過(guò)從同一個(gè) checkpoint 中加載分詞器和模型,可以確保對(duì)輸入字符串使用的分詞方法符合模型預(yù)期。如果你從另一個(gè)模型中選擇分詞器,則其分詞結(jié)果很可能會(huì)完全不同,此時(shí)模型的性能就會(huì)受到嚴(yán)重?fù)p害。這種現(xiàn)象叫?分布漂移 (distribution shift): 模型一直從一種分布學(xué)習(xí) (即訓(xùn)練分詞器),突然,數(shù)據(jù)分布變成了另一個(gè)不同的分布。
無(wú)論你是微調(diào)模型還是直接用它進(jìn)行推理,讓這種分布上的變化盡可能小,并保持提供的輸入盡可能與訓(xùn)練時(shí)的輸入一致總是一個(gè)好主意。對(duì)于常規(guī)語(yǔ)言模型,做到這一點(diǎn)相對(duì)容易 - 只需從同一檢查點(diǎn)加載分詞器和模型,就可以了。
然而,對(duì)于聊天模型來(lái)說(shuō),情況有點(diǎn)不同。這是因?yàn)椤傲奶臁辈粌H僅是直接對(duì)單個(gè)文本字符串進(jìn)行分詞 - 它需要對(duì)一系列消息進(jìn)行分詞。每個(gè)消息都包含一個(gè)?角色
?及其?內(nèi)容
?,其內(nèi)容是消息的實(shí)際文本。最常見的,角色是“用戶”(用于用戶發(fā)送的消息) 、“助理”(用于模型生成的響應(yīng)),以及可選的“系統(tǒng)”(指在對(duì)話開始時(shí)給出的高級(jí)指令)。
干講可能有點(diǎn)抽象,下面我們給出一個(gè)示例聊天,把問(wèn)題具象化:?
此消息序列需要先轉(zhuǎn)換為一個(gè)文本字符串,然后才能對(duì)其進(jìn)行分詞以輸入給模型。但問(wèn)題是,轉(zhuǎn)換方法有很多!例如,你可以將消息列表轉(zhuǎn)換為“即時(shí)消息”格式:?
或者你可以添加特殊詞元來(lái)指示角色:?
抑或你可以添加詞元以指示消息之間的邊界,而將角色信息作為字符串插入:
方法多種多樣,但沒有哪種方法是最好的或是最正確的。因此,不同的模型會(huì)采用截然不同的格式進(jìn)行訓(xùn)練。上面這些例子不是我編造的,它們都是真實(shí)的,并且至少被一個(gè)現(xiàn)存模型使用過(guò)!但是,一旦模型接受了某種格式的訓(xùn)練,你需要確保未來(lái)的輸入使用相同的格式,否則就可能會(huì)出現(xiàn)損害性能的分布漂移。
模板: 一種保存格式信息的方式
當(dāng)前的狀況是: 如果幸運(yùn)的話,你需要的格式已被正確記錄在模型卡中的某個(gè)位置; 如果不幸的話,它不在,那如果你想用這個(gè)模型的話,只能祝你好運(yùn)了; 在極端情況下,我們甚至?xí)⒄麄€(gè)提示格式放在 相應(yīng)模型的博文 中,以確保用戶不會(huì)錯(cuò)過(guò)它!但即使在最好的情況下,你也必須找到模板信息并在微調(diào)或推理流水線中手動(dòng)將其寫進(jìn)代碼。我們認(rèn)為這是一個(gè)特別危險(xiǎn)的做法,因?yàn)槭褂缅e(cuò)誤的聊天格式是一個(gè)?靜默錯(cuò)誤?- 一旦出了錯(cuò),不會(huì)有顯式的失敗或 Python 異常來(lái)告訴你出了什么問(wèn)題,模型的表現(xiàn)只會(huì)比用正確格式時(shí)差多了,但很難調(diào)試其原因!
這正是?聊天模板?旨在解決的問(wèn)題。聊天模板是一個(gè) Jinja 模板字符串,你可以使用分詞器保存和加載它。聊天模板包含了將聊天消息列表轉(zhuǎn)換為模型所需的、格式正確的輸入字符串所需要的全部信息。下面是三個(gè)聊天模板字符串,分別對(duì)應(yīng)上文所述的三種消息格式:
如果你不熟悉 Jinja,我強(qiáng)烈建議你花點(diǎn)時(shí)間研究下這些模板字符串及其相應(yīng)的模板輸出,看看你是否可以弄清楚這些模板如何將消息列表轉(zhuǎn)換為格式化的消息字符串!其語(yǔ)法在很多方面與 Python 非常相似。
為什么要使用模板?
如果你不熟悉 Jinja,一開始上手可能會(huì)有點(diǎn)困惑,但我們?cè)趯?shí)踐中發(fā)現(xiàn) Python 程序員可以很快上手它。在開發(fā)此功能的過(guò)程中,我們考慮了其他方法,例如允許用戶按角色指定消息的前綴和后綴。我們發(fā)現(xiàn)該方法會(huì)變得令人困惑且笨重,而且它非常不靈活,以至于對(duì)一些模型而言,我們得需要一些巧妙的變通才行。而另一方面,模板功能強(qiáng)大到足以完全支持我們所知的所有消息格式。
為什么要這樣做呢?為什么大家不統(tǒng)一到一個(gè)標(biāo)準(zhǔn)格式呢?
好主意!不幸的是,為時(shí)已晚,因?yàn)楝F(xiàn)有的多個(gè)重要模型已經(jīng)基于迥異的聊天格式進(jìn)行了訓(xùn)練。
然而,我們?nèi)匀豢梢陨晕⒕徑庀逻@個(gè)問(wèn)題。我們認(rèn)為最接近“標(biāo)準(zhǔn)”的格式是?OpenAI?創(chuàng)建的 ChatML 格式。如果你正在訓(xùn)練新的聊天模型,并且此格式適合你,我們建議你使用它并給分詞器添加特殊的?<|im_start|>
?和?<|im_end|>
?詞元。它的優(yōu)點(diǎn)是角色非常靈活,因?yàn)榻巧皇亲鳛樽址迦耄皇翘囟ǖ慕巧~元。如果你想使用這個(gè),它是上面的第三個(gè)模板,你可以簡(jiǎn)單地使用一行代碼進(jìn)行設(shè)置:
tokenizer.chat_template?=?"{%?for?message?in?messages?%}{{'<|im_start|>'?+?message['role']?+?'\n'?+?message['content']?+?'<|im_end|>'?+?'\n'}}{%?endfor?%}"
不過(guò),除了格式林立的現(xiàn)狀之外,還有第二個(gè)不硬設(shè)標(biāo)準(zhǔn)格式的原因 - 我們預(yù)計(jì)模板將廣泛用于多種類型模型的預(yù)處理,包括那些可能與標(biāo)準(zhǔn)聊天操作迥異的模型。硬設(shè)標(biāo)準(zhǔn)格式限制了模型開發(fā)人員使用此功能完成我們尚未想到的任務(wù)的能力,而模板則為用戶和開發(fā)人員提供了最大的自由度。甚至可以在模板中加入邏輯檢查和判斷,這是目前任何默認(rèn)模板中都沒有深入使用的功能,但我們希望它能成為喜歡冒險(xiǎn)的用戶手中的利刃。我們堅(jiān)信,開源生態(tài)系統(tǒng)應(yīng)該讓你能夠做你想做的事,而不是命令你做什么。
模板如何工作?
聊天模板是?分詞器?的一部分,因?yàn)樗鼈兟男信c分詞器相同的角色: 存儲(chǔ)有關(guān)如何預(yù)處理數(shù)據(jù)的信息,以確保你以與訓(xùn)練時(shí)相同的格式將數(shù)據(jù)提供給模型。我們的設(shè)計(jì)使得用戶非常容易將模板信息添加到現(xiàn)有分詞器并將其保存或上傳到 Hub。
在有聊天模板這個(gè)功能之前,聊天格式信息都存儲(chǔ)在?類級(jí)別?- 這意味著,例如,所有 LLaMA checkpoint 都將使用同一個(gè)硬設(shè)在?transformers
?的 LLaMA 模型類代碼中的聊天格式。為了向后兼容,目前具有自定義聊天格式方法的模型類也已被賦予了?默認(rèn)聊天模板。
在類級(jí)別設(shè)置默認(rèn)聊天模板,用于告訴?ConversationPipeline
?等類在模型沒有聊天模板時(shí)如何格式化輸入,這樣做?純粹是為了向后兼容。我們強(qiáng)烈建議你在任何聊天模型上顯式設(shè)置聊天模板,即使默認(rèn)聊天模板是合適的。這可以確保默認(rèn)聊天模板中的任何未來(lái)的更改或棄用都不會(huì)破壞你的模型。盡管我們將在可預(yù)見的將來(lái)保留默認(rèn)聊天模板,但我們希望隨著時(shí)間的推移將所有模型轉(zhuǎn)換為顯式聊天模板,屆時(shí)默認(rèn)聊天模板可能會(huì)被完全刪除。
有關(guān)如何設(shè)置和應(yīng)用聊天模板的詳細(xì)信息,請(qǐng)參閱 技術(shù)文檔。
我該如何開始使用模板?
很簡(jiǎn)單!如果分詞器設(shè)置了?chat_template
?屬性,則它已準(zhǔn)備就緒。你可以在?ConversationPipeline
?中使用該模型和分詞器,也可以調(diào)用?tokenizer.apply_chat_template()
?來(lái)格式化聊天以進(jìn)行推理或訓(xùn)練。請(qǐng)參閱我們的 開發(fā)者指南 或 如何應(yīng)用聊天模板的文檔 以了解更多!
如果分詞器沒有?chat_template
?屬性,它可能仍然可以工作,但它將使用該模型類的默認(rèn)聊天模板。正如我們上面提到的,這是脆弱的,并且當(dāng)類模板與模型實(shí)際訓(xùn)練的內(nèi)容不匹配時(shí),它同樣會(huì)導(dǎo)致靜默錯(cuò)誤。如果你想使用沒有?chat_template
?的 checkpoint,我們建議檢查模型卡等文檔以確保使用正確的格式,然后為該格式添加正確的?chat_template
?。即使默認(rèn)聊天模板是正確的,我們也建議這樣做 - 它可以使模型面向未來(lái),并且還可以清楚地表明該模板是存在的且是適用的。
即使不是你的 checkpoint,你也可以通過(guò)提交 合并請(qǐng)求 (pull request) ?的方式為其添加?chat_template
?。僅需將?tokenizer.chat_template
?屬性設(shè)置為 Jinja 模板字符串。完成后,推送更改就可以了!
如果你想在你的聊天應(yīng)用中使用某 checkpoint,但找不到有關(guān)其使用的聊天格式的任何文檔,你可能應(yīng)該在 checkpoint 上提出問(wèn)題或聯(lián)系其所有者!一旦你弄清楚模型使用的格式,請(qǐng)?zhí)峤灰粋€(gè) PR 以添加合適的?chat_template
?。其他用戶將會(huì)非常感激你的貢獻(xiàn)!
總結(jié): 模板理念
我們認(rèn)為模板是一個(gè)非常令人興奮的新特性。除了解決大量無(wú)聲的、影響性能的錯(cuò)誤之外,我們認(rèn)為它們還開辟了全新的方法和數(shù)據(jù)模式。但最重要的也許是,它們還代表了一種理念轉(zhuǎn)變: 從核心?transformers
?代碼庫(kù)中挪出一個(gè)重要功能,并將其轉(zhuǎn)移到各自模型的倉(cāng)庫(kù)中,用戶可以自由地做各種奇怪、狂野抑或奇妙的事情。我們迫不及待想看看你會(huì)發(fā)現(xiàn)哪些用途!
英文原文:?https://hf.co/blog/chat-templates
原文作者: Matthew Carrigan
譯者: Matrix Yao (姚偉峰),英特爾深度學(xué)習(xí)工程師,工作方向?yàn)?transformer-family 模型在各模態(tài)數(shù)據(jù)上的應(yīng)用及大規(guī)模模型的訓(xùn)練推理。
審校/排版: zhongdongy (阿東)