newsence

讓 Claude 進行自主研究以改進稀疏自編碼器(SAEs)

Lesswrong·26 天前

我讓 Claude 針對合成稀疏自編碼器基準測試進行自主研究,它成功將 F1 分數從 0.88 提升至 0.97,甚至自主發現並應用了 2010 年的 LISTA 演算法,展現了 AI 在自動化科研上的強大潛力。

本研究為 MATS 7.1 計畫的一部分

我將 Claude 對準我們新的 合成稀疏自編碼器基準測試 (synthetic Sparse Autoencoder benchmark),告訴它去提升稀疏自編碼器(SAE)的性能,然後讓它運行了一整夜。到了早上,它將 F1 分數從 0.88 提升到了 0.95。又過了一天,在我偶爾的引導下,它達到了邏輯回歸探針(logistic regression probe)0.97 的天花板——老實說,我原以為 SAE 在這個基準測試上不可能達到這個分數。

最令人驚訝的進展是,Claude 自主找到了一篇 2010 年的字典學習論文,將其演算法轉化為 SAE 編碼器,並對其進行了俄羅斯娃娃化(Matryoshka-ified),在此過程中將性能提升了幾個百分點。我以前從未聽說過這個演算法(雖然我確實應該聽說過)。

在這篇文章中,我將描述實驗設置,回顧 Claude 發現的改進,並討論這次實驗讓我對自主 AI 研究的優缺點有了哪些認識。

我們尚未驗證這些改進在大型語言模型(LLM)SAE 上的遷移效果,所以請先不要急著將這裡提到的每一項改動都應用到你的 SAE 中!我們將在文章末尾討論 LLM 驗證的挑戰和後續步驟。

我們給 Claude 的 TASK.md 以及產生的 SAE 程式碼可在 Github 上取得。

*最終產生的 SAE 在此稱為「LISTA-Matryoshka」,其表現優於所有測試過的標準 SAE,並在 L0=25 時與 SynthSAEBench-16k 上的邏輯回歸探針性能持平。

實驗設置

我們最近發布了一個名為 SynthSAEBench 的合成 SAE 基準測試。該基準測試包含一個具有 1.6 萬個基準真相特徵(ground-truth features)的合成模型(SynthSAEBench-16k)。我們刻意將此模型設計得對 SAE 來說很困難*,包含了層次化特徵、特徵相關性和特徵疊加(superposition)等已知挑戰。在論文中,我們發現測試中最好的 SAE 架構——Matryoshka SAE,僅達到了 0.88 的 F1 分數,而邏輯回歸探針則達到了 0.97。表現最好的 SAE 在其學習到的潛在方向與基準真相特徵方向之間的平均餘弦相似度(MCC)也僅為 0.78。有關這些指標的更多細節,請參閱論文

在 SynthSAEBench-16k 上訓練一個 SAE 在單個 GPU 上大約需要 20 分鐘,這使其成為快速迭代的理想試驗場。我在伺服器上設置了 Claude Code,並讓它在 Ralph Wiggum 迴圈中運行,每一次迭代 Claude 都會進行一次「研究衝刺」:產生一個想法、實作它、運行實驗並撰寫報告。我會透過在 TASK.md 文件中添加或刪除想法來進行輕微引導,但它基本上是自主運行的。完整的 TASK.md 文件可在此處取得

SAE 的改進

下表總結了 Claude 用於將 F1 分數從 0.88 提升到 0.97,並將 MCC 從 0.78 提升到 0.84 的組件。有關各項的完整細節請參見附錄

改進項目描述來源
線性遞減 K 值從較高的 K 值開始,並在訓練期間退火至目標 K 值。類似於 Anthropic 的 JumpReLU 訓練建議在我的程式庫中發現,Claude 自主嘗試。
分離內部 Matryoshka 層級除了最外層外,分離各個 Matryoshka 層級之間的梯度,使內部層級僅從全寬度重建中獲取梯度。在我的程式庫中發現,由我提示。
LISTA 編碼器使用 LISTA(傳統稀疏編碼的神經網路近似法)的一次迭代作為 SAE 編碼器。Claude 的創新。
TERM 損失函數源自這篇論文:透過傾斜指數增加高損失樣本的權重。Claude 將其改造成通用的 SAE 訓練改進,使用較小的傾斜係數(~2e-3)。改進非常微小。Claude 的創新。
按頻率排序 Matryoshka 層級在應用 Matryoshka 損失之前,根據激活頻率動態排序潛在變量,提高穩定性並有助於死掉的潛在變量(dead latent)復活。我的想法,Claude 實作。

