使用 StarCoder 創(chuàng)建一個編程助手

如果你是一個軟件開發(fā)者,你可能已經(jīng)使用過 ChatGPT 或 GitHub 的 Copilot 去解決一些寫代碼過程中遇到的問題,比如將代碼從一種語言翻譯到另一種語言,或者通過自然語言,諸如“寫一個計(jì)算斐波那契數(shù)列第 N 個元素的 Python 程序”,來自動生成代碼。盡管這些專有系統(tǒng)功能強(qiáng)大,但它們?nèi)匀挥泻芏嗖蛔?,比如對?xùn)練所使用的公共數(shù)據(jù)透明度的缺失、沒有能力去讓它們適配自己的使用領(lǐng)域或代碼庫。
幸運(yùn)的是,現(xiàn)在我們有了很多高質(zhì)量開源替代品!包括 SalesForce 為 Python 語言開發(fā)的 CodeGen Mono 16B,以及 Replit 開發(fā)的、在 20 種編程語言上訓(xùn)練過的 一個 3B 參數(shù)量的模型。
而最近新出現(xiàn)的一個選擇則是 BigCode 開發(fā)的 StarCoder,這是一個在一萬億的 token、80 多種編程語言上訓(xùn)練過的 16B 參數(shù)量的模型。訓(xùn)練數(shù)據(jù)多來自 GitHub 上的 issues、使用 Git 提交的代碼、Jupyter Notebook 等等 (相關(guān)使用都已經(jīng)過許可)。得益于對企業(yè)友好的許可證、長度為 8192 的 token、借助 multi-query attention 的快速大批量推理,StarCoder 可以說是當(dāng)前對代碼相關(guān)的應(yīng)用最合適的開源選擇。
本文將介紹如何對 StarCoder 進(jìn)行微調(diào),進(jìn)而創(chuàng)建一個可以聊天的個人編程助手。這個編程助手我們將稱之為 StarChat。借助 StarChat 的開發(fā)過程,我們將探索以下幾個使用大語言模型 (LLM) 創(chuàng)建編程助手時可能遇到的幾個技術(shù)細(xì)節(jié):
我們應(yīng)該怎樣對大語言模型進(jìn)行提詞,使得它成為一個對話代理
我們也將介紹 OpenAI 的 Chat Markup Language (簡稱 ChatML),它為人類用戶和 AI 助手之間的對話信息傳遞提供了一種結(jié)構(gòu)化的格式
怎樣在一個多樣性很強(qiáng)的語料庫上,使用 ?? Transformers 和 DeepSpeed ZeRO-3 去微調(diào)一個大語言模型
最后,為了嘗試一下效果,我們還會問 StarChat 幾個編程方面的問題 (參考下面的演示)。

