用 Python 从零开始创建神经网络(二十):模型评估

devtools/2025/1/17 11:36:04/

模型评估

  • 引言

引言

在第11章《测试或样本外数据》中,我们讨论了验证数据和测试数据之间的区别。对于目前的模型,我们在训练过程中进行了验证,但目前没有一个好的方法来对测试数据运行测试或进行预测。首先,我们将在Model类中添加一个新的evaluate方法:

python">    # Evaluates the model using passed in datasetdef evaluate(self, X_val, y_val, *, batch_size=None):

此方法接收样本( X v a l X_{val} Xval)、目标输出( y v a l y_{val} yval)以及一个可选的批次大小参数。首先,根据数据的长度和批次大小参数计算步骤数量。这与train方法中的计算方式相同:

python">        # Default value if batch size is not being setvalidation_steps = 1# Calculate number of stepsif batch_size is not None:validation_steps = len(X_val) // batch_size# Dividing rounds down. If there are some remaining# data, but not a full batch, this won't include it# Add `1` to include this not full batchif validation_steps * batch_size < len(X_val):validation_steps += 1

然后,我们将从Model类的train方法中移动一段代码。我们将这段代码以及用于计算步骤数量和重置累积损失与准确率的代码部分移动到evaluate方法中,使其变成:

python">    # Evaluates the model using passed in datasetdef evaluate(self, X_val, y_val, *, batch_size=None):# Default value if batch size is not being setvalidation_steps = 1# Calculate number of stepsif batch_size is not None:validation_steps = len(X_val) // batch_size# Dividing rounds down. If there are some remaining# data, but not a full batch, this won't include it# Add `1` to include this not full batchif validation_steps * batch_size < len(X_val):validation_steps += 1# Reset accumulated values in loss# and accuracy objectsself.loss.new_pass()self.accuracy.new_pass()# Iterate over stepsfor step in range(validation_steps):# If batch size is not set -# train using one step and full datasetif batch_size is None:batch_X = X_valbatch_y = y_val# Otherwise slice a batchelse:batch_X = X_val[step*batch_size:(step+1)*batch_size]batch_y = y_val[step*batch_size:(step+1)*batch_size]# Perform the forward passoutput = self.forward(batch_X, training=False)# Calculate the lossself.loss.calculate(output, batch_y)# Get predictions and calculate an accuracypredictions = self.output_layer_activation.predictions(output)self.accuracy.calculate(predictions, batch_y)# Get and print validation loss and accuracyvalidation_loss = self.loss.calculate_accumulated()validation_accuracy = self.accuracy.calculate_accumulated()# Print a summaryprint(f'validation, ' +f'acc: {validation_accuracy:.3f}, ' +f'loss: {validation_loss:.3f}')

现在,在Model类的train方法中原本放置那段代码的位置,我们可以调用新的evaluate方法:

python"># Model class
class Model:...# def train(self, X, y, *, epochs=1, print_every=1, validation_data=None):def train(self, X, y, *, epochs=1, batch_size=None, print_every=1, validation_data=None):......# If there is the validation dataif validation_data is not None:# Evaluate the model:self.evaluate(*validation_data, batch_size=batch_size)

如果你对*validation_data部分感到困惑,这里的星号(称为“解包表达式”)会将validation_data列表解包为单个值。以下是一个简单的示例,说明其工作原理:

python">a = (1, 2)def test(n1, n2):print(n1, n2)test(*a)
python">>>>
1 2

现在我们有了这个独立的evaluate方法,可以随时评估模型——无论是在训练期间还是按需评估,只需传入验证数据或测试数据即可。首先,我们像往常一样创建并训练一个模型:

python"># Create dataset
X, y, X_test, y_test = create_data_mnist('fashion_mnist_images')# Shuffle the training dataset
keys = np.array(range(X.shape[0]))
np.random.shuffle(keys)
X = X[keys]
y = y[keys]# Scale and reshape samples
X = (X.reshape(X.shape[0], -1).astype(np.float32) - 127.5) / 127.5
X_test = (X_test.reshape(X_test.shape[0], -1).astype(np.float32) - 127.5) / 127.5# Instantiate the model
model = Model()# Add layers
model.add(Layer_Dense(X.shape[1], 128))
model.add(Activation_ReLU())
model.add(Layer_Dense(128, 128))
model.add(Activation_ReLU())
model.add(Layer_Dense(128, 10))
model.add(Activation_Softmax())# Set loss, optimizer and accuracy objects
model.set(loss=Loss_CategoricalCrossentropy(),optimizer=Optimizer_Adam(decay=1e-3),accuracy=Accuracy_Categorical())# Finalize the model
model.finalize()# Train the model
model.train(X, y, validation_data=(X_test, y_test), epochs=10, batch_size=128, print_every=100)

然后我们可以添加代码来进行评估。目前,除了我们用于验证的数据之外,没有其他特定的测试数据,但现在我们可以使用这些数据来测试这个方法:

python">model.evaluate(X_test, y_test)

运行之后,我们得到:

