【问题标题】:How to improve this cntk xor implementation如何改进这个cntk xor实现
【发布时间】:2017-05-24 05:56:51
【问题描述】:

我已经用 cntk (python) 实现了“异或问题”。

目前它只是偶尔解决问题。如何实现更可靠的网络?

我想只要起始随机权重接近最优,问题就会得到解决。我试过binary_cross_entropy 作为损失函数,但没有改善。我尝试将tanh 作为非线性函数,但它也不起作用。我还尝试了许多不同的参数组合learning_rateminibatch_sizenum_minibatches_to_train。请帮忙。

谢谢

# -*- coding: utf-8 -*-

import numpy as np
from cntk import *
import random
import pandas as pd

input_dim = 2
output_dim = 1

def generate_random_data_sample(sample_size, feature_dim, num_classes):
    Y = []
    X = []
    for i in range(sample_size):
        if i % 4 == 0:
            Y.append([0])
            X.append([1,1])
        if i % 4 == 1:
            Y.append([0])
            X.append([0,0])
        if i % 4 == 2:
            Y.append([1])
            X.append([1,0])
        if i % 4 == 3:
            Y.append([1])
            X.append([0,1])

    return np.array(X,dtype=np.float32), np.array(Y,dtype=np.float32)   

def linear_layer(input_var, output_dim,scale=10):
    input_dim = input_var.shape[0]

    weight = parameter(shape=(input_dim, output_dim),init=uniform(scale=scale))
    bias = parameter(shape=(output_dim))

    return bias + times(input_var, weight)

def dense_layer(input_var, output_dim, nonlinearity,scale=10):
    l = linear_layer(input_var, output_dim,scale=scale)

    return nonlinearity(l)


feature = input(input_dim, np.float32)
h1 = dense_layer(feature, 2, sigmoid,scale=10)
z = dense_layer(h1, output_dim, sigmoid,scale=10)

label=input(1,np.float32)
loss = squared_error(z,label)
eval_error = squared_error(z,label)


learning_rate = 0.5
lr_schedule = learning_rate_schedule(learning_rate, UnitType.minibatch) 
learner = sgd(z.parameters, lr_schedule)
trainer = Trainer(z, (loss, eval_error), [learner])

def print_training_progress(trainer, mb, frequency, verbose=1):
    training_loss, eval_error = "NA", "NA"

    if mb % frequency == 0:
        training_loss = trainer.previous_minibatch_loss_average
        eval_error = trainer.previous_minibatch_evaluation_average
        if verbose: 
            print ("Minibatch: {0}, Loss: {1:.4f}, Error: {2:.2f}".format(mb, training_loss, eval_error))

    return mb, training_loss, eval_error

minibatch_size = 800
num_minibatches_to_train = 2000
training_progress_output_freq = 50

for i in range(0, num_minibatches_to_train):
    features, labels = generate_random_data_sample(minibatch_size, input_dim, output_dim)
    trainer.train_minibatch({feature : features, label : labels})
    batchsize, loss, error = print_training_progress(trainer, i, training_progress_output_freq, verbose=1)

out = z
result = out.eval({feature : features})
a = pd.DataFrame(data=dict(
        query=[str(int(x[0]))+str(int(x[1])) for x in features],
        test=[int(l[0]) for l in labels],
        pred=[l[0] for l in result]))
print(pd.DataFrame.drop_duplicates(a[["query","test","pred"]]).sort_values(by="test"))

