相同的 LLM 在「不同 GPU 上」會產(chǎn)生不同輸出?為什么? 原創(chuàng)
編者按: 在大語言模型(LLMs)的部署及其相關(guān)的算力擴容過程中,更換 GPU 是否也可能會對模型的輸出產(chǎn)生重大影響?這個問題的答案對于確保 LLMs 在不同硬件環(huán)境下的一致性和可靠性至關(guān)重要。
我們今天為大家?guī)淼倪@篇文章,作者的核心觀點是:即使在相同的開發(fā)環(huán)境、系統(tǒng)配置和隨機種子下,不同的 GPU 也會導致 LLMs 產(chǎn)生不同的模型輸出。
作者通過實驗證明,在使用 Nvidia Tesla T4 和 Nvidia A10G 兩種不同 GPU 的情況下,Mistral-7b-v0.1 模型對相同的輸入產(chǎn)生了不同的輸出。這種差異主要源于 GPU 在并行計算處理、硬件架構(gòu)和模型量化的影響等方面的不同。隨著提示詞長度的增加,這種不準確性會被放大,因為更長的提示詞需要進行更多計算,從而加劇了不準確性的傳播。在使用多個 GPU 擴展時,如果采用模型分片策略,理論上可能會因計算分布的不同而導致結(jié)果產(chǎn)生變化,但實踐中 PyTorch 的設(shè)計似乎保證了結(jié)果的一致性。
作者 | Anis Zakari
編譯 | 岳揚
大多數(shù)技術(shù)工程師都了解,依賴庫或依賴組件的版本不同都可能會導致系統(tǒng)行為產(chǎn)生變化。但在大語言模型(Large Language Models)領(lǐng)域,由于算力需求巨大,在訓練和推理任務中我們都極度依賴 GPU。然而,很少有人真正意識到,更換 GPU 也會對 LLMs 的輸出產(chǎn)生影響。
假如你想創(chuàng)建兩個完全一致的開發(fā)環(huán)境:
- 可以指定依賴庫或組件的版本。
- 可以使用 Dockerization。
- 可以將 LLMs 的 temperature 設(shè)置為 0。
- 可以選擇任意的隨機種子。 但是,如果使用的不是完全相同的 GPU 型號,以上所有努力都將白費。
本文將進行一次實驗來強調(diào)這一現(xiàn)象,說明差異出現(xiàn)的位置及其原因。
Note:如果對實驗過程的重現(xiàn)或具體代碼不感興趣,可以跳過本文展示代碼片段,直接閱讀“7. 為什么同樣的 inputs 和同樣的 LLMs 在兩塊不同 GPU 上生成的模型響應會有如此大的差別?”這部分內(nèi)容。即便不看前面的代碼片段,Conclusion 部分仍然有助于我們理解其中的原理。
01 為什么要寫這篇文章?
有一天,我和一些人討論為什么 OpenAI 和 Anthropic 的那些模型在設(shè)計時沒有被構(gòu)建為確定性的系統(tǒng)。我解釋說,它們可能采用了混合專家模型(Mixture of Experts, MoE)方法<sup>[1]</sup>,偶爾不會將 tokens 路由給最優(yōu)的專家模型,因為這些專家模型可能正忙于處理其他 tokens,所以可能會導致模型響應的不一致。
另一個因素可能是 OpenAI 為了提高效率而對 queries 進行了批量處理。batches size 會根據(jù)傳入的 queries 數(shù)量而變化,可能會改變 GPU 的計算策略,從而導致不同的模型響應。
當有人指出,“不同的 GPU 也可能導致出現(xiàn)不同的模型響應,不是嗎?”時,我們之間的對話開始變得耐人尋味起來了。
仔細想一想……當我們使用 OpenAI API 時,實際上是有一臺遠程服務器幫我們執(zhí)行計算并返回模型響應。現(xiàn)在,如果這臺機器并非總是在相同的算力基礎(chǔ)設(shè)施上運行,那么最終得到的模型響應就不會相同。
想到這一點,可能就會出現(xiàn)其他問題:
- 如果有一個在生產(chǎn)開發(fā)環(huán)境中運行的 LLM app,并且需要將其擴展到擁有不同 GPU 的其他實例,是否會出現(xiàn)很嚴重的問題?
- 如果開發(fā)環(huán)境(development environment)中的 GPU 與生產(chǎn)環(huán)境(production environment)存在大量不同之處,會怎么樣?
這些問題促使我想設(shè)置一個實驗來突出這一現(xiàn)象,并探究它可能造成的影響有多大。
02 配置實驗環(huán)境
為了突出這一現(xiàn)象,我將設(shè)置兩個完全相同的開發(fā)環(huán)境,它們唯一的區(qū)別在于其所使用的 GPU:第一個開發(fā)環(huán)境中使用的是 Nvidia Tesla T4,第二個開發(fā)環(huán)境使用的便是 Nvidia A10G。然后,我們將使用 Mistral-7b-v0.1 進行測試,看看會發(fā)生什么。
要在 notebook 中運行實驗,請按照以下步驟操作。
2.1 配置開發(fā)環(huán)境(Setup the environment)
1. 配置 CUDA 版本

