使用python DyNet包

使用python DyNet包

 DyNet包计划用于训练和使用神经网络,尤其适合于动态变化的神经网络结构的应用。这是DyNet C++包的python包装器。
 在一个神经网络包中通常有两种运作方式:
静态网络,其构建了一个网络并fed不同的输入/输出。大多数神经网络(Neural Network)包以这种方式工作。
动态网路,其为每一个训练样本构建了新的网络(和其他训练样本的网络共享参数)。这种方法使得DyNet是独一无二的,并且这也是它的强大之处。
 我们将会描述这两者的模式。

包的基础知识

 DyNet的主要部分是计算图(ComputationGraph),其本质是一个神经网络的定义。计算图由与网络的输入和输出相关的表达式(Expression)以及网络的参数(Parameter)组成。参数就是随时间优化的网络中的东西,所有的参数放在参数集合(ParameterCollection)中。训练器(Trainer)(比如SimpleSGDTrainer)负责设置参数值。
 我们将不会直接使用计算图,但是其作为一个单独的对象存在于后台。导入DyNet时,就创建了一个新的计算图。我们可以通过调用dy.renew_cg()重置计算图到一个新的状态。

静态网络

 一个DyNet程序的生命周期是: 1. 创建一个计算图,并使用参数来填充该计算图。2. 更新计算图,并且创建表征该网络(该网络将会包含定义在参数集合中的参数的表达式)的表达式。3. 用网络的目标函数优化该模型。
 作为示例,考虑用于解决异或(xor)问题的模型。该模型有两个输入,要么是0要么是1,以及两个输入的疑惑(xor)后的单个输出。我们将会对此建模成有一个隐层的多层感知机。
 令 x=x1,x2 x = x 1 , x 2 是我们的输入,我们将会有8个节点的一个隐层,以及只有一个节点的输出层。隐层的激活函数是 tanh t a n h 。我们的网络会是:

σ(V(tanh(Wx+b))) σ ( V ( t a n h ( W x + b ) ) )

其中 W W 是一个8×2的矩阵, V V 是一个8×1的矩阵, b b 是一个8-维的向量。
 我们想让输出要么是0要么是1,因此我们把输出层送进logistic-sigmoid函数, σ(x) σ ( x ) , 其以 − ∞ 和+ 之间的数作为输出,并返回 [0,1] [ 0 , 1 ] 之间的数。
 我们将会开始定义该模型和计算图。

#导入dynet
import dynet as dy
#创建参数集合并添加参数
m = dy.ParameterCollection()
w = m.add_parameters((8, 2))
v = m.add_parameters((1, 8))
b = m.add_parameters((8))
#新的计算图。这不是严格要求的,但这是比较好做法
dy.renew_cg()
b.value()

 第一块创建了一个参数集合并且填充了参数。第二块创建了计算图。
 在计算图中,模型参数将会用作表达式。为了为该网络创建表达式,我们现在使用 V,W V , W b b <script type="math/tex" id="MathJax-Element-1315">b</script>。

#规模为2一个输入向量, 也是一个表达式。
x = dy.vecInput(2)
output = dy.logistic(v * (dy.tanh(w * x + b)))
#我们现在可以查询到我们的网络
x.set([0, 0])
output.value()
#我们想要能够定义一个损失,因此我们需要一个输入对应的表达式
y = dy.scalarInput(0)#用来保留正确的答案
loss = dy.binary_log_loss(output, y)
x.set([1, 0])
y.set(0)
print(loss.value())

y.set(1)
print(loss.value())

训练

 我们现在想要设置参数权重,以便最小化损失。
 鉴于此,我们将会使用trainer对象。构建一个trainer是与一个给定模型参数相关的。

trainer = dy.SimpleSGDTrainer(m)

 要使用该训练器,我们需要调用计算图的forward_scalar方法。这将会通过网络运行一个前向传递, 计算所有的中间值直到最后一个(在我们的案例中是损失),然后将该值转换为一个标量。我们网络的最终输出必须是一个单一的标量值。然而,如果我们不关心该值,那么只需使用cg.forward()来代替cg.forward_scalar()。调用计算图的backward方法。这会从最后一个节点运行一个反向传递,计算关于最小化表达式(在我们 的案例中想要最小化的是损失)的梯度。该梯度将会存储在参数集合中,现在我们可以用trainer来关注最优化步。调用trainer_update()会优化关于最新梯度的值。