Claude 也嘗試了許多行不通的想法,這裡就不一一列舉了,但這也是研究過程的一部分!

其中一些想法是 Claude 在我的 SAE 實驗程式庫中找到的組件,有些是我建議的想法,但最讓我印象深刻的——LISTA 和 TERM 損失——完全是 Claude 自己的主動嘗試。在這兩個案例中,Claude 都在網上找到了相關論文,將想法改編應用於 SAE,並在沒有我任何提示的情況下進行了測試。

深入探討:LISTA 編碼器

Claude 將 LISTA 重新混編進 SAE 並對其進行 Matryoshka 化的想法真的讓我驚訝,因為這是我不會想到、甚至在之前都不知道 LISTA 的東西。然而,如果你是現代 SAE 和傳統字典學習方面的專家,這可能是個顯而易見的嘗試。Claude 實作的 LISTA BatchTopK 編碼如下方的 pytorch 虛擬碼所示:

def encode(sae_in, W_enc, W_dec, b_enc, b_dec, k, eta=0.3, n_iterations=1):
	# 標準 BatchTopK SAE
	sae_in_centered = sae_in - b_dec
	hidden_pre = W_enc @ sae_in_centered + b_enc
	latent_acts = batch_topk(hidden_pre, k)
	residual = sae_in_centered
	# 迭代優化初始編碼
	for _ in range(n_iterations):
		residual = residual - (latent_acts @ W_dec)
		correction = W_enc @ residual
		hidden_pre += eta * correction
		latent_acts = batch_topk(hidden_pre, k)
	return latent_acts

這個想法是透過多個步驟迭代優化 SAE 的預測,最終收斂到「最佳」的潛在激活。LISTA 論文中的版本甚至比這更通用,實際上每一輪迭代都有學習到的 W_enc、b_enc 和 W_dec,且 eta 也是學習得到的;而 Claude 的版本在迭代中重複使用 W_enc,並在初始 SAE 編碼後的每一輪迭代中設置 b_enc = 0。原始的 LISTA 研究並未嘗試同時學習字典和編碼器,而是試圖讓學習到的編碼器逼近 ISTA(其中 W_enc = W_dec.T),因此令我驚訝的是,像 Claude 那樣直接對所有內容進行反向傳播竟然有效。

在與 Claude 的後續調查中,似乎偏離這個公式會導致較差的結果。例如:超過 3 次迭代、學習 eta、學習多個 W_enc / b_enc 等……似乎都會導致 SAE 過擬合,不再能很好地追蹤基準真相特徵(儘管解釋變異量較高)。

我對於在整個編碼過程中運行反向傳播感到有些不安,因為這會給最終未進入 latent_acts 的潛在變量帶來梯度壓力,從而無法獲得重建壓力。然而,出於我尚不完全理解的原因,嘗試阻斷對最終未被選中之潛在變量的梯度似乎效果並不理想。

雖然我還不確定這在 LLM SAE 中是否有效(目前的結果褒貶不一),但這非常符合我預期會有效的類型。SAE 可以被視為 LISTA 演算法的單個步驟,理論上單個步驟表現不應特別出色。進行 2 個步驟、1.5 個步驟,或者 Claude 具體想出的任何方案能有所幫助,這聽起來並不瘋狂。進行太多步驟似乎會讓 SAE 很容易找到過擬合的創意方法(例如利用相關性或疊加噪聲)。

使用 SAEBench 在 LLM 上驗證

我一直試圖使用 SAEBench 驗證這些想法是否能提升 LLM SAE 的性能,但到目前為止還無法給出決定性的證明。核心問題在於 SAEBench 的指標存在噪聲:你需要多個種子、多個 L0 值,且結果往往指向不同方向(例如 TPP 增加但 SCR 減少)。妥善評估單個架構改動可能輕易耗費 1000 美元以上的運算成本,對於沒有強大預驗信心能獲得清晰結果的獨立研究者來說,這是難以負擔的。

到目前為止,eta=0.3 的 LISTA 在 LLM 上似乎會失效,而使用較低的 eta 則很難從噪聲中區分信號。某些改動——如 Matryoshka 頻率排序——幾乎可以肯定是改進,但要嚴謹地證明這一點需要訓練更多的 LLM SAE。

