個人原文:2019-CS224n-Assignment3html
上個禮拜作完了,今天作個總結,主要方法和2017年差很少。python
這一節沒什麼難度,認真看 a3.pdf 就行。git
Adam的論文:ADAM: A METHOD FOR STOCHASTIC OPTIMIZATIONweb
Dropout論文:Dropout: A Simple Way to Prevent Neural Networks from Overfitting網絡
依賴解析,就是分析句子的句法結構,創建 head 詞和修飾這些head的詞之間的關係。此次構建的是 transition-based 解析器,它增量的,每一次只進行一步解析動做來生成依賴關係,每一步解析稱爲 partial parse,可表示爲:app
初始狀態下,stack裏有隻 ROOT 一個詞,在每一次解析中,運行 transition 操做,分爲三個類型:機器學習
當buffer長度爲0,stack長度爲1(只有ROOT)時就算解析完畢了。函數
上圖是初始操做+三步解析動做的示意圖。學習
若A依賴於B,則B爲 head ,A爲 dependent,記爲 spa
幾個問題:
長度爲n的句子,通過多少步後能夠被解析完(用n表示)?簡要解析爲何
答:要使buffer長度爲0,則須要n步,使stack長度爲1,也須要n步,因此通過2n步後解析完畢。
完成parser_trainsitions.py
初始化函數
self.stack = ['ROOT']
self.buffer = self.sentence.copy()
self.dependencies = []
複製代碼
注意,stack的棧頂是list的右邊,buffer隊頭是list的左邊
if transition == 'S':
self.stack.append(self.buffer[0])
self.buffer = self.buffer[1:]
elif transition == 'LA':
self.dependencies.append((self.stack[-1], self.stack[-2]))
self.stack[-2:] = self.stack[-1:]
elif transition == 'RA':
self.dependencies.append((self.stack[-2], self.stack[-1]))
self.stack.pop()
else:
raise Exception('Unknown transition %s' % transition)
複製代碼
sentences含多個句子,每一個句子都有一個partial parse對象。因此每一次取出一個batch的parse來進行一次transition操做,同時要過濾掉已經完成的parse。
partial_parses = [PartialParse(s) for s in sentences]
unfinished_parses = partial_parses.copy()
while len(unfinished_parses) > 0:
batch_parses = unfinished_parses[:batch_size].copy()
transition = model.predict(batch_parses)
for i, parse in enumerate(batch_parses):
parse.parse_step(transition[i])
if len(parse.stack) == 1 and len(parse.buffer) == 0:
unfinished_parses.remove(parse)
dependencies = [parse.dependencies for parse in partial_parses]
複製代碼
完成 parser_model.py
實質上就是搭建一個三層的前饋神經網絡,用ReLU作激活函數,最後一層用softmax輸出,交叉熵作損失函數,同時還加了embedding層
初始化三個層,n_features
表示每個詞用幾個特徵來表示,每個特徵都要embed,因此輸入層的大小是 n_features * embed_size
。
# Input Layer
self.embed_to_hidden = nn.Linear(self.n_features*self.embed_size, self.hidden_size)
nn.init.xavier_uniform_(self.embed_to_hidden.weight, gain=1)
# Dropout Layer
self.dropout = nn.Dropout(self.dropout_prob)
# Output Layer
self.hidden_to_logits = nn.Linear(self.hidden_size, self.n_classes)
nn.init.xavier_uniform_(self.hidden_to_logits.weight, gain=1)
複製代碼
使用的是預訓練的embedding(Collobert at. 2011)
x = self.pretrained_embeddings(t)
x = x.view(x.shape[0], x.shape[1]*x.shape[2])
複製代碼
提取特徵、輸入網絡拿到節點,這裏沒用加softmax層是由於 torch.nn.CrossEntropyLoss 會內部幫咱們加
a = self.embedding_lookup(t)
h = self.embed_to_hidden(a)
h = F.relu(h)
h = self.dropout(h)
logits = self.hidden_to_logits(h)
複製代碼
接着完成run.py
optimizer = optim.Adam(parser.model.parameters(), lr=lr)
loss_func = nn.CrossEntropyLoss()
複製代碼
logits = parser.model(train_x)
loss = loss_func(logits, train_y)
loss.backward()
optimizer.step()
複製代碼
[1] CS224n: Natural Language Processing with Deep Learning, 2019-03-21.
[2] CS224n Assignment 2, 2019-03-21.