2. 配置 transformers 和其他依賴

3. 設(shè)置隨機種子(random seeds)

注釋 1:
僅設(shè)置 transformers.set_seed 應該就足夠了,但我還是想要確保萬無一失。
注釋 2:
本例使用的是 Python 3.10。
2.2 加載 Mistral 模型
要從 Hugging Face 中加載 Mistral-7B-v0.1 模型,我們需要在環(huán)境變量 HF_TOKEN 中設(shè)置 Hugging Face tokens。
本文將會使用量化版本的模型,降低計算精度來減少 GPU 的內(nèi)存占用。

2.3 使用 transformers 庫中的 pipeline
我們將使用 transformers 庫中的 pipeline 來簡化從大語言模型(LLMs)生成模型響應的過程。
為了確保模型輸出是可預測和一致的,我們希望從大語言模型的 vocabulary 中持續(xù)預測出最有可能的 tokens,因此我們可以將 top_k 設(shè)置為 1 或?qū)?temperature 設(shè)置為接近 0 的值。
此外,為了簡單起見,我們將把 max_new_tokens 參數(shù)設(shè)置為 1,這樣 LLMs 就能只用單個 token 完成提示詞。

當給出提示詞序列 “I enjoy walking in the” 時,大語言模型(LLMs)只會生成一個單詞:“woods”。如果大語言模型(LLMs)正確地生成并輸出了這個單詞,我們就可以繼續(xù)進行實驗了。
03 實驗結(jié)果:T4 vs A10G
為了能夠使用這兩塊 GPU,我通過 AWS SageMaker 啟動了 ml.g4dn.xlarge (T4) 和 ml.g5.xlarge (A10G) 實例。
讓我們嘗試運行一個簡單的 query :


T4 和 A10G 給我的模型響應是一樣的:

到目前為止一切進展順利。不過,這只是一個簡短的 query 。在 RAG(檢索增強生成)的應用場景里,我們通常會處理成千上萬個 tokens 。現(xiàn)在讓我們使用在 Hugging Face 上托管的 llama-2-arxiv-papers-chunked 數(shù)據(jù)集來進行更大規(guī)模的 query 測試。
在下面的代碼示例中,我將模仿 RAG 的工作方式,使用數(shù)據(jù)集索引 0、4518、4519 和 799 處獲取的文本片段。其中第 4518 和 4519 個數(shù)據(jù)塊(chunks)討論了 “Llama 2”,而其他片段則沒有提及。我們期待 LLMs 能基于這些上下文信息回答:“Llama 2 有什么特別之處?”該提示詞大概有 1,400 個 tokens 長。

T4 模型的輸出如下:

A10G 模型的輸出如下:

