歡迎直接到我的博客查看最近文章:www.pkudodo.com。更新會比較快,評論回覆我也能比較快看見,排版也會更好一點。
原始blog鏈接: http://www.pkudodo.com/2019/06/14/1-13/
Memory NetWorks介紹
在文本的處理上,由於很多地方對記憶的需要,因此誕生了RNN及LSTM。但RNN和LSTM也只能用於短時間內的記憶(一般來說也就十幾個step)。所以如果文本較長的話,RNN和LSTM也無能爲力了。
當然也有一種方法,就是直接擴大RNN和LSTM的隱狀態大小,讓其可以存儲更多的信息。但相對於這種方式,我們更希望能夠任意地增加記憶量,同時能夠對模型做盡可能小的改變。
Memory Networks正是從這一角度出發得到的產物。直觀來講,Memory Networks可以理解成正常的model額外加一個記憶模塊。
就好像我們使用的CPU(普通的model),它內部是有一個很小的ram的(我本科階段是嵌入式方向,目前見過cpu內部最小的ram只是kb的量級),但如果要運行操作系統或軟件的話,內部ram就不夠了(memory不夠),所以通常會外擴一個ram芯片(Memory Networks),這樣cpu的運行並沒有什麼改變,只不過在需要memory來配合推理的時候,直接從Memory Networks中存取就可以了。
memory network在提出後又經歷了幾次變體,這次先寫《memory networks》,這是memory networks被facebook首次提出的原始論文。後續又經歷了幾次變體。下一篇就會講它end-to-end 的memory network,這是對於原始MemNN的一次改進。
《Memory Networks》
Memory Networks一共有5個部分,分別是memory m、I、G、O、R,其中
memory m:m由一系列的mi組成,其中mi是單個向量,每個mi都表示某一個方面的記憶存儲。當要更新記憶的時候,就操作使用新記憶去更新相應的mi,要寫入記憶時直接寫入mi即可。至於i的範圍則依據實際的使用策略不同而作相應的修改。
I:輸入特徵映射,它負責將輸入轉換成內部的特徵表示形式。比如說輸入的是文本,就需要它將其轉換成model可以看懂的數學形式(比如說word轉換成embedding形式、文本轉換成向量等),也可以認爲是數據的預處理的一個過程。用I(x)表示運算過程,其中x是輸入。
G:更新記憶,根據當前的memory狀態(m)、當前的輸入(I(x))、要更新的記憶(mi),得到更新後的記憶,並更新mi。用mi=G(mi, I(x), m)表示,其中i爲m的數目範圍內的任意數,具體怎麼指定i的值,後續會解釋。
O:輸出映射,根據當前的記憶狀態以及當前的輸入,確定當前的輸出,但輸出是內部特徵表示形式(比如說一個稠密的向量),因此還需要一個步驟作轉換。用o=O(I(x), m)表示。
R:迴應,負責將O步驟輸出的o轉換成系統交互的形式,例如文本或系統動作。用r=R(o)表示,最簡單的理解就是把o輸入一個rnn,使用seq2seq或者類似的結構輸出對應的文本或動作即可。
一個文本的例子——最基本的模型應用
怎麼把數據存到memory
最簡單的一個方法就是順序存,比如說定義有n個m,即mi中i的取值範圍爲0-999。那麼每次要往memory存的時候,就找到下一個空着的memory,將輸入x原封不動地放進去(這是最簡單的策略,比如說x是個句子,就把句子直接放到memory中),之後N+1,下次就會往下一個memory存。
由於G是負責更新memory的,所以在這種策略中,G只是很簡單的原封不動地輸出x。
怎麼提取指定記憶
那麼存記憶已經搞定了,另一個主要的問題是取記憶,比如說下面這段小故事:
- Joe去了廚房。
- Fred去了廚房。
- Joe拿起了牛奶。
- Joe去了辦公室。
- Joe放下了牛奶。
- Joe上了廁所。
提問:牛奶現在在哪裏?
一共6句話,根據當前的存儲策略,6句話直接以原始形式存在了m中,這個時候根據提問怎麼知道哪句話是和提問相關的呢?
如果我們自己做這個題,就會把每個句子再看一遍,定位到了第五句——Joe放下了牛奶。memory network做的也是這件事情,它使用了O模塊,去計算當前輸入x和每一個m的相關程度,找到最相關的句子mi,公式如下:
其中so是一類計算相關程度的函數,它最後會輸出一個得分,x和所有的m遍歷計算,直到找到得分最高的即爲最相關的句子i。
其中score函數如下:
U的大小爲[n,D],Φx和Φy是D維向量,Φ(x)負責將x映射到內部向量表示形式(比如說最簡單的就是詞袋模型)。所以最後的s(x,y)的結果是一個實數,表示了分數。
但是這其中存在一個問題,比如說我們找到了最相關的i是5,放下了牛奶,但牛奶在哪裏我們仍然不知道。所以對於人來說,會往前看一句,發現第4句“Joe去了辦公室”直接暗示了牛奶在辦公室。第4句和第5句結合才能得到牛奶在辦公室的答案。
因此不光要找到最相關的句子,還應該找到第二相關的句子(paper中用k來定義一共找前k個相關的句子,這裏k=2)。
值得注意的是,並不是簡單地找到前2個相關句子,在找第2個句子時,需要以找到的第一個句子爲條件。像上面的式子中,需要以x和m01爲條件去找mo2。作者沒有提到這麼做的原因,但我認爲是爲了能夠在有了第一個句子的情況下,再去找到一個另外的能夠有最強代表性的句子,而不是說兩個句子其實指代的是同一個方面,這樣跟找一個句子也沒什麼差別。
輸出
在這個例子中,輸出並不要求是字符串,只要一個word即可,比如說“辦公室”(這裏引用的是原文中的例子,在英文中是單個的“office”,如果是中文情況下,可以加一個rnn來生成字符串)。
所以輸出函數的輸入是當前輸入、m01,m02和字典,輸出是字典當中最有可能的那個單詞,公式如下:
訓練
k=2時的目標函數如下:
(6)表示挑出來的句子是否是正確的句子,(7)表示在第一個句子被正確挑出來的情況下,第二個句子是否是正確的句子。(8)最後輸出的是否是正確的答案。
可以看到loss其實對train的各個方面都做了一個約束,最後的performance效果也是非常好。
其他
論文的後半部分補充了很多小技巧,例如memory如果非常大的解決方法、遇到新詞等。這裏就不再過多展開了。