我有一段时间使用工具keras得到了相当糟糕的结果,并且对这个工具的怀疑并不多......但我现在开始有点担心了。
我试图看看它是否可以处理一个简单的XOR问题,并且在30000个时代之后它还没有解决它......
代码:
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.optimizers import SGD
import numpy as np
np.random.seed(100)
model = Sequential()
model.add(Dense(2, input_dim=2))
model.add(Activation('tanh'))
model.add(Dense(1, input_dim=2))
model.add(Activation('sigmoid'))
X = np.array([[0,0],[0,1],[1,0],[1,1]], "float32")
y = np.array([[0],[1],[1],[0]], "float32")
model.compile(loss='binary_crossentropy', optimizer='adam')
model.fit(X, y, nb_epoch=30000, batch_size=1,verbose=1)
print(model.predict_classes(X))
以下是我的结果的一部分:
4/4 [==============================] - 0s - loss: 0.3481
Epoch 29998/30000
4/4 [==============================] - 0s - loss: 0.3481
Epoch 29999/30000
4/4 [==============================] - 0s - loss: 0.3481
Epoch 30000/30000
4/4 [==============================] - 0s - loss: 0.3481
4/4 [==============================] - 0s
[[0]
[1]
[0]
[0]]
该工具是否有问题 - 或者我做错了什么?
我正在使用的版本:
MacBook-Pro:~ usr$ python -c "import keras; print keras.__version__"
Using TensorFlow backend.
2.0.3
MacBook-Pro:~ usr$ python -c "import tensorflow as tf; print tf.__version__"
1.0.1
MacBook-Pro:~ usr$ python -c "import numpy as np; print np.__version__"
1.12.0
更新版本:
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.optimizers import Adam, SGD
import numpy as np
#np.random.seed(100)
model = Sequential()
model.add(Dense(units = 2, input_dim=2, activation = 'relu'))
model.add(Dense(units = 1, activation = 'sigmoid'))
X = np.array([[0,0],[0,1],[1,0],[1,1]], "float32")
y = np.array([[0],[1],[1],[0]], "float32")
model.compile(loss='binary_crossentropy', optimizer='adam')
print model.summary()
model.fit(X, y, nb_epoch=5000, batch_size=4,verbose=1)
print(model.predict_classes(X))
答案 0 :(得分:2)
我不能对Daniel的回复添加评论,因为我没有足够的声誉,但我相信他是在正确的轨道上。虽然我没有亲自尝试使用Keras运行XOR,但这篇文章可能很有趣 - 它分析了2-2-1网络的局部最小区域,显示更高的数值精度会导致更少的卡住实例在梯度下降算法上。
另一方面,我不会考虑使用2-4-1网络来解决问题。在0-1平面上进行4次线性切割(切割成2x2网格)而不是2次切割(沿对角线切割角落)只是以不同方式分离数据,但由于我们只有4个数据点并且没有噪声数据,使用4个线性切割的神经网络不描述“噪声”而不是XOR关系。
答案 1 :(得分:1)
尝试使用relu
激活隐藏图层而不是tanh
,而不仅仅是增加时代数。只对您提供的代码进行更改,我只能在2000个时期(Theano后端)之后获得以下结果:
import numpy as np
print(np.__version__) #1.11.3
import keras
print(theano.__version__) # 0.9.0
import theano
print(keras.__version__) # 2.0.2
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.optimizers import Adam, SGD
np.random.seed(100)
model = Sequential()
model.add(Dense(units = 2, input_dim=2, activation = 'relu'))
model.add(Dense(units = 1, activation = 'sigmoid'))
X = np.array([[0,0],[0,1],[1,0],[1,1]], "float32")
y = np.array([[0],[1],[1],[0]], "float32")
model.compile(loss='binary_crossentropy', optimizer='adam'
model.fit(X, y, epochs=2000, batch_size=1,verbose=0)
print(model.evaluate(X,y))
print(model.predict_classes(X))
4/4 [==============================] - 0s
0.118175707757
4/4 [==============================] - 0s
[[0]
[1]
[1]
[0]]
很容易得出结论,这是由于vanishing gradient problem。但是,这个网络的简单性表明情况并非如此。实际上,如果我将优化器从'adam'
更改为SGD(lr=0.01, momentum=0.0, decay=0.0, nesterov=False)
(默认值),我可以在隐藏层中激活tanh
的5000个纪元后看到以下结果。
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.optimizers import Adam, SGD
np.random.seed(100)
model = Sequential()
model.add(Dense(units = 2, input_dim=2, activation = 'tanh'))
model.add(Dense(units = 1, activation = 'sigmoid'))
X = np.array([[0,0],[0,1],[1,0],[1,1]], "float32")
y = np.array([[0],[1],[1],[0]], "float32")
model.compile(loss='binary_crossentropy', optimizer=SGD())
model.fit(X, y, epochs=5000, batch_size=1,verbose=0)
print(model.evaluate(X,y))
print(model.predict_classes(X))
4/4 [==============================] - 0s
0.0314897596836
4/4 [==============================] - 0s
[[0]
[1]
[1]
[0]]
修改: 5/17/17 - 包含完整代码以启用复制
答案 2 :(得分:1)
我认为它在损失函数中是"本地最小值" 。
为什么?
我一遍又一遍地运行相同的代码几次,有时它是正确的,有时它会陷入错误的结果。请注意,此代码"重新创建"每次运行它时的模型。 (如果我坚持训练一个发现错误结果的模型,它将永远保存在那里)。
from keras.models import Sequential
from keras.layers import *
import numpy as np
m = Sequential()
m.add(Dense(2,input_dim=2, activation='tanh'))
#m.add(Activation('tanh'))
m.add(Dense(1,activation='sigmoid'))
#m.add(Activation('sigmoid'))
X = np.array([[0,0],[0,1],[1,0],[1,1]],'float32')
Y = np.array([[0],[1],[1],[0]],'float32')
m.compile(optimizer='adam',loss='binary_crossentropy')
m.fit(X,Y,batch_size=1,epochs=20000,verbose=0)
print(m.predict(X))
运行此代码,我发现了一些不同的输出:
我们可以从中得出什么结论?
优化器未正确处理此本地最小值。如果它变得幸运(适当的重量初始化),它将落在最低限度,并带来正确的结果。
如果它运气不好(一个糟糕的权重初始化),它将落在局部最小值,而不是真的知道损失函数中有更好的位置,并且其learn_rate不足以逃脱这个最小值。小渐变在同一点上转动。
如果你花时间研究哪个渐变出现在错误的情况下,你可能会看到它一直指向同一个点,并且稍微提高学习率可能会让它逃脱漏洞。
直觉让我觉得这种非常小的模型具有更突出的局部最小值。
答案 3 :(得分:0)
学习XOR所需的最小神经元网络体系结构,它应该是(2,2,1)网络。实际上,如果数学表明(2,2,1)网络可以解决XOR问题,但数学并不表明(2,2,1)网络易于训练。有时可能需要花费很多时间(迭代次数)或无法收敛到全局最小值。就是说,使用(2,3,1)或(2,4,1)网络体系结构,我很容易获得良好的结果。
问题似乎与许多局部极小值的存在有关。请看1998年Richard Bland的论文《 Learning XOR: exploring the space of a classic problem》。此外,权重初始化(随机数在0.5到1.0之间)有助于收敛。
它与Keras或TensorFlow一起使用损失函数'mean_squared_error',S型激活和Adam优化器可以正常工作。即使有了非常好的超参数,我也观察到学习到的XOR模型被困在局部最小值中的时间约为15%。
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
from tensorflow.keras import initializers
import numpy as np
X = np.array([[0,0],[0,1],[1,0],[1,1]])
y = np.array([[0],[1],[1],[0]])
def initialize_weights(shape, dtype=None):
return np.random.normal(loc = 0.75, scale = 1e-2, size = shape)
model = Sequential()
model.add(Dense(2,
activation='sigmoid',
kernel_initializer=initialize_weights,
input_dim=2))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='mean_squared_error',
optimizer='adam',
metrics=['accuracy'])
print("*** Training... ***")
model.fit(X, y, batch_size=4, epochs=10000, verbose=0)
print("*** Training done! ***")
print("*** Model prediction on [[0,0],[0,1],[1,0],[1,1]] ***")
print(model.predict_proba(X))
***培训... ***
***培训完成! ***
*** [[0,0],[0,1],[1,0],[1,1]] ***上的模型预测
[[0.08662204] [0.9235283] [0.92356336] [0.06672956]]