我用cntk(python)实现了“xor问题”。
目前它只是偶尔解决问题。我怎样才能实现更可靠的网络?
我猜想只要起始随机权重接近最优,问题就会得到解决。我已经尝试过binary_cross_entropy
作为损失功能,但它没有改善。我尝试使用tanh
作为非线性函数,但它也没有用。我也尝试了许多不同的参数组合learning_rate
,minibatch_size
和num_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"))
我不认为你可以通过直接将输入映射到具有一定重量和偏差的输出来“解决”XOR。您将需要至少一个隐藏层(至少有两个节点)。
将scale=10
的四个实例更改为scale=1
似乎可以修复脚本。
我没有做任何其他更改,并且能够连续几次运行它并且在2000次迭代中获得了不错的结果。当然,增加迭代(例如20,000或更多)会产生更好的结果。
初始重量的初始范围-10到10可能允许偶尔非常大的重量使一些神经元饱和并干扰训练。贪婪的学习率可能会进一步加剧这种影响。
与目前的深网趋势相比,XOR网络相当稀少。一些饱和神经元可能更难锁定深网的训练 - 但也许并非不可能。
在昔日的日子里,我似乎记得我们经常将初始权重设置得相对较小并且分布在零附近。不确定理论家现在推荐的是什么。
运行第一张海报提供的脚本总会产生类似于此的结果(这里只给出结果的尾端) - 这是之前的:
...
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问题的可行解决方案。网络的训练不会收敛到XOR真值表,并且误差和损失不会收敛到零。
将4个scale = 10的实例更改为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设置权重初始条件可能与这些问题解决方案有关,大多数通信只发布在网上。
最后,在这些测试过程中,我的系统上的库中没有更改(安装或更新)。所以关于库版本存在问题的断言似乎没有事实根据。
通过添加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
总之,需要的是:
scale = 10
但偶尔需要更多迭代的问题)squared_error
到binary_cross_entropy
的损失函数(收敛速度更快,即在搜索正确的权重时效率更高)