用 keras 前馈神经网络预测鼻窦

数据挖掘 张量流 喀拉斯
2022-03-01 12:32:02

我有一个非常简单的带有 keras 的前馈神经网络,它应该学习一个窦。为什么预测能力如此糟糕?通常来说,查明网络问题的最佳方法是什么?

在下面的代码中,我有一个输入神经元,隐藏层中有 10 个,还有一个输出。我希望网络能够更准确地执行。

import numpy as np
from keras.layers import Dense, Activation
from keras.models import Sequential

x = np.arange(100)
y = np.sin(x)

model = Sequential([
    Dense(10, input_shape=(1,)),
    Activation('sigmoid'),
    Dense(1),
    Activation('sigmoid')
])

model.compile(loss='mean_squared_error', optimizer='SGD', metrics=['accuracy'])
model.fit(x, y, epochs=10, batch_size=1)

scores = model.evaluate(x, y, verbose=0)
print("Baseline Error: %.2f%%" % (100-scores[1]*100))

print(model.predict(np.array([.5])))

输出:

  1/100 [..............................] - ETA: 0s - loss: 1.2016 - acc: 0.0000e+00
 79/100 [======================>.......] - ETA: 0s - loss: 0.4665 - acc: 0.0127    
100/100 [==============================] - 0s - loss: 0.5044 - acc: 0.0100     
Baseline Error: 99.00%
[[ 0.35267803]]
3个回答

请记住,准确度度量是测量值是否完全相同即它是一种分类测量,而近似正弦曲线更适合作为回归问题的测量。

那说:

在评估网络的性能时,网络实际上在做什么?让我们以网络为例,对其性能进行一点可视化分析:

import matplotlib.pyplot as plt
preds = model.predict(x)
plt.plot(x, y, 'b', x, preds, 'r--')
plt.ylabel('Y / Predicted Value')
plt.xlabel('X Value')
plt.show()

在此处输入图像描述

唔。该模型似乎通过简单地越来越接近猜测每个值的 0 来最小化错误,而不是逼近函数。这里有几个假设来解释这一点。一是网络不够复杂,无法对函数进行建模。为了测试这一点,让我们简化函数——也就是说,让我们将范围缩小到一个正弦周期:

x = np.arange(0, math.pi*2, 0.1)
y = np.sin(x)

并尝试再次训练网络:

在此处输入图像描述

不是很好,但更合适,当然。

100 个 epoch而不是 10 个呢?

在此处输入图像描述

1000 epochs怎么样?

在此处输入图像描述

当然,这是非常有趣的。在 1000 个 epoch 之后,我们的网络能够大致逼近从 1:0 开始的下降曲线(π/2π) 的正弦响应,但不是初始向上曲线 0:1 (0:π/2) 或函数为负的区域 (π2π)。

这个结果引出了一个问题——在10000 个 epoch之后它会是什么样子

在此处输入图像描述

没有明显好转。看起来我们将不得不改变网络的架构(更多的层、更多的神经元和/或不同的激活函数)以改进这一点。

为了了解这种架构变化,让我们看一下 sigmoid 激活函数:

在此处输入图像描述

哦哦。这个 sigmoid 函数的值只能在 0:1 范围内,而 sin 函数的范围是 -1:1。

为了纠正这个问题,让我们在 0 和 1 之间标准化 sin 响应:

y = (np.sin(x)+1)/2 

现在,在 1000 个 epoch 之后,网络的性能比以前好得多:

在此处输入图像描述

和 10000:

在此处输入图像描述

在 100000 个 epoch 之后,它大致完美:

在此处输入图像描述

即便如此,这种进步对更大的 sin 范围(在 1000 个 epoch 之后)并没有太大帮助:

x = np.arange(0, 100, 1)
y = (np.sin(x)+1)/2 

在此处输入图像描述

但是,如果我们采用在单个 sin 曲线上训练的模型并在更大范围内进一步训练它,我们会在 1000 个 epoch 后开始看到进步:

x = np.arange(0, 100, .1)
y = (np.sin(x)+1)/2 