體驗(yàn)地址:https://huggingfaceh4-starchat-playground.hf.space
你也可以查看生成上面演示所使用的代碼、數(shù)據(jù)集和模型:
代碼:
https://github.com/bigcode-project/starcoder數(shù)據(jù)集:
https://hf.co/datasets/HuggingFaceH4/oasst1_en模型:
https://hf.co/HuggingFaceH4/starchat-alpha
接下來第一步,我們先來看看怎樣把語言模型轉(zhuǎn)化為一個對話代理。這里我們不是用任何微調(diào)。
針對對話任務(wù)對大語言模型合理提詞
DeepMind 和 Anthropic 的相關(guān)研究指出,大語言模型 (LLM) 可以通過選取合適的文本提示 (prompt) 來轉(zhuǎn)化為對話代理。這些文本提示通常包含一種所謂的“系統(tǒng)”信息來定義 LLM 的角色,以及一系列人機(jī)對話的示例。
比如這里,就是 Anthropic’s HHH prompt 這一文本提示的一些節(jié)選 (總計(jì) 6k 的 token 數(shù)量):
As we can see, the first part of the prompt “Below are a series…” corresponds to the system message and specifies that the assistant should have characteristics like “helpfulness” and “politeness”. The dialogue examples then condition the model to follow the multi-turn format of a conversation. When a user asks a question, the whole prompt is fed to the model and it generates an answer after the?Assistant:
?prefix. The answer is then concatenated to the prompt and the process repeated at every turn.
Somewhat surprisingly, this technique also works for StarCoder! This is enabled by the model’s 8k token context length, which allows one to include a wide variety of programming examples and covert the model into a coding assistant. Here’s an excerpt of the StarCoder prompt:
這里我們就可以看到精心打造的文本提示是如何引導(dǎo)出像 ChatGPT 中看到的那樣的編程行為的。完整的文本提示可以在 這里 找到,你也可以在 HuggingChat 上嘗試和受提示的 StarCoder 聊天。
然而,一個明顯的缺陷就是推理成本會非常高: 每次對話都需要有上千的 token 被輸入進(jìn)去,這會非常消耗推理資源!
所以,一個顯而易見的改進(jìn)措施就是使用一個對話的語料庫去微調(diào)這個大語言模型,使得它會聊天。接下來我們就看看幾個有趣的數(shù)據(jù)集,這幾個數(shù)據(jù)集最近登陸了 HuggingFace Hub,當(dāng)前很多開源的聊天機(jī)器人都是基于它們訓(xùn)練的。
對話語言模型的數(shù)據(jù)集
如今的開源社區(qū)正在加快創(chuàng)建多樣和高性能的數(shù)據(jù)集,以便將各種基礎(chǔ)的語言模型轉(zhuǎn)換為能遵照指示來對話的對話代理模型。這里我們找了一些示例數(shù)據(jù)集,可以用于生產(chǎn)對話語言模型:
OpenAssistant’s dataset: 包含超過四萬段對話,由社區(qū)的人輪流模仿用戶或 AI 的角色而產(chǎn)生。
The ShareGPT dataset: 包含了大約九萬段人類用戶和 ChatGPT 的對話。
在本文中,我們將使用 OpenAssistant 來微調(diào) StarCoder,主要是出于許可證的原因,而且它是完全由人工生成的。
由于原始的數(shù)據(jù)集是以對話樹的格式收集起來的,我們預(yù)處理了數(shù)據(jù),確保每行單獨(dú)對應(yīng)一段用戶和 AI 模型的對話。為防止模型演化得距離原始預(yù)訓(xùn)練數(shù)據(jù)太遠(yuǎn),我們也過濾掉了非英語文本。
首先我們下載這個已經(jīng)處理過的數(shù)據(jù)集:
可以看到,數(shù)據(jù)集包含大約 21000 段英文對話。我們先來看看這些訓(xùn)練數(shù)據(jù),拿第一條數(shù)據(jù)看看:
這是一段關(guān)于倫理學(xué)的有趣對話。每一輪對話信息都包含了 role 和 content 兩部分,用于指出是誰在說話以及談話內(nèi)容是什么。我們接下來看看如何把這些對話轉(zhuǎn)化為標(biāo)準(zhǔn)格式,以便簡化推理階段信息的生成方式。
對話數(shù)據(jù)的標(biāo)準(zhǔn)格式
一種在對話數(shù)據(jù)上微調(diào)模型的方法是,單純地把系統(tǒng)信息和角色信息插入到每個訓(xùn)練樣本中,然后把對話用“序列結(jié)尾”的 token (如 <EOS>) 分隔開。舉例而言,上面的對話可以轉(zhuǎn)換成這個形式:
雖然這種方法對訓(xùn)練而言是可行的,但它對于推理而言并不理想。因?yàn)槟P蜁茏匀坏厣鷮硬幌胍膶υ捿喆?,直到它輸出了一個 <EOS> 的 token,因此還需要一些后處理或額外設(shè)計(jì)的邏輯來阻止這一情況。
一個更好的方法是使用一種結(jié)構(gòu)化的格式,比如 ChatML。這種格式會對每一個對話輪次進(jìn)行包裝。包裝使用的是一些特殊的 token,用以標(biāo)明詢問或回答的角色。
在這種格式下,我們使用這些特殊的 token:
<|system|>
: 表示系統(tǒng)信息開始的地方,這里的系統(tǒng)信息描述了這個聊天機(jī)器人的身份角色。<|user|>
: 表示這里的話語是人類用戶說出來的。<|assistant|>
: 表示這里的話語是 AI 機(jī)器人說出來的。<|end|>
: 表示說話內(nèi)容的結(jié)尾,或系統(tǒng)信息的結(jié)尾。
下面我們寫一個函數(shù),把我們的實(shí)例數(shù)據(jù)用這些特殊的 token 包裝起來:
以上就是包裝好后的數(shù)據(jù)!下一步,我們還需要把這些特殊的 token 加入到分詞器 (tokenizer) 的詞匯表中。我們這里下載 StarCoder 的分詞器,然后加入這些特殊 token:
作為檢驗(yàn),我們看看把 “<|assistant|>” 輸入到分詞器中是否會輸出單獨(dú)一個 token 的 ID:
很好!有效!
掩蓋掉用戶話語部分的標(biāo)簽
使用特殊 token 還有一個好處,就是我們可以把來自用戶話語部分的損失函數(shù)值給掩蓋掉。因?yàn)槲覀兊哪P褪腔谟脩舻脑捳Z而只被訓(xùn)練去預(yù)測 AI 助手說話的部分 (模型推理時只需要根據(jù)用戶的話回答用戶)。下面就是一個簡單的函數(shù),用于掩蓋掉用戶部分的標(biāo)簽,并把所有的用戶部分的 token 轉(zhuǎn)為 -100 (接下來 -100 會被損失函數(shù)忽略掉):
可以看到,用戶部分的輸入 ID 全都被掩蓋掉了。這些特殊的 token 在微調(diào)階段將會學(xué)習(xí)到自己特定的嵌入 (embedding)。接下來我們看看如何微調(diào)。
使用 DeepSpeed ZeRO-3 微調(diào) StarCoder
StarCoder 和 StarCoderBase 模型的參數(shù)量達(dá)到了 160 億,如果我們把模型以 FP32 的精度載入到 GPU 中,將需要大約 60 GB 的 vRAM。然而幸運(yùn)的是,我們有其它方法去應(yīng)對這種規(guī)模的大模型:
使用對參數(shù)而言更高效的一些技術(shù),如 LoRA,保持基礎(chǔ)模型的權(quán)重不變,插入少量的需要學(xué)習(xí)的參數(shù)。類似的技術(shù)可以在 ?? PEFT 中找到。
使用 DeepSpeed ZeRO-3 或 FSDP 等方法,在多個 GPU 之間共享模型權(quán)重、優(yōu)化器狀態(tài)以及提督信息。
我們將使用 DeepSpeed 來訓(xùn)練我們的模型,因?yàn)樗呀?jīng)被整合進(jìn)了 ?? Transformers。首先,我們先從 GitHub 下載 StarCoder 的代碼倉庫,進(jìn)入?chat
?文件夾:
接下來用 Conda 創(chuàng)建一個 Python 的虛擬環(huán)境:
再然后,安裝 PyTorch (這里使用 v1.13.1,注意這一步和硬件有關(guān),請參考官方安裝頁面)。之后安裝本項(xiàng)目的相關(guān)依賴項(xiàng):
同時,我們還需要登錄上 Hugging Face。執(zhí)行以下指令:
最后,安裝 Git LFS:
接下來我們就可以訓(xùn)練了!如果你有幸擁有 8 個 A100 (80 GB 顯存),你可以通過下下面的命令去開始訓(xùn)練。訓(xùn)練會花費(fèi)大約 45 分鐘:
這里的?config.yaml
?指定了關(guān)于數(shù)據(jù)集、模型、訓(xùn)練的所有參數(shù)。你可以在 這里 重新配置它,以適應(yīng)新的訓(xùn)練數(shù)據(jù)集。稍后,訓(xùn)練好的模型將會出現(xiàn)在 Hub 上。
使用 StarCoder 作為一個編程助手
繪圖
仿照著名的 讓 GPT-4 用 TikZ 畫獨(dú)角獸 的實(shí)驗(yàn),我們想看看我們的模型是否可以完成一些基本的數(shù)據(jù)可視化編程任務(wù)。為此,我們向我們的模型提出了一些編程任務(wù),得到了出色的結(jié)果!是的,這是我們精心挑選的,因?yàn)槲覀冎贿x了那些真正能運(yùn)行的代碼,但一些其它結(jié)果也差不了太遠(yuǎn)。
例 1: 繪制柱狀圖
用戶提出的文本提示:
模型給出的回答:

