用超位置解開複雜神經網絡的特徵
複雜的神經網絡,例如大型語言模型 (LLMs),經常面臨可解釋性挑戰。這種困難的主要原因之一是超位置——這是一種神經網絡的現象,它的維度少於它需要表示的特徵數量。例如,一個有兩個神經元的玩具大型語言模型需要呈現六種不同的語言特徵。因此,我們經常會發現一個神經元需要為多個特徵激活。想了解更多有關超位置的詳細解釋和定義,請參考我之前的部落格文章:“超位置:為什麼解釋神經網絡這麼困難”。
在這篇部落格文章中,我們更進一步:讓我們試著解開一些超位置的特徵。我將介紹一種稱為稀疏自編碼器 (Sparse Autoencoder) 的方法,來分解複雜的神經網絡,特別是大型語言模型,並用語言特徵的玩具範例來說明。
稀疏自編碼器的定義是,在其隱藏層的激活中故意引入稀疏性。它的結構相當簡單,訓練過程也輕便,旨在以更可解釋的方式分解複雜的神經網絡,讓人類更容易理解。
假設你有一個訓練好的神經網絡。自編碼器並不是模型本身訓練過程的一部分,而是一種事後分析工具。原始模型有自己的激活,這些激活在之後被收集,然後用作稀疏自編碼器的輸入數據。
例如,假設你的原始模型是一個有一個隱藏層和五個神經元的神經網絡。此外,你有一個包含5000個樣本的訓練數據集。你需要收集所有5000個訓練樣本的五維隱藏層激活值,這些值現在成為你的稀疏自編碼器的輸入。
然後,自編碼器從這些激活中學習一個新的稀疏表示。編碼器將原始多層感知器 (MLP) 的激活映射到一個具有更高表示維度的新向量空間。回顧我之前的五個神經元的簡單範例,我們可以考慮將其映射到一個具有20個特徵的向量空間。希望我們能夠有效地獲得一個稀疏自編碼器,將原始的MLP激活分解為更易於解釋和分析的表示。
稀疏性在自編碼器中非常重要,因為它對於自編碼器“解開”特徵是必要的,這樣可以在一個稠密、重疊的空間中獲得更多的“自由”。如果沒有稀疏性,自編碼器可能只會學習到一個簡單的壓縮,而沒有形成任何有意義的特徵。
語言模型
現在讓我們建立我們的玩具模型。我請讀者注意,這個模型在實際上並不現實,甚至有點傻,但它足以展示我們如何構建稀疏自編碼器並捕捉一些特徵。
假設我們現在建立了一個語言模型,它有一個特定的隱藏層,其激活有三個維度。假設我們有以下標記:“貓”、“快樂的貓”、“狗”、“精力充沛的狗”、“不是貓”、“不是狗”、“機器人”和“人工智慧助手”,這些標記在訓練數據集中,並且它們有以下的激活值。
data = torch.tensor([# 貓類別[0.8, 0.3, 0.1, 0.05], # “貓”[0.82, 0.32, 0.12, 0.06], # “快樂的貓”(類似於”貓”)# 狗類別[0.7, 0.2, 0.05, 0.2], # “狗”[0.75, 0.3, 0.1, 0.25], # “忠誠的狗”(類似於”狗”)
# “不是動物”類別[0.05, 0.9, 0.4, 0.4], # “不是貓”[0.15, 0.85, 0.35, 0.5], # “不是狗”
# 機器人和人工智慧助手(在四維空間中更明顯)[0.0, 0.7, 0.9, 0.8], # “機器人”[0.1, 0.6, 0.85, 0.75] # “人工智慧助手”], dtype=torch.float32)
自編碼器的構建
我們現在用以下代碼構建自編碼器:
class SparseAutoencoder(nn.Module):def __init__(self, input_dim, hidden_dim):super(SparseAutoencoder, self).__init__()self.encoder = nn.Sequential(nn.Linear(input_dim, hidden_dim),nn.ReLU())self.decoder = nn.Sequential(nn.Linear(hidden_dim, input_dim))
def forward(self, x):encoded = self.encoder(x)decoded = self.decoder(encoded)return encoded, decoded
根據上面的代碼,我們看到編碼器只有一個完全連接的線性層,將輸入映射到一個具有hidden_dim的隱藏表示,然後通過ReLU激活。解碼器僅使用一個線性層來重建輸入。請注意,解碼器中缺少ReLU激活是故意的,因為重建可能包含實值和潛在的負值數據。ReLU會強迫輸出保持非負,這對我們的重建來說並不理想。
我們使用下面的代碼訓練模型。在這裡,損失函數有兩個部分:重建損失,測量自編碼器對輸入數據的重建準確性,以及稀疏性損失(帶權重),這鼓勵編碼器中的稀疏性形成。
# 訓練循環for epoch in range(num_epochs):optimizer.zero_grad()
# 前向傳播encoded, decoded = model(data)
# 重建損失reconstruction_loss = criterion(decoded, data)
# 稀疏性懲罰(對編碼特徵的L1正則化)sparsity_loss = torch.mean(torch.abs(encoded))
# 總損失loss = reconstruction_loss + sparsity_weight * sparsity_loss
# 反向傳播和優化loss.backward()optimizer.step()
現在我們可以看看結果。我們已經繪製了原始模型每個激活的編碼器輸出值。回想一下,輸入標記是“貓”、“快樂的貓”、“狗”、“精力充沛的狗”、“不是貓”、“不是狗”、“機器人”和“人工智慧助手”。
即使原始模型的設計非常簡單,沒有深入考慮,自編碼器仍然捕捉到了這個簡單模型的有意義特徵。根據上面的圖,我們可以觀察到至少四個特徵似乎是編碼器學到的。
首先考慮特徵1。這個特徵在以下四個標記上有較大的激活值:“貓”、“快樂的貓”、“狗”和“精力充沛的狗”。結果表明,特徵1可能與“動物”或“寵物”有關。特徵2也是一個有趣的例子,對兩個標記“機器人”和“人工智慧助手”激活。因此,我們猜測這個特徵與“人工和機器人”有關,顯示模型對技術背景的理解。特徵3在四個標記上激活:“不是貓”、“不是狗”、“機器人”和“人工智慧助手”,這可能是一個“不是動物”的特徵。
不幸的是,原始模型並不是一個在真實文本上訓練的真實模型,而是基於假設相似的標記在激活向量空間中有某種相似性而人工設計的。然而,結果仍然提供了有趣的見解:稀疏自編碼器成功地顯示了一些有意義的、對人類友好的特徵或真實世界的概念。
這篇部落格文章中的簡單結果表明,稀疏自編碼器可以有效地幫助從複雜的神經網絡(如LLM)中獲得高層次、可解釋的特徵。
對於對稀疏自編碼器的真實世界實施感興趣的讀者,我推薦這篇文章,其中一個自編碼器被訓練來解釋一個擁有512個神經元的真實大型語言模型。這項研究提供了稀疏自編碼器在大型語言模型可解釋性背景下的真實應用。
最後,我在這裡提供這個Google Colab筆記本,詳細說明了我在這篇文章中提到的實施。
本文由 AI 台灣 運用 AI 技術編撰,內容僅供參考,請自行核實相關資訊。
歡迎加入我們的 AI TAIWAN 台灣人工智慧中心 FB 社團,
隨時掌握最新 AI 動態與實用資訊!