一、图像分类
主要从图像中识别出是什么类别,从10种不同的物种、物体中准确识别出来。
使用公共数据集、样本数60000个,训练集占总样本的83.33%,测试集占总样本的16.67%,其中训练集包含50000个样本,测试集包含10000个样本。样本的形状宽高是32x32,有3个颜色通道。50000个样本对应50000个标签。标签是一维的每个标签是单一的一个值
1、分析数据集
import tensorflow as tf
from tensorflow.keras.datasets import cifar10
import matplotlib
matplotlib.use('TkAgg') # 添加这一行
import matplotlib.pyplot as plt
# 忽略 CUDA 相关警告
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
# 加载CIFAR-10数据集
(train_images, train_labels), (_, _) = cifar10.load_data()
# 定义类别标签
class_labels = ['飞机', '汽车', '鸟类', '猫', '鹿', '狗', '青蛙', '马', '船', '卡车']
# 打印整个数据集的信息
print("训练集图像形状:", train_images.shape)
print("训练集标签形状:", train_labels.shape)
print("测试集图像形状:", test_images.shape)
print("测试集标签形状:", test_labels.shape)
# 显示前 5 张训练集图像
plt.figure(figsize=(15, 3))
for i in range(5):
plt.subplot(1, 5, i + 1)
plt.imshow(train_images[i])
plt.title(class_labels[train_labels[i][0]])
plt.axis('off')
# 显示图像结果
plt.show()
打印
数据集:
图像:
2、整个图像分类模型
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.utils import to_categorical
# 加载CIFAR-10数据集
(train_images, train_labels), (test_images, test_labels) = cifar10.load_data()
# 数据预处理
train_images = train_images.astype('float32') / 255
test_images = test_images.astype('float32') / 255
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
# 定义CNN模型
def create_cnn_model(input_shape=(32, 32, 3), num_classes=10):
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(num_classes, activation='softmax'))
return model
# 创建CNN模型
model = create_cnn_model(input_shape=(32, 32, 3), num_classes=10)
# 编译模型
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
# 训练模型
model.fit(train_images, train_labels, epochs=5, batch_size=64, validation_split=0.2)
# 评估模型
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(f'Test accuracy: {test_acc}')
打印
准确率:
分析:
(1)图像分类步骤:
收集数据,定义模型,特征提取,模型训练,模型评估,模型性能优化
(2)收集数据
使用公共数据集:CIFAR-10数据集,该数据集包含10个类别的彩色图像, 类别有飞机、汽车、鸟类、猫、鹿、狗、青蛙、马、船、卡车。每个类别有6000张图像,总共包含60000张图像。每张图像的尺寸为32x32像素,具有RGB(红、绿、蓝)三个颜色通道。
(3)数据集信息:
总样本数60000个,训练集50000,测试集10000,输入模型尺寸32*32,3通道,每个样本对应每个标签。
(4)数据预处理:
归一化:将像素值缩放到0到1的范围内。假如原始图像某个像素为102,归一化后新值为102/255=0.4,因此归一化实现了把像素值缩放到0-1范围内。
图像以数据形式表示:
代码:
import tensorflow as tf
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.utils import to_categorical
# 加载CIFAR-10数据集
(train_images, train_labels), (test_images, test_labels) = cifar10.load_data()
# 数据预处理
train_images = train_images.astype('float32') / 255
test_images = test_images.astype('float32') / 255
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
# 打印部分样本数据
num_samples_to_display = 3
for i in range(num_samples_to_display):
print(f"样本 {i + 1}:")
print("图像:")
print(train_images[i])
print("标签:")
print(train_labels[i])
print("=" * 30)
打印:
(5)分析:
每个样本的图像数据是一个三维数组,其形状为 (32, 32, 3) ,图像数据的数值都是进行归一化后处理的结果。标签也是使用to_categorical函数对10个类别独热编码转换,做到了其他全为0,样本对应的那个标签才为1。
3、定义模型/特征提取
代码:
def create_cnn_model(input_shape=(32, 32, 3), num_classes=10):
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(num_classes, activation='softmax'))
return model
create_cnn_model()函数中两个形参,第一个形参input_shape代表输入的图像宽高是32*32像素的,3通道彩色图像第二个形参num_classes代表这个模型应该输出的数量是10个类别。models.Sequential()函数是Keras定义网络模型的一种方式,可以一层一层堆叠各种层。Keras 定义网络模型的另一种方式是函数式 API ,用于定义更为灵活和复杂的神经网络模型, 允许构建具有多个输入和多个输出的模型,以及共享层等更复杂的模型结构。
layers.Conv2D(32, (3, 3), activation='relu'添加了一个卷积层,该层使用了 32 个大小为 3x3 的卷积核,激活函数为 ReLU。
layers.MaxPooling2D((2, 2)),最大池化层会对输入的特征图进行下采样,窗口大小为 2x2,步长(strides)默认为与窗口大小相同。
三次卷积两次池化之后,最后使用一个Flatten()函数,将多维数据(例如卷积层的输出)展平成一维数组。
layers.Dense(64, activation='relu'),模型中添加了一个具有 64 个神经元的全连接层,激活函数为 ReLU。
layers.Dense(num_classes, activation='softmax'),用于多类别分类的全连接层。
4、训练模型、评估模型
model.compile(optimizer='adam', loss='categorical_crossentropy',metrics=['accuracy']),该函数确定了优化器是adam,损失函数:categorical crossentropy,评估指标是准确率
model.fit(train_images, train_labels, epochs=5, batch_size=64, validation_split=0.2)
第一个参数是训练图像,第二个是图像标签,第三个是训练轮次,第四个是指定了在训练过程中将20%的训练数据用于验证。
(1)卷积层优化
def create_cnn_model(input_shape=(32, 32, 3), num_classes=10):
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(num_classes, activation='softmax'))
return model
打印准确率
def create_cnn_model(input_shape=(32, 32, 3), num_classes=10):
model = models.Sequential()
model.add(layers.Conv2D(128, (3, 3), activation='relu', input_shape=input_shape))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(num_classes, activation='softmax'))
return model
def create_cnn_model(input_shape=(32, 32, 3), num_classes=10):
model = models.Sequential()
model.add(layers.Conv2D(512, (3, 3), activation='relu', input_shape=input_shape))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(512,(3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(256, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dense(num_classes, activation='softmax'))
return model
def create_cnn_model(input_shape=(32, 32, 3), num_classes=10):
model = models.Sequential()
model.add(layers.Conv2D(512, (3, 3), activation='relu', input_shape=input_shape))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(512,(3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(512, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(num_classes, activation='softmax'))
return model
激活函数优化
Leaky ReLU:
def create_cnn_model(input_shape=(32, 32, 3), num_classes=10):
model = models.Sequential()
# 第一层卷积层
model.add(layers.Conv2D(32, kernel_size=(3, 3), strides=(1, 1), padding='valid', input_shape=input_shape))
model.add(LeakyReLU(alpha=0.01)) # 使用 Leaky ReLU 激活函数
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
# 第二层卷积层
model.add(layers.Conv2D(64, kernel_size=(3, 3), strides=(1, 1), padding='same'))
model.add(LeakyReLU(alpha=0.01)) # 使用 Leaky ReLU 激活函数
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
# 第三层卷积层
model.add(layers.Conv2D(64, kernel_size=(3, 3), strides=(1, 1), padding='same'))
model.add(LeakyReLU(alpha=0.01)) # 使用 Leaky ReLU 激活函数
# 展平层
model.add(layers.Flatten())
# 全连接层
model.add(layers.Dense(64))
model.add(LeakyReLU(alpha=0.01)) # 使用 Leaky ReLU 激活函数
# 输出层
model.add(layers.Dense(num_classes, activation='softmax'))
return model
知识补充:
1、常见激活函数:ReLu、softmax、Sigmoid、Tanh
2、池化:减小特征图的空间尺寸,保留特征的最显著部分。
卷积:特征提取
卷积核:
-
特征提取: 卷积核通过滑动在输入数据上,将其与卷积核进行卷积操作,从而提取输入数据中的不同特征。每个卷积核可以学习识别不同的局部特征,例如边缘、纹理或更高级的特征。
-
模式识别: 卷积核的权重参数决定了它对输入数据的响应方式。通过训练过程中调整这些权重,卷积核可以变成不同的模式识别器,捕捉输入数据中的不同模式和结构。
-
参数共享: 卷积核的参数是共享的,这意味着相同的卷积核会在整个输入图像上滑动,对不同的位置执行相同的卷积操作。这种参数共享有助于减少模型的参数数量,提高模型的效率。
-
空间局部性: 卷积核的局部感受野决定了它在输入数据中关注的空间范围。这种局部性使得卷积操作能够更好地捕捉输入数据的局部模式,从而提高模型的表示能力。
3、