python">>>>
...
epoch: 10
step: 0, acc: 0.906, loss: 0.198 (data_loss: 0.198, reg_loss: 0.000), lr: 0.0001915341888527102
step: 100, acc: 0.930, loss: 0.193 (data_loss: 0.193, reg_loss: 0.000), lr: 0.00018793459875963167
step: 200, acc: 0.922, loss: 0.175 (data_loss: 0.175, reg_loss: 0.000), lr: 0.00018446781036709093
step: 300, acc: 0.922, loss: 0.245 (data_loss: 0.245, reg_loss: 0.000), lr: 0.00018112660749864155
step: 400, acc: 0.898, loss: 0.303 (data_loss: 0.303, reg_loss: 0.000), lr: 0.00017790428749332856
step: 468, acc: 0.938, loss: 0.144 (data_loss: 0.144, reg_loss: 0.000), lr: 0.00017577781683951485
training, acc: 0.915, loss: 0.237 (data_loss: 0.237, reg_loss: 0.000), lr: 0.00017577781683951485
validation, acc: 0.881, loss: 0.334
validation, acc: 0.881, loss: 0.334

验证准确率和损失在末尾重复显示两次,并显示相同的值,因为我们在训练期间进行了验证,并在相同数据上立即进行了评估。通常,你会训练一个模型,调整其超参数,然后重新训练,依此类推,使用传递给训练方法的训练和验证数据。接着,当你找到表现最佳的模型和超参数时,你会将该模型应用于测试数据,并在将来用于生产环境中的预测。

接下来,我们还可以对训练数据进行评估:

python">model.evaluate(X, y)

运行之后打印结果:

python">>>>
validation, acc: 0.915, loss: 0.231

这里的“验证”是指我们对模型进行了评估,但这是使用训练数据完成的。我们将其与刚刚在这些数据上进行的训练结果进行比较:

python">training, acc: 0.915, loss: 0.237 (data_loss: 0.237, reg_loss: 0.000), lr: 0.00017577781683951485

你可能会注意到,尽管使用的是相同的数据集,但准确率和损失值之间仍存在一些差异。这种差异源于以下事实:模型打印的是训练轮次期间累积的准确率和损失,而此时模型仍在学习;因此,平均准确率和损失与训练结束后在训练数据上进行的评估结果有所不同。在训练过程结束时对训练数据运行评估将返回最终的准确率和损失。

在下一章中,我们将添加保存和加载模型的功能;同时,我们还将构建一种方法来获取和设置模型的参数。



本章的章节代码、更多资源和勘误表:https://nnfs.io/ch20


http://www.ppmy.cn/devtools/151263.html

相关文章

C#局部函数 VS Lambda表达式

一、引言 在 C# 的编程世界里&#xff0c;我们常常会遇到各种实现功能的方式&#xff0c;其中 Lambda 表达式和局部函数都是非常强大的特性。Lambda 表达式自诞生以来&#xff0c;凭借其简洁的语法和强大的功能&#xff0c;深受广大开发者的喜爱&#xff0c;尤其是在处理集合操…

springboot中创建自定义注解和AOP

一、自定义注解的创建 在 Java 中&#xff0c;自定义注解使用 interface 关键字来定义。例如&#xff0c;我们创建一个名为 LogExecutionTime 的自定义注解&#xff0c;用于标记需要记录执行时间的方法&#xff1a; import java.lang.annotation.ElementType; import java.lan…

[NOIP2007 提高组] 矩阵取数游戏

[NOIP2007 提高组] 矩阵取数游戏 显示标签 题目讨论 题目统计 全部提交 时间限制&#xff1a;C/C 1000MS&#xff0c;其他语言 2000MS 内存限制&#xff1a;C/C 256MB&#xff0c;其他语言 512MB 难度&#xff1a;提高/省选- 分数&#xff1a;100 描述 帅帅经常跟同学玩一…

【Sharding-JDBC学习】读写分离_shardjdbc5 不支持 shardingdatasource

8.读写分离 8.1 理解读写分离 面对日益增加的系统访问量&#xff0c;数据库的吞吐量面临着巨大瓶颈。 对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说&#xff0c;将数据库拆分为主库和从库&#xff0c;主库负责处理事务性的增删改操作&#xff0c;从库负责处理…

【计算机网络】lab8 DNS协议

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;计算机网络_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2.…

PyTorch框架——基于深度学习YOLOv11神经网络路面坑洞检测系统

基于深度学习YOLOv11神经网络路面坑洞检测系统&#xff0c;其能识别路面坑洞&#xff0c;见如下 第一步&#xff1a;YOLOv11介绍 YOLOv11是由Ultralytics公司开发的新一代目标检测算法&#xff0c;它在之前YOLO版本的基础上进行了显著的架构和训练方法改进。以下是YOLOv11的一…

带头双向循环链表(数据结构初阶)

文章目录 双向链表链表的分类概念与结构实现双向链表定义链表结构链表打印判空申请结点初始化头插尾插头删尾删查找指定位置插入和删除销毁链表 顺序表和链表的分析结语 欢迎大家来到我的博客&#xff0c;给生活来点impetus&#xff01;&#xff01; 这一节我们学习双向链表&a…

root后如何隐藏环境?

很多小伙伴在给手机root之后以为就大功告成啦&#xff01;其实你要做的才刚刚开始&#xff0c;很多安全性强的软件会侦查出你手机里的root&#xff0c;进而限制部分功能或直接拒绝你的访问。今天我来教大家一些常见的隐藏环境的方法以及步骤&#xff0c;希望对大家有帮助。 方…