例 2: 繪制地圖
用戶提出的文本提示:
模型給出的回答:

例 3: 籃球比賽數(shù)據(jù)的散點(diǎn)圖
用戶提出的文本提示:
模型給出的回答:

評估編程助手的性能
評估編程助手 (或更廣泛地講,聊天機(jī)器人) 其實(shí)是一個比較棘手的任務(wù),因?yàn)槊嫦蛴脩舻脑u測標(biāo)準(zhǔn)通常難以被傳統(tǒng)自然語言處理的基準(zhǔn)上體現(xiàn)出來。比如,我們使用基礎(chǔ)的和微調(diào)過的 StarCoderBase 模型在 EleutherAI 的 language model evaluation harness 做如下測試:
AI2 Reasoning Challenge (ARC): 小學(xué)難度的科學(xué)學(xué)科多項(xiàng)選擇題
HellaSwag: 圍繞日常生活的常識推理
MMLU: 專業(yè)和學(xué)術(shù)領(lǐng)域 57 個學(xué)科的多項(xiàng)選擇題
TruthfulQA: 測試模型能否從一系列錯誤描述中選出一個事實(shí)描述
測試結(jié)果在下表中統(tǒng)計(jì)了出來。我們可以看出微調(diào)過的模型多少有了點(diǎn)提升,但這并不能反映出對話相關(guān)的能力。

