【问题标题】:How to predict on new data using a trained and saved Feedforward NN如何使用经过训练和保存的前馈神经网络预测新数据
【发布时间】:2021-01-14 00:20:29
【问题描述】:

我正在尝试使用经过训练和保存的模型对新数据进行预测。我的新数据与用于构建已保存模型的数据的形状不同。

我尝试过使用 model.save() 和 model.save_weights(),因为我仍然想保留训练配置,但它们都会产生相同的错误。

有没有办法在新数据上使用保存的模型,即使形状不同?

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Activation, Dense

model = Sequential([
    Dense(units=11, activation='relu', input_shape = (42,), kernel_regularizer=keras.regularizers.l2(0.001)),
    Dense(units=1, activation='sigmoid')
])

new_model.load_weights('Fin_weights.h5')

y_pred = new_model.predict(X)
ValueError: Error when checking input: expected dense_6_input to have shape (44,) but got array with shape (42,)

【问题讨论】:

  • 顺便说一句,我今天才知道你也可以为keras训练提供类权重,像这样model.fit(X_train, Y_train, class_weight = {0: 0.3, 1: 0.7})这是有两个标签时的情况,标签030%数据集和170%。然后你不需要复制你的数据集条目来实现平衡的类集,就像我之前说的那样。
  • 感谢您分享@Arty!我一定会记住这一点。有趣的是你提到了权重,我实际上很好奇是否有办法只查看模型中权重最高的输入。我很想知道哪些输入对模型的输出贡献最大。有办法吗?
  • 刚刚创建了代码并发布到this old chat,还有算法描述。
  • 受您有趣的新任务的启发,我实现了非常快速的通用函数来解决按元素频率顺序对任何数组进行排序的任务,here is my solution。如果上述新任务需要速度(可能不需要),那么您也可以使用我的新通用函数。
  • 哦,哇,从没想过会这样。谢谢你。问题:(参考您的第一个解决方案)代替“a”,我会使用 X_train 作为我的数组还是模型的保存权重?我实际上尝试过使用 X_train ,结果一团糟。再说一次,我认为使用 X_train 没有意义,因为它只是我没有权重的输入?

标签: python tensorflow machine-learning keras neural-network


【解决方案1】:

不,您必须完全匹配相同的输入形状。

