第一名由 Numina 和 Hugging Face 的大佬們合作拿下,解決了private test set 中的 29/50 個問題,最終喜提美金 $131,072 而歸!
第二名和第三名分別解出 22 道和 21 道題目,所以第一名解出 29 題可以說是大幅度領先其他參賽者的~
我們今天就一起來欣賞一下第一名的作法吧!
第一名的解法大致分成三個部分:
DeepSeekMath-Base 7B
微調的訓練方法,使其能作為「推理代理」(Reasoning Agent) 結合自然語言與 Python REPL(一個交互式的 Python 解釋器環境) 解決數學問題。昨天我們做 "Zero-shot MMOS-DeepSeekMath-7B with Self-Consistency" 的實驗時,發現有時候 LLM 沒有辦法順利把問題成「可執行的代碼」,例如有時候轉出來的 code 我們一執行就會跳出 Syntax Error
,這時候就沒辦法 run 這個壞掉的程式,只能依靠 LLM 的推論然後我們擷取它回覆末尾的答案當作這題的輸出。
但不知道大家有沒有這樣的經驗:有時候我們讓 GPT-4o 幫忙寫一段程式,執行後發現有問題,把 error message 丟回去叫它修改一下,不要太複雜並且給予充足上下文資訊的話,通常兩三回 GPT-4o 就可以修復問題給出可執行的 code。
那我們是不是也可以應用這套思路呢? 不要 DeepSeekMath-Base 7B
給出壞掉的 code 我們就 return -1 跳出 function,我們可以把錯誤訊息回傳給 LLM 多給他幾次機會修正,就有機會得到可以執行的 program ,以及程式跑出來的精確答案。
他們的訓練流程如上圖分成兩個部分:
DeepSeekMath-Base 7B
在這個擴增版的 chain-of-thoughts 數學問題繼續 fine-tuned。按照上面的流程,他們將 MuMath 的題目拿去問 GPT-4 ,並特別收集 GPT-4 給出錯誤代碼,然後人工反饋錯誤訊息給 GPT-4,GPT-4 再根據這些信息給出修正版本的代碼。
他們特別收集這種情況過程中的對話到 MuMath-Code 的資料集中,使得第二階段的模型可以透過這些訓練資料,學會根據編譯器的錯誤訊息來回修正代碼,在和 python interpretor 的多次交互中,達到 self-improvement 的目的。
下面是他們 NuminaMath 使用階段一和階段一二全流程訓練後的模型,在 MATH 這個 banchmark 的 performance 比較。
看起來只有階段一的訓練還是不太夠,結合階段一和階段二才突然拉開與其他 Baseline 的差距。所以重點還是在提升模型 code debugging 能力後,之前試一次失敗就掰掰的題目現在有更多機會從錯誤中學習。
不過他們的模型,全部都是「全參數訓練」,沒有用 quantization 也沒有用 LORA,總共在八張 H100 GPU 訓練大約十小時。
哎,這對一般參賽者來說真的還滿難有這樣的硬體條件去 reproduce 他們的結果,或是採用類似的策略 QQ
不過說到這裡,不知道大家會不會有個疑惑:
🤔 到底什麼時候要用 LoRA/QLoRA fine-tuned,什麼時候要用 FFT(全參數微調)呢?兩者需要的算力相差甚巨,但在不同規模的領域資料上微調,performance實際上又會有多大的差距呢?
其實我也不知道,希望之後有時間可以去 survey 看看~
接下來,為了增加模型回覆的穩定性,他們在 Inference 的時候結合 Self-Consistency 和 TIR 的方式來 prompt 模型。
其實講簡單一點,就是同一道問題會讓模型多 inference 幾次,然後每次 inference 都會讓模型寫 code 執行他自己寫的 code,如果 code compile 不通過或是執行中遇到問題,就反饋 error message 給模型叫模型重新改一版 code,重複這個流程直到模型產生可正確執行的程式碼或是達到最大嘗試次數。
假設每道問題都會 inferencen n 次,這 n 次中都會反覆提出code、執行 code、修改 code,最後得到執行結果也就是該次 inference 的答案,我們再從這 n 個答案做 majority vote 就可以了!
這個模型本身在 stage2 訓練的時候,就已經很習慣做這些事了(反覆提出可行的代碼、發現錯誤、重新修正再執行),所以 inference 的時候結合 self-consistency 和 TIR ,還是可以 align 到模型訓練時候學到的東西。
不知道你看到這邊會不會覺得...
好像...還滿直覺的呦!
確實有不少參賽者都發現像是昨天 zero-shot + Sympy 常常模型寫的程式有問題,那我們就跟他說問題在哪裡叫他改一改應該也會有一樣的效果吧!
但問題就是,多數參賽者使用的 7B 模型沒有經過前面 Stage 2 的訓練,往往沒辦法根據 error 做出適當的修正。
所以前面 Stage2 的訓練在這樣的思路下,還是有其必要性在~
看這麼多 Kaggle 賽題的解法,我會覺得對每個開發團隊來說,最重要的事情就是----
📌 "Build a reliable local validation strategy!"
昨天有提到由於模型回覆的不穩定性的關係,同樣的代碼繳交到 LB 上,分差可能會來到 4 分以上。因此第一名的團隊小心地使用四個內部 validation set 來評估模型在不同難度數學問題上的表現,避免 overfit 在 LB score 上,並從中挑選在這些 validation set 都表現得非常穩定的模型來提交。
AMC:他們選擇了 AMC12 競賽中 2022 和 2023 年的所有題目,並篩選出可以轉換為整數輸出的問題,最終得到 83 個題目。
這個驗證集的設計是為了模擬 Kaggle 上的 private testset,結果顯示模型可以解出約 60-65% 的問題。為了衡量模型表現的變異性,他們每次使用 5-10 個不同的隨機種子進行評估,通常變異範圍在 1-3% 之間。
AIME:他們選擇了 AIME 競賽中 22、23 和 24 年的所有題目,用來測量模型在解決困難問題時的表現,並觀察模型的常見失敗模式。與 AMC 驗證集一樣,他們使用 5-10 個隨機種子來測量變異。
MATH 第4和第5級:他們擔心中等/困難的驗證集樣本過小,無法提供可靠的信號,因此從 MATH 測試集中篩選出有整數解的第4和第5級問題,每個級別大約有 750 個問題,並對每個模型使用單一隨機種子進行評估。
通過這四個驗證集,他們能夠在不同的訓練階段中選擇最具潛力的模型,並進一步縮小 Hyper Parameter的選擇範圍。他們發現,將小而具有代表性的驗證集與較大的驗證集結合使用,在這種競賽中特別有效,因為每次提交都會受到取樣隨機性的影響,所以觀察模型在這些不同難度的問題中是否還能保持一定的穩定性,是很重要的評估項目。
非常可惜他們的 demo 網址現在好像壞掉了沒辦法玩,我就貼一些之前別人玩過的截圖讓大家體驗看看吧~
我們問一道用來欺騙AI的入門題:一斤棉花和一斤鐵,誰比較重?
雖然這道題根本不用算任何東西就是考個常識,但是它真的嚴格按照分解步驟、列式子、寫代碼,最後再分析代碼執行結果得出結論:一樣重。
硬寫了一個判斷式出來滿足人類 XDD
第二題則是一道國中奧數訓練題。
甲乙二人從AB兩地出發,相向而行,在距離B地6公里處相遇,相遇後兩人又繼續按原方向、原速度前進,當他們分別到達B地,A地後,立刻返回,又在距A地4公里處相遇,求AB兩地相距多少公里?
哇,這次模型沒能列成正確的算式,因為第二次甲,乙走的路程分別為D+2,D-2而非D+4,D-4,因而正確答案應該是14而非模型回答的16。
(以上題目和截圖來自這裡)
第一名的解法介紹就到這邊了~
雖然第一名的作法在 LB 上取得很高的成績,但實際使用下來感覺還是很多簡單數學問題解不出來,不過也可能因為這邊是用中文問的(?,也許用英文問結果會不一樣。
個人感覺他們最大的亮點在前期的二階段訓練中產出的 MuMath
和 MuMath-Code
dataset,值得做相關領域的朋友參考他們建立資料集的方式。至於 "Self-Consistency with Tool-Integrated Reasoning (SC-TIR)" 之前有看過類似的討論了,就比較沒有經驗的感覺。
對我自己來說,因為沒辦法reproduce他們的結果,所以讀起來好像參與感(?)、沈浸感就比較少,我們明天一起來看看金牌區有沒有其他小而美的作法吧!
大家明天見~
謝謝讀到最後的你,希望你會覺得有趣!
如果喜歡這系列,別忘了按下訂閱,才不會錯過最新更新,也可以按讚⭐️給我鼓勵唷!
如果有任何回饋和建議,歡迎在留言區和我說✨✨
(Kaggle - AI Mathematical Olympiad - Progress Prize 1 解法分享系列)