x.set([1, 0])
y.set(1)
loss_value = loss.value()#通过网路执行前向传递
print("the loss before step is: ", loss_value)
#现在做一个优化步
loss.backward()
trainer.update()
#查看其如何影响loss
loss_value = loss.value(recalculate=True)#recalculate=True意味着不使用预计算的值。
print("the loss after step is: ", loss_value)

 该优化步的确使得损失减小。我们现在需要在一个循环中运行该优化步。做完这一步,我们将会创建一个训练集,并在这上面迭代。
 对于异或(xor)问题,训练实例是容易创建的。

def create_xor_instances(num_rounds=2000):
    questions = []
    answers = []
    for round in range(num_rounds):
        for x1 in 0, 1:
            for x2 in 0, 1:
                answer = 0 if x1 == x2 else 1
                questions.append((x1, x2))
                answers.append(answer)
    return questions, answers

questions, answers = create_xor_instances()

 我们现在要feed每对question/answer进网络,并且尝试最小化该损失。

total_loss = 0
seen_instances = 0
for question, answer in zip(questions, answers):
    x.set(question)
    y.set(answer)
    seen_instances += 1
    total_loss += loss.value()
    trainer.update()
    if seen_instances > 1 and seen_instances % 100 == 0:
        print('average loss is', total_loss / seen_instances)

 我们的网络已经被训练了,现在来验证的确是学到了xor函数。

x.set([0, 1])
print('0, 1', output.value())

x.set([1, 0])
print('1, 0', output.value())

x.set([0, 0])
print('0, 0', output.value())

x.set([1, 1])
print('1, 1', output.value())

 如果我们对参数感到好奇,我们可以查询它们:

w.value()
v.value()
b.value()

总结

 这是完整的程序

import dynet as dy

m = dy.ParameterCollection()
w = m.add_parameters((8, 2))
v = m.add_parameters((1, 8))
b = m.add_parameters((8))

dy.renew_cg()
b.value()

x = dy.vecInput(2)
output = dy.logistic(v * (dy.tanh(w * x + b)))

x.set([0, 0])
output.value()

y = dy.scalarInput(0)
loss = dy.binary_log_loss(output, y)

x.set([1, 0])
y.set(0)
print(loss.value())

y.set(1)
print(loss.value())

trainer = dy.SimpleSGDTrainer(m)

x.set([1, 0])
y.set(1)
loss_value = loss.value()
print("the loss before step is: ", loss_value)
loss.backward()
trainer.update()
loss_value = loss.value(recalculate=True)
print("the loss after step is: ", loss_value)

def create_xor_instances(num_rounds=2000):
    questions = []
    answers = []
    for round in range(num_rounds):
        for x1 in 0, 1:
            for x2 in 0, 1:
                answer = 0 if x1 == x2 else 1
                questions.append((x1, x2))
                answers.append(answer)
    return questions, answers

questions, answers = create_xor_instances()

total_loss = 0
seen_instances = 0
for question, answer in zip(questions, answers):
    x.set(question)
    y.set(answer)
    seen_instances += 1
    total_loss += loss.value()
    trainer.update()
    if seen_instances > 1 and seen_instances % 100 == 0:
        print('average loss is', total_loss / seen_instances)

动态网络

 动态网络和静态的网络非常相似,但不是创建网络一次,而是在每个训练示例中调用“set”来改变输入,我们职位每个训练示例创建一个新网络。
 我们在下面给出一个例子。虽然在xor示例中这个值可能不明确,但动态方法对于结构固定的网络非常方便,例如循环网络或递归网络。

import dynet as dy
#如此前一样,创建训练实例
def create_xor_instances(num_rounds=2000):
    questions = []
    answers = []
    for round in range(num_rounds):
        for x1 in 0,1:
            for x2 in 0,1:
                answer = 0 if x1==x2 else 1
                questions.append((x1,x2))
                answers.append(answer)
    return questions, answers

questions, answers = create_xor_instances()

# 创建一个给定输入或输出的xor问题网络
def create_xor_network(W, V, b, inputs, expected_answer):
    dy.renew_cg() # new computation graph
    x = dy.vecInput(len(inputs))
    x.set(inputs)
    y = dy.scalarInput(expected_answer)
    output = dy.logistic(V*(dy.tanh((W*x)+b)))
    loss =  dy.binary_log_loss(output, y)
    return loss

m2 = dy.ParameterCollection()
W = m2.add_parameters((8,2))
V = m2.add_parameters((1,8))
b = m2.add_parameters((8))
trainer = dy.SimpleSGDTrainer(m2)

seen_instances = 0
total_loss = 0
for question, answer in zip(questions, answers):
    loss = create_xor_network(W, V, b, question, answer)
    seen_instances += 1
    total_loss += loss.value()
    loss.backward()
    trainer.update()
    if (seen_instances > 1 and seen_instances % 100 == 0):
        print("average loss is:",total_loss / seen_instances)
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值