什么时候需要手动提取特征以输入神经网络而不是提供原始数据?

人工智能 神经网络 深度学习 特征提取 特征 特征工程
2021-11-10 10:01:32

通常,神经网络使用原始数据。您不需要手动提取特征。NN 可以找到并提取良好的特征,即图像、信号或任何类型的数据的模式。当我们检查 NN 中的层输出时,我们可以看到和可视化 NN 如何提取特征。

神经网络每次都自己提取特征吗?什么时候需要手动提取或设计特征以输入神经网络而不是提供原始数据?

例如,我有一个时间序列传感器数据。当我在原始数据集上使用 LSTM 和 GRU 时,我的测试准确度很差,但是当我手动提取一些特征时,我得到了非常好的测试集准确度结果。我提取了快速傅里叶变换、互相关特征,这对提高准确性有很大帮助。“手动提取特征”帮助解决了我的问题。

2个回答

是的,神经网络自己学习特征,使您无需手动设计它们。我将在这里用一个玩具问题来说明它。

假设我们想学习建立在向量对上的平行四边形的面积:在此处输入图像描述

输入数据是六个坐标:(x1,y1,x2,y2,x3,y3).

import numpy as np

n_tr = 1000 # training data
x_tr = np.random.uniform(low=-1.0, high=1.0, size=(n_tr, 6))

n_ts = 100 # test data                                        
x_ts = np.random.uniform(low=-1.0, high=1.0, size=(n_ts, 6)) 

目标(区域)是y=|adbc|, 在哪里a=x3x1,b=y3y1,c=x2x1,d=y2y1.

a_tr = x_tr[:,4] - x_tr[:,0] # x_3 - x_1
b_tr = x_tr[:,5] - x_tr[:,1] # y_3 - y_1
c_tr = x_tr[:,2] - x_tr[:,0] # x_2 - x_1
d_tr = x_tr[:,3] - x_tr[:,1] # y_2 - y_1
y_tr = np.abs(a_tr*d_tr-b_tr*c_tr)

a_ts = x_ts[:,4] - x_ts[:,0] # x_3 - x_1
b_ts = x_ts[:,5] - x_ts[:,1] # y_3 - y_1
c_ts = x_ts[:,2] - x_ts[:,0] # x_2 - x_1
d_ts = x_ts[:,3] - x_ts[:,1] # y_2 - y_1
y_ts = np.abs(a_ts*d_ts-b_ts*c_ts)

要从坐标中学习区域,我将使用我最喜欢的机器学习库super_magic_learn

from super_magic_learn import wonder_network

wonder_network.init()

它将在神经元中初始化一个具有随机激活函数的网络,并且它们之间的随机连接具有随机权重。它还随机分配一些神经元作为输入,而其他输出或内部神经元。

在此处输入图像描述

然后我训练我的网络

wonder_network.fit(x_tr, y_tr, use_wand=True)

在训练过程中,神经元内部的激活函数发生变化,神经元之间的连接形成、消失、再形成,并调整它们的权重。一些神经元分层组织,每一层的神经元个数发生变化,最终训练出的网络如下:

在此处输入图像描述

它以 100% 的准确率解决了训练和测试数据的任务,并且仅使用原始数据:坐标来解决任务。无需设计功能。

但是,您可能无权访问该库super_magic_learn让我们看看我们可以用稍微劣质的东西做什么tensorflow

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential(
    [
        layers.Dense(64, activation="tanh", input_dim=6),
        layers.Dense(4, activation="tanh"),
        layers.Dense(1),
    ]
)

optimizer = tf.keras.optimizers.RMSprop(learning_rate=0.001)

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

model.fit(x_tr, y_tr, epochs=512, batch_size=64, validation_split = 0.2, verbose=1)
y_pr = model.predict(x_ts)

现在计算测试集的性能

from sklearn.metrics import r2_score
print('Rsq:', r2_score(y_ts,y_pr))

R2

Rsq: 0.4802872880495598

不好。如果我设计一些功能会发生什么?

让我们训练相同的模型,但不是用原始数据输入它,输入将是以下手动设计的特征:a=x3x1,b=y3y1,c=x2x1,d=y2y1(不要忘记input_dim=4在第一层进行更改)。

x_tr = np.c_[a_tr, b_tr, c_tr, d_tr]
x_ts = np.c_[a_ts, b_ts, c_ts, d_ts]

R2

Rsq: 0.8841499533897564

现在好多了。不过还不到100%。

为什么神经网络在tensorflow原始数据上表现不佳,需要特征工程,而super_magic_learn在原始数据上表现完美,不需要任何特征工程?

原因是那个tensorflow或我知道的任何其他图书馆都比我心爱的图书馆更受限制super_magic_learn限制如下(请注意一个非常小的问题:super_magic_learn不存在,但我希望它存在):

  • 您只有极少数的激活函数可供选择,例如 tanh、relu 和少数其他函数。
  • 激活函数在训练期间保持不变。你不能改变它们。
  • 您不能添加/删除图层。
  • 您无法更改层中的神经元数量。
  • 您不能添加/删除神经元之间的连接。
  • 你必须只分层组织你的神经元,不允许其他排列。
  • 在训练期间,网络无法学习到最适合该任务的架构。例如,考虑到问题的对称性,它不能重新组织自己。
  • 等等 ...
  • 基本上,您在训练期间唯一能做的就是学习权重。

教科书是对的:理想情况下,神经网络应该只从原始数据中学习。但这仅适用于我的理想化库,而不适用于现有的现实世界实现。

为了让网络真正学习任何任务的特征,它应该摆脱这些限制。

如果你对架构、激活函数和其他参数设置了如此多的限制,以至于在训练期间无法从数据中学习它们,那么你必须自己设计它们并为你的任务手动调整它们。如果您正确地设计它们,那么您的网络将从原始数据中愉快地学习。但它可能在其他任务上表现不佳。

卷积神经网络就是这种情况。它们的设计考虑了图像中特征的跨国等效性,这就是它们可以从原始图像数据中学习特征的原因。但是,它们不一定在其他领域表现良好。

当无法达到可接受的错误率时(在预算范围内或原则上),特征工程可能是必要的。

NN 可能由于信息瓶颈而停滞:鸽子太多,洞不够。在这种情况下,自定义功能可能会提供更好的信息压缩。(唉,这不是灵丹妙药:有些层可能仍然太窄。这就是为什么开始脂肪和后来修剪被认为更好,尽管并不总是负担得起。)

不是必需品,但不费吹灰之力:对底层流程有深入的了解是对特征工程的明确要求。比方说,很明显,已知的有意义的变换很难用(相当小的)子网络来近似:例如,周期性和非周期性函数之间的映射。

就我个人而言,在我的清单中,功能阶段与搜索领域专家的提醒相结合。在某些实际意义上,特征是从人而不是数据中提取的。我们的神经网络也很不错!