你有沒(méi)深入想過(guò),什么造成了GPT-4的輸出很隨機(jī)?
今年,大型語(yǔ)言模型(LLM)成為 AI 領(lǐng)域最受關(guān)注的焦點(diǎn),OpenAI 的 ChatGPT 和 GPT-4 更是爆火出圈。GPT-4 在自然語(yǔ)言理解與生成、邏輯推理、代碼生成等方面性能出色,令人驚艷。
然而,人們逐漸發(fā)現(xiàn) GPT-4 的生成結(jié)果具有較大的不確定性。對(duì)于用戶輸入的問(wèn)題,GPT-4 給出的回答往往是隨機(jī)的。
我們知道,大模型中有一個(gè) temperature 參數(shù),用于控制生成結(jié)果的多樣性和隨機(jī)性。temperature 設(shè)置為 0 意味著貪婪采樣(greedy sampling),模型的生成結(jié)果應(yīng)該是確定的,而 GPT-4 即使在 temperature=0.0 時(shí),生成的結(jié)果依然是隨機(jī)的。
在一場(chǎng)圓桌開(kāi)發(fā)者會(huì)議上,有人曾直接向 OpenAI 的技術(shù)人員詢問(wèn)過(guò)這個(gè)問(wèn)題,得到的回答是這樣的:「老實(shí)說(shuō),我們也很困惑。我們認(rèn)為系統(tǒng)中可能存在一些錯(cuò)誤,或者優(yōu)化的浮點(diǎn)計(jì)算中存在一些不確定性......」
值得注意的是,早在 2021 年就有網(wǎng)友針對(duì) OpenAI Codex 提出過(guò)這個(gè)疑問(wèn)。這意味著這種隨機(jī)性可能有更深層次的原因。
圖源:https://community.openai.com/t/a-question-on-determinism/8185
現(xiàn)在,一位名為 Sherman Chann 的開(kāi)發(fā)者在個(gè)人博客中詳細(xì)分析了這個(gè)問(wèn)題,并表示:「GPT-4 生成結(jié)果的不確定性是由稀疏 MoE 引起的」。
Sherman Chann 博客地址:https://152334h.github.io/blog/non-determinism-in-gpt-4/
Sherman Chann 這篇博客受到了 Google DeepMind 最近一篇關(guān)于 Soft MoE 的論文《From Sparse to Soft Mixtures of Experts》啟發(fā)。
論文地址:https://arxiv.org/pdf/2308.00951.pdf
在 Soft MoE 論文的 2.2 節(jié)中,有這樣一段描述:
在容量限制下,所有稀疏 MoE 都以固定大小的組來(lái)路由 token,并強(qiáng)制(或鼓勵(lì))組內(nèi)平衡。當(dāng)組內(nèi)包含來(lái)自不同序列或輸入的 token 時(shí),這些 token 通常會(huì)相互競(jìng)爭(zhēng)專家緩沖區(qū)中的可用位置。因此,模型在序列級(jí)別不再具有確定性,而僅在批次級(jí)別(batch-level)具有確定性,因?yàn)槟承┹斎胄蛄锌赡軙?huì)影響其他輸入的最終預(yù)測(cè)。
此前,有人稱 GPT-4 是一個(gè)混合專家模型(MoE)。Sherman Chann 基于此做出了一個(gè)假設(shè):
GPT-4 API 用執(zhí)行批推理(batch inference)的后端來(lái)托管。盡管一些隨機(jī)性可能是因?yàn)槠渌蛩?,?API 中的絕大多數(shù)不確定性是由于其稀疏 MoE 架構(gòu)未能強(qiáng)制執(zhí)行每個(gè)序列的確定性。
也就是說(shuō),Sherman Chann 假設(shè):「稀疏 MoE 模型中的批推理是 GPT-4 API 中大多數(shù)不確定性的根本原因」。為了驗(yàn)證這個(gè)假設(shè),Sherman Chann 用 GPT-4 編寫了一個(gè)代碼腳本:
import os
import json
import tqdm
import openai
from time import sleep
from pathlib import Path
chat_models = ["gpt-4", "gpt-3.5-turbo"]
message_history = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Write a unique, surprising, extremely randomized story with highly unpredictable changes of events."}
]
completion_models = ["text-davinci-003", "text-davinci-001", "davinci-instruct-beta", "davinci"]
prompt = "[System: You are a helpful assistant]\n\nUser: Write a unique, surprising, extremely randomized story with highly unpredictable changes of events.\n\nAI:"
results = []
import time
class TimeIt:
def __init__(self, name): self.name = name
def __enter__(self): self.start = time.time()
def __exit__(self, *args): print(f"{self.name} took {time.time() - self.start} seconds")
C = 30 # number of completions to make per model
N = 128 # max_tokens
# Testing chat models
for model in chat_models:
sequences = set()
errors = 0 # although I track errors, at no point were any errors ever emitted
with TimeIt(model):
for _ in range(C):
try:
completion = openai.ChatCompletion.create(
model=model,
messages=message_history,
max_tokens=N,
temperature=0,
logit_bias={"100257": -100.0}, # this doesn't really do anything, because chat models don't do <|endoftext|> much
)
sequences.add(completion.choices[0].message['content'])
sleep(1) # cheaply avoid rate limiting
except Exception as e:
print('something went wrong for', model, e)
errors += 1
print(f"\nModel {model} created {len(sequences)} ({errors=}) unique sequences:")
print(json.dumps(list(sequences)))
results.append((len(sequences), model))
# Testing completion models
for model in completion_models:
sequences = set()
errors = 0
with TimeIt(model):
for _ in range(C):
try:
completion = openai.Completion.create(
model=model,
prompt=prompt,
max_tokens=N,
temperature=0,
logit_bias = {"50256": -100.0}, # prevent EOS
)
sequences.add(completion.choices[0].text)
sleep(1)
except Exception as e:
print('something went wrong for', model, e)
errors += 1
print(f"\nModel {model} created {len(sequences)} ({errors=}) unique sequences:")
print(json.dumps(list(sequences)))
results.append((len(sequences), model))
# Printing table of results
print("\nTable of Results:")
print("Num_Sequences\tModel_Name")
for num_sequences, model_name in results:
print(f"{num_sequences}\t{model_name}")
當(dāng) N=30,max_tokens=128 時(shí),結(jié)果如下表所示:
在 Sherman Chann 注意到 logit_bias 問(wèn)題之前,還得到了如下結(jié)果(max_tokens=256):
實(shí)驗(yàn)結(jié)果表明,GPT-4 的輸出總是不確定的(unique completion 數(shù)值很高,表明對(duì)于相同的輸入,GPT-4 生成的輸出總是不同的),這幾乎可以證實(shí) GPT-4 存在問(wèn)題。并且,所有其他不會(huì)陷入重復(fù)無(wú)用循環(huán)的模型也存在某種程度的不確定性。這似乎說(shuō)明不可靠的 GPU 計(jì)算也會(huì)造成一定程度的隨機(jī)性。
Sherman Chann 表示:「如果不確定性是稀疏 MoE 批推理固有的特征,那么這一事實(shí)對(duì)于任何使用該類模型的研究來(lái)說(shuō)都應(yīng)該是顯而易見(jiàn)的。Google Deepmind 的研究團(tuán)隊(duì)顯然知道這一點(diǎn),并且他們認(rèn)為這個(gè)問(wèn)題很微不足道,以至于只是把它寫成了一句不經(jīng)意的話放在論文中」。
此外,Sherman Chann 還推測(cè) GPT-3.5-Turbo 可能也使用了 MoE。
網(wǎng)友怎么看
這篇博客發(fā)表后,開(kāi)發(fā)者們也開(kāi)始討論 GPT-4 輸出的不確定問(wèn)題。有人認(rèn)為這可能是「多線程并行」造成的:
也有人表示:「雖然計(jì)算是確定的,但是執(zhí)行計(jì)算的多個(gè)處理器之間可能存在時(shí)鐘頻率偏差」:
一位支持 Sherman Chann 的假設(shè)的開(kāi)發(fā)者說(shuō)道:「GPT-3.5-Turbo 可能就是 OpenAI 為 GPT-4 構(gòu)建的小型測(cè)試模型」。
還有開(kāi)發(fā)者分析道:「按照 Soft MoE 論文的說(shuō)法,稀疏 MoE 不僅引入了不確定性,還可能會(huì)使模型的響應(yīng)質(zhì)量取決于有多少并發(fā)請(qǐng)求正在爭(zhēng)奪專家模塊的分配」。
對(duì)此,你怎么看?