【问题讨论】:

    标签: python neural-network cntk


    【解决方案1】:

    我不认为你可以通过直接将 input 映射到 output 并带有一些 weightbias 来真正“解决”XOR 。它们之间至少需要一个隐藏层(至少有两个节点)。

    【讨论】:

    • 我会说,它试图做到这一点。 XOR 不是一个线性问题,我们可以在输入和输出之间没有隐藏层的情况下解决。我们只能在没有任何隐藏层的情况下解决 OR、AND 和 NOT。但是,我们肯定需要一个隐藏层来执行 XOR、XNOR 等。XOR 的数据点之间没有平面分离,这就是为什么你需要一个隐藏层来引入所需的非线性。 This 答案用一张漂亮的图表解释了它。
    • 我以为我正在这样做。第一层是h1,第二层也是最后一层是z。 “尝试这样做”是什么意思?
    • 你只有一个权重和一个偏差。假设是 W 和 B。所以,您的代码正在做的是 y = Input * W + B。但是,要实现 XOR,您至少需要:h1 = sigmoid(Input * W1 + B1) h2 = sigmoid(Input * W2 + B2) y = sigmoid([h1 h2] * W + B),或者,在 CNTK 中,只需:model = Sequential([ Dense(2), Dense(1) ]) * 当然需要适当的缩放和激活。
    • @Vasco 抱歉,我的浏览器没有加载完整的代码。我现在看到您正在使用这些功能创建隐藏层。对评论风暴感到抱歉。 :P
    【解决方案2】:

    scale=10 的四个实例更改为scale=1 似乎可以修复脚本。

    我没有进行任何其他更改,并且能够连续运行几次,并通过 2000 次迭代获得了不错的结果。当然,增加迭代次数(例如 20,000 次或更多)会产生更好的结果。

    初始权重的 -10 到 10 的原始范围可能导致偶尔非常大的权重会使某些神经元饱和并干扰训练。贪婪的学习率可能会进一步加剧这种影响。

    与当前的深度网络趋势相比,XOR 网络非常稀疏。一些饱和的神经元可能更难锁定深度网络的训练 - 但也许并非不可能。

    我似乎记得在过去的日子里,我们经常将初始权重设置为相对较小并且分布在零附近。不知道理论家现在推荐什么。

    【讨论】:

    • 也许一些输出有助于理解seems to fix the script,有点像之前/之后。我觉得使用的库版本可能会对输出产生影响。
    • 好的,我添加了输出。还使用最新的 cntk 2.6 版进行了测试。
    【解决方案3】:

    运行第一张海报提供的脚本总是会产生与此类似的结果(此处仅给出结果的尾部)- 这是之前的结果。:

    ...
    Minibatch: 1900, Loss: 0.1266, Error: 0.13
    Minibatch: 1950, Loss: 0.1266, Error: 0.13
      query  test      pred
    0    11     0  0.501515
    1    00     0  0.037678
    2    10     1  0.497704
    3    01     1  0.966931
    

    我只是重新运行了几次,结果相似。 即使将迭代次数增加到 20,000 次也会得到类似的结果。最初构成的这个脚本似乎没有为 XOR 问题提供可行的解决方案。网络的训练不收敛到异或真值表,误差和损失也不收敛到零。

    scale=10 的 4 个实例更改为 scale=1 似乎总是为 XOR 问题提供可行的解决方案。典型结果如下。这是之后。

    ...
    Minibatch: 1900, Loss: 0.0129, Error: 0.01
    Minibatch: 1950, Loss: 0.0119, Error: 0.01
      query  test      pred
    0    11     0  0.115509
    1    00     0  0.084174
    2    10     1  0.891398
    3    01     1  0.890891
    

    多次重新运行会产生类似的结果。训练似乎收敛于 XOR 真值表,误差和损失收敛于零。 将迭代次数增加到 20,000 次会产生以下典型结果。训练现在产生了一个可行的 XOR 解决方案,并且脚本似乎是“固定的”。

    ...
    Minibatch: 19900, Loss: 0.0003, Error: 0.00
    Minibatch: 19950, Loss: 0.0003, Error: 0.00
      query  test      pred
    0    11     0  0.017013
    1    00     0  0.015626
    2    10     1  0.982118
    3    01     1  0.982083
    

    更准确地说,提议的脚本更改可能会修复用于设置权重初始条件的方法。我对 CNTK 还很陌生,所以我不知道使用 scale=10 的效果如何。由于我为 CNTK 程序找到的大多数示例都是针对深度网络类型的问题,因此我怀疑使用 scale=10 设置权重初始条件可能与大多数常见的问题解决方案有关,仅发布在网络上。

    最后,在这些测试过程中,我系统上的库没有任何更改(安装或更新)。因此,关于库版本存在问题的断言似乎没有事实依据。

    【讨论】:

    • 有趣。在不改变迭代时间的情况下,它在 5 次尝试中成功了 3 次,而增加迭代次数在 5 次尝试中成功了 5 次。
    【解决方案4】:

    我能够通过添加更多隐藏层来提高稳定性 h1 = dense_layer(feature, 5, sigmoid,scale=10) 并将学习率提高到 learning_rate = 0.8

    这提高了稳定性,但它仍然不时出错。此外,将损失修改为二进制交叉熵loss = binary_cross_entropy(z,label) 大大提高了正确处理的机会。

    之前:

    Minibatch: 1900, Loss: 0.1272, Error: 0.13
    Minibatch: 1950, Loss: 0.1272, Error: 0.13
      query  test      pred
    0    11     0  0.502307
    1    00     0  0.043964
    2    10     1  0.951571
    3    01     1  0.498055
    

    之后:

    Minibatch: 1900, Loss: 0.0041, Error: 0.00
    Minibatch: 1950, Loss: 0.0040, Error: 0.00
      query  test      pred
    0    11     0  0.006617
    1    00     0  0.000529
    2    10     1  0.997219
    3    01     1  0.994183
    

    还按照Davi 的建议将比例从 10 修改为 1,从而提高了收敛速度:

    10 级:

    Minibatch: 1300, Loss: 0.0732, Error: 0.01
    Minibatch: 1350, Loss: 0.0483, Error: 0.00
    

    比例 1:

    Minibatch: 500, Loss: 0.0875, Error: 0.01
    Minibatch: 550, Loss: 0.0639, Error: 0.00
    

    总之,需要的是:

    1. 将比例从 10 更改为 1(对于稳定的求解器,它需要大量迭代)
    2. 从 2 到 5 添加更多隐藏层(克服来自 scale = 10 但偶尔需要更多迭代的问题)
    3. 将损失函数从 squared_error 修改为 binary_cross_entropy(收敛速度更快,即更有效地搜索正确的权重)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-12
      • 2018-03-06
      • 2011-01-21
      • 1970-01-01
      • 2016-01-01
      • 2013-10-10
      • 2011-07-25
      • 1970-01-01
      相关资源
      最近更新 更多