那除了使用這種在基準(zhǔn)測試集上的指標(biāo),我們還可以怎么做評測呢?最近,兩種主流的評測方法被提了出來:
人為評估: 給人類標(biāo)注者提供一系列基于一個文本提示 (prompt) 的不同回答,從最好到最差對它們排序。這是當(dāng)前評估模型的黃金法則,創(chuàng)造 InstructGPT 時就使用了這個方法。
AI 評估: 給一個有足夠性能的語言模型 (如 GPT-4) 提供文本提示 (prompt) 和對應(yīng)的回答,讓這個語言模型在質(zhì)量層面對其進(jìn)行評估。這一方法曾被用來評估 LMSYS 的 Vicuna 模型。
為了簡單起見,我們使用 ChatGPT 去檢驗(yàn)我們的 StarCoder 模型在多種編程語言上的性能。為此,我們首先創(chuàng)建了一個 包含了很多有趣的文本提示的數(shù)據(jù)集。我們使用 ChatGPT 去創(chuàng)建這個數(shù)據(jù)集,通過問它類似這樣的問題:
或者
在第二個例子中,ChatGPT 實(shí)際上生成了比我們要求更多的數(shù)據(jù)。當(dāng)前,這個數(shù)據(jù)集包含了 115 條文本提示 (prompt),而且主要是使用 Python。四分之三的文本提示是要求提供代碼的,剩下四分之一是索要針對有 bug 代碼的反饋的。
在我們的實(shí)驗(yàn)中,我們要求 OpenAI 的模型去評估得到的回答,對它們進(jìn)行 1 到 8 分的打分,使用的是略加修改的 Vicuna code prompt 數(shù)據(jù)。這里,使用我們這個數(shù)據(jù)集微調(diào)過的 StarCoder 在 95.6% 的情況下得分都高于原始的基礎(chǔ)模型。我們還發(fā)現(xiàn)了一個有趣的瑕疵現(xiàn)象: ChatGPT 喜歡打處于中位的安全分,而 GPT-4 更敢于去給極端分?jǐn)?shù),如 1 分和 8 分。
以下示例就展示了大語言模型 (LLM) 是如何去給一個問答的質(zhì)量打分的:
文本提示 (prompt):
經(jīng)過微調(diào)的模型的回答 (助手 2):
原始的基礎(chǔ)模型的回答 (助手 1):
GPT4 給出的評價:
下面是 ChatGPT 的回復(fù),似乎 ChatGPT 忽視了助手 1 并未完成任務(wù)這個事實(shí)。ChapGPT 說第二個回答更好,然而卻給助手 2 打了相對較低的分?jǐn)?shù)。
ChatGPT 給出的評價:
8?7
Assistant?1's?solution?attempts?to?use?a?variable?assignment?operator,?:=,?which?is?a?new?feature?added?to?Python?3.8,?but?is?not?necessarily?standard?practice?or?available?in?all?environments.?Additionally,?the?solution?does?not?actually?perform?the?desired?operation?of?reversing?the?input?string.?Instead,?it?creates?a?new?variable?and?assigns?it?the?value?of?the?original?input?string?but?with?the?characters?reversed.?This?means?that?the?original?input?string?is?not?modified,?and?the?function?does?not?actually?return?anything.
Assistant?2's?solution?correctly?implements?the?desired?operation?of?reversing?the?input?string?using?a?list?to?store?each?character,?then?joining?the?list?back?into?a?string?in?reverse?order.?The?use?of?comments?and?a?docstring?provide?good?context?and?explanation?for?the?code.?However,?the?variable?name?"output"?could?be?improved?to?something?more?descriptive,?and?the?solution?could?be?made?more?efficient?by?using?Python's?built-in?string?reversal?methods?instead?of?manually?creating?a?list?and?joining?it?back?into?a?string.
Overall,?Assistant?2's?solution?is?more?accurate,?efficient,?and?readable.?The?code?structure?is?clear?and?easy?to?follow,?and?the?inclusion?of?helpful?comments?improves?the?overall?quality?of?the?code.?However,?Assistant?1's?attempt?to?use?the?new?assignment?operator?shows?an?effort?to?stay?current?with?the?latest?features?in?Python,?which?is?a?positive?trait?in?a?developer.
看起來,即使 AI 給出的評價也挺有價值,但我們還是有必要人為地去對比一下模型、適當(dāng)修正結(jié)果!
局限性和偏向性
和很多語言模型一樣,這版 Alpha 版的 StarChat 還是有著很明顯的待解決的局限性問題,包括趨向于去掩蓋事實(shí)以及生成有問題的回答 (尤其是我們故意引導(dǎo)它這么做時)。這是由于這個模型還沒有通過類似 RLHF 的技術(shù)去對齊人類的偏好,也沒有在部署時像 ChatGPT 一樣添加避免進(jìn)入循環(huán)性回復(fù)的邏輯。此外,主要依賴代碼作為訓(xùn)練數(shù)據(jù),也會產(chǎn)生和 GitHub 的群體性量級相當(dāng)?shù)呐で娜后w性偏差,具體情況可以詳細(xì)參考 StarCoder 數(shù)據(jù)集。讀者還可以參考對應(yīng)的 model card 來更詳細(xì)地了解模型在事實(shí)性和偏向性方面的問題。
未來的工作
基于我們上述的各種實(shí)驗(yàn),我們很驚訝地發(fā)現(xiàn),像 StarCoder 這樣的代碼生成模型,可以通過在諸如 OpenAssistant 的數(shù)據(jù)集上微調(diào),被轉(zhuǎn)化為一個對話機(jī)器人。一種可能的解釋是,因?yàn)?StarCoder 已經(jīng)在代碼和 GitHub 的 issue 上訓(xùn)練過了,而后者提供了豐富的自然語言信息。我們期待看到社區(qū)引領(lǐng) StarCoder 走向新的方向,甚至激發(fā)下一個開源對話問答助手的熱潮 ??。
致謝
我們感謝 Nicolas Patry 和 Olivier Dehaene,他們在部署 StarCoder 到 Inference API,以及實(shí)現(xiàn) blazing fast text generation 方面提供了很多幫助。我們也感謝 Omar Sanseviero 在數(shù)據(jù)收集方面給出的指導(dǎo),以及他為改進(jìn)演示示例提出的寶貴建議。最后,我們也感謝 Abubakar Abid 和 Gradio 團(tuán)隊(duì)提供的完美開發(fā)體驗(yàn),以及為制作出色演示示例所分享的專業(yè)知識。
相關(guān)鏈接
代碼:
https://github.com/bigcode-project/starcoder/tree/main/chat經(jīng)過過濾的訓(xùn)練數(shù)據(jù)集:
https://hf.co/datasets/HuggingFaceH4/oasst1_en代碼評估使用的數(shù)據(jù)集:
https://hf.co/datasets/HuggingFaceH4/code_evaluation_prompts模型:
https://hf.co/HuggingFaceH4/starchat-alpha
引用
如有需要,請按照如下方式引用本篇文章。
@article{Tunstall2023starchat-alpha,
??author?=?{Tunstall,?Lewis?and?Lambert,?Nathan?and?Rajani,?Nazneen?and?Beeching,?Edward?and?Le?Scao,?Teven?and?von?Werra,?Leandro?and?Han,?Sheon?and?Schmid,?Philipp?and?Rush,?Alexander},
??title?=?{Creating?a?Coding?Assistant?with?StarCoder},
??journal?=?{Hugging?Face?Blog},
??year?=?{2023},
??note?=?{https://huggingface.co/blog/starchat-alpha},
}
原文鏈接:?https://hf.co/blog/starchat-alpha
作者: Lewis Tunstall, Nathan Lambert, Nazneen Rajani, Edward Beeching, Teven Le Scao, Sheon Han, Philipp Schmid, Leandro von Werra, Sasha Rush
譯者: hugging-hoi2022
審校/排版: zhongdongy (阿東)