確實很有趣。乍一看,由于兩個模型響應開頭相同,區(qū)別卻不太明顯。但在“等等(etc)……”之后,兩者就有所差異了。
T4 模型輸出如下:“etc… This also means you can trust the output more since everything inside will be consistent across different runs!…”
A10G 模型輸出如下:“etc… This also means you can be more confident when asking questions specifically related to topics covered within those texts…”
04 T4 Colab vs T4 SageMaker
想知道使用相同 GPU 的兩個開發(fā)環(huán)境是否會產(chǎn)生相同的模型輸出?我進行了一系列測試,結(jié)果確實完全相同。
05 為什么相同的用戶輸入(inputs)和相同的 LLMs 在兩個 GPUs 上生成的答案會如此不同?
最終,這些模型響應因為 LLMs 的自回歸特性而變得截然不同。由于下一個 token 是根據(jù)之前的 tokens 選擇的,任何細微的變化都會引發(fā)一連串的連鎖反應,就像蝴蝶效應(butterfly effect)一樣。
請注意,這些模型響應并沒有像提示詞中所要求的那樣基于所提供的上下文。LLMs 并沒有完全遵循指導性提示詞(instructions),但這并不是很重要。
因為我們假設(shè) LLMs 總是基于前面的 tokens 選擇概率(probabilities)最高的 token,所以我們可以肯定,區(qū)別在于如何在 GPU 上計算該概率(probabilities),下面讓我們來看一看如何計算該概率~
06 計算 tokens 的選擇概率(probabilities)
為了打印出每個被選中 token 的概率,我們將繞過常規(guī)處理流程(pipeline),直接使用 tokenizer 和 model.generate 方法。這樣我們就能設(shè)置 return_dict_in_generate=True 和 output_scores=True。接著,我們就可以進行計算(compute)操作、對其進行歸一化操作(normalize),并將 transition scores(譯者注:在自然語言處理領(lǐng)域,尤其是使用自回歸模型生成文本時,模型會為每個 next token 分配一個概率分數(shù),這個分數(shù)反映了該 token 作為 tokens 序列中 next token 的可能性大小。) 轉(zhuǎn)換為概率(probabilities)。

上述代碼會顯示每個 token 的 ID、解碼后的 token 以及其對應的概率(probability)。此處我只列出相關(guān)的模型輸出內(nèi)容,因為完整的內(nèi)容非常長。
T4 Output:

A10G Output:

好了,現(xiàn)在事情變得越來越有趣了。T4 和 A10G 上的概率值(probabilities)并不完全一致。一般情況下,這樣并不會影響 tokens 的排序序列(無法在生成的 tokens 序列中察覺到任何不同),但有時候確實會造成影響。
例如,在 T4 模型中,“trust” 出現(xiàn)的概率為 18.74 %,而在 A10G 上,“be” 出現(xiàn)的概率則更高,達到了 18.62 %。從這一點來看,由于大語言模型的自回歸特性,生成的內(nèi)容將會出現(xiàn)偏差(diverge)。
注釋:量化大語言模型會降低計算精度(calculation precision),導致這類差異變得更為常見。
現(xiàn)在,一個非常合理的問題就出現(xiàn)了:“為什么計算結(jié)果會因為 GPU 的不同而產(chǎn)生差異呢?”
07 為什么 GPU 不同,模型運算結(jié)果也不同?
雖然我不是 CUDA expert(譯者注:這類人能夠熟練使用 CUDA C/C++ 編程語言來開發(fā)高性能的并行計算應用,并了解如何優(yōu)化 GPU 上的計算任務來獲得最佳性能。),但我進行過一些研究。不同 GPU 之間的計算差異可以歸因于以下幾個因素:
并行計算處理(Parallel Computation Handling):
GPUs 的特點是能夠高效地并行處理大量的計算任務。然而,不同 GPU 在管理這些并行任務時可能會有所差異,從而影響到運算順序以及內(nèi)存的訪問方式。
這一點非常重要,因為在編程過程中,即使是數(shù)值大小相差很大的簡單加法也可能是 non-associative,從而影響到精確計算(precise calculations)的準確性。所謂 “Non-associativity” 是指:(a + b) + c ≠ a + (b + c)。

因此,計算任務會被分割開來,獨立進行處理,然后以 non-associative 方式組合在一起。因此,這些部分的內(nèi)容如何重新組合會影響到最終結(jié)果。
這里有一個關(guān)于 non-associative computation 的簡單示例:

