18 残差网络
import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Input, Add, Dense, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D, AveragePooling2D, MaxPooling2D, GlobalMaxPooling2D
from tensorflow.keras.models import Model, load_model
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.imagenet_utils import preprocess_input
import pydot
from IPython.display import SVG
from tensorflow.keras.utils import plot_model
from resnets_utils import *
import scipy.misc
from matplotlib.pyplot import imshow
%matplotlib inline
这段代码是一个使用TensorFlow实现的ResNet(深度残差网络)模型的一部分。ResNet是一种深度学习架构,通常用于图像分类任务。
-
import numpy as np
:导入NumPy库,它用于处理数组和矩阵数据。 -
import tensorflow as tf
:导入TensorFlow库,这是一个用于构建和训练深度学习模型的强大库。 -
from tensorflow.keras.layers import ...
:从TensorFlow的Keras模块中导入各种神经网络层,例如卷积层、池化层、批量归一化等。 -
from tensorflow.keras.models import Model, load_model
:导入Keras中的Model
类,用于构建模型。还导入了load_model
函数,用于加载预训练模型。 -
from tensorflow.keras.preprocessing import image
:导入图像预处理工具,用于处理输入图像数据。 -
from tensorflow.keras.applications.imagenet_utils import preprocess_input
:导入图像预处理函数,用于将输入图像进行预处理以适应模型。 -
import pydot
:导入PyDot库,它通常用于可视化神经网络模型的结构。 -
from IPython.display import SVG
:导入IPython库中的SVG类,用于在Jupyter Notebook中显示SVG格式的图形。 -
from tensorflow.keras.utils import plot_model
:导入Keras中的plot_model
函数,用于绘制模型的结构图。 -
from resnets_utils import *
:导入自定义的resnets_utils
模块,其中可能包含有关ResNet的其他帮助函数和工具。 -
import scipy.misc
:导入SciPy的图像处理模块,用于处理图像。 -
from matplotlib.pyplot import imshow
:从Matplotlib库中导入imshow
函数,用于显示图像。 -
%matplotlib inline
:这是Jupyter Notebook的一个魔术命令,它用于在Notebook中内联显示Matplotlib图形。
这段代码主要是导入所需的库和模块,以及定义一些用于图像处理和可视化的工具。
# 维度相同时的残差块
def identity_block(X, f, filters, stage, block):
"""
实现了图4中展示的残差块
参数:
X -- 要跳跃的激活值矩阵
f -- 整型。指示卷积层的窗口大小
filters -- 整型数组,指示残差块中的卷积层的过滤器的个数
stage -- 整型。用来辅助给网络层取名。
block -- 字符串。用来辅助给网络层取名。
返回:
X -- 残差块的最终输出矩阵
"""
# 取一些名字而已,无关紧要
conv_name_base = 'res' + str(stage) + block + '_branch'
bn_name_base = 'bn' + str(stage) + block + '_branch'
# 获取每一个卷积层对应的过滤器的个数
F1, F2, F3 = filters
# 定义参数初始化的方法
initializer = tf.keras.initializers.GlorotUniform
# 保存输入的激活值,以便后面跳插入到后面的网络层中
X_shortcut = X
# 这里我们使用functional API方式来构建模型
# 因为在开头处已经从keras里面导入了Conv2D,所以这里我们就可以直接使用了,相当于tensorflow.keras.layers.Conv2D
# 主路中的第一组网络层,就是图4的第一组绿橙黄小方块
X = Conv2D(filters=F1, kernel_size=(1, 1), strides=(1, 1), padding='valid', name=conv_name_base + '2a',
kernel_initializer=initializer(seed=0))(X)
X = BatchNormalization(axis=3, name=bn_name_base + '2a')(X)
X = Activation('relu')(X)
# 主路中的第二组网络层,就是图4的第二组绿橙黄小方块
X = Conv2D(filters=F2, kernel_size=(f, f), strides=(1, 1), padding='same', name=conv_name_base + '2b',
kernel_initializer=initializer(seed=0))(X)
X = BatchNormalization(axis=3, name=bn_name_base + '2b')(X)
X = Activation('relu')(X)
# 主路中的第三组网络层,图4的第三组绿橙小方块
X = Conv2D(filters=F3, kernel_size=(1, 1), strides=(1, 1), padding='valid', name=conv_name_base + '2c',
kernel_initializer=initializer(seed=0))(X)
X = BatchNormalization(axis=3, name=bn_name_base + '2c')(X)
# 这一步就是实现小路的地方。其实就是简单的将前面层的激活值X_shortcut与第三组网络层的输出激活值合并在一起
# 然后将合并的激活值向下传入到激活函数中,进入到后面的神经网络中去
X = Add()([X, X_shortcut])
X = Activation('relu')(X)
return X
这段代码实现了ResNet中的“恒等残差块”(identity block)。ResNet中的残差块是一种用于构建深度神经网络的模块,它允许有效地训练非常深的神经网络,避免了梯度消失问题。以下是对这个恒等残差块的详细解释:
-
def identity_block(X, f, filters, stage, block):
:这是一个Python函数,用于构建恒等残差块。它接受以下参数:X
:输入激活值的张量。f
:整数,指定卷积层的窗口大小。filters
:包含三个整数的列表,指定残差块中每个卷积层的过滤器数量。stage
:整数,用于辅助命名网络层。block
:字符串,用于辅助命名网络层。
-
conv_name_base
和bn_name_base
:这些是用于辅助给网络层取名的字符串。 -
F1, F2, F3
:这些变量从filters
列表中获取,分别表示残差块中的第一个、第二个和第三个卷积层的过滤器数量。 -
initializer
:这是一个用于参数初始化的方法,它使用Glorot均匀初始化。 -
X_shortcut
:这个变量用于保存输入的激活值,以便在后面将其添加到网络的输出中。
接下来,这个函数使用了ResNet的核心思想,即通过跳跃连接(或者称为“快捷连接”)将输入直接添加到网络的输出中。具体步骤如下:
-
X_shortcut = X
:将输入激活值保存到X_shortcut
变量中,以备后面的跳跃连接使用。 -
X = Conv2D(filters=F1, kernel_size=(1, 1), strides=(1, 1), padding='valid', name=conv_name_base + '2a', kernel_initializer=initializer(seed=0))(X)
:这是残差块的主要路径的第一组卷积层。它包括一个1x1的卷积层,用于改变通道数和一个BatchNormalization层,以及ReLU激活函数。 -
X = Conv2D(filters=F2, kernel_size=(f, f), strides=(1, 1), padding='same', name=conv_name_base + '2b', kernel_initializer=initializer(seed=0))(X)
:这是主路径的第二组卷积层,包括一个fxf大小的卷积层,padding为'same',以保持输入和输出的尺寸相同,然后再次应用BatchNormalization和ReLU激活函数。 -
X = Conv2D(filters=F3, kernel_size=(1, 1), strides=(1, 1), padding='valid', name=conv_name_base + '2c', kernel_initializer=initializer(seed=0))(X)
:这是主路径的第三组卷积层,同样包括一个1x1的卷积层,然后再次应用BatchNormalization。 -
X = Add()([X, X_shortcut])
:这一步实现了跳跃连接,将主路径的输出X
与输入X_shortcut
相加。 -
X = Activation('relu')(X)
:最后,将合并的激活值通过ReLU激活函数,以得到最终的残差块输出。
这个函数的作用是构建一个恒等残差块,它可以在深度神经网络中重复使用,以构建更深的网络结构。这种残差块的关键特点是输入和输出的维度相同。
np.random.seed(1)
X = tf.cast(np.random.randn(3, 4, 4, 6),tf.float32)
A = identity_block(X, f=2, filters=[2, 4, 6], stage=1, block='a')
tf.print("out = ", A[1][1][0])
这段代码演示了如何使用先前定义的 identity_block
函数来构建一个恒等残差块,并输出其中一个元素的值。
-
np.random.seed(1)
:设置随机数种子,以确保随机数生成的结果可重复。 -
X = tf.cast(np.random.randn(3, 4, 4, 6),tf.float32)
:创建一个4维张量X
,其中包含随机生成的数值。这个张量的形状是 (3, 4, 4, 6),表示了一个批次大小为3的输入数据,每个数据点是一个4x4x6的多通道图像。 -
A = identity_block(X, f=2, filters=[2, 4, 6], stage=1, block='a')
:调用identity_block
函数来构建一个恒等残差块,并将随机生成的输入张量X
传递给函数。函数的参数指定了残差块的参数,例如窗口大小f
、过滤器数量filters
、阶段stage
和块名称block
。函数返回的结果存储在变量A
中。 -
tf.print("out = ", A[1][1][0])
:使用tf.print
打印了A
中的特定元素的值。具体地说,它打印了A
的第2个维度的第2行、第2列、第1个通道的值。
这段代码的目的是演示如何创建并使用 identity_block
函数来构建神经网络中的一个残差块,并查看其中某个特定位置的激活值。通过这种方式,您可以验证残差块是否按预期工作。
# 实现图5中的残差块
def convolutional_block(X, f, filters, stage, block, s=2):
conv_name_base = 'res' + str(stage) + block + '_branch'
bn_name_base = 'bn' + str(stage) + block + '_branch'
F1, F2, F3 = filters
initializer = tf.keras.initializers.GlorotUniform
X_shortcut = X
X = Conv2D(filters=F1, kernel_size=(1, 1), strides=(s, s), padding='valid', name=conv_name_base + '2a',
kernel_initializer=initializer(seed=0))(X)
X = BatchNormalization(axis=3, name=bn_name_base + '2a')(X)
X = Activation('relu')(X)
X = Conv2D(filters=F2, kernel_size=(f, f), strides=(1, 1), padding='same', name=conv_name_base + '2b',
kernel_initializer=initializer(seed=0))(X)
X = BatchNormalization(axis=3, name=bn_name_base + '2b')(X)
X = Activation('relu')(X)
X = Conv2D(filters=F3, kernel_size=(1, 1), strides=(1, 1), padding='valid', name=conv_name_base + '2c',
kernel_initializer=initializer(seed=0))(X)
X = BatchNormalization(axis=3, name=bn_name_base + '2c')(X)
# 在小路上面加上一个卷积层和一个BatchNormalization
# 卷积层会改变X_shortcut的维度,这样一来,就能与X矩阵合并在一起了
X_shortcut = Conv2D(filters=F3, kernel_size=(1, 1), strides=(s, s), padding='valid', name=conv_name_base + '1',
kernel_initializer=initializer(seed=0))(X_shortcut)
X_shortcut = BatchNormalization(axis=3, name=bn_name_base + '1')(X_shortcut)
# 将变维后的X_shortcut与X合并在一起
X = Add()([X, X_shortcut])
X = Activation('relu')(X)
return X
这段代码实现了ResNet中的“卷积残差块”(convolutional block),这种残差块用于处理输入和输出维度不匹配的情况。
-
def convolutional_block(X, f, filters, stage, block, s=2):
:这是一个Python函数,用于构建卷积残差块。它接受以下参数:X
:输入激活值的张量。f
:整数,指定卷积层的窗口大小。filters
:包含三个整数的列表,指定残差块中每个卷积层的过滤器数量。stage
:整数,用于辅助命名网络层。block
:字符串,用于辅助命名网络层。s
:整数,指定卷积层的步幅(stride),默认为2。
-
conv_name_base
和bn_name_base
:这些是用于辅助给网络层取名的字符串。 -
F1, F2, F3
:这些变量从filters
列表中获取,分别表示残差块中的第一个、第二个和第三个卷积层的过滤器数量。 -
initializer
:这是一个用于参数初始化的方法,它使用Glorot均匀初始化。 -
X_shortcut = X
:将输入激活值保存到X_shortcut
变量中,以备后面的跳跃连接使用。 -
X = Conv2D(filters=F1, kernel_size=(1, 1), strides=(s, s), padding='valid', name=conv_name_base + '2a', kernel_initializer=initializer(seed=0))(X)
:这是卷积残差块的主要路径的第一组卷积层。它包括一个1x1的卷积层,用于改变通道数和一个BatchNormalization层,以及ReLU激活函数。此处的strides
参数为2,表示卷积层的步幅为2。 -
X = Conv2D(filters=F2, kernel_size=(f, f), strides=(1, 1), padding='same', name=conv_name_base + '2b', kernel_initializer=initializer(seed=0))(X)
:这是主路径的第二组卷积层,包括一个fxf大小的卷积层,padding为'same',以保持输入和输出的尺寸相同,然后再次应用BatchNormalization和ReLU激活函数。 -
X = Conv2D(filters=F3, kernel_size=(1, 1), strides=(1, 1), padding='valid', name=conv_name_base + '2c', kernel_initializer=initializer(seed=0))(X)
:这是主路径的第三组卷积层,同样包括一个1x1的卷积层,然后再次应用BatchNormalization。 -
X_shortcut = Conv2D(filters=F3, kernel_size=(1, 1), strides=(s, s), padding='valid', name=conv_name_base + '1', kernel_initializer=initializer(seed=0))(X_shortcut)
:在跳跃连接的小路上面添加一个卷积层,以使输入X_shortcut
的维度与主路径的输出相匹配。 -
X = Add()([X, X_shortcut])
:这一步实现了跳跃连接,将主路径的输出X
与输入X_shortcut
相加。 -
X = Activation('relu')(X)
:最后,将合并的激活值通过ReLU激活函数,以得到最终的残差块输出。
这个函数的作用是构建一个卷积残差块,它可以处理输入和输出维度不匹配的情况,通过改变维度并使用卷积操作来实现跳跃连接。
np.random.seed(1)
X = tf.cast(np.random.randn(3, 4, 4, 6),dtype=tf.float32)
A = convolutional_block(X, f=2, filters=[2, 4, 6], stage=1, block='a')
tf.print("out = ", (A[1][1][0]))
这段代码演示了如何使用先前定义的 convolutional_block
函数来构建一个卷积残差块,并输出其中一个元素的值。
-
np.random.seed(1)
:设置随机数种子,以确保随机数生成的结果可重复。 -
X = tf.cast(np.random.randn(3, 4, 4, 6), dtype=tf.float32)
:创建一个4维张量X
,其中包含随机生成的数值。这个张量的形状是 (3, 4, 4, 6),表示了一个批次大小为3的输入数据,每个数据点是一个4x4x6的多通道图像。请注意,添加了dtype=tf.float32
以确保数据类型为浮点型。 -
A = convolutional_block(X, f=2, filters=[2, 4, 6], stage=1, block='a')
:调用convolutional_block
函数来构建一个卷积残差块,并将随机生成的输入张量X
传递给函数。函数的参数指定了卷积残差块的参数,例如窗口大小f
、过滤器数量filters
、阶段stage
和块名称block
。函数返回的结果存储在变量A
中。 -
tf.print("out = ", (A[1][1][0]))
:使用tf.print
打印了A
中的特定元素的值。具体地说,它打印了A
的第2个维度的第2行、第2列、第1个通道的值。
这段代码的目的是演示如何创建并使用 convolutional_block
函数来构建神经网络中的一个卷积残差块,并查看其中某个特定位置的激活值。通过这种方式,可以验证卷积残差块是否按预期工作。
# 实现ResNet50
def ResNet50(input_shape=(64, 64, 3), classes=6):
"""
参数:
input_shape -- 输入的图像矩阵的维度
classes -- 类别数量
Returns:
model -- 网络模型
"""
# 根据输入维度定义一个输入向量
X_input = Input(input_shape)
initializer = tf.keras.initializers.GlorotUniform
# 用0填充输入向量的周边
X = ZeroPadding2D((3, 3))(X_input)
# 实现第一个阶段。Stage 1
X = Conv2D(64, (7, 7), strides=(2, 2), name='conv1', kernel_initializer=initializer(seed=0))(X)
X = BatchNormalization(axis=3, name='bn_conv1')(X)
X = Activation('relu')(X)
X = MaxPooling2D((3, 3), strides=(2, 2))(X)
# Stage 2
X = convolutional_block(X, f=3, filters=[64, 64, 256], stage=2, block='a', s=1)
X = identity_block(X, 3, [64, 64, 256], stage=2, block='b')
X = identity_block(X, 3, [64, 64, 256], stage=2, block='c')
# Stage 3
X = convolutional_block(X, f=3, filters=[128, 128, 512], stage=3, block='a', s=2)
X = identity_block(X, 3, [128, 128, 512], stage=3, block='b')
X = identity_block(X, 3, [128, 128, 512], stage=3, block='c')
X = identity_block(X, 3, [128, 128, 512], stage=3, block='d')
# Stage 4
X = convolutional_block(X, f=3, filters=[256, 256, 1024], stage=4, block='a', s=2)
X = identity_block(X, 3, [256, 256, 1024], stage=4, block='b')
X = identity_block(X, 3, [256, 256, 1024], stage=4, block='c')
X = identity_block(X, 3, [256, 256, 1024], stage=4, block='d')
X = identity_block(X, 3, [256, 256, 1024], stage=4, block='e')
X = identity_block(X, 3, [256, 256, 1024], stage=4, block='f')
# Stage 5 (≈3 lines)
X = X = convolutional_block(X, f=3, filters=[512, 512, 2048], stage=5, block='a', s=2)
X = identity_block(X, 3, [512, 512, 2048], stage=5, block='b')
X = identity_block(X, 3, [512, 512, 2048], stage=5, block='c')
# 平均池化层
X = AveragePooling2D(pool_size=(2, 2), padding='same')(X)
# 扁平化激活值矩阵,对接上全连接层,softmax层
X = Flatten()(X)
X = Dense(classes, activation='softmax', name='fc' + str(classes),
kernel_initializer=initializer(seed=0))(X)
# 构建模型
model = Model(inputs=X_input, outputs=X, name='ResNet50')
return model
这段代码实现了ResNet50模型的构建,ResNet50是一个深度残差网络,用于图像分类任务。
-
ResNet50(input_shape=(64, 64, 3), classes=6)
:这是一个Python函数,用于构建ResNet50模型。它接受以下参数:input_shape
:输入图像的维度,默认为(64, 64, 3)。classes
:要分类的类别数量,默认为6。
-
X_input = Input(input_shape)
:创建一个Keras的Input层,用于接受输入图像数据。input_shape
参数指定了输入图像的维度。 -
initializer = tf.keras.initializers.GlorotUniform
:定义一个参数初始化方法,这里使用了Glorot均匀初始化。 -
X = ZeroPadding2D((3, 3))(X_input)
:通过在输入图像周围填充3个零,扩展图像的尺寸。 -
X = Conv2D(64, (7, 7), strides=(2, 2), name='conv1', kernel_initializer=initializer(seed=0))(X)
:实现ResNet50的第一个卷积层,包括一个7x7的卷积核、步幅为2、64个滤波器(通道数)、ReLU激活函数等。 -
X = BatchNormalization(axis=3, name='bn_conv1')(X)
:应用BatchNormalization来标准化卷积层的输出。 -
X = Activation('relu')(X)
:应用ReLU激活函数。 -
X = MaxPooling2D((3, 3), strides=(2, 2))(X)
:应用最大池化层,缩小特征图的尺寸。
接下来,代码实现了ResNet50中的5个阶段(Stage),每个阶段包括一些卷积残差块和恒等残差块。这些阶段逐渐减小特征图的尺寸,同时增加通道数。
最后,代码通过全局平均池化层将特征图降维为一维向量,然后连接全连接层和softmax层,以进行分类。
-
X = Flatten()(X)
:将特征图扁平化为一维向量。 -
X = Dense(classes, activation='softmax', name='fc' + str(classes), kernel_initializer=initializer(seed=0))(X)
:连接全连接层和softmax层,用于最终的分类。 -
model = Model(inputs=X_input, outputs=X, name='ResNet50')
:构建Keras模型,将输入层和输出层连接起来,创建ResNet50模型。
最后,函数返回构建的ResNet50模型。您可以使用这个模型进行图像分类任务。
model = ResNet50(input_shape=(64, 64, 3), classes=6)
通过调用 ResNet50
函数创建了一个ResNet50模型,指定了输入图像的形状为(64, 64, 3)和要分类的类别数量为6。现在,您已经成功地创建了一个ResNet50模型,并可以使用它进行图像分类或训练。如果您希望进一步使用或训练这个模型,可以根据需要执行相关操作。
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
已经成功地配置了模型的编译步骤。这里是所执行的编译操作的解释:
-
optimizer='adam'
:选择了Adam优化器作为模型的优化器。Adam是一种常用的优化算法,用于自适应学习率和有效地训练深度神经网络。 -
loss='categorical_crossentropy'
:选择了交叉熵损失函数作为模型的损失函数。对于多类别分类任务,交叉熵通常是一个合适的损失函数。 -
metrics=['accuracy']
:选择了度量模型性能的指标。在这种情况下,您选择了准确率作为评估模型性能的指标。
一旦模型编译完成,您就可以使用训练数据对模型进行训练,然后使用验证数据进行验证,最终评估模型的性能。通常,模型的编译步骤是模型训练的前提条件。
如果您想要继续进行模型的训练、验证和评估,请执行相应的步骤,如拟合数据、验证模型性能和保存训练好的模型。
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()
X_train = X_train_orig / 255.
X_test = X_test_orig / 255.
Y_train = convert_to_one_hot(Y_train_orig, 6).T
Y_test = convert_to_one_hot(Y_test_orig, 6).T
print("number of training examples = " + str(X_train.shape[0]))
print("number of test examples = " + str(X_test.shape[0]))
print("X_train shape: " + str(X_train.shape))
print("Y_train shape: " + str(Y_train.shape))
print("X_test shape: " + str(X_test.shape))
print("Y_test shape: " + str(Y_test.shape))
这段代码执行了数据加载和预处理的操作,具体解释如下:
-
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()
:这里调用了一个函数load_dataset()
来加载数据集,包括原始训练集、原始测试集以及类别信息。通常,这个函数会从文件或其他来源加载数据集。 -
X_train = X_train_orig / 255.
和X_test = X_test_orig / 255.
:这两行代码将原始训练集和测试集的像素值进行了归一化处理,将像素值范围从[0, 255]缩放到[0, 1]。这是一种常见的数据预处理步骤,有助于提高模型的训练效果。 -
Y_train = convert_to_one_hot(Y_train_orig, 6).T
和Y_test = convert_to_one_hot(Y_test_orig, 6).T
:这两行代码将原始训练集和测试集的标签进行了独热编码处理。独热编码将类别标签转换成了一个与类别数量相等的向量,其中只有一个元素是1,表示样本所属的类别,其他元素都是0。这是多类别分类问题的常见标签表示方法。 -
打印了一些数据集信息,包括训练样本数量、测试样本数量,以及数据集的形状信息。这些信息有助于了解数据集的规模和维度。
总之,这段代码的目的是加载数据集、对图像像素值进行归一化处理,并将标签进行独热编码,为后续的模型训练做好了准备。
# 之前我们在使用fit时,是传入了dataset对象,在这里我们分别传入了训练样本和训练标签。这两种方法都是可用的。
# 具体fit的用法可以查看官方文档https://tensorflow.google.cn/api_docs/python/tf/keras/Model#fit
model.fit(X_train, Y_train, epochs = 2, batch_size = 32)
提到的两种方式都可以用于模型的训练。一种方式是将整个数据集打包成tf.data.Dataset
对象并传递给fit
方法,另一种方式是分别传递训练样本和标签。这两种方式在使用上都是可行的,取决于您的偏好和数据处理的方式。
在这里,您选择了将训练样本X_train
和标签Y_train
分别传递给fit
方法进行训练。这是一种简单和直观的方式,特别适用于小型数据集。
以下是您的训练代码的解释:
model.fit(X_train, Y_train, epochs=2, batch_size=32)
:这一行代码使用模型的fit
方法进行训练。参数解释如下:X_train
:训练样本,包含了图像数据。Y_train
:训练标签,包含了类别标签的独热编码。epochs=2
:指定了训练的轮数,这里设置为2。batch_size=32
:指定了每个小批量的样本数量,这里设置为32。
训练模型时,会按照指定的轮数(epochs)迭代训练数据,并在每个小批量(batch)上更新模型的权重,以减小损失函数。这个过程将不断调整模型的参数,使其更好地适应训练数据,从而提高在测试数据上的性能。
preds = model.evaluate(X_test, Y_test)
print("Loss = " + str(preds[0]))
print("Test Accuracy = " + str(preds[1]))
您的代码执行了模型在测试集上的评估操作,并打印了损失值和测试准确率。
-
preds = model.evaluate(X_test, Y_test)
:使用模型的evaluate
方法对测试集进行评估。该方法接受测试样本X_test
和相应的标签Y_test
作为输入,并返回损失值和指定的评估指标(在模型编译时指定,通常为准确率)。 -
print("Loss = " + str(preds[0]))
:打印了模型在测试集上的损失值。preds[0]
包含了损失值。 -
print("Test Accuracy = " + str(preds[1]))
:打印了模型在测试集上的准确率。preds[1]
包含了准确率值。
这段代码的目的是评估模型在测试数据上的性能,并输出损失值和准确率作为评估指标。这些指标可以帮助您了解模型在新数据上的表现,以及是否需要进一步改进模型或调整超参数。
model = load_model('ResNet50.h5')
preds = model.evaluate(X_test, Y_test)
print("Loss = " + str(preds[0]))
print("Test Accuracy = " + str(preds[1]))
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~