我是TensorFlow和数据科学的新手。我做了一个简单的模块,应该弄清楚输入和输出数字之间的关系。在这种情况下,x和x平方。 Python中的代码:
import numpy as np
import tensorflow as tf
# TensorFlow only log error messages.
tf.logging.set_verbosity(tf.logging.ERROR)
features = np.array([-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10], dtype = float)
labels = np.array([100, 81, 64, 49, 36, 25, 16, 9, 4, 1, 0, 1, 4, 9, 16, 25, 36, 49, 64,
81, 100], dtype = float)
model = tf.keras.Sequential([
tf.keras.layers.Dense(units = 1, input_shape = [1])
])
model.compile(loss = "mean_squared_error", optimizer = tf.keras.optimizers.Adam(0.0001))
model.fit(features, labels, epochs = 50000, verbose = False)
print(model.predict([4, 11, 20]))
我尝试了不同数量的单位,并添加了更多层,甚至使用了relu
激活功能,但结果始终是错误的。
它可以与其他关系(例如x和2x)一起使用。 这是什么问题?
答案 0 :(得分:7)
问题在于x*x
是与a*x
完全不同的野兽。
请注意通常的“神经网络”的作用:它堆叠y = f(W*x + b)
几次,而不会与其自身相乘x
。因此,您将永远无法完美重构x*x
。除非您设置f(x) = x*x
或类似的内容。
您可以得到的是训练期间显示的值范围的近似值(也许是一点点外推)。无论如何,我建议您使用较小的值范围,这将更容易优化问题。
还有一个哲学上的注释:在机器学习中,我认为思考好/不好而不是正确/错误是有用的。尤其是对于回归,除非您拥有精确的模型,否则您将无法获得“正确”的结果。在这种情况下,没有什么可学的。
实际上有一些NN体系结构将f(x)
与g(x)
相乘,最著名的是LSTMs和Highway networks。但是,即使这些对象受f(x)
,g(s)
约束(由逻辑S形或tanh约束)中的一个或两个,因此也无法完全建模x*x
。
由于评论中表达了一些误解,所以让我强调几点:
作为示例,这是一个模型的结果,该模型具有10个具有tanh激活的单层隐藏层,该模型由SGD用学习速率1e-3进行15k迭代训练,以最小化数据的MSE。五次最佳:
这是再现结果的完整代码。不幸的是,我无法在当前环境中安装Keras / TF,但希望PyTorch代码可访问:-)
#!/usr/bin/env python
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
X = torch.tensor([range(-10,11)]).float().view(-1, 1)
Y = X*X
model = nn.Sequential(
nn.Linear(1, 10),
nn.Tanh(),
nn.Linear(10, 1)
)
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
loss_func = nn.MSELoss()
for _ in range(15000):
optimizer.zero_grad()
pred = model(X)
loss = loss_func(pred, Y)
loss.backward()
optimizer.step()
x = torch.linspace(-12, 12, steps=200).view(-1, 1)
y = model(x)
f = x*x
plt.plot(x.detach().view(-1).numpy(), y.detach().view(-1).numpy(), 'r.', linestyle='None')
plt.plot(x.detach().view(-1).numpy(), f.detach().view(-1).numpy(), 'b')
plt.show()
答案 1 :(得分:3)
您犯了两个非常基本的错误:
当然可以理解,神经网络要解决问题就必须具有某种复杂性,即使它们像x*x
一样简单。而当它们充满了大型训练数据集时,它们真正发挥作用的地方。
尝试求解此类函数逼近的方法不仅是列出(很少)可能的输入,然后将其与所需的输出一起输入模型中;请记住,NN是通过示例而不是通过符号推理来学习的。例子越多越好。在类似情况下,我们通常要做的是生成大量示例,然后将它们提供给模型进行训练。
已经说过,这是Keras中一个三层神经网络的简单演示,它使用x*x
中生成的10,000个随机数作为输入来逼近函数[-50, 50]
:
import numpy as np
import keras
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adam
from keras import regularizers
import matplotlib.pyplot as plt
model = Sequential()
model.add(Dense(8, activation='relu', kernel_regularizer=regularizers.l2(0.001), input_shape = (1,)))
model.add(Dense(8, activation='relu', kernel_regularizer=regularizers.l2(0.001)))
model.add(Dense(1))
model.compile(optimizer=Adam(),loss='mse')
# generate 10,000 random numbers in [-50, 50], along with their squares
x = np.random.random((10000,1))*100-50
y = x**2
# fit the model, keeping 2,000 samples as validation set
hist = model.fit(x,y,validation_split=0.2,
epochs= 15000,
batch_size=256)
# check some predictions:
print(model.predict([4, -4, 11, 20, 8, -5]))
# result:
[[ 16.633354]
[ 15.031291]
[121.26833 ]
[397.78638 ]
[ 65.70035 ]
[ 27.040245]]
嗯,还不错!请记住,NN是函数逼近器:我们不应该期望它们既不能精确地再现函数关系,也不能“知道” 4
和{{1 }}应该相同。
让我们在-4
中生成一些新的随机数据(记住,出于所有实际目的,这些都是该模型的 unemeen 数据),并将它们与原始数据一起绘制以得到更一般的图片:
[-50,50]
结果:
嗯,可以说确实确实是一个很好的近似...
您也可以查看this thread来得到正弦近似值。
最后要记住的一点是,尽管即使使用相对简单的模型也能获得不错的近似值,但我们不应该期望的是外推。在plt.figure(figsize=(14,5))
plt.subplot(1,2,1)
p = np.random.random((1000,1))*100-50 # new random data in [-50, 50]
plt.plot(p,model.predict(p), '.')
plt.xlabel('x')
plt.ylabel('prediction')
plt.title('Predictions on NEW data in [-50,50]')
plt.subplot(1,2,2)
plt.xlabel('x')
plt.ylabel('y')
plt.plot(x,y,'.')
plt.title('Original data')
之外表现出色;有关详细信息,请参见我在Is deep learning bad at fitting simple non linear functions outside training scope?