人們聽說大模型已經(jīng)有兩年多了,不少人自己測試了對(duì)話。但輿論對(duì)于大模型還是有很多誤解,應(yīng)用時(shí)摸不清特性,一不小心就上當(dāng),更不知道大模型是怎么開發(fā)出來的。 性能頂級(jí)的Deepseek火爆開源之后,意想不到的事發(fā)生了,人們居然很簡單地就把大模型部署用上了! ![]() 一個(gè)朋友,在3000多元的聯(lián)想lecoo酷310 PC機(jī)上,就安裝Deepseek R1成功了。機(jī)器配置不高,裝的是7B(70億)參數(shù)的版本,聊天能力明顯差很多。性能最強(qiáng)的是671B的版本,需要高一些的配置,但PC機(jī)完全可行,國外有人6000美元的機(jī)器上裝成了。 首先要知道,大模型開發(fā)有兩種場景,難度高的是訓(xùn)練,難度低的是推理(inference),人們熟悉的也是推理。訓(xùn)練的成果就是“權(quán)重”,能生成性能從高到低的幾個(gè)版本,權(quán)重文件從大到小。 有了權(quán)重文件,大模型的推理其實(shí)很簡單!即使對(duì)機(jī)器學(xué)習(xí)不太熟悉的人,只要稍有點(diǎn)知識(shí),看了本文,完全可以理解,大模型的推理是怎么做的,真的不難。 其實(shí)大模型的科普文章非常多,但為啥公眾還是不太明白大模型是怎么運(yùn)作的?這是因?yàn)榭傄帷癟ransformer”這個(gè)東西,許多人都聽過,是大模型算法核心。但是要解釋清楚它是啥,需要非常多的概念。我總結(jié)了下,大約需要30個(gè)前置概念,看著看著就迷糊了。但如果不說清楚,后面又沒法說了。 因此,本文放棄這個(gè)路線,不強(qiáng)行去解釋Transformer。只要還原到“矩陣”這個(gè)簡單的東西,就能明白大模型推理的運(yùn)行機(jī)制了。即使人們從來沒聽說過Transformer、不懂它是什么,大模型推理也能明白。 本文從大家都有過的,和大模型對(duì)話的推理使用經(jīng)驗(yàn),以及一點(diǎn)點(diǎn)簡單的程序知識(shí)出發(fā),解釋大模型推理。 一.自回歸生成文本的過程![]() 我們從大模型最直觀的輸入輸出行為開始解釋。用過的人都知道,用戶輸入一段話,大模型就會(huì)經(jīng)過一段時(shí)間的搜索、思考,輸出反饋。有一定經(jīng)驗(yàn)的人知道,可以把“聯(lián)網(wǎng)搜索”點(diǎn)上,信息會(huì)準(zhǔn)確得多;而把“深度思考”也點(diǎn)上,Deepseek會(huì)把思考過程也展示給用戶看,這是它率先引入的新特性。 不少人知道,用戶輸入的提示,叫“prompt”。大模型反饋輸出的文字,是怎么產(chǎn)生的?把這些事說解釋明白,大模型推理就清楚了。確實(shí)有些關(guān)鍵的細(xì)節(jié),雖然簡單,但是人們還真不清楚。 prompt一般是文字序列。如果有圖片、錄像、語音輸入,那就是“多模態(tài)”,為簡單起見先不管。文字的prompt,如何產(chǎn)生輸出序列,很簡單。 ![]() 大模型連續(xù)生成文本的方式是“自回歸”(auto-regressive)。聽上去有點(diǎn)專業(yè),其實(shí)就是重復(fù)調(diào)用,生成的新詞輸出,“自回歸”加到prompt后面。 舉個(gè)例子,上圖的過程中,用戶給的prompt是“Quantum mechanics is a fundamental theory in physics that”。中間的運(yùn)算過程先不管,大模型會(huì)產(chǎn)生一個(gè)“sample token”,如一個(gè)詞“provides”。注意,這個(gè)詞是程序內(nèi)部產(chǎn)生的,可以立刻輸出給客戶,也可以等詞多了一起輸出。 “自回歸”是說,將這個(gè)provides加到prompt后面去,“Quantum mechanics is a fundamental theory in physics that provides”成為新的prompt,再次運(yùn)算產(chǎn)生第二個(gè)新詞。不斷出新詞加到prompt后面,最后就得到了一句完整的話,終止運(yùn)算,最終輸出給用戶: Quantum mechanics is a fundamental theory in physics that provides insights into how matter and energy behave at the atomic scale. 大模型怎么知道要終止運(yùn)算最終輸出了呢?如果運(yùn)算產(chǎn)生了一個(gè)<EOF>(end of sequence)的特殊標(biāo)記,說明可以終止運(yùn)算,就最終輸出了。另外,如果輸出長度到界限了(各種模型容許的最大長度不同,Kimi的特色就是長文本能力),也只有終止了,prompt會(huì)太長沒法處理了。有的大模型,會(huì)有內(nèi)部邏輯判斷是一個(gè)完整的句子和上下文了,直接輸出終止計(jì)算。 從上圖我們還能發(fā)現(xiàn),大模型在運(yùn)算之后,不是只給一個(gè)輸出選擇,而是會(huì)給多種都說得過去的詞。在that后面,還可以接describe、explains、gives等等,都能生成合理的句子。這些選擇,各有大小不同的概率。這個(gè)概率組合叫l(wèi)ogits(原始輸出值),是大模型最直接的輸出結(jié)果。不同選擇后面輸出序列會(huì)不一樣,所以要把新生成的詞加到prompt后面去。 其實(shí)我們想想,如果大模型運(yùn)算之后只會(huì)輸出一個(gè)詞,反而能力差。大模型提供多種輸出選擇的概率,每種都合理、有的更常見,這才是本事。開發(fā)者可以考察概率組合,判斷模型性能。最后的輸出給用戶看,需要確定的結(jié)果。大模型會(huì)面對(duì)許多人,雖然單次輸出是確定的,但這些輸出互相不同,會(huì)有一定統(tǒng)計(jì)規(guī)律。和人類的語言材料庫一樣,詞語分布也是有概率的。 從語言角度來看,大模型最根本的功能就是統(tǒng)計(jì)和輸出概率。賈島琢磨,是“僧推月下門”還是“僧敲月下門”,韓愈說“敲”更好,這是文科思維。大模型是理科思維,會(huì)說“推”的概率15%,“敲”的概率20%,還有“叩、拍、打、撞、觸、啟、扣、撫、擊、砸、碰、踢”都各有概率,都說得通。因?yàn)榭创龁栴}的角度獨(dú)特,大模型能把文科本事學(xué)得非常好,我們要習(xí)慣大模型的統(tǒng)計(jì)概率視角。 計(jì)算概率過程很長,有了概率,最終選一個(gè)詞輸出簡單,用個(gè)函數(shù)選一個(gè)就好了。有時(shí)選概率最大那個(gè)詞,有時(shí)會(huì)加一些隨機(jī)性,是一個(gè)叫“溫度”的參數(shù)控制的。低溫輸出序列穩(wěn)定,高溫輸出序列靈活、變化大。我們讓大模型作詩、寫文,同樣的輸入,輸出都會(huì)不同,就是輸出選擇有一定隨機(jī)性。 ![]() 再來看中間的計(jì)算過程,有兩個(gè)東西要解釋,一個(gè)叫“token”,一個(gè)叫“embedding”。有的文章把token翻譯成“令牌”,很不對(duì)勁,個(gè)人覺得“詞元”更好,但還是直接寫成token更為精準(zhǔn)。它就是將輸入文字分為不同的類別,有時(shí)一個(gè)詞會(huì)分成幾個(gè)token(如不少英文單詞有共同的詞根、后綴)。 要注意,token是跨語言的。很多人誤認(rèn)為有“英文大模型”、“中文大模型”,以為訓(xùn)練素材是分開的,中文素材不如英文好,所以“中國大模型不如美國,原因是中文互聯(lián)網(wǎng)內(nèi)容質(zhì)量差”。這都是誤會(huì),素材是很多語言的都收集,中國開發(fā)團(tuán)隊(duì)也是英文和外文的都收集,可能會(huì)精心準(zhǔn)備更多中文素材,但不會(huì)占主要部分。而且,大模型的輸出是中文、英文、其它外文都會(huì)的,并沒有特別區(qū)分。它是看用戶提示詞用哪種語言,就會(huì)輸出對(duì)應(yīng)的語言,天生就是通萬國語言的。 所以,大模型的token種類是很多的,不止?jié)h字?jǐn)?shù)量或者英文單詞那么多。Deepseek V3的“詞匯表”大小是129280,意思就是有這么多token種類。 要明白,token不是一個(gè)個(gè)字符,也不是一個(gè)個(gè)單詞。如何將一門語言的字符、單詞變換成token,需要深入研究,每個(gè)大模型都要“tokenizer”(分詞算法),把輸入和訓(xùn)練語料轉(zhuǎn)成token。在OpenAI的說明中,1個(gè)token大約為4個(gè)字符或0.75個(gè)單詞。對(duì)于漢語,簡單起見,我們就把token理解為一個(gè)字符,有時(shí)一個(gè)固定詞組就好了。 但是,tokenizer并不是專門為大模型開發(fā)的。之前業(yè)界做機(jī)器翻譯的時(shí)候,就有很深研究。這些研究成果,正好用到大模型上,所以大模型是“大語言模型”。而token也不算生僻的概念,不少人知道大模型面對(duì)的是token世界,不難懂。 但是“embedding”,知道的人就少多了,或者聽過概念,了解也是模糊的。embedding翻譯成“嵌入”,個(gè)人認(rèn)為這是從“數(shù)學(xué)模型”角度解釋大模型的關(guān)鍵,必須了解。 從概念上來說,embedding會(huì)把一個(gè)token,變成一個(gè)“向量”,也就是一維的數(shù)組。但是要注意,在大模型中,這個(gè)數(shù)組非常大!不了解的人,想不到會(huì)這么大。 例如在Deepseek V3中(671B版本),一個(gè)token通過embedding,會(huì)變成一個(gè)7168維的向量!Meta開源的LLaMa 大模型(7B版本)中,token是embedding變成4096維,都不小。一個(gè)token,要轉(zhuǎn)換成好幾千個(gè)浮點(diǎn)數(shù)組成的向量。常見的圖例中,都只會(huì)畫少量格子示意(如上圖畫成8維),有時(shí)造成錯(cuò)覺。 大模型之“大”,首先就是從embedding開始。在程序中,一個(gè)token用一個(gè)整數(shù)代表就行,占空間很小。但是從embedding開始,就進(jìn)入了正式的矩陣處理過程,輸入一下變大很多。 每個(gè)token都對(duì)應(yīng)固定的向量,維度都一樣,如7168維。有專門的embedding算法,詞元嵌入算法。嵌入算法定好以后,就能初始化算出固定的“詞元嵌入矩陣”,供直接查表。Deepseek V3的詞元嵌入矩陣大小是129280 * 7168,每個(gè)類別的token,直接根據(jù)序號(hào),查到對(duì)應(yīng)的7168維的向量。 一個(gè)prompt會(huì)有多個(gè)token,在embedding之后合成一個(gè)矩陣。如8個(gè)token,就會(huì)生成一個(gè)8*7168的矩陣,作為大規(guī)模矩陣計(jì)算的起點(diǎn)。新prompt增加長度,輸入矩陣也會(huì)變大,但7168這個(gè)維度是不變的。 計(jì)算過程,會(huì)經(jīng)過多個(gè)“中間矩陣”(intermediate matrices),一個(gè)個(gè)往下算。最后,就從矩陣變成logits那個(gè)概率分布組成的向量。這就完成了“對(duì)于這個(gè)prompt,下面一個(gè)詞接什么好”的計(jì)算任務(wù)。 這個(gè)過程也不需要太多矩陣知識(shí),就是矩陣乘法和加法。例如,8*7168的矩陣,與7168*7168的“方陣”相乘,結(jié)果還會(huì)是一個(gè)8*7168的矩陣,維度不變。還有矩陣加法,相同大小的矩陣可以相加。 這一節(jié)就粗略理解,主要計(jì)算過程就是embedding出來的輸入矩陣,不斷相乘相加。相乘相加的對(duì)象,從輸入矩陣開始,有中間矩陣,還有固定的參數(shù)矩陣(訓(xùn)練好之后,推理應(yīng)用中不變)。最終目標(biāo),是為了計(jì)算最后那個(gè)概率向量。 如果看到這真理解了,即使往下不看了,也應(yīng)該學(xué)到不少知識(shí)了。矩陣計(jì)算細(xì)節(jié)不了解,也不影響前面學(xué)到的知識(shí),比一般人對(duì)大模型的理解要多了。是不是很簡單? 下面我們?cè)侔丫仃囅嚓P(guān)的大模型操作介紹一下,也不復(fù)雜。這對(duì)應(yīng)了Transformer內(nèi)部的一些操作,如果用正宗的機(jī)器學(xué)習(xí)術(shù)語,會(huì)比較難懂。但我們用矩陣來解釋,就容易理解。 解釋矩陣操作,我們可以參考一點(diǎn)開源大模型的代碼。不是說要讀者去看代碼,而是引用代碼的一些簡單信息,更容易理解矩陣操作的過程。這樣介紹,比解釋Transformer的一堆學(xué)術(shù)名詞要容易。下面我們就來介紹一點(diǎn)開源代碼的簡單信息。 二.簡單的大模型開源代碼我們聽說Deepseek是開源的,這具體是什么意思?訓(xùn)練代碼沒有開源,但是在論文與技術(shù)報(bào)告中介紹了關(guān)鍵的Deepseek V3和R1大模型訓(xùn)練的的一些細(xì)節(jié),業(yè)界人士積極閱讀解釋。開源的是兩個(gè)東西,一個(gè)是權(quán)重,一個(gè)是推理代碼。這兩者是什么關(guān)系?可以理解為:權(quán)重是人類知識(shí)的加密壓縮,推理是解碼檢索知識(shí)的工具。 權(quán)重方面,主要是Deepseek R1的6710億個(gè)參數(shù)的版本,代表了最強(qiáng)性能。還有6個(gè)小一些的,這比較特別。參數(shù)個(gè)數(shù)為15億、70億、140億、320億的,是用6710億參數(shù)那個(gè)R1和阿里開源的Qwen“聯(lián)合培養(yǎng)”出來的。這些參數(shù)數(shù)量是Qwen四個(gè)模型開源時(shí)定下的,Deepseek幫著把里面的系數(shù)改進(jìn)了下,性能強(qiáng)大了不少。參數(shù)個(gè)數(shù)為80億、700億的,是Meta的LLaMa系列兩個(gè)開源的大模型,Deepseek同樣幫著改進(jìn)了系數(shù),提升了性能。 大模型開源,還要把推理相關(guān)的代碼公布出來。有推理代碼、有權(quán)重文件,別人就能用了。大模型推理過程很簡單,從程序代碼行數(shù)就能看出來。Deepseek V3的推理源碼,是用python語言寫的,最大一個(gè)代碼文件model.py才800行!加上別的源文件,一共1500行代碼就差不多了。 需要解釋下,我們測試的是Deepseek R1大模型。它和Deepseek V3是啥關(guān)系?其實(shí),兩個(gè)大模型結(jié)構(gòu)是一樣的,都是6710億個(gè)參數(shù)。V3在2024年12月26日先公布,業(yè)界有不小反響,當(dāng)時(shí)就說了550萬美元訓(xùn)練成功,但由于性能還不如OpenAI最強(qiáng)的o1閉源大模型,沒有出圈。2025年1月20日公布的R1,性能追平o1,又開源、又低價(jià),這才引爆全球輿論。 R1就是從V3改進(jìn)而來,通過幾個(gè)階段的“強(qiáng)化學(xué)習(xí)”,能力變強(qiáng)了,但區(qū)別只是權(quán)重不同。所以,V3的推理代碼直接給R1用就行。關(guān)注工程實(shí)現(xiàn)的人會(huì)更注意看V3的技術(shù)報(bào)告,里面有更詳細(xì)的大模型細(xì)節(jié)。而R1的技術(shù)報(bào)告,主要是解釋開創(chuàng)性的“強(qiáng)化學(xué)習(xí)”技術(shù),學(xué)術(shù)意義更大。工程意義上,V3的細(xì)節(jié)比R1的多得多,算法與數(shù)據(jù)結(jié)構(gòu)細(xì)節(jié)更值得研究。 ![]() Deepseek V3 inference源碼:model.py 我們來看看Deepseek V3推理源碼中的model.py的開頭幾行。例如里面有個(gè)fp8_gemm,就是說Deepseek實(shí)現(xiàn)了fp8的gemm。新聞里提到Deepseek將8比特的浮點(diǎn)數(shù)用于大模型開發(fā),是一大創(chuàng)新,能加速運(yùn)行。fp8就是用8比特表示浮點(diǎn)數(shù)(一般是32比特來表示,或者16比特),gemm是指矩陣乘法,機(jī)器學(xué)習(xí)的許多加速大招都是對(duì)它下手的。 從“import torch”兩個(gè)詞,可以看出Deepseek用了Meta的PyTorch深度學(xué)習(xí)框架。這就是開源的力量,很厲害的程序代碼也不長。美國Meta公司開源了LLaMa大模型,之前還建立了PyTorch(基于Torch機(jī)器學(xué)習(xí)庫)開源社區(qū),這有力促進(jìn)了全球機(jī)器學(xué)習(xí)與大模型研發(fā)的發(fā)展。而Deepseek也開源自己的推理代碼和權(quán)重,大模型性能超過LLaMa,進(jìn)一步壯大了開源社區(qū)的力量。 Deepseek推理代碼很短,只有1500行,還因?yàn)閜ython就是伴隨著機(jī)器學(xué)習(xí)流行起來的,很合適。用C++來寫大模型推理代碼也是可以的,一些讀者更習(xí)慣,但是代碼就要長一些。 ![]() LLama源碼中g(shù)gml庫相關(guān)部分 Meta的LLama大模型有C++工程源碼,也是關(guān)于推理的。核心的llama.cpp有1萬行,里面描述了如何進(jìn)行推理計(jì)算。加上別的源文件,一共3萬多行代碼,底層實(shí)現(xiàn)都寫清楚了。如果對(duì)C語言與C++開發(fā)有一定經(jīng)驗(yàn),會(huì)明白3萬行代碼不算復(fù)雜,代碼結(jié)構(gòu)模塊化封裝好了并不難懂。 LLama源碼中另外還有個(gè)張量(tensor,可簡單理解為向量和矩陣)運(yùn)算庫ggml,要支持各種平臺(tái)和硬件,如cuda、opencl、blas,代碼量要更大。這是C工程的特色,代碼文件較多,python的代碼和庫更緊湊。但C工程的庫函數(shù)弄好了就不用管了,編譯就行。 張量運(yùn)算庫ggml里出現(xiàn)了cuda,這個(gè)就是英偉達(dá)GPU相關(guān)的內(nèi)容??梢赃@樣理解,源碼中的一般邏輯,用CPU去執(zhí)行就行,但是與矩陣計(jì)算相關(guān)的,需要GPU硬件加速。不少新聞?wù)f,訓(xùn)練高水平大模型需要幾千、幾萬個(gè)英偉達(dá)GPU,萬卡陣列,用別家的GPU不好用,因?yàn)樾枰狢UDA環(huán)境。需要注意,這說的是大模型訓(xùn)練,現(xiàn)在還是英偉達(dá)壟斷。 但是,如果是說大模型推理,真的不需要英偉達(dá)GPU,不需要CUDA。從上面ggml張量庫的目錄就能看出,有很多種選擇。代碼都寫好了,不用英偉達(dá)GPU也沒問題,甚至不用GPU用CPU都可以,就是慢點(diǎn)。新聞中說了,AMD、華為昇騰的GPU,還有不少公司的GPU,乃至個(gè)人PC沒有專用GPU的,都成功整合了Deepseek R1。這說明大模型推理的計(jì)算,是相對(duì)簡單的。 ![]() Deepseek V3 671B的Jason格式config配置文件 看代碼,很多東西都非常清楚,有些資料反而說得稀里糊涂。如Deepseek性能最強(qiáng)的671B版本,上圖是配置文件,其中明確寫了,vocab_size是129280。這是說,詞匯表(vocabulary)大小是129280,也就是有這么多類的token。而“dim”是7168,就是指embedding的向量維度(dimension)是7168。 還有一些數(shù)值,一時(shí)不明白不要緊。也不需要把什么參數(shù)都搞懂,把容易懂的解釋下,就能明白大模型的大致結(jié)構(gòu)了。代碼中的一些關(guān)鍵信息,可以讓讀者最直接理解大模型。 我們接著解釋大模型中的矩陣運(yùn)算過程。前面一節(jié)說到embedding生成了輸入矩陣,從這往下說。 三.大模型中的矩陣分層計(jì)算![]() 首先要明白,大模型的矩陣計(jì)算,是分層進(jìn)行的,一個(gè)layer接一個(gè)layer。如果對(duì)神經(jīng)網(wǎng)絡(luò)有點(diǎn)基本常識(shí)不難理解,和深度學(xué)習(xí)里面的“前向推導(dǎo)”計(jì)算是差不多的。如上圖,在大模型中,每個(gè)layer都是Transformer Layer??梢韵炔还苡疫匱ransformer的內(nèi)部結(jié)構(gòu),搞不懂不要緊。就看左邊簡單的layer結(jié)構(gòu),這還是好懂的。 ![]() 為難讀者的Transformer原始結(jié)構(gòu)圖,2017年論文提出 不少大模型科普文章,會(huì)從上面這個(gè)經(jīng)典的Transformer結(jié)構(gòu)圖開始。個(gè)人感覺里面不好懂的概念較多,外行很難抓住重點(diǎn)。例如很多人看了好久還沒明白一個(gè)基本點(diǎn),其實(shí)這只是一層的結(jié)構(gòu),大模型里會(huì)有很多層。而且這個(gè)結(jié)構(gòu)是2017年的經(jīng)典論文《Attention Is All You Need》提出的,那時(shí)還沒有大模型,引入它的目的是機(jī)器翻譯,而不是大模型。所以圖中的結(jié)構(gòu)解的是seq2seq問題,從一個(gè)文字sequence(一國文本)轉(zhuǎn)換到另一個(gè)sequence(另一國文本),先用Encoder(編碼器)計(jì)算輸入sequence的“狀態(tài)”,然后再將“狀態(tài)”輸入到Decoder(解碼器),解碼輸出對(duì)應(yīng)的翻譯文本。筆者之前介紹機(jī)器翻譯的文章《每當(dāng)我解雇一個(gè)語言學(xué)家,語音識(shí)別的性能就會(huì)上升 | 科技袁人》,就解釋過Encoder-Decoder架構(gòu)。 現(xiàn)在流行的GPT大模型,和機(jī)器翻譯是很不相同的,不是Encoder-Decoder架構(gòu)。機(jī)器翻譯是一段文字對(duì)應(yīng)另一段文字,對(duì)應(yīng)關(guān)系較為明確,翻譯不會(huì)差異太大。而大語言模型是根據(jù)prompt生成一段輸出,對(duì)應(yīng)關(guān)系靈活,小段提示能有差異很大的大段輸出。而且有上下文連續(xù)對(duì)話,前面的對(duì)話也有關(guān)。 現(xiàn)在說大模型,一般是指GPT(Generative Pre-trained Transformer),用于文本生成任務(wù)。它的架構(gòu)應(yīng)該算是“純Decoder”,也就是拿embedding出來的矩陣當(dāng)輸入,就能解碼出一個(gè)token輸出,那些連接的layer全都算是一個(gè)Decoder。 如果只看推理應(yīng)用,從大的架構(gòu)上看,GPT大模型其實(shí)比機(jī)器翻譯簡單。個(gè)人認(rèn)為,很多人從機(jī)器翻譯的Transformer學(xué)起,前面還要學(xué)習(xí)RNN(循環(huán)神經(jīng)網(wǎng)絡(luò),Recurrent Neural Network)引入的“注意力機(jī)制”,這反而造成了學(xué)習(xí)大模型的困難。不如直接學(xué)簡單的GPT推理架構(gòu),不懂Transformer,不懂Attention,不懂“自注意力”Self-Attention,也能根據(jù)矩陣操作看懂計(jì)算過程。 ![]() 在前面的Deepseek V3的配置文件中(6710億參數(shù)版本),n_layers是61,就是說有61個(gè)Transformer Layer。而LLaMa(70億參數(shù)版本)的layer數(shù)量是32,參數(shù)少的模型,向量維度小一些,層數(shù)也會(huì)少。每個(gè)Layer的輸出,就是后一個(gè)Layer的輸入,維度要保持一致,和一開始embedding形成的矩陣一樣大小。最后一個(gè)layer的輸出,會(huì)特別變換成為logits概率向量,就對(duì)應(yīng)圖中的“Prediction Head”,再選擇一個(gè)token作為一次生成的輸出。 要注意,每個(gè)layer的“結(jié)構(gòu)”都是一樣的,所以代碼里就是循環(huán)。但是,每個(gè)layer都有自己固定的參數(shù)矩陣(訓(xùn)練出來的),這是不一樣的。大模型的威力,就在這些參數(shù)矩陣中,但是推理代碼里看不出,直接從權(quán)重文件中讀取。 下面介紹layer內(nèi)部的計(jì)算過程。如果光介紹計(jì)算過程,相對(duì)簡單。論文和科普文章會(huì)抽象描述Transformer架構(gòu)中的概念,有算法意義,但比較復(fù)雜,可以先不管。 ![]() 上圖就是從輸入的矩陣,經(jīng)過幾步計(jì)算,形成輸出矩陣的過程。上半部分是幾個(gè)矩陣計(jì)算步驟,只有三四種概念,不難。下半部分是說,矩陣計(jì)算需要的“參數(shù)”,是訓(xùn)練好放那的,不變的,幾套矩陣參數(shù)分別參與某個(gè)矩陣計(jì)算步驟。再次指出,每個(gè)layer都有自己的參數(shù)矩陣。為了簡單起見,上圖以LLaMa的layer為例。DeepSeek對(duì)Transformer進(jìn)行了底層創(chuàng)新,細(xì)節(jié)有些不一樣,但大體一致。 ![]() 我們先來看前半部分。一層的輸入矩陣進(jìn)來了,就是“Input”,它會(huì)做一個(gè)“Norm”操作,然后再來個(gè)“Self-Attention”操作,然后再和Input矩陣Add相加。矩陣相加很容易理解,需要解釋的是Norm和Self-Attention這兩個(gè)矩陣操作。這圖是LLaMa 7B的,圖中n_embd等于4096。需要指出,這個(gè)維度數(shù)值在大模型中特別重要,有時(shí)它被稱為“hidden size”,相關(guān)矩陣或者向量的維度都是它。 Norm操作,圖里對(duì)應(yīng)LLaMa中的RMSNorm(根均方歸一化,Root Mean Square Normalization)。數(shù)學(xué)意義很簡單,就是對(duì)一個(gè)4096維的向量,算出均方根值(所有數(shù)值的平方和除以4096,然后開根號(hào));再把每個(gè)數(shù)值除以這個(gè)均方根值,這叫做“歸一化”。最后一個(gè)特別的處理是,對(duì)每一個(gè)維度數(shù)值,都乘以一個(gè)訓(xùn)練而來的“縮放因子”,一共4096個(gè)縮放因子,組成“norm weights”(歸一化權(quán)重)作為固定的參數(shù)。 從這個(gè)操作可以看出,它是在對(duì)Input矩陣中的元素進(jìn)行計(jì)算,還要和固定的參數(shù)向量相乘。這是可以并行加速的,用GPU來做快得多,所有矩陣操作都是如此。 ![]() 而Self-Attention(自注意力)操作,是大模型最核心的數(shù)學(xué)計(jì)算。意義可以說得比天還大,就是建立起一個(gè)prompt中所有token與token之間的復(fù)雜聯(lián)系,數(shù)值大聯(lián)系就大。它關(guān)心的是輸入內(nèi)部的聯(lián)系,就好像是人的自省,所以叫做“自注意力”。 矩陣操作上并不復(fù)雜,就是有四個(gè)訓(xùn)練好的大小一樣的方陣W_k、W_q、W_v和W_o(都是4096*4096),與上步Norm輸出的矩陣(大小是n_tokens*4096,n_tokens是prompt生成的token數(shù)量)進(jìn)行相乘運(yùn)算。 ![]() 一個(gè)4096維的向量,和4096*4096大小的方陣相乘,會(huì)得到一個(gè)4096維的向量。而輸入矩陣有n_tokens個(gè)向量,將它和W_k、W_q、W_v相乘后,我們能得到三個(gè)n_tokens * 4096的矩陣,分別叫K、Q、V。這三個(gè)矩陣,在科普中叫作“鍵”、“查詢”、“值”矩陣。 然后,再將Q和K的“轉(zhuǎn)置矩陣”相乘。也就是n_tokens * 4096的矩陣Q,乘以4096 * n_tokens的矩陣K’,得到一個(gè)n_tokens * n_tokens的方陣,叫它KQ方陣。這我們可以介紹下直覺意義了,這等于是,將prompt中的每個(gè)token,和所有別的token,都用一個(gè)數(shù)值建立聯(lián)系。prompt中兩個(gè)詞聯(lián)系緊,對(duì)應(yīng)的數(shù)值就高,這就是所謂的“注意力”(Attention)。 ![]() 在常見的解釋“注意力機(jī)制”的科普文章中,這個(gè)句子“The animal didn’t cross the street because it was too tired.”常常被引用。對(duì)“it”對(duì)應(yīng)的token,和別的所有token建立聯(lián)結(jié)。it實(shí)際是指代the animal,聯(lián)結(jié)就應(yīng)該深一些(在方陣中數(shù)值高)。而it理論上可能是指street,但實(shí)際不是,聯(lián)結(jié)就應(yīng)該淺一些(方陣中數(shù)值低)。 而所謂Self-Attention(自注意力),就是一個(gè)prompt中的token序列對(duì)自己內(nèi)部的token的注意力。在RNN的注意力機(jī)制中,不是self-Attention,不是“自”的。這與機(jī)器學(xué)習(xí)發(fā)展歷史有關(guān),弄懂需要一些背景知識(shí),有興趣的讀者可自行搜索。大模型用“自注意力”就行,不了解怎么從Attention發(fā)展出來的,不影響理解。 ![]() 接著往下處理。Q和K的轉(zhuǎn)置矩陣相乘,得到KQ矩陣(還要除以64,也就是維度4096的根號(hào))。KQ矩陣會(huì)來個(gè)掩碼操作,把上半部分?jǐn)?shù)值移除設(shè)為無效,得到KQ_masked矩陣。 在LLaMa代碼中,掩碼操作是有一個(gè)掩碼矩陣,右上角是負(fù)無窮大,別的地方是0。KQ矩陣和它相加得到KQ_masked。這樣右上角數(shù)值變成負(fù)無窮大,別的地方注意力分?jǐn)?shù)不受影響。負(fù)無窮大在變換為概率時(shí),對(duì)應(yīng)0概率。 進(jìn)行這個(gè)掩碼操作的具體原因是,大模型要“用前面的輸入預(yù)測后面那一個(gè)詞”,而非“預(yù)測后面跟著的一堆詞”。 ![]() Self-Attention最后一步,將KQ_masked矩陣(n_tokens * n_tokens),與V矩陣(n_tokens*4096)相乘,得到最終的KQV矩陣(n_tokens * 4096的)。它就是Self-Attention這步的輸出。 ![]() 這個(gè)KQV矩陣,和Input輸入矩陣是一樣大的。所以,可執(zhí)行一個(gè)Add操作,矩陣相加。別看這么簡單的相加,學(xué)名叫“殘差連接”(Residual Connection),對(duì)于深度學(xué)習(xí)訓(xùn)練很重要。這些操作精心設(shè)計(jì),就是要弄得輸入和輸出矩陣維度一樣,很大原因也是為了干“殘差”連接。 在訓(xùn)練神經(jīng)網(wǎng)絡(luò)的過程中,為了知道每一個(gè)參數(shù)下一步向什么方向改變、改變多少,需要計(jì)算“梯度”,即某些導(dǎo)數(shù)。但這些梯度的數(shù)值容易失控,網(wǎng)絡(luò)層數(shù)一多,梯度就過小逐漸消失,或者過大爆炸。殘差連接引入一個(gè)直接的路徑,將輸入直接往后傳遠(yuǎn)一些,避免了梯度在傳播過程中的消失或者爆炸。簡而言之,就是加強(qiáng)了訓(xùn)練的穩(wěn)定性。 前面說了計(jì)算自注意力需要四個(gè)方陣,到這里為止已經(jīng)解釋了三個(gè),W_k、W_q、W_v。還剩下一個(gè)叫做W_o,這個(gè)和“多頭注意力機(jī)制”(Multi-Head Attention)有關(guān)。為簡單起見,我們前面說的計(jì)算過程,都是“單頭注意力”(Single-Head Attention),等于用一個(gè)視角看prompt內(nèi)部的自注意力。高水平的大模型,必須有其它視角(注意力頭)來觀察,注意力的值會(huì)發(fā)生變化。如有的視角重視邏輯關(guān)聯(lián),有的重視語法關(guān)聯(lián),有的詞本身就是多種含義。W_o是幫助KQV矩陣進(jìn)行線性變換,映射回原始的特征空間。先不要管它,多頭就是在單頭的基礎(chǔ)上,建多份結(jié)構(gòu)差不多的東西。 LLaMa 7B有32個(gè)“注意力頭”,等于這些結(jié)構(gòu)要抄32份。而Deepseek V3的多頭注意力機(jī)制,有128個(gè)“注意力頭”。 ![]() ![]() 下面,我們?cè)賮砜磍ayer內(nèi)部的計(jì)算過程的后半部分,這就簡單多了。先是一個(gè)和前面一樣的Norm操作,對(duì)前面KQV與Input加出來的矩陣,來個(gè)歸一化。尾巴上又是一個(gè)一樣的Add操作,還是“殘差連接”。只要理解那個(gè)Feed-Forward(前饋神經(jīng)網(wǎng)絡(luò))就行了。 ![]() Feed-Forward被稱為FF網(wǎng)絡(luò),有一個(gè)參數(shù)n_ff。如果對(duì)于深度學(xué)習(xí)中常見的,一個(gè)隱藏層(hidden layer)的“全連接”神經(jīng)網(wǎng)絡(luò)有點(diǎn)了解,會(huì)發(fā)現(xiàn)就是一樣的東西。FF網(wǎng)絡(luò)就是有一個(gè)維度為n_ff的隱藏層。在Deepseek V3的配置文件中,有個(gè)inter_dim參數(shù)是18432,就對(duì)應(yīng)n_ff。在LLaMa 7B大模型中,n_ff數(shù)值是11008。這都是說FF網(wǎng)絡(luò)中的隱藏層維度。 而FF網(wǎng)絡(luò)的Input layer是n_tokens*4096的矩陣。對(duì)于每個(gè)4096維的向量(一共n_tokens個(gè)),都和全連接上的系數(shù)矩陣相乘,在隱藏層會(huì)得到一個(gè)n_tokens*11008的矩陣。用矩陣語言來說,是一個(gè)n_tokens*4096的輸入矩陣,和4096*11008的矩陣乘(就是前圖中的W_1),得到n_tokens*11008的中間矩陣。然后再用它和11008*4096的矩陣乘(就是前圖中的W_2),得到n_tokens*4096的輸出矩陣,又和輸入矩陣維度一樣了。 在深度學(xué)習(xí)和大模型的FF網(wǎng)絡(luò)計(jì)算細(xì)節(jié)中,向量與矩陣乘了之后,還得對(duì)每個(gè)元素再加上一個(gè)bias數(shù)值,再用ReLU(一個(gè)函數(shù),當(dāng)x < 0時(shí)取0,當(dāng)x ≥ 0時(shí)等于x)等“激活函數(shù)”生成最終的值。這就是一點(diǎn)附加小處理,沒矩陣乘法那么壯觀。 前圖的FF網(wǎng)絡(luò)還有個(gè)W_3,那也是為了多頭注意力機(jī)制引入的。主要還是W_1和W_2,進(jìn)行了“先把4096的輸入向量維度升到11008,又降回4096”的操作。 到這,Layer前半部分和后半部分的矩陣運(yùn)算都介紹了。我們基本解釋了大模型Layer內(nèi)部矩陣運(yùn)算的過程。 幾十層的layer結(jié)構(gòu)中,KQV矩陣不斷被計(jì)算出來,又傳輸?shù)紽F網(wǎng)絡(luò),再到下一個(gè)layer,中間隔著一些Norm和Add操作。推理就是這么簡單,矩陣概念上并不復(fù)雜。 ![]() 還差最后一個(gè)環(huán)節(jié)要介紹。在最后一個(gè)Transformer Layer輸出后,要計(jì)算logits(概率向量)。最后一層輸出是n_tokens*4096的矩陣,和embedding形成的輸入矩陣維度一樣。最后一個(gè)矩陣操作是,將它乘以一個(gè)固定的output矩陣(4096*32000的),得到一個(gè)n_tokens*32000的矩陣,32000是LLaMa 7B的詞匯表大小。 雖然最終得到了一個(gè)大矩陣,但我們只關(guān)心它最后一行的那個(gè)32000維的向量。它就代表最終需要的logits概率向量,說明下一個(gè)token可以是什么。所以我們知道,logits向量是非常細(xì)的,詞表中的每個(gè)token都可能輸出,只是絕大多數(shù)概率為0或者極小。神奇的是,概率較大的那些token,還真就能接上prompt形成合理句子。 至此,生成一個(gè)token的計(jì)算過程描述完畢,基本全是矩陣操作。再結(jié)合第一節(jié)的“自回歸文本生成”方式,我們能大致明白,大模型推理時(shí),是如何一個(gè)個(gè)詞不斷跳出來的。 為了讓大模型的推理過程好懂,筆者對(duì)以上的過程還是進(jìn)行了一些簡化。例如,雖然過程中我們說的都是矩陣運(yùn)算,但是在實(shí)際代碼中是張量(tensor)運(yùn)算。張量可以是向量,也可以是矩陣,還可以是多個(gè)矩陣,相當(dāng)于在矩陣的二維之外,再多出一個(gè)或更多的維度。因?yàn)閷?shí)踐中,有“多頭注意力機(jī)制”,我們說的一個(gè)矩陣運(yùn)算,實(shí)際對(duì)應(yīng)“一套矩陣”。在訓(xùn)練以及推理的優(yōu)化中,還會(huì)有一個(gè)批次的輸入,而非一個(gè)prompt。但理解了矩陣運(yùn)算,再去理解張量運(yùn)算也不難,就是多了需要加速的維度。 而我們描述的大模型推理,是最基本的結(jié)構(gòu),并非對(duì)應(yīng)Deepseek V3改良后的結(jié)構(gòu)。但有了最基本的理解,再去看V3的技術(shù)報(bào)告,學(xué)習(xí)MoE(混合專家模型,Mixture of Experts)、MLA(多頭潛在注意力機(jī)制,Multi-Head Latent Attention)這些復(fù)雜概念,都會(huì)變得容易一些。 我們還可以注意到,大模型推理過程有非常多的優(yōu)化空間。prompt不斷更新,但和前一次推理的prompt非常相似,極多的矩陣運(yùn)算其實(shí)是重復(fù)的。這些優(yōu)化就需要對(duì)底層代碼實(shí)現(xiàn)深入討論,對(duì)于一般讀者過于復(fù)雜了。 本文希望讀者大略明白大模型的推理過程,理解一些關(guān)鍵名詞,腦海中建立矩陣與向量分層不斷計(jì)算的圖景,理解大模型輸出token概率的特性。這樣,就會(huì)對(duì)神秘的大模型祛魅,不會(huì)被嚇住。 如果有志于了解深度學(xué)習(xí)、大模型研發(fā)相關(guān)的技術(shù)名詞,那確實(shí)有非常多細(xì)節(jié),需要下功夫仔細(xì)學(xué)習(xí)。但數(shù)學(xué)水平過得去的讀者,只要肯從最基本的數(shù)學(xué)概念建立起理解,明白大模型研發(fā)在干什么,并沒有那么難。 大模型訓(xùn)練比推理要復(fù)雜得多,但相比推理,主要的計(jì)算過程和數(shù)據(jù)結(jié)構(gòu),并沒有復(fù)雜太多。只是訓(xùn)練過程有很多步,有的訓(xùn)練這個(gè)性能,有的訓(xùn)練那個(gè)性能,要有“pipeline”(管線)來組織訓(xùn)練過程。由于訓(xùn)練需要的算力比推理高得多,還要優(yōu)化高效利用英偉達(dá)GPU卡,別的卡還不好用。所以,學(xué)習(xí)難度要高得多。但基本操作是類似的,只要不被名詞嚇住,還原到向量和矩陣運(yùn)算上去,都是可以理解的。 四.聯(lián)網(wǎng)搜索與深度思考![]() 最后一節(jié),我們把Deepseek的“聯(lián)網(wǎng)搜索”和“深度思考”功能解釋下。有些別的大模型也有了類似功能,高水平的都必須有。 不聯(lián)網(wǎng)、不深度思考,根據(jù)用戶prompt大模型給出反饋的過程,前面解釋了。這種情況下,它只能用內(nèi)部固定的權(quán)重來回答問題,只有訓(xùn)練完成時(shí)的信息。2024年上半年之前的事Deepseek R1知道,之后的事不知道了。而且知道的事也不那么詳細(xì),即使訓(xùn)練素材中有,也通過訓(xùn)練“壓縮”進(jìn)權(quán)重里了。 大模型輸出最看重的是語言形式“像模像樣”,人們乍一看,還以為它真知道,其實(shí)很多輸出的信息都是胡編的,矩陣算出來token是啥就輸出啥。解數(shù)學(xué)題也是,形式上一步步挺像回事,仔細(xì)一看推理邏輯是蒙的。這就是著名的“幻覺”問題,其實(shí)非常嚴(yán)重,很多人被大模型蒙了還不知道。 一個(gè)緩解問題的辦法,是用“聯(lián)網(wǎng)搜索”,得到更多信息幫助,減少幻覺。有時(shí)大模型會(huì)自行判斷,需要聯(lián)網(wǎng)搜索獲得更多信息。應(yīng)用“聯(lián)網(wǎng)搜索”的過程并不簡單。 大模型需要聯(lián)網(wǎng)搜索時(shí),會(huì)通過內(nèi)置的工具調(diào)用,根據(jù)用戶輸入的prompt,生成搜索參數(shù),將參數(shù)發(fā)送給指定的搜索引擎(或數(shù)據(jù)源)。搜索引擎返回相關(guān)的搜索結(jié)果,可能包括網(wǎng)頁內(nèi)容、新聞?wù)?shù)據(jù)等等。 這些搜索結(jié)果會(huì)作為額外的上下文信息,供大模型處理。大模型不是簡單地將其與用戶輸入的prompt拼接,而是動(dòng)態(tài)地將搜索結(jié)果整合到知識(shí)體系中,結(jié)合prompt生成最終的輸出。模型有內(nèi)部邏輯和注意力機(jī)制,對(duì)用戶輸入和搜索結(jié)果進(jìn)行綜合分析和理解,生成更準(zhǔn)確、更全面的回答。為了提高效率和減少計(jì)算開銷,還需要對(duì)搜索結(jié)果進(jìn)行篩選和壓縮,如只提取與用戶問題最相關(guān)的部分,或者對(duì)搜索結(jié)果進(jìn)行總結(jié)和提煉。 大模型肯定需要對(duì)搜索結(jié)果進(jìn)行處理,因?yàn)楹芏嗨阉鹘Y(jié)果本身就挺復(fù)雜,大模型得去“理解”它。就如有些用戶對(duì)大模型應(yīng)用時(shí),會(huì)先輸入一個(gè)pdf文件(如論文),大模型先會(huì)“閱讀理解”里面的大段信息,內(nèi)部狀態(tài)更新,準(zhǔn)備好之后,就能與用戶連續(xù)對(duì)話聊這個(gè)文件中的信息了。這個(gè)大模型能力是需要開發(fā)的。 因此,大模型的“聯(lián)網(wǎng)搜索”,是智能、動(dòng)態(tài)的功能,會(huì)耗費(fèi)更多算力。有時(shí)用戶較多就沒法支持了,就如Deepseek爆火之后,沒想到需求這么多,有時(shí)不讓用聯(lián)網(wǎng)搜索了。 “深度思考”的學(xué)術(shù)意義更大,更值得向讀者介紹。 “深度思考”在算法意義上,是目前大模型開發(fā)的最前沿技術(shù)。DeepSeek就是率先向用戶展示了深度思考的中間結(jié)果,而且很像人在自我思考,在國際上引發(fā)轟動(dòng)了。深度思考是OpenAI先引入的,但在其領(lǐng)先的o1模型中,中間思考沒輸出,技術(shù)細(xì)節(jié)也按慣例神秘化不說清楚,夸大實(shí)力。 Deepseek向全球公布了“強(qiáng)化學(xué)習(xí)”訓(xùn)練深度思考的完整機(jī)制,讓業(yè)界驚嘆,這是繼“涌現(xiàn)”(人工智能大模型神奇的“涌現(xiàn)”到底是什么?| 陳經(jīng))之后最重要的大模型研發(fā)成果。機(jī)器自言自語思考越來越厲害,居然是可以直接“強(qiáng)化學(xué)習(xí)”,不要人類中間提示,只靠最終答案訓(xùn)練出來。 一般認(rèn)為,需要人為準(zhǔn)備很多COT(思維鏈,Chain of Thought,類似人類做數(shù)學(xué)題生成的中間步驟)素材,進(jìn)行SFT(有監(jiān)督微調(diào),Supervised Fine-Tuning),象老師教學(xué)生一步步解題那樣,很麻煩地教會(huì)大模型深度思考、深入推理。因?yàn)樘闊?,教得不太成功。以前的大模型不是沒探索過“思維鏈”,但成果不突出。甚至也試過類似DeepSeek的“自己看題目和答案沒老師”強(qiáng)化學(xué)習(xí)的辦法,但訓(xùn)練不收斂,失敗了。所以業(yè)界才認(rèn)為,看來是需要SFT才能學(xué)會(huì)思維鏈。 ![]() 而Deepseek讓基礎(chǔ)能力不錯(cuò)的V3(就是本文介紹的版本),面對(duì)海量有答案的問題(準(zhǔn)備答案容易,準(zhǔn)備詳細(xì)邏輯過程很麻煩),自己“強(qiáng)化學(xué)習(xí)”摸索,不要人工監(jiān)督干預(yù)。思考其實(shí)也是不斷生成token(就是本文介紹的推理過程),但是在輸出中明確用<think>和</think>包起來。V3自己不斷思考,生成COT。有些COT是無效的,但有些與最終答案是相關(guān)的,就據(jù)此修改自己的系數(shù),學(xué)習(xí)逐漸有進(jìn)步。 隨著訓(xùn)練進(jìn)行,V3生成的COT越來越長,邏輯水平越來越高。甚至有“頓悟時(shí)刻”(Aha moment)發(fā)生,大模型明顯邏輯能力躍升,對(duì)標(biāo)OpenAI發(fā)現(xiàn)的大模型能力“涌現(xiàn)”。最后訓(xùn)練成功收斂,V3進(jìn)化為邏輯能力明顯強(qiáng)得多的R1-Zero。 研究者總結(jié),這是因?yàn)閂3的基礎(chǔ)能力不錯(cuò),像聰明學(xué)生一樣“自學(xué)成材”了?;A(chǔ)能力不夠的硬來,那自學(xué)的結(jié)果就會(huì)是悲劇。所以,V3的精細(xì)開發(fā)可能起了更重要的作用,并非想到一個(gè)簡單的好主意就能成功,別人并不是沒想到過。 R1-Zero的邏輯能力強(qiáng),但只會(huì)在<think>和</think>中間展示能力,不太會(huì)和人溝通,自言自語不太好懂,甚至?xí)鄧Z言混著來。OpenAI被DeepSeek逼得著急發(fā)布了o3-mini展示能力,也公開了思維過程,但就被人發(fā)現(xiàn)有時(shí)居然用中文思考,引發(fā)懷疑。從本文介紹的推理原理看,應(yīng)該是token中包括了英文和中文等多種文字,計(jì)算結(jié)果輸出中文對(duì)應(yīng)的token了。 DeepSeek就再用許多訓(xùn)練手段,如給COT輸出打分,消除語言混亂,提高COT輸出的可讀性。這樣就開發(fā)出了大家熟悉的R1,邏輯能力非常強(qiáng)大,輸出對(duì)用戶也友好。 我們?cè)趹?yīng)用時(shí)選“深度思考R1”,會(huì)先有COT思考中間輸出,類似“聯(lián)網(wǎng)搜索”一樣,也結(jié)合進(jìn)大模型知識(shí)體系里,一起給出更有邏輯性的最終輸出。用戶都會(huì)發(fā)現(xiàn),大模型能力明顯比不深度思考要強(qiáng)得多。 Deepseek還有許多模型結(jié)構(gòu)創(chuàng)新、深度優(yōu)化,是與大模型訓(xùn)練相關(guān)的。本文介紹的推理過程,能夠幫助讀者理解相關(guān)細(xì)節(jié)。 ![]() |
|