無論如何,這些改進最終是否能遷移到 LLM 並不是 Claude 的錯。Claude 出色地完成了我為它設定的任務,即進行 SAE 架構改進以提高 SynthSAEBench-16k 上的 F1 分數和 MCC。

Claude 的研究優勢與劣勢

總體而言,我對 Claude Opus 4.6 進行自主研究的能力印象深刻。它能提出衝刺想法、自行運行、總結結果,然後在成功的基礎上繼續發展。最令我印象深刻的是它在網上尋找隨機研究論文並測試其中想法的能力,而不需要我太多的提示(除了告訴它在開始衝刺前花時間看看相關領域)。

我認為 LISTA 的想法特別精妙,這是我自己想不出來的,但對於傳統字典學習專家來說可能顯而易見。我認為這些模型的一個大優勢是它們在基本上每個領域都知識淵博,所以如果某個想法對我不擅長領域的專家來說是顯而易見的,模型很可能會嘗試我想不到的想法。

話雖如此,Claude 嘗試的許多其他想法要麼是由我提示的,要麼是在它瀏覽過的我的 SAE 研究程式庫中流傳的。我發現一旦我透過將想法添加到清單中來提示 Claude 嘗試,它非常有能力理解該想法、編寫程式碼並進行測試,但對於其中許多想法,我不確定如果沒有這些提示,它是否會自己想出來。

我注意到的一點是,Claude 傾向於對其衝刺結果的解讀過於自信,而沒有深入思考衝刺可能出錯的所有原因,或者結果可能有哪些替代解釋。例如,有一次衝刺涉及 Claude 的一個實作錯誤,導致該衝刺實際上沒有測試任何內容,而 Claude 隨後自信地宣稱該想法無效。一旦我指出要檢查程式碼是否真的在運行,Claude 才意識到錯誤並重新進行了衝刺。我確實擔心 Claude 得出的結論並不總是經過最嚴謹的測試,但這是快速測試大量想法的一種廉價方式。

我還發現 Claude 傾向於困在它發現的第一批似乎有效的東西上,而不是嘗試廣泛的不同想法。我需要一些推動才能讓 Claude 嘗試完全不同的想法,因為它會看到之前的衝刺,這似乎會讓它產生偏見去思考那些過去的衝刺。我懷疑可以透過不讓它看到過去的衝刺,或者在單個衝刺之外進行單獨的「想法產生」環節來解決這個問題,在那裡你可以協作提出要嘗試的衝刺想法。

我還發現,讓 Claude 運行這些衝刺解決了我自己在機器學習研究中面臨的專注力問題——當你需要不斷運行某些東西並在 1 小時後回來檢查時,真的很難保持在心流狀態。我不喜歡頻繁的任務切換,往往會因此分心。Claude 不會分心,它會盡職地在 1 小時後運行下一步,並持續進行直到所有內容完成並記錄下來。

總體而言,這感覺就像僱用了一位反應極快且極其聰明的碩士生,他可以快速迭代,但需要一點指導。我也認為這種設置受益於有明確的優化數值和相對較快的迭代週期。我不認為如果 Claude 必須訓練 LLM SAE 並運行 SAEBench,會取得同樣的成功。

下一步

我現在有了一套流程,可以向 Claude 提出一個想法,然後讓它去調查、進行衝刺、撰寫報告,並在完成時通知我。我也很想將其整合到 Slack 中,這樣我就可以直接在對話串中與它聊天,讓它運行衝刺並將結果和 PDF 報告放入 Slack 頻道。

到目前為止,我只讓 Claude 嘗試最大化單個 SynthSAEBench-16k 模型的得分,它在這方面做得非常出色,但我懷疑部分成功是因為它對該特定模型進行了過度的爬山優化(hill-climbing)。接下來我將嘗試建立一套具有不同屬性的合成模型,以確保 Claude 想出的想法不會過度擬合這個特定的合成模型。

最後,我們需要提高在 LLM SAE / SAEBench 上的評估能力。這可能包括嘗試大幅擴展每個指標中數據集的數量和質量(也許我可以要求 Claude 來做這件事),或者可能只是涉及獲得更多運算資金,以便為每個 SAE 使用多個種子來妥善測試這些想法。我也很想聽聽社群中其他人對此的任何想法!

