2019-CS224n-Assignment3

我的原文:2019-CS224n-Assignment3

上个礼拜做完了,今天做个总结,主要方法和2017年差不多。

机器学习和神经网络 (8分)

这一节没什么难度,认真看 a3.pdf 就行。

Adam的论文:ADAM: A METHOD FOR STOCHASTIC OPTIMIZATION

Dropout论文:Dropout: A Simple Way to Prevent Neural Networks from Overfitting

基于神经Transition的依赖解析 (42分)

依赖解析,就是分析句子的句法结构,建立 head 词和修饰这些head的词之间的关系。这次构建的是 transition-based 解析器,它增量的,每一次只进行一步解析动作来生成依赖关系,每一步解析称为 partial parse,可表示为:

  • 一个 stack ,已被处理的词
  • 一个 buffer ,待处理的词
  • 一个 dependencies ,解析器生成的依赖

初始状态下,stack里有只 ROOT 一个词,在每一次解析中,运行 transition 操作,分为三个类型:

  • SHIFT:将buffer的左边(头部)第一个词取出,放到stack的右边(尾部)
  • LEFT-ARC:将stack的右第二个词作为依赖项,它依赖于右边第一个词,生成一个依赖关系,并删除右第二个词。
  • RIGHT-ARC:将stack的右第一个词作为依赖项,它依赖于右边第二个词,生成一个依赖关系,并删除右第一个词。

当buffer长度为0,stack长度为1(只有ROOT)时就算解析完毕了。

上图是初始操作+三步解析动作的示意图。

若A依赖于B,则B为 head ,A为 dependent,记为 B \rightarrow A

几个问题:

问题(b) 6分

长度为n的句子,经过多少步后可以被解析完(用n表示)?简要解析为什么

答:要使buffer长度为0,则需要n步,使stack长度为1,也需要n步,所以经过2n步后解析完毕。

问题(c) 6分

完成parser_trainsitions.py

init

初始化函数

self.stack = ['ROOT']
self.buffer = self.sentence.copy()
self.dependencies = []
复制代码
parse_step

注意,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)
复制代码
minibatch_parse

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]
复制代码

问题(e) 10分

完成 parser_model.py

实质上就是搭建一个三层的前馈神经网络,用ReLU做激活函数,最后一层用softmax输出,交叉熵做损失函数,同时还加了embedding层

init

初始化三个层,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_lookup

使用的是预训练的embedding(Collobert at. 2011)

x = self.pretrained_embeddings(t)
x = x.view(x.shape[0], x.shape[1]*x.shape[2])
复制代码
forward

提取特征、输入网络拿到节点,这里没用加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

train
optimizer = optim.Adam(parser.model.parameters(), lr=lr)
loss_func = nn.CrossEntropyLoss()
复制代码
train_for_epoch
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.

转载于:https://juejin.im/post/5c9355966fb9a070ef60a2e3

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值