model_copy = model
model_copy.fit(x, y, epochs=1000, batch_size=8, verbose=0)
model_copy_preds = model_copy.predict(x)

在此处输入图像描述

在 10000 个 epoch 之后更是如此:在此处输入图像描述

更重要的是,在 100000 个 epoch 之后进入第三次重复:

在此处输入图像描述

因此,经过仔细的训练,我们具有单层 sigmoid 激活的网络似乎正在学习泛化 sin 曲线。当然,进一步的调查可能会发现这种概括的限制。

对于复制:

import numpy as np
from keras.layers import Dense
from keras.models import Sequential
import matplotlib.pyplot as plt
import math

x = np.arange(0, math.pi*2, .1)
y = (np.sin(x)+1)/2 

model = Sequential([
    Dense(10, input_shape=(1,)),
    Activation('sigmoid'),
    Dense(1)
])

model.compile(loss='mean_squared_error', optimizer='SGD', metrics=['mean_squared_error'])
model.fit(x, y, epochs=100000, batch_size=8, verbose=0)

preds = model.predict(x)

plt.plot(x, y, 'b', x, preds, 'r--')
plt.ylabel('Y / Predicted Value')
plt.xlabel('X Value')
plt.show()

x = np.arange(0, 100, .1)
y = (np.sin(x)+1)/2 

model_copy = model
model_copy.fit(x, y, epochs=10000, batch_size=8, verbose=0)
model_copy_preds = model_copy.predict(x)

plt.plot(x, y, 'b', x, model_copy_preds, 'r--')
plt.ylabel('Y / Predicted Value')
plt.xlabel('X Value')
plt.show()

准确性是用于分类问题的指标,请查看均方误差。您的网络对于您想要学习的高度波动的函数来说太小了,如果您将 x 除以较小的数量,它会更容易学习。其次,添加另一层并在最后进行身份激活将有很大帮助。同样采用大于 1 的批次将使梯度更稳定。使用 1000 个 epoch,我得到 0.00167 作为均方误差。

x = np.arange(200).reshape(-1,1) / 50
y = np.sin(x)

model = Sequential([
Dense(40, input_shape=(1,)),
Activation('sigmoid'),
Dense(12),
Activation('sigmoid'),
Dense(1)
    ])

model.compile(loss='mean_squared_error', optimizer='SGD', metrics=['mean_squared_error'])

for i in range(40):
    model.fit(x, y, nb_epoch=25, batch_size=8, verbose=0)
    predictions = model.predict(x)
    print(np.mean(np.square(predictions - y)))

最大的问题是你原来的小数据集中的信号很难学习,你可以在绘制它时看到这一点,它只会崩溃到平均值。

我的代码...

from keras.models import Sequential
from keras.layers import Dense
import numpy as np
import matplotlib.pylab as plt

# Create dataset
x = np.arange(0, np.pi * 2, 0.1)
y = np.sin(x)

# Some parameters
ACTIVE_FUN = 'tanh'
BATCH_SIZE = 1
VERBOSE=0

# Create the model
model = Sequential()
model.add(Dense(5, input_shape=(1,), activation=ACTIVE_FUN))
model.add(Dense(5, activation=ACTIVE_FUN))
model.add(Dense(1, activation='linear'))

# Compile the model
model.compile(loss='mean_squared_error', optimizer='sgd', metrics=['mean_squared_error'])

# Fit the model
model.fit(x, y, epochs=1000, batch_size=BATCH_SIZE, verbose=VERBOSE)

# Evaluate the model
scores = model.evaluate(x, y, verbose=VERBOSE)
print('%s: %.2f%%' % (model.metrics_names[1], scores[1] * 100))

# Make predictions
y_pred = model.predict(x)

# Plot
plt.plot(x, y, color='blue', linewidth=1, markersize='1')
plt.plot(x, y_pred, color='green', linewidth=1, markersize='1')
plt.xlabel('Angle [rad]')
plt.ylabel('sin(x)')
plt.axis('tight')
plt.show()