16 使用TF构建卷积神经网络
import math
import numpy as np
import h5py
import matplotlib.pyplot as plt
import scipy
from PIL import Image
from scipy import ndimage
import tensorflow as tf
from tensorflow.keras import *
from cnn_utils import *
%matplotlib inline
np.random.seed(1)
导入了一些常用的Python库和模块,并设置了一些全局配置。
-
import math
:导入Python的数学库,可以用于执行数学运算。 -
import numpy as np
:导入NumPy库,并给它起了一个别名np。NumPy是用于处理数组和矩阵的库,通常与科学计算和数据分析一起使用。 -
import h5py
:导入h5py库,它用于读取和写入HDF5文件格式的数据。 -
import matplotlib.pyplot as plt
:导入Matplotlib库,并给它起了一个别名plt。Matplotlib是一个用于绘制图形的库,这里用于在Notebook中显示图像。 -
import scipy
:导入SciPy库,它是一个科学计算库,提供了许多数学、科学和工程计算的功能。 -
from PIL import Image
:从PIL库中导入Image模块,用于处理图像。 -
from scipy import ndimage
:从SciPy库中导入ndimage模块,用于图像处理和分析。 -
import tensorflow as tf
:导入TensorFlow库,这是一个用于机器学习和深度学习的强大框架。 -
from tensorflow.keras import *
:从TensorFlow的Keras模块中导入所有内容。Keras是一个高级神经网络API,与TensorFlow紧密集成,用于构建深度学习模型。 -
from cnn_utils import *
:从cnn_utils模块中导入所有内容。这可能是自定义的工具函数或类,用于协助卷积神经网络 (CNN) 的构建和训练。 -
%matplotlib inline
:这是一个Jupyter Notebook的魔术命令,用于在Notebook中显示Matplotlib图形。 -
np.random.seed(1)
:设置随机数种子为1,以确保随机数的可重复性。这在机器学习中很常见,以便能够重现实验结果。
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()
加载数据集。它调用了名为load_dataset
的函数,并将返回的数据分别赋值给了一些变量。
-
X_train_orig
:这是训练集的特征数据,通常是包含许多训练样本的数组,每个样本都是一个图像。这些图像通常以数字矩阵的形式表示。 -
Y_train_orig
:这是训练集的标签数据,与X_train_orig
对应。它包含了与每个训练样本相关联的标签或类别信息。 -
X_test_orig
:这是测试集的特征数据,与X_train_orig
类似,但是用于测试模型性能的数据。 -
Y_test_orig
:这是测试集的标签数据,与X_test_orig
对应。它包含了与每个测试样本相关联的标签或类别信息。 -
classes
:这个变量包含了数据集中的类别标签,通常是一个包含类别名称或数字标识的列表或数组。
load_dataset()
函数的作用是从某个数据源中加载这些数据,可能是从文件中读取、从网络下载或从其他地方获取。这个函数通常会将数据加载到内存中,并将数据分为训练集和测试集,同时返回这些数据以及类别信息。
index = 6
plt.imshow(X_train_orig[index])
print ("y = " + str(np.squeeze(Y_train_orig[:, index])))
这段代码展示了如何可视化训练数据集中的第六个样本并打印其相关的标签信息。让我来详细解释这段代码:
-
index = 6
:设置一个变量index
的值为6,这将用于选择训练数据集中的第七个样本(Python中的索引从0开始)。 -
plt.imshow(X_train_orig[index])
:使用Matplotlib库中的imshow
函数,显示训练数据集中第七个样本的图像。X_train_orig[index]
包含了第七个样本的图像数据。这行代码会在Notebook中显示图像。 -
print("y = " + str(np.squeeze(Y_train_orig[:, index])))
:打印与第七个样本相关的标签信息。Y_train_orig
是训练数据集的标签数组,通过Y_train_orig[:, index]
可以获取第七个样本的标签。np.squeeze()
函数用于删除多余的维度,确保输出是一个标量值,然后将其转换为字符串并与 "y = " 字符串连接以进行打印。
这段代码的目的是帮助您可视化训练数据集中的一个样本,并查看其对应的标签。这对于理解数据集和调试代码非常有用。
X_train = X_train_orig/255.
X_test = X_test_orig/255.
# tf.one_hot是tensorflow提供的工具函数,可以把输入变成one hot向量
# tf.squeeze是删除大小为1的维度
Y_train = tf.squeeze(tf.one_hot(Y_train_orig, 6))
Y_test = tf.squeeze(tf.one_hot(Y_test_orig, 6))
print ("训练样本数 = " + str(X_train.shape[0]))
print ("测试样本数 = " + str(X_test.shape[0]))
print ("X_train的维度: " + str(X_train.shape))
print ("Y_train的维度: " + str(Y_train.shape))
print ("X_test的维度: " + str(X_test.shape))
print ("Y_test的维度: " + str(Y_test.shape))
conv_layers = {}
-
X_train = X_train_orig/255.
和X_test = X_test_orig/255.
:将训练集和测试集中的图像数据进行归一化处理。将每个像素的值除以255,以将其缩放到范围[0, 1]之间。这是常见的图像预处理步骤,有助于神经网络的训练。 -
Y_train = tf.squeeze(tf.one_hot(Y_train_orig, 6))
和Y_test = tf.squeeze(tf.one_hot(Y_test_orig, 6))
:对训练集和测试集的标签进行独热编码(One-Hot Encoding)。具体来说,它将原始的多类别标签转换为一个二进制矩阵,其中每一行对应一个样本的类别,对应类别的位置上的元素为1,其他位置为0。tf.one_hot()
用于执行这个操作,然后tf.squeeze()
用于删除大小为1的维度,以得到一个更紧凑的表示。 -
打印了一些关于数据维度的信息,包括训练样本数、测试样本数,以及特征和标签的维度。
-
conv_layers = {}
:创建了一个名为conv_layers
的空字典,这可能会在构建卷积神经网络(CNN)的过程中用于存储卷积层的参数和中间结果。
总结一下,这段代码对数据进行了预处理,包括图像的归一化和标签的独热编码,为接下来构建CNN模型做好了准备。
#首先手工创建一个非常简单的数据集,该数据包含10个样本,每个样本由1个浮点数组成。
data = np.array([0.1, 0.4, 0.6, 0.2, 0.8, 0.8, 0.4, 0.9, 0.3, 0.2])
#其中大于0.5的样本为正样本,即标签记为1,否则为0。
label = np.array([0, 0, 1, 0, 1, 1, 0, 1, 0, 0])
#然后,可以通过tf.data.Dataset.from_tensor_slices建立数据集。
dataset = tf.data.Dataset.from_tensor_slices((data, label))
#该数据集可以直接由python原生语法进行迭代
for x, y in dataset:
print('x =', x, 'y =', y)
这段代码演示了如何手动创建一个非常简单的数据集,并使用 TensorFlow 的 tf.data.Dataset.from_tensor_slices
函数来将数据集建立起来,以便进行迭代。
-
data
和label
:这两个数组分别包含了样本的特征和标签。data
包含了10个浮点数作为样本特征,而label
包含了对应的二元标签,其中大于0.5的样本标签为1,否则为0。 -
tf.data.Dataset.from_tensor_slices((data, label))
:这行代码使用 TensorFlow 的tf.data.Dataset.from_tensor_slices
函数创建了一个数据集。这个函数接受一个或多个张量(tensor)作为输入,然后将它们“切片”成单个元素的数据项。在这里,我们将data
和label
作为元组传递给函数,从而创建了一个包含10个样本的数据集,每个样本都包括一个特征和一个标签。 -
for x, y in dataset:
:这是一个简单的 for 循环,用于迭代数据集中的样本。在每次迭代中,x
表示样本的特征,y
表示样本的标签。循环中的print
语句用于打印每个样本的特征和标签。
当您运行这段代码时,它会输出每个样本的特征和标签,以便您可以查看数据集的内容。这是一个非常简单的示例,用于演示如何使用 TensorFlow 创建和迭代数据集。在实际应用中,数据集通常更复杂,而 TensorFlow 提供了更多的功能来处理大规模的数据集和数据管道。
#将X_train和Y_train打包成一个dataset对象
ds_train = tf.data.Dataset.from_tensor_slices((X_train,Y_train))
# shuffle会在每个epoch都将1080个样本打乱
# batch会将每64个样本打包成一个batch
ds_train = ds_train.shuffle(1080, 1, True).batch(64)
ds_test = tf.data.Dataset.from_tensor_slices((X_test,Y_test)).batch(64)
这段代码演示了如何使用 TensorFlow 创建训练集和测试集的数据集对象,并对它们进行一些预处理操作。
-
ds_train = tf.data.Dataset.from_tensor_slices((X_train, Y_train))
:使用tf.data.Dataset.from_tensor_slices
函数将训练集的特征数据X_train
和标签数据Y_train
打包成一个数据集对象ds_train
。这个数据集对象将用于训练模型。 -
ds_train = ds_train.shuffle(1080, 1, True).batch(64)
:对训练集的数据集进行预处理操作。具体来说:ds_train.shuffle(1080, 1, True)
:使用shuffle
方法,将训练集中的样本打乱。shuffle
函数的第一个参数1080
表示要从数据集中随机抽取的样本数,第二个参数1
表示随机数种子,以确保每次训练都使用不同的随机顺序,第三个参数True
表示每个 epoch 都重新打乱数据集。这有助于模型学习不同的样本顺序,增加泛化能力。.batch(64)
:使用batch
方法,将训练集中的样本分成批次。每个批次包含 64 个样本。批次处理有助于在训练过程中更高效地使用计算资源,同时可以提高训练的稳定性。
-
ds_test = tf.data.Dataset.from_tensor_slices((X_test, Y_test)).batch(64)
:对测试集的数据集进行类似的预处理操作,将测试集的特征数据X_test
和标签数据Y_test
打包成一个数据集对象ds_test
,并将每个批次中包含 64 个样本。
这些操作使您能够更方便地在训练和测试期间使用数据集,并且可以充分利用 TensorFlow 的数据管道功能,提高训练效率。
# 因为前面我们导入了keras,所以下面代码相当于cnnmodel = tf.keras.Sequential()
cnnmodel = Sequential()
# 有同学可能发现在《手把手教你从Tensorflow1.x到2.x》中的sequential方式的用法与这里的不同。
# 使用add也是sequential的一种用法!
cnnmodel.add(layers.Input((64,64,3)))
# 添加一个卷积层。指定了8个过滤器。
# 每个过滤器的宽高都是4,深度是3,因为过滤器的深度必须要与输入矩阵相同,所以不需要指定深度。
# 不需要我们自己定义训练参数,框架内部会帮我们处理好
# 参数的初始化方法我们选择了GlorotUniform,并将随机种子设为了1
cnnmodel.add(layers.Conv2D(filters=8,kernel_size=(4, 4),kernel_initializer = initializers.GlorotUniform(1),
activation='relu',padding='same'))
# 添加一个最大池化层,池化窗口的宽高都是8,步进也是8
cnnmodel.add(layers.MaxPool2D(pool_size=(8, 8), strides=(8, 8), padding='same'))
cnnmodel.add(layers.Conv2D(filters=16,kernel_size=(2, 2),kernel_initializer = initializers.GlorotUniform(1),
activation='relu',padding='same'))
cnnmodel.add(layers.MaxPool2D(pool_size=(4, 4), strides=(4, 4), padding='same'))
# 添加一个扁平层,将卷积层扁平化
cnnmodel.add(layers.Flatten())
# 添加一个全连接层,该层有6个神经元,参数也是框架自动生成的,参数的初始化函数为GlorotUniform。激活函数是softmax
cnnmodel.add(layers.Dense(6,kernel_initializer = initializers.GlorotUniform(1), activation='softmax'))
这段代码创建了一个卷积神经网络(CNN)模型,使用了 TensorFlow 的 Keras 接口,具体说明如下:
-
cnnmodel = Sequential()
:创建了一个顺序模型(Sequential Model),该模型可以逐层堆叠神经网络层。这是一个基本的CNN模型。 -
cnnmodel.add(layers.Input((64, 64, 3)))
:添加了一个输入层,指定了输入数据的形状为(64, 64, 3)
,表示每个样本是一个64x64像素的彩色图像(RGB通道),其中3表示RGB通道数。 -
cnnmodel.add(layers.Conv2D(filters=8, kernel_size=(4, 4), kernel_initializer=initializers.GlorotUniform(1), activation='relu', padding='same'))
:添加了一个卷积层。具体说明如下:filters=8
:指定了该卷积层使用了8个滤波器(卷积核)。kernel_size=(4, 4)
:指定了每个滤波器的大小为4x4。kernel_initializer=initializers.GlorotUniform(1)
:使用Glorot均匀初始化方法来初始化卷积层的权重参数,随机种子设置为1。activation='relu'
:使用ReLU(Rectified Linear Unit)激活函数。padding='same'
:使用"same"填充方式,以保持输入输出的尺寸相同。
-
cnnmodel.add(layers.MaxPool2D(pool_size=(8, 8), strides=(8, 8), padding='same'))
:添加了一个最大池化层,池化窗口的大小为8x8,步幅也为8x8,使用"same"填充方式,以保持输出的尺寸相同。 -
cnnmodel.add(layers.Conv2D(filters=16, kernel_size=(2, 2), kernel_initializer=initializers.GlorotUniform(1), activation='relu', padding='same'))
:再次添加了一个卷积层,类似于第2步的卷积层,但这次使用了16个滤波器。 -
cnnmodel.add(layers.MaxPool2D(pool_size=(4, 4), strides=(4, 4), padding='same'))
:再次添加了一个最大池化层,池化窗口大小为4x4,步幅也为4x4,使用"same"填充方式。 -
cnnmodel.add(layers.Flatten())
:添加了一个扁平层,将卷积层的输出扁平化,以便连接到全连接层。 -
cnnmodel.add(layers.Dense(6, kernel_initializer=initializers.GlorotUniform(1), activation='softmax'))
:添加了一个全连接层,该层有6个神经元,使用Glorot均匀初始化方法来初始化权重参数,激活函数为softmax,用于多类别分类任务。
这个CNN模型是一个典型的卷积神经网络,包括卷积层、池化层、扁平层和全连接层,适用于图像分类等任务。
cnnmodel.summary()
cnnmodel.summary()
是一个用于打印模型摘要信息的函数,它会列出模型中每一层的名称、输出形状、参数数量等重要信息。通过查看模型摘要,可以更好地理解和调试模型。
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 64, 64, 3)] 0
_________________________________________________________________
conv2d (Conv2D) (None, 64, 64, 8) 392
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 8, 8, 8) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 8, 8, 16) 528
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 2, 2, 16) 0
_________________________________________________________________
flatten (Flatten) (None, 64) 0
_________________________________________________________________
dense (Dense) (None, 6) 390
=================================================================
Total params: 1,310
Trainable params: 1,310
Non-trainable params: 0
_________________________________________________________________
-
Model: "sequential"
:模型的名称为 "sequential"。 -
Layer (type)
:每一层的类型和名称。 -
Output Shape
:每一层的输出形状,例如(None, 64, 64, 8)
表示输出是一个 64x64x8 的张量。 -
Param #
:每一层的参数数量,表示模型中需要学习的权重和偏差的数量。 -
Total params
:模型的总参数数量,包括可训练参数和不可训练参数。 -
Trainable params
:可训练参数的数量,这些参数会在训练中进行优化。 -
Non-trainable params
:不可训练参数的数量,这些参数通常是与模型结构相关的,不会在训练中更新。
通过查看模型摘要,您可以了解模型的架构和参数量,以便更好地理解和调整模型。
utils.plot_model(cnnmodel, "model.png")
utils.plot_model(cnnmodel, "model.png")
这行代码用于绘制模型结构图并将其保存为 "model.png" 图像文件。这个操作通常需要借助额外的绘图库,比如 Matplotlib。这行代码假定您导入了名为 utils
的自定义模块,该模块可能包含了绘制模型结构图的功能。
绘制模型结构图有助于可视化和理解模型的层次结构,包括输入、各层的连接关系和输出。生成的 "model.png" 图像文件将包含模型的可视化表示,可以在工作目录中找到。
# 编译上面构建的模型。
# 指定adam为优化函数,这个函数里面设置了默认的学习率,当然你也可以修改学习率,详情可以查看官方文档
# 又为其指定了一个成本函数——交叉熵成本函数
cnnmodel.compile(optimizer=tf.keras.optimizers.Adam(),
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True),
metrics='acc')
这段代码编译了之前构建的CNN模型 cnnmodel
,设置了以下模型的训练配置:
-
optimizer=tf.keras.optimizers.Adam()
:指定优化器为Adam。Adam是一种常用的梯度下降优化算法,它根据梯度自适应地调整学习率,通常表现良好。 -
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True)
:指定成本函数为交叉熵成本函数(Categorical Crossentropy)。这是一种常用于多类别分类问题的损失函数。from_logits=True
表示模型的输出是未经过Softmax激活的原始分数,模型内部将自动应用Softmax。 -
metrics='acc'
:指定了评估指标为准确率(Accuracy)。在训练过程中,模型将计算并显示准确率。
通过编译模型,您已经设置了模型的训练配置,包括优化器、损失函数和评估指标。接下来,您可以使用训练数据集来训练模型,并使用测试数据集来评估模型的性能。
# 开始训练模型
# 将训练数据ds_train传入。
# epochs=100是指训练100个epoch。
history = cnnmodel.fit(ds_train,epochs=100)
这段代码用于开始训练之前编译好的CNN模型 cnnmodel
,并指定了以下训练参数:
-
ds_train
:这是训练数据集,包含了特征和标签,用于模型的训练。 -
epochs=100
:指定了训练的轮数,即训练100个epoch。一个epoch表示模型完整地遍历了一次训练数据集中的所有样本。在每个epoch中,模型将根据损失函数和优化器来更新参数,以提高模型性能。
训练过程会将模型逐渐调整到最佳状态,以最小化损失函数。训练过程的详细信息(例如损失值和准确率)将会被记录在 history
对象中,您可以在训练完成后使用这些信息来分析模型的性能和训练过程。
请注意,训练一个深度学习模型可能需要一些时间,具体取决于模型的大小、数据集的大小和计算资源的性能。训练完成后,您可以使用训练好的模型来进行预测或评估性能。
plt.plot(history.history['loss'], 'b--')
plt.ylabel('cost')
plt.xlabel('epoch')
plt.show()
plt.plot(history.history['acc'], 'r-')
plt.ylabel('acc')
plt.xlabel('epoch')
plt.show()
这段代码用于绘制训练过程中损失函数值和准确率的变化图。它使用了 history
对象中存储的训练过程历史数据。
-
plt.plot(history.history['loss'], 'b--')
:这行代码绘制了损失函数值随着训练轮数的变化图。history.history['loss']
包含了每个epoch的训练损失值。'b--'
指定了蓝色虚线样式。 -
plt.ylabel('cost')
:设置Y轴的标签为 "cost",表示损失函数值。 -
plt.xlabel('epoch')
:设置X轴的标签为 "epoch",表示训练轮数。 -
plt.show()
:显示绘制的图形。
接下来的代码块是类似的,它绘制了准确率随着训练轮数的变化图:
-
plt.plot(history.history['acc'], 'r-')
:绘制准确率随着训练轮数的变化图,history.history['acc']
包含了每个epoch的训练准确率值,'r-'
指定了红色实线样式。 -
plt.ylabel('acc')
:设置Y轴的标签为 "acc",表示准确率。 -
plt.xlabel('epoch')
:设置X轴的标签为 "epoch",表示训练轮数。 -
plt.show()
:显示绘制的图形。
这些图形可以帮助您可视化训练过程中损失函数的下降趋势以及模型准确率的提高趋势。通常,随着训练轮数的增加,损失函数应该逐渐减小,而准确率应该逐渐增加。如果您看到损失函数仍在波动或准确率不再提高,可能需要调整模型的超参数或采用其他策略来改善模型的性能。
# 最后看看在测试集上的损失和准确率是多少
loss, acc = cnnmodel.evaluate(ds_test)
print('loss:', loss, 'acc:', acc)
这段代码用于在测试集上评估已经训练好的CNN模型 cnnmodel
的性能。
-
loss, acc = cnnmodel.evaluate(ds_test)
:使用测试数据集ds_test
对模型进行评估,返回测试集上的损失值和准确率。 -
print('loss:', loss, 'acc:', acc)
:将损失值和准确率打印到控制台。
通过执行这段代码,您可以获取模型在测试数据集上的性能指标,其中:
loss
表示模型在测试集上的损失值。通常,损失值越低表示模型的性能越好。acc
表示模型在测试集上的准确率。它表示模型正确分类的样本比例,通常作为分类任务的性能指标。
这些指标可以帮助您评估模型的泛化性能,即模型在未见过的数据上的表现。较低的损失值和较高的准确率通常是良好模型性能的指示。
如果您运行这段代码并得到了测试集上的损失值和准确率,请注意评估结果,以确保模型在测试数据上表现良好。
import imageio
fname = "images/thumbs_up.jpg"
image = imageio.imread(fname)
plt.imshow(image)
这段代码用于加载并显示一张图像,其中 imageio.imread(fname)
用于加载图像文件,然后 plt.imshow(image)
用于显示图像。具体来说:
-
fname = "images/thumbs_up.jpg"
:指定了要加载的图像文件的文件名和路径。这里假设图像文件位于 "images" 目录下,文件名为 "thumbs_up.jpg"。 -
image = imageio.imread(fname)
:使用imageio
库的imread
函数加载指定路径的图像文件,并将加载的图像存储在image
变量中。 -
plt.imshow(image)
:使用 Matplotlib 库的imshow
函数显示加载的图像。这将在图形用户界面中显示图像。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 易语言 —— 开山篇
· 实操Deepseek接入个人知识库
· Trae初体验