對于大語言模型(LLMs),數(shù)百萬次的計算可能會因為重復出現(xiàn)的微小誤差而導致出現(xiàn)偏差(diverge),進而影響到序列生成過程中的字詞選擇。
硬件架構(gòu)(Hardware Architecture):
不同型號的 GPU,如 Nvidia Tesla T4 和 Nvidia A10G ,具備不同的硬件架構(gòu)。這些硬件架構(gòu)能夠優(yōu)化模型各個方面的性能,包括并行處理能力(parallel processing capabilities)、內(nèi)存帶寬(memory bandwidth)和計算單元(compute units)。
例如,T4 模型采用了 Turing<sup>[2]</sup> 架構(gòu),而 A10G 模型基于 Ampere<sup>[3]</sup> 架構(gòu)。
不同的模型架構(gòu)意味著在浮點運算(floating-point arithmetic)、內(nèi)存訪問模式(memory access patterns)和其他底層操作上有著不同的實現(xiàn)方式。即使這些實現(xiàn)方式(implementations)存在細微差別,也可能會導致計算結(jié)果出現(xiàn)差異。
例如,與針對更高計算精度而進行優(yōu)化的模型架構(gòu)相比,為了計算速度而優(yōu)化的模型架構(gòu)可能會產(chǎn)生不同的模型響應,即便兩者都在執(zhí)行相同的浮點運算。
模型量化的影響(Quantization Effects):
通過模型量化(Quantizing)來降低計算精度可以節(jié)省內(nèi)存資源和計算資源,但這樣做也會引入額外的誤差源(sources of error)。這些誤差的影響因 GPU 對低精度運算(lower precision arithmetic)的處理方式不同而不同。
由于模型量化(quantization)過程中涉及到對數(shù)值的近似處理,因此不同的 GPU 在處理這些近似值時可能會有所差異,從而最終會導致 token 的預測概率產(chǎn)生變化。
08 使用多個 GPU 水平擴展 LLMs 時需要注意什么?
這個問題問得非常好,非常感謝!: )
如果只是簡單地增加相同型號的 GPU 數(shù)量(例如,從單個 A10G GPU 擴展到擁有 4 個 A10G GPU 的實例),是否還有必要擔心?
使用多個 GPU 進行推理時,有幾種策略可供選擇:
- 第一種策略是,如果模型可以裝入 GPU 中,可以在每個 GPU 上加載一份模型副本。例如,如果向 pipeline 發(fā)送四條查詢語句(queries),每條查詢語句(queries)可以由不同的 GPU 來處理。這樣,我們將得到與僅使用一個 GPU 時相同的輸出內(nèi)容,但吞吐量會有所提高。
- 第二種策略通常用于因為模型太大一個 GPU 無法裝入的情況,可以采用模型分片策略(sharding),將模型的權(quán)重分布到各個 GPU 上。雖然從理論上講,這種做法可能會因為計算(computation)的分布(distribution)和執(zhí)行(execution)的不同而導致模型響應產(chǎn)生變化,但在實踐測試中,使用模型切片技術(shù)得到的序列(sequences)和概率(probabilities)與單個 GPU 上得到的結(jié)果是一致的。我猜測這是因為 PyTorch 在設(shè)計時考慮到了 deterministic operations(譯者注:那些每次在相同輸入下都能產(chǎn)生相同輸出的操作過程。)。
09 Conclusion
我們已經(jīng)證明了,即便是相同的開發(fā)環(huán)境(environment)、系統(tǒng)配置(settings)和隨機種子(seed),不同的 GPU 也會導致 LLMs 產(chǎn)生不同的結(jié)果。隨著提示詞長度的增長,這種不準確性(inaccuracies)也會隨之增加,因為更長的提示詞需要更多的算力,這會加劇不準確性(inaccuracies)的傳播并促進兩個 GPU 之間的差異。此外,在進行模型量化的情況下,這種效應更加顯著。
我并不是說這種情況一定是災難性的,但這是我們在處理 LLMs 的部署時需要注意的一個因素。
如果我們開發(fā)時使用的 GPU 與生產(chǎn)環(huán)境中使用的 GPU 不同,應該設(shè)置測試實驗確保性能仍然保持在可接受的范圍內(nèi)。如果我們計劃將 LLMs 擴展到擁有不同 GPU 的新實例上,這一點也很重要。
如果你堅持讀到了最后,那我可太高興了,希望你會喜歡這篇文章。如果你喜歡的話,希望你能給我點贊,鼓勵我繼續(xù)寫作,也歡迎在評論區(qū)中分享你的想法。
Anis Zakari
I’m a passionate ML/AI Engineer based in Paris. I am particularly interested in NLP, LLM, Software Engineering and Cloud Engineering subjects
文中鏈接
[1]https://standardscaler.com/2024/03/06/the-non-determinism-of-openai-and-anthropic-models/
[2]https://www.nvidia.com/fr-fr/geforce/turing/
[3]https://www.nvidia.com/fr-fr/data-center/ampere-architecture/
原文鏈接:
https://medium.com/@anis.zakari/changing-the-gpu-is-changing-the-behaviour-of-your-llm-0e6dd8dfaaae


