您的模型代码(model = Sequential([... 行)应与您保存的模型完全对应,并且您的输入数据(y_pred = new_model.predict(X) 行中的X)应与保存的模型('Fin_weights.h5')中的形状相同。

您唯一能做的就是以某种方式填充您的新数据,例如零。但这只有在其余值对应相同的特征或信号时才有帮助。

例如,假设您正在训练 NN 来识别形状为 (2, 3) 的灰色图像,如下所示:

1 2 3
4 5 6

然后您训练模型并将其保存以供以后使用。之后你决定要在更小或更大尺寸的图像上使用你的神经网络,像这样

1 2
3 4

或者这个

1  2  3  4
5  6  7  8
9 10 11 12

而且您几乎可以肯定,您的 NN 在不同形状的输入上仍然会产生良好的结果。

然后你只需像这样在右边用额外的零填充第一个不匹配的图像:

1 2 0
3 4 0

或另一种填充方式,在左侧

0 1 2
0 3 4

第二张图片你剪了一点

1  2  3
5  6  7

(或从其他方面切)。

只有这样你才能将你的神经网络应用到这个处理过的输入图像上。

在您的情况下,您必须添加两个零。但前提是它是几乎相同的编码输入信号或特征序列。

如果您的预测数据大小错误,请执行以下操作:

y_pred = new_model.predict(
    np.pad(X, ((0, 0), (0, 2)))
)

这会在右侧用两个零填充您的数据,尽管您可能希望在左侧((2, 0) 而不是 (0, 2))或两侧((1, 1) 而不是 (0, 2))填充它。

如果您保存的权重形状不同,该模型的代码在模型代码中执行此操作(更改 42 --> 44):

model = Sequential([
    Dense(units=11, activation='relu', input_shape = (44,), kernel_regularizer=keras.regularizers.l2(0.001)),
    Dense(units=1, activation='sigmoid')
])

您可能应该同时执行上述两项操作,以匹配您保存的模型/权重。

如果针对 44 数字的输入进行训练的 NN 对于 42 数据的任何填充都会给出完全错误的结果,那么唯一的方法是针对 42 输入重新训练您的 NN 并再次保存模型。

但是你必须考虑到 keras 库中的 input_shape = (44,) 实际上意味着输入到 model.predict(X) 的最终数据 X 应该是二维形状,如 (10, 44)(其中 10 是您的NN要识别的不同对象的数量),keras隐藏了第0维,即所谓的批量维。批次 (0-th) 维度实际上可以变化,您可以输入 5 个对象(即形状数组 (5, 44))或 7 个(形状 (7, 44))或任何其他数量的对象。批处理仅意味着 keras 在一次调用中并行处理多个对象,只是为了快速/高效。但是每个单个对象都是形状为(44,) 的一维子数组。可能您对数据如何馈送到网络和表示的方式有误解。 44 不是数据集的大小(对象数),它是单个对象的特征数,例如如果网络识别/分类一个人,那么 44 可能意味着只有一个人的 44 个特征,例如年龄、性别、身高、体重、出生月份、种族、肤色、每天的呼叫次数、月收入、月支出、薪水、等共 44 个不同的固定特征的 1 个人体对象。他们可能不会改变。但是,如果您获得的其他数据仅具有 4236 特征,而您只需将 0 恰好放置在 44 中缺失的特征位置,则用零填充是不正确的在右侧或左侧,您必须将0s 准确地放置在44 中缺少的位置。

但是您的 44 和 42 和 36 可能意味着不同输入对象的数量,每个对象都只有 1 特征。想象一个任务,当你有一个 50 人类的数据集(表)只有两列数据 salarycountry 然后你可能想要构建 NN 猜测 countrysalary 然后你会有input_shape = (1,)(对应于 1 个数字的一​​维数组 - salary),但绝对不是 input_shape = (50,)(表中的人数)。 input_shape 仅表示 1 个物体的形状,1 个人类。 50 是对象(人)的数量,它是用于预测的 numpy 数组中的批次(第 0 个)维度,因此 model.predict(X)X 数组的形状为 (50, 1),但 @987654371 @在模型中。基本上 keras 省略(隐藏)第 0 个批次维度。如果 44 在您的情况下实际上是指数据集大小(对象数),那么您错误地训练了 NN,应该使用 input_shape = (1,) 重新训练它,44 作为批处理维度,而这个 44 可能会有所不同关于训练或测试数据集的大小。

如果你要重新训练你的网络,那么整个训练/评估过程的简单形式如下:

  1. 假设您在 CSV 文件 data.csv 中有一个数据集。例如,您总共有 126 行和 17 列。

  2. 以某种方式读入您的数据,例如通过np.loadtxtpd.read_csv 或通过标准python 的csv.reader()。将数据转换为数字(浮点数)。

  3. 将您的数据按行随机分成两部分training/evaluation,大致对应行的大小90%/10%,例如110 行用于训练,16 行用于评估(总共 126 行)。

  4. 确定要预测数据中的哪些列,您可以预测任意数量的列,假设我们要预测两列,第 16 列和第 17 列。现在您的数据列分为两部分 X(15 列,编号 1-15)和 Y(2 列,编号 16-17)。

  5. 在您的网络层代码中,在第一层设置input_shape = (15,)(15 是X 中的列数),在最后一层设置Dense(2)(2 是Y 中的列数)。

  6. 使用model.fit(X, Y, epochs = 1000, ...) 方法在训练数据集上训练您的网络。

  7. 通过model.save(...)将训练好的网络保存到模型文件到net.h5这样的文件中。

  8. 通过model.load(...)加载您的网络。

  9. 通过predicted_Y = model.predict(testing_X)测试网络质量,与testing_Y比较,如果网络模型选择正确,那么testing_Y应该接近predicted_Y,例如80% 正确(这个比例叫做准确率)。

  10. 我们为什么要将数据集拆分为训练/测试部分。因为训练阶段只看到训练数据集子部分。网络训练的任务是很好地记住整个训练数据,并通过在XY 之间找到一些隐藏的依赖关系来泛化预测。因此,如果在训练数据上调用model.predict(...) 应该接近100% 准确度,因为网络会看到所有这些训练数据并记住它。但是它根本看不到测试数据,因此需要聪明并真正通过 X 预测测试 Y,因此测试的准确性较低,例如80%.

  11. 如果测试结果的质量不是很好,你必须改进你的网络架构并从头开始重新运行整个训练过程。

  12. 如果您需要预测部分数据,例如当您的X 数据中只有 15 个可能的列中的 12 个时,然后用零填充缺失的列值,例如如果您缺少第 7 列和第 11 列,则在第 7 和第 11 位插入零。这样总列数又是 15。您的网络将仅支持在 model.predict() 的输入中与训练时使用的列数完全相同,即 15,此数字在 input_shape = (15,) 中提供。

【讨论】:

猜你喜欢
  • 2017-09-01
  • 2015-06-04
  • 1970-01-01
  • 2016-12-16
  • 2016-12-06
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多