網(wǎng)站建設(shè)的概念成都網(wǎng)站建設(shè)技術(shù)支持
背景
預(yù)訓(xùn)練語言模型已經(jīng)成為了現(xiàn)代自然語言處理pipeline中的基石,因為其在少量的標(biāo)注數(shù)據(jù)上產(chǎn)生更好的結(jié)果。隨著ELMo、ULMFiT、GPT和BERT的開發(fā),使用預(yù)訓(xùn)練模型在下游任務(wù)上微調(diào)的范式被廣泛使用。隨后發(fā)現(xiàn)預(yù)訓(xùn)練語言模型在沒有任何額外訓(xùn)練的情況下任務(wù)能執(zhí)行有用的任務(wù),進一步證明了其實用性。此外,根據(jù)經(jīng)驗觀察,語言模型的性能隨著模型的增大而增加(有時是可預(yù)測的,有時是突然的),這也導(dǎo)致了模型規(guī)模越來越多的趨勢。拋開環(huán)境的問題,訓(xùn)練大語言模型(LLM)的代價僅有資源豐富的組織可以負擔(dān)的起。此外,直至最終,大多數(shù)LLM都沒有公開發(fā)布。因此,大多數(shù)的研究社區(qū)都被排除在LLM的開發(fā)之外。這在不公開發(fā)布導(dǎo)致的具體后果:例如,大多數(shù)LLM主要是在英文文本上訓(xùn)練的。
為了解決這些問題,BigScience團隊提出了BigScience Large Open-science Open-access Multilingual Language Model(BLOOM)。BLOOM是在46種自然語言和13種編程語言上訓(xùn)練的1760億參數(shù)語言模型,其是由數(shù)百名研究人員合作開發(fā)和發(fā)布的。訓(xùn)練BLOOM的計算力是由來自于法國公共撥款的GENCI和IDRIS,利用了IDRIS的Jean Zay超級計算機。為了構(gòu)建BLOOM,對于每個組件進行了詳細的設(shè)計,包括訓(xùn)練數(shù)據(jù)、模型架構(gòu)和訓(xùn)練目標(biāo)、以及分布式學(xué)習(xí)的工程策略。BigScience也執(zhí)行了模型容量的分析。他們的總體目標(biāo)不僅是公開發(fā)布一個能夠和近期開發(fā)的系統(tǒng)相媲美的大規(guī)模多語言的語言模型,而且還記錄其開發(fā)中的協(xié)調(diào)過程。
BigScience
在解讀論文前,我們先介紹下BigScience團隊,BigScience 不是財團(consortium),也不是正式成立的實體。這是一個由HuggingFace、GENCI和IDRIS發(fā)起的開放式協(xié)作組織,以及一個同名的研究研討會(workshop)。其主頁為 https://bigscience.huggingface.co/。
BigScience發(fā)布 BLOOM,旨在為學(xué)術(shù)界、非營利組織和小型公司的研究實驗室能夠更好的研究和使用LLM。并且,BLOOM 本身也是由大量的是AI研究人員參與的單個研究項目,同時也是迄今為止最大規(guī)模的合作結(jié)果。
BLOOM
概述
BLOOM是由BigScience社區(qū)開發(fā)和發(fā)布的,也是第一個開源開放的超過100B的語言模型。BLOOM 本身是變換器網(wǎng)絡(luò)Transformer解碼器(Decoder-Only)模型,在一個稱之為ROOTS的語料庫上訓(xùn)練出來的176B參數(shù)規(guī)?!竞?GPT-3一樣的規(guī)?!康淖曰貧w語言模型。訓(xùn)練 BLOOM 的算力成本超過300萬歐元,由CNRS 和 GENCI提供,訓(xùn)練模型的機器是法國巴黎的Jean Zay超級計算機。BLOOM是在2021年5月至2022年5月的一年時間里完成訓(xùn)練并發(fā)布的。初始版本發(fā)布于2022年5月19日。目前最新的版本是2022年7月6日發(fā)布的1.3版本。
該項目由 Thomas Wolf (Hugging Face 聯(lián)合創(chuàng)始人兼 CSO) 發(fā)起,他敢于與大公司競爭,提出不僅要訓(xùn)練出立于世界上最大的多語言模型之林的模型,還要讓所有人都可以公開訪問訓(xùn)練結(jié)果,圓了大多數(shù)人的夢想。BLOOM由來自39個國家的1200多名參與者共同開發(fā),是全球努力的產(chǎn)物。該項目由 BigScience 與 Hugging Face 和法國 NLP社區(qū)合作協(xié)調(diào),超越了地理和機構(gòu)的界限。BLOOM不僅是一個技術(shù)奇跡,也是國際合作和集體科學(xué)追求力量的象征。
參數(shù)
名稱 | BLOOM-176B |
---|---|
參數(shù)規(guī)模 (params) | 176,247M (176B) |
隱變量維度 (dimension) | 14336 |
自注意力頭的個數(shù) (n heads) | 112 |
層數(shù) (n layers) | 70 |
詞表大小 (Vocab size) | 250,680 |
輸入序列長度 (sequence length) | 2048 |
數(shù)據(jù)規(guī)模詞元數(shù)量 (n tokens) | 366B |
訓(xùn)練時長 (Training GPU-hours) | 1,082,990 (A100) |
訓(xùn)練硬件
- GPU: 384 張 NVIDIA A100 80GB GPU (48 個節(jié)點) + 32 張備用 GPU
- 每個節(jié)點 8 張 GPU,4 條 NVLink 卡間互聯(lián),4 條 OmniPath 鏈路
- CPU: AMD EPYC 7543 32 核處理器
- CPU 內(nèi)存: 每個節(jié)點 512GB
- GPU 顯存: 每個節(jié)點 640GB
- 節(jié)點間連接: 使用 Omni-Path Architecture (OPA) 網(wǎng)卡,網(wǎng)絡(luò)拓撲為無阻塞胖樹
- NCCL - 通信網(wǎng)絡(luò): 一個完全專用的子網(wǎng)
- 磁盤 IO 網(wǎng)絡(luò): GPFS 與其他節(jié)點和用戶共享
訓(xùn)練數(shù)據(jù)
訓(xùn)練數(shù)據(jù)集ROOTS
BLOOM在 ROOTS 語料庫上訓(xùn)練,該語料庫是 59 種語言的498來源的數(shù)據(jù)集的總和(數(shù)據(jù)集全部來自HuggingFace),總計 1.61 TB 的文本,包含46 種自然語言和 13 種編程語言。詞元(Token)數(shù)量為366B。下圖給出了所有語言的占比:
對于編程語言:數(shù)據(jù)的選擇和處理參照 DeepMind 的 AlphaCode。數(shù)據(jù)的獲取利用了Google的BigQuery項目。包含語言為Java,PHP,C++,Python,JavaScript,C#,Ruby,Lua,TypeScript,Go,C,Scala,Rust。語言的分布如下圖所示:
訓(xùn)練數(shù)據(jù)集xP3
這是一個提示數(shù)據(jù)集,用于多任務(wù)提示微調(diào)(也稱為指令調(diào)優(yōu)),涉及在由通過自然語言提示指定的大量不同任務(wù)組成的訓(xùn)練混合體上微調(diào)預(yù)訓(xùn)練語言模型。原始 P3 數(shù)據(jù)集被擴展為包括英語以外的語言的新數(shù)據(jù)集和新任務(wù),例如翻譯。 這導(dǎo)致了 xP3,它是 83 個數(shù)據(jù)集的提示集合,涵蓋 46 種語言和 16 個任務(wù)。
數(shù)據(jù)處理
獲取到數(shù)據(jù)后,設(shè)計者使用了兩種方式處理數(shù)據(jù):
- 質(zhì)量過濾:大規(guī)模數(shù)據(jù)通常由自動化腳本獲取,這其中包含了大量的非自然語言文本,如預(yù)處理錯誤、SEO頁面或垃圾信息。為了過濾非自然語言,定義了一組質(zhì)量指標(biāo),確保文本是由人類為人類撰寫的。這些指標(biāo)根據(jù)每種語言和每個來源的需求進行了調(diào)整,通過流利的語言使用者選擇參數(shù),并手動檢查每個來源以識別非自然語言。這一過程得到了工具的支持,以可視化其影響,從而提高文本的質(zhì)量和自然度。
- 去重和隱私信息處理:通過兩個去重步驟,模型移除了近似重復(fù)的文檔,確保數(shù)據(jù)的唯一性和多樣性。同時,為了保護隱私,從語料庫的OSCAR版本中刪除了能夠識別的個人身份信息,如社會安全號碼,即使這可能導(dǎo)致一些誤報,也應(yīng)用了基于正則表達式的處理。
模型架構(gòu)
BLOOM的模型架構(gòu)采用了類似GPT-3的Decoder-Only架構(gòu),模型架構(gòu)如下圖所示:
與Transformers架構(gòu)中的自回歸(因果)解碼器相比,BLOOM做出了兩個改進:
ALiBi 位置嵌入
在Transformer模型中,通常使用位置編碼(如絕對位置編碼或相對位置編碼)來為輸入序列的每個元素分配一個位置標(biāo)識,以便模型能夠理解輸入序列中元素之間的順序。然而,這種位置編碼往往會增加計算復(fù)雜度,特別是在長序列的情況下,位置編碼可能不具備良好的泛化能力。
ALiBi提出了一種新的方法來處理自注意力機制中的位置關(guān)系,而不依賴于傳統(tǒng)的顯式位置編碼。具體來說,ALiBi通過在計算注意力權(quán)重時引入線性偏置,從而將位置的影響直接嵌入到注意力分數(shù)的計算中。ALiBi(Attention with Linear Biases)是一種用于改進自注意力機制(self-attention)位置編碼(position embedding)的方法,它是由Google Research在2021年提出的。ALiBi的目的是通過引入線性偏置來減少對顯式位置嵌入的依賴,從而提高計算效率和模型的泛化能力。
ALiBi的實現(xiàn)是通過修改自注意力機制中的注意力得分計算公式。標(biāo)準(zhǔn)的自注意力機制中的得分計算為:
Attention?Score = Q K T d k \text{Attention Score} = \frac{QK^T}{\sqrt{d_k}} Attention?Score=dk??QKT?
其中, Q Q Q是查詢向量, K K K 是鍵向量, d k d_k dk?是向量的維度。ALiBi則通過添加一個與位置相關(guān)的線性偏置項 B i j B_{ij} Bij? 來修改這一得分:
Attention?Score = Q K T d k + B i j \text{Attention Score} = \frac{QK^T}{\sqrt{d_k}} + B_{ij} Attention?Score=dk??QKT?+Bij?
這里, B i j B_{ij} Bij?是一個基于位置的線性偏置,它對不同位置對之間的關(guān)系進行建模。通過這種方式,ALiBi將位置嵌入直接整合到了注意力分數(shù)中。
通過使用ALiBi位置嵌入:
- 簡化了位置編碼的設(shè)計:傳統(tǒng)的Transformer模型需要額外的固定位置編碼(例如,正弦和余弦函數(shù)生成的編碼)或相對位置編碼,而ALiBi通過引入線性偏置使得位置關(guān)系能夠在注意力機制中動態(tài)地體現(xiàn)。
- 無參數(shù)化的空間擴展:傳統(tǒng)的絕對或相對位置編碼在處理不同長度的序列時,往往需要重新調(diào)整編碼的大小,而ALiBi的方法可以無縫適應(yīng)長序列。
- 增強了模型的泛化能力:通過這種方式,ALiBi能夠幫助模型更好地學(xué)習(xí)和推斷不同長度和位置關(guān)系的序列,進而提高其泛化性能。
BLOOM 團隊認為ALiBi 位置嵌入使用在推斷中能夠完成更長序列的任務(wù),同時訓(xùn)練時更加平滑,以及對下游任務(wù)來說有更好的性能。
具體給出實現(xiàn):
def build_alibi_tensor(attention_mask, num_heads, dtype) -> mindspore.Tensor:batch_size, seq_length = attention_mask.shape# closet_power_of_2是與num_head接近的2的次方# 例如:num_heads為5/6/7時,closest_power_of_2為4closest_power_of_2 = 2 ** math.floor(math.log2(num_heads))# 計算斜率base = mindspore.Tensor(2 ** (-(2 ** -(math.log2(closest_power_of_2) - 3))),dtype=mindspore.float32)powers = mindspore.ops.arange(1, 1 + closest_power_of_2,dtype=mindspore.int32)slopes = mindspore.ops.pow(base, powers)# 注意力頭數(shù)量不是2的次方if closest_power_of_2 != num_heads:extra_base = mindspore.Tensor(2 ** (-(2 ** -(math.log2(2 * closest_power_of_2) - 3))), dtype=mindspore.float32)num_remaining_heads = min(closest_power_of_2, num_heads - closest_power_of_2)extra_powers = mindspore.ops.arange(1, 1 + 2 * num_remaining_heads, 2, dtype=dtype=mindspore.int32)slopes =mindspore.ops.cat([slopes, torch.pow(extra_base, extra_powers)], axis=0)# 相對距離arange_tensor = ((attention_mask.cumsum(dim=-1) - 1) * attention_mask)[:, None, :]# alibi會與query和key的乘積相加# alibi的形狀為[batch_size, num_heads, query_length, key_length]alibi = slopes[..., None] * arange_tensorreturn alibi.reshape(batch_size * num_heads, 1, seq_length).to(dtype)
Embedding LayerNorm
這項技術(shù)簡單直接且有效, 如下圖所示,在嵌入層之后立即包含額外的層歸一化,這提高了訓(xùn)練穩(wěn)定性。這一決定在一定程度上受到在最終訓(xùn)練中使用 bfloat16 的影響,它比 float16 更穩(wěn)定。
在訓(xùn)練一個104B參數(shù)模型的初步實驗中,研究人員嘗試在嵌入層之后立即添加一個額外的層歸一化(Layer Normalization),這是根據(jù)bitsandbytes17庫及其StableEmbedding層的推薦。他們發(fā)現(xiàn)這顯著提高了訓(xùn)練的穩(wěn)定性。盡管他們也發(fā)現(xiàn)這會懲罰零樣本泛化能力,但他們?nèi)匀辉贐LOOM的訓(xùn)練中在第一個嵌入層之后添加了一個額外的層歸一化,以避免訓(xùn)練不穩(wěn)定。需要注意的是,初步的104B實驗是在float16精度下進行的,而最終的訓(xùn)練是在bfloat16精度下進行的。自那以后,float16被認為是導(dǎo)致許多大型語言模型(LLMs)訓(xùn)練中出現(xiàn)不穩(wěn)定性的原因(Zhang et al., 2022; Zeng et al., 2022)。因此,有可能bfloat16精度緩解了對嵌入層歸一化的需求。
工程實現(xiàn)
176B BLOOM 模型使用 Megatron-DeepSpeed 進行訓(xùn)練,它結(jié)合了兩種主要技術(shù):
- DeepSpeed 是一個深度學(xué)習(xí)優(yōu)化庫,讓分布式訓(xùn)練變得簡單、高效且有效。
- Megatron-LM 是由 NVIDIA 的應(yīng)用深度學(xué)習(xí)研究團隊開發(fā)的大型、強大的 transformer 模型框架。
DeepSpeed 團隊通過將 DeepSpeed 庫中的 ZeRO 分片和流水線并行 (Pipeline Parallelism) 與 Megatron-LM 中的張量并行 (Tensor Parallelism) 相結(jié)合,開發(fā)了一種基于 3D 并行的方案。有關(guān)每個組件的更多詳細信息,請參見下表。
組件 | DeepSpeed | Megatron-LM |
---|---|---|
ZeRO 數(shù)據(jù)并行 | 是 | |
張量并行 | 是 | |
流水線并行 | 是 | |
BF16 優(yōu)化器 | 是 | |
CUDA 融合核函數(shù) | 是 | |
數(shù)據(jù)加載器 | 是 |
Megatron-DeepSpeed 實現(xiàn)了 3D 并行以允許大模型以非常有效的方式進行訓(xùn)練。
- 數(shù)據(jù)并行 (Data Parallelism,DP) - 相同的設(shè)置和模型被復(fù)制多份,每份每次都被饋送不同的一份數(shù)據(jù)。處理是并行完成的,所有份在每個訓(xùn)練步結(jié)束時同步。
- 張量并行 (Tensor Parallelism,TP) - 每個張量都被分成多個塊,因此張量的每個分片都位于其指定的 GPU 上,而不是讓整個張量駐留在單個 GPU 上。在處理過程中,每個分片在不同的 GPU 上分別并行處理,結(jié)果在步驟結(jié)束時同步。這就是所謂的水平并行,因為是做的水平拆分。
- 流水線并行 (Pipeline Parallelism,PP) - 模型在多個 GPU 上垂直 (即按層) 拆分,因此只有一個或多個模型層放置在單個 GPU 上。每個 GPU 并行處理流水線的不同階段,并處理 batch 的一部分數(shù)據(jù)。
- 零冗余優(yōu)化器 (Zero Redundancy Optimizer,ZeRO) - 也執(zhí)行與 TP 相類似的張量分片,但整個張量會及時重建以進行前向或反向計算,因此不需要修改模型。它還支持各種卸載技術(shù)以補償有限的 GPU 內(nèi)存。
數(shù)據(jù)集上的評價指標(biāo)得分
SuperGLUE
SuperGLUE(Super General Language Understanding Evaluation)是一個用于評估自然語言理解(NLU)模型性能的基準(zhǔn)測試套件。它由Wang等人于2019年提出,旨在替代早期的GLUE基準(zhǔn),提供更具挑戰(zhàn)性的任務(wù),以推動NLU模型的發(fā)展。
SuperGLUE包含以下幾個主要任務(wù):
- AX-b:一種二元分類任務(wù),用于評估模型對句子對之間關(guān)系的理解。
- AX-g:另一種二元分類任務(wù),類似于AX-b,但更具挑戰(zhàn)性。
- BoolQ:布爾問答任務(wù),模型需要判斷給定的問題是否為真或假。
- CB:文本分類任務(wù),模型需要對給定的句子對進行分類。
- WiC:詞義消歧任務(wù),模型需要判斷兩個句子中的同一個詞是否具有相同的含義。
- WSC:代詞消解任務(wù),模型需要確定句子中的代詞指代的具體對象。
- RTE:文本蘊含任務(wù),模型需要判斷一個句子是否蘊含另一個句子。
上圖展示了在SuperGLUE上的零樣本和單樣本性能。在兩種設(shè)置下,在蘊含任務(wù)(BoolQ和CB)上,BLOOM、T0、OPT和GPT-J的表現(xiàn)都遠高于隨機水平。
隨著模型從零樣本到單樣本的轉(zhuǎn)變,所有提示和模型的變異性都減少了,性能略有且不一致地提高。值得注意的是,BLOOM在從零樣本到單樣本的轉(zhuǎn)變中,性能提升比其他可比模型更大,盡管它在零樣本設(shè)置中通常落后于OPT,但在單樣本設(shè)置中與之匹配或超越了OPT,盡管它僅部分地用英語進行了訓(xùn)練。這可能是因為多語言模型在輸入和輸出語言的上下文更長時,對語言的確定性更高。
作為基線,論文還測量了相似大小的OPT模型(從350M參數(shù)到175B參數(shù))的平均單樣本準(zhǔn)確率。上圖展示了每個提示在每個任務(wù)上的準(zhǔn)確率隨模型規(guī)模的變化。OPT和BLOOM模型家族隨著規(guī)模的增加略有提升,只有超過20億參數(shù)的模型顯示出信號,并且在所有任務(wù)上沒有一致的家族間差異。在單樣本設(shè)置中,BLOOM176B在Ax-b、CB、WSC和WiC上領(lǐng)先于OPT-175B,并在其他任務(wù)上與之匹配,這表明多語言性并不限制BLOOM在零樣本設(shè)置中對僅英語任務(wù)的性能。
機器翻譯
WMT數(shù)據(jù)集
上表給出了BLOOM-176B在零樣本和單樣本設(shè)置下的WMT結(jié)果。最佳提示往往是更詳細的提示;a_good_translation-source+target、gpt3-target、version-target、xglm-source+target提示中,version-target提示始終表現(xiàn)更好,而gpt3-target和xglm-source+target提示的性能非常差,尤其是在零樣本設(shè)置下。在單樣本設(shè)置下,BLOOM在正確的提示下可以執(zhí)行有能力的翻譯,盡管它落后于專門的(監(jiān)督)模型,如M2M-100(英語→法語的BLEU得分為43.8,法語→英語的BLEU得分為40.4,而BLOOM的BLEU得分分別為34.2和35.4)。觀察到的兩個主要問題,特別是在零樣本設(shè)置下,是(i)過度生成和(ii)未生成正確的語言(這是良好翻譯的明顯前提)。隨著少樣本示例數(shù)量的增加,這兩個方面都得到了極大的改善。
DiaBLa數(shù)據(jù)集
上表展示了使用DiaBLa(一個非正式雙語對話的平行數(shù)據(jù)集)進行語言上下文測試的結(jié)果。在單樣本上下文中,使用“xglm-source+target”提示,比較了使用隨機測試集示例作為單樣本示例與使用前一個對話話語的效果。鑒于觀察到的過度生成問題,為了獨立于過度生成評估預(yù)測質(zhì)量,論文報告了原始輸出和應(yīng)用自定義截斷函數(shù)后的結(jié)果。自動結(jié)果并不明確,得分差異不大(BLEU分數(shù)在前一個上下文中較高,但COMET分數(shù)較低)。盡管如此,預(yù)測本身有證據(jù)表明模型能夠利用單樣本示例的上下文來進行翻譯選擇。
Flores數(shù)據(jù)集
在單樣本設(shè)置下,使用“xglm-source+target”提示在Flores-101開發(fā)測試集上測試了幾種語言方向。單樣本示例從開發(fā)集中隨機選取。將結(jié)果分為低資源語言對(表8a)、羅曼語族相關(guān)語言之間(表8b)、高資源語言對(表8c)和高到中等資源語言對(表8d)。
根據(jù)語言在ROOTS中的表示,語言被分類為低資源、中等資源和高資源。與M2M-100模型的監(jiān)督結(jié)果進行比較,該模型的參數(shù)為615M。此外,還與高資源語言對的樣本AlexaTM結(jié)果進行比較。在單樣本設(shè)置下,高資源語言之間的翻譯和從高資源到中等資源語言的翻譯結(jié)果普遍良好,表明BLOOM具有良好的多語言能力,即使在不同文字之間(如拉丁文(或擴展拉丁文)、中文、阿拉伯文和天城文之間)也是如此。與監(jiān)督的M2M-100模型相比,結(jié)果往往相當(dāng),有時甚至更好,并且在許多情況下與AlexaTM的結(jié)果相當(dāng)。
許多低資源語言的翻譯質(zhì)量良好,可與監(jiān)督的M2M模型相媲美,甚至略好。然而,斯瓦希里語和約魯巴語之間的翻譯結(jié)果非常差,這兩種語言在BLOOM的訓(xùn)練數(shù)據(jù)中存在但代表性不足(每種語言<50k個標(biāo)記)。這與羅曼語(因此是相關(guān)語言)之間的翻譯結(jié)果形成對比,后者的結(jié)果普遍良好,包括加利西亞語(glg)的翻譯,該語言未包含在訓(xùn)練數(shù)據(jù)中,但與葡萄牙語(por)等其他羅曼語有許多相似之處。然而,這確實對BLOOM在訓(xùn)練中包含的那些代表性不足的低資源語言的質(zhì)量提出了質(zhì)疑。
文本摘要
BLOOM在多語言摘要任務(wù)上的表現(xiàn)優(yōu)于OPT,并且隨著模型參數(shù)數(shù)量的增加,性能有所提高。
代碼生成
預(yù)訓(xùn)練的BLOOM模型的性能與在Pile上訓(xùn)練的類似大小的GPT模型相似。Pile包含英語數(shù)據(jù)和約13%的代碼,這與ROOTS中的代碼數(shù)據(jù)源和比例相似。僅在代碼上微調(diào)的Codex模型明顯強于其他模型。多任務(wù)微調(diào)的BLOOMZ模型在BLOOM模型上沒有顯著改進。
多任務(wù)微調(diào)
使用xP3語料庫對BLOOM模型進行了多語言多任務(wù)微調(diào)。發(fā)現(xiàn)零樣本性能顯著提高。上圖比較了預(yù)訓(xùn)練的BLOOM和XGLM模型與多任務(wù)微調(diào)的BLOOMZ、T0和mTk-Instruct的零樣本性能。BLOOM和XGLM在NLI(XNLI)上的性能接近33%的隨機基線,在指代消解(XWinograd)和句子補全(XCOPA和XStoryCloze)上的性能接近50%的隨機基線。經(jīng)過多語言多任務(wù)微調(diào)(BLOOMZ)后,零樣本性能在描繪的保留任務(wù)上顯著提高。盡管T0也是多任務(wù)微調(diào)的,但由于它是一個單語英語模型,因此在顯示的多語言數(shù)據(jù)集上表現(xiàn)不佳。
使用 MindNLP 進行模型評估
本文代碼全部開源,已經(jīng)上傳到代碼倉庫。
BLOOM MindNLP代碼生成評估代碼:https://github.com/ResDream/BLOOM2CodeGeneration
我們以Bloom 3B為例,使用MindNLP完成代碼生成任務(wù)。
數(shù)據(jù)集
實驗思路和論文一致,我們使用HumanEval數(shù)據(jù)集,HumanEval 數(shù)據(jù)集是由 OpenAI 開發(fā)的一個用于評估代碼生成模型的基準(zhǔn)數(shù)據(jù)集。它旨在測試模型在生成正確、高效且可運行的代碼方面的能力。HumanEval 數(shù)據(jù)集包含了一系列編程問題,每個問題都附帶了問題的描述、輸入輸出示例以及一個或多個測試用例。
生成代碼
import json
from mindnlp.transformers import AutoModelForCausalLM, AutoTokenizer
import mindspore
from tqdm import tqdm# 加載模型和分詞器
model_path = "bigscience/bloom-7b1"
model = AutoModelForCausalLM.from_pretrained(model_path, ms_dtype=mindspore.float16, mirror="huggingface")
tokenizer = AutoTokenizer.from_pretrained(model_path, mirror="huggingface")# 讀取數(shù)據(jù)集文件
input_file_path = "./data/human-eval.jsonl"
output_file_path = "./results/human-eval-output.jsonl"# 定義生成樣本的數(shù)量
k = 100# 打開輸出文件
with open(output_file_path, "w") as output_file:# 逐行讀取輸入文件with open(input_file_path, "r") as input_file:lines = input_file.readlines()for line in tqdm(lines, desc="Generating Code"):# 解析每一行的JSON數(shù)據(jù)data = json.loads(line)task_id = data["task_id"]prompt = data["prompt"]# 生成多個代碼樣本for _ in range(k):inputs = tokenizer(prompt, return_tensors="ms")outputs = model.generate(inputs.input_ids,do_sample=False, max_length=2048,# temperature=0.8, top_k=2, repetition_penalty=1.5)completion = tokenizer.decode(outputs[0], skip_special_tokens=True)# 構(gòu)建輸出結(jié)果output_data = {"task_id": task_id,"completion": completion}# 將結(jié)果寫入輸出文件output_file.write(json.dumps(output_data) + "\n")print("生成完成,結(jié)果已保存到", output_file_path)
Pass@K指標(biāo)
Pass@k
是一種用于評估代碼生成模型性能的指標(biāo),特別是在 HumanEval 數(shù)據(jù)集等基準(zhǔn)測試中廣泛使用。Pass@k
指標(biāo)衡量的是在模型生成 k
個候選代碼樣本中,至少有一個樣本能夠通過所有測試用例的概率。
定義
給定一個編程問題,模型生成 k
個候選代碼樣本。Pass@k
的定義如下:
- 通過率:在
k
個候選代碼樣本中,至少有一個樣本能夠通過所有測試用例的概率。
計算方法
假設(shè)模型生成了 k
個候選代碼樣本,并且每個樣本通過所有測試用例的概率為 p
。那么 Pass@k
可以通過以下公式計算:
Pass@k = 1 ? ( 1 ? p ) k \text{Pass@k} = 1 - (1 - p)^k Pass@k=1?(1?p)k
其中:
p
是單個樣本通過所有測試用例的概率。k
是生成的候選代碼樣本數(shù)量。
解釋
-
高
Pass@k
值:表示模型生成的代碼樣本中,有較高的概率至少有一個樣本能夠通過所有測試用例。這意味著模型在生成正確代碼方面表現(xiàn)較好。 -
低
Pass@k
值:表示模型生成的代碼樣本中,通過所有測試用例的概率較低。這意味著模型在生成正確代碼方面表現(xiàn)較差。
對于Pass@k的計算,我們使用如下代碼進行計算:
from collections import defaultdict, Counter
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import List, Union, Iterable, Dict
import itertoolsimport numpy as np
import tqdmfrom human_eval.data import HUMAN_EVAL, read_problems, stream_jsonl, write_jsonl
from human_eval.execution import check_correctnessdef estimate_pass_at_k(num_samples: Union[int, List[int], np.ndarray],num_correct: Union[List[int], np.ndarray],k: int
) -> np.ndarray:"""Estimates pass@k of each problem and returns them in an array."""def estimator(n: int, c: int, k: int) -> float:"""Calculates 1 - comb(n - c, k) / comb(n, k)."""if n - c < k:return 1.0return 1.0 - np.prod(1.0 - k / np.arange(n - c + 1, n + 1))if isinstance(num_samples, int):num_samples_it = itertools.repeat(num_samples, len(num_correct))else:assert len(num_samples) == len(num_correct)num_samples_it = iter(num_samples)return np.array([estimator(int(n), int(c), k) for n, c in zip(num_samples_it, num_correct)])def evaluate_functional_correctness(sample_file: str,k: List[int] = [1, 10, 100],n_workers: int = 4,timeout: float = 3.0,problem_file: str = HUMAN_EVAL,
):"""Evaluates the functional correctness of generated samples, and writesresults to f"{sample_file}_results.jsonl.gz""""problems = read_problems(problem_file)# Check the generated samples against test suites.with ThreadPoolExecutor(max_workers=n_workers) as executor:futures = []completion_id = Counter()n_samples = 0results = defaultdict(list)print("Reading samples...")for sample in tqdm.tqdm(stream_jsonl(sample_file)):task_id = sample["task_id"]completion = sample["completion"]args = (problems[task_id], completion, timeout, completion_id[task_id])future = executor.submit(check_correctness, *args)futures.append(future)completion_id[task_id] += 1n_samples += 1assert len(completion_id) == len(problems), "Some problems are not attempted."print("Running test suites...")for future in tqdm.tqdm(as_completed(futures), total=len(futures)):result = future.result()results[result["task_id"]].append((result["completion_id"], result))# Calculate pass@k.total, correct = [], []for result in results.values():result.sort()passed = [r[1]["passed"] for r in result]total.append(len(passed))correct.append(sum(passed))total = np.array(total)correct = np.array(correct)ks = kpass_at_k = {f"pass@{k}": estimate_pass_at_k(total, correct, k).mean()for k in ks if (total >= k).all()}# Finally, save the results in one file:def combine_results():for sample in stream_jsonl(sample_file):task_id = sample["task_id"]result = results[task_id].pop(0)sample["result"] = result[1]["result"]sample["passed"] = result[1]["passed"]yield sampleout_file = sample_file + "_results.jsonl"print(f"Writing results to {out_file}...")write_jsonl(out_file, tqdm.tqdm(combine_results(), total=n_samples))return pass_at_k
實驗結(jié)果
論文中的結(jié)果為:
Model | PASS@k=1 | PASS@k=10 | PASS@k=100 |
---|---|---|---|
BLOOM-3B | 6.48% | 11.35% | 20.43% |
基于MindNLP的復(fù)現(xiàn)實驗后的結(jié)果為:
Model | PASS@k=1 | PASS@k=10 | PASS@k=100 |
---|---|---|---|
BLOOM-3B | 2.44% | 7.32% | 17.6% |
基于HuggingFace的Transformers的復(fù)現(xiàn)實驗后的結(jié)果為:
Model | PASS@k=1 | PASS@k=10 | PASS@k=100 |
---|---|---|---|
BLOOM-3B | 3.05% | 8.53% | 16.5% |
可以看到,使用Transformers和MindNLP的結(jié)果相差不大,平均誤差只有0.64%。與論文結(jié)果出現(xiàn)差距可能是由于提示的差別,并且沒有探索BLOOM模型生成代碼的最優(yōu)超參數(shù)組(topk,采樣方式,溫度等)導(dǎo)致的。
總結(jié)
BLOOM模型是超大規(guī)模語言模型早期的探索。雖然放在現(xiàn)在來看存在一些技術(shù)上的不成熟或者不明智的地方,但它為后續(xù)的研究和開發(fā)奠定了堅實的基礎(chǔ)。BLOOM模型的出現(xiàn)標(biāo)志著人工智能領(lǐng)域在自然語言處理方面邁出了重要的一步,尤其是在處理復(fù)雜文本和生成高質(zhì)量內(nèi)容方面取得了顯著進展。
首先,BLOOM模型的規(guī)模和復(fù)雜性在當(dāng)時是前所未有的。它采用了大量的參數(shù)和深度學(xué)習(xí)架構(gòu),使得模型能夠捕捉到語言中的細微差別和復(fù)雜模式。這種大規(guī)模的模型設(shè)計為后來的百花齊放的開源大模型提供了寶貴的經(jīng)驗,尤其是在如何有效管理和優(yōu)化大規(guī)模參數(shù)方面。
其次,BLOOM模型在多語言處理方面也取得了突破。它不僅能夠處理英語等主流語言,還能夠理解和生成多種非英語語言的文本。這種多語言能力的提升為全球范圍內(nèi)的應(yīng)用提供了可能性,尤其是在跨文化交流和多語言內(nèi)容生成方面。
然而,BLOOM模型也存在一些明顯的不足。例如,模型的訓(xùn)練成本極高,需要大量的計算資源和時間。此外,模型的生成結(jié)果有時會出現(xiàn)不準(zhǔn)確或不連貫的情況,尤其是在處理長文本或復(fù)雜語境時。這些問題在后續(xù)的模型中得到了改進,但BLOOM模型的早期探索為這些改進提供了重要的參考。
總的來說,BLOOM模型雖然在技術(shù)上存在一些不成熟的地方,但它的出現(xiàn)推動了超大規(guī)模語言模型的發(fā)展,為后續(xù)的研究和應(yīng)用開辟了新的道路。隨著技術(shù)的不斷進步,我們有理由相信,未來的語言模型將會更加智能、高效和可靠,為人類社會帶來更多的便利和創(chuàng)新。