試試看吧!

我發現讓 Claude 在 SynthSAEBench 上自主嘗試 SAE 架構想法出奇地容易。你可以在 https://github.com/chanind/claude-auto-research-synthsaebench 查看 Claude 想出的 SAE 程式碼以及 TASK.md 提示詞版本。去試試看吧!


附錄:改進細節

訓練期間線性遞減 K 值

Claude 發現,從較高的 K 值開始並在訓練期間線性減少到目標 K 值,似乎有助於提升 SAE 的品質。這在隱含意義上類似於 Anthropic 建議訓練 JumpReLU SAE 的方式,所以這對 BatchTopK SAE 也有幫助並不令人意外。

這個設置原本是我 SAE 程式庫中的一個選項,但 Claude 發現了它,嘗試設置後發現了良好的結果。

分離內部 Matryoshka 層級,但不分離最終層級

Matryoshka SAE 採用固定大小的前綴(此處稱為層級),並在訓練期間將這些全部加總。這就像是在訓練不同寬度的 SAE,而它們恰好共享潛在變量。Claude 發現,除了最外層之外,分離每個 Matryoshka 層級之間的梯度可以提高性能。因此,如果一個 Matryoshka SAE 使用層級 [128, 512, 2048, 4096] 進行訓練,其中 4096 是 SAE 的全寬度,則 128 層級不會從 512 和 2048 層級接收梯度,但從完整的 4096 重建中接收梯度。

這個設置是我 SAE 程式庫中的一個選項,也是我在任務中提到的一個想法。

LISTA 編碼器

Claude 找到了一篇 2010 年名為「Learning Fast Approximations of Sparse Coding」的字典學習論文,該論文使用神經網路來近似一種稱為迭代收縮閾值演算法 (ISTA) 的傳統字典學習技術。Claude 迅速製作了一個 SAE 版本,使用 LISTA 作為編碼器,並混編了一個 Matryoshka 版本。

Claude 發現使用單次迭代效果最好,並在每次迭代後的調整中使用 0.3 的權重。Claude 在這裡真的讓我驚艷,因為我永遠不會想到 LISTA SAE,尤其是那種刻意只訓練 1 次迭代而不是讓它收斂的版本。Claude 的實作在訓練期間也只是直接對迭代進行反向傳播,我原以為這行不通,但看來它是有效的!

我以前沒聽說過 LISTA(回想起來我真的應該聽說過),而且通常對傳統的字典學習論文感到吃力。

TERM 損失函數

Claude 找到了論文 Decoding Dark Matter: Specialized Sparse Autoencoders for Interpreting Rare Concepts in Foundation Models,其中包含一種稱為 TERM 的損失函數,它會增加具有較大損失之訓練樣本的權重,以鼓勵 SAE 訓練更多地關注這些樣本。TERM 損失的公式如下:

(此處省略原始 Markdown 中的複雜 MathJax 樣式代碼,保留公式邏輯描述)

其中 $L(w; z_i)$ 是樣本 $i$ 的正常 SAE 損失,$N$ 是批次中的樣本數,而 $t$ 是一個傾斜係數,決定損失向高損失樣本偏斜的程度。

有趣的是,該論文甚至沒有建議將此作為提高 SAE 性能的方法,但 Claude 還是這麼做了,並發現使用帶有小係數(~2e-3)的 TERM 似乎有助於提升 SAE 品質。這是一個相當微小的改進,但仍然是一個非常有趣的想法。標準 SAE 損失的其他類似調整也可能助於提升性能。

按激活頻率動態排序 Matryoshka 層級

通常,Matryoshka SAE 強制要求較早的潛在索引必須學習較高頻率的概念。然而,我們在 SAE 訓練期間已經在追蹤潛在激活頻率,因此我們可以在應用 Matryoshka 損失之前,根據激活頻率動態排序潛在變量。一個更嚴謹的版本可能是按預期 MSE(預期激活幅度的平方)進行排序。這有助於訓練穩定性,因為如果後面的潛在變量恰好學習到了高頻概念,它就不需要在訓練期間取消學習。這也有助於死掉的潛在變量復活,因為死掉的潛在變量總是隱含地被復活到最外層的 Matryoshka 層級中。

參與討論

https://lesswrong.com/posts/rbqJoxFZtae9x93mx/letting-claude-do-autonomous-research-to-improve-saes