我正在学习Theano,并且构建了一个非常简单的学习XOR的神经网络。一个简单的问题应该很快就能学会。但我发现答案有时并不正确,而是出现了一种奇怪的特定错误。
我输入[[0,0],[1,0],[0,1],[1,1]]来测试XOR。我期望得到[0,1,1,0]的输出。确实,大约有一半的时间我得到了这样的结果。
[[ 0.01763905] [ 0.99207316] [ 0.99207316] [ 0.00663723]]
但其他时候我得到了一些组合,其中两个输出几乎正好是0.5,一个接近1,另一个接近0。如下所示,
[[ 0.49998723] [ 0.49998723] [ 0.99430759] [ 0.00622013]]
或者类似的情况如
[[ 0.49957245] [ 0.98064991] [ 0.49957245] [ 0.02422073]]
这是我的代码。如果我训练的方式有问题,请随时告诉我(因为我完全是猜测是否应该为每一层分别计算梯度)
import theanoimport theano.tensor as Timport numpy as npclass HiddenLayer(object): def __init__(self, input, layerShape): # Input should be matrix of size (batch size, input nodes) # Layer shape is (input nodes, hidden nodes) self.input = input self.W = theano.shared(np.random.normal(0,1,layerShape)) self.b = theano.shared(np.random.normal(0,1,layerShape[1])) self.output = T.nnet.nnet.relu(T.dot(self.input,self.W)+self.b) def train(self, cost, rate): WGrad = T.grad(cost=cost, wrt=self.W) bGrad = T.grad(cost=cost, wrt=self.b) return [[self.W, self.W - WGrad * rate], [self.b, self.b - bGrad * rate]]class OutputLayer(object): def __init__(self, input, layerShape): self.input = input self.W = theano.shared(np.random.normal(0,1,layerShape)) self.b = theano.shared(np.random.normal(0,1,layerShape[1])) self.output = T.nnet.nnet.sigmoid(T.dot(self.input,self.W)+self.b) def train(self, cost, rate): WGrad = T.grad(cost=cost, wrt=self.W) bGrad = T.grad(cost=cost, wrt=self.b) return [[self.W, self.W - WGrad * rate], [self.b, self.b - bGrad * rate]]class Model(object): def __init__(self, inputNodes, hiddenNodes, outputNodes, rate): self.x = T.matrix() self.y_ = T.matrix() hiddenLayer = HiddenLayer(self.x, (inputNodes, hiddenNodes)) outputLayer = OutputLayer(hiddenLayer.output, (hiddenNodes, outputNodes)) self.layers = [hiddenLayer, outputLayer] self.y = outputLayer.output self.train = self.buildTrainOp(rate) self.infer = self.buildInferenceOp() def buildTrainOp(self, rate): cost = T.mean(T.sqr(self.y - self.y_)) updates = [update for updates in [layer.train(cost, rate) for layer in self.layers] for update in updates] return theano.function(inputs=[self.x, self.y_], outputs=cost, updates=updates) def buildInferenceOp(self): return theano.function(inputs=[self.x], outputs=self.y)nn = Model(2, 3, 1, 0.05)print(nn.infer([[0,0],[1,0],[0,1],[1,1]]))xorTableX = [[0,0],[1,0],[0,1],[1,1]]xorTableY = [[i!=j] for i,j in xorTableX]for i in range(100000): batchX = xorTableX batchY = xorTableY nn.train(batchX, batchY)print(nn.infer([[0,0],[1,0],[0,1],[1,1]]))
如果你有关于使用Theano的好做法和惯例的建议,我也非常乐意听取。谢谢!
** 编辑:** 有趣的是,当我添加了第二个相同大小的隐藏层时,”错误”的输出变成了[0.5, 0.5, 0.5, 0.5]。但同样,我仍然大约有一半的时间得到正确输出。
回答:
天哪!这太明显了。这就是我为什么不应该在深夜编程的原因。
我将隐藏层的激活函数改成了ReLU,想看看这对神经网络有什么影响,但忘记改回Tanh了。显然ReLU不允许需要的负权重。