【人工智能Ⅰ】实验10:人工神经网络图像分类

实验10 人工神经网络图像分类

一、实验目的

1:了解人工神经网络的结构和原理。

2:应用人工神经网络建立和训练模型,对模型进行评估。

二、实验内容和要求

【实验内容】

选择人工神经网络,对花卉图像或玉米果穗图像进行分类。花卉图像包括玫瑰,向日葵和蒲公英;玉米果穗图像包括虫蛀,损伤,发霉。

(1)可针对这些特点对图像的颜色、纹理、形状进行分析,从而进行特征选择与提取(例如:方向梯度直方图、灰度共生矩阵);

(2)也可以尝试不提取特征,直接将图像作为输入,对比效果;

(3)调整人工神经网络的参数,观察不同的参数对分类结果的影响;

(4)实现对花卉图像的分类。

【实验要求】

1:完成对数据集的分类任务。

2:调整不同的参数,通过对分类结果的对比,选取合适的参数。

3:使用不同的样本数量,查看是否对分类结果产生影响。可对样本进行扩增(例如:反转、平移、缩放、亮度变化)。

三、实验结果与分析

1:构建方向梯度直方图 & 灰度共生矩阵,并输入单张图片进行测试(花卉)


    在任务1中,调用路径【data1/1/55.jpg】下的花卉图片作为示例,进行方向梯度直方图(HOG)和灰度共生矩阵(GLCM)的测试,原始图像如下图所示。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第1张图片

根据依赖调用【from skimage.feature import graycomatrix, graycoprops】后,输入像素对之间的距离(distances)、像素对之间的角度(angles)、经过灰度处理的图像等信息,可以得到GLCM的各种特征,包括对比度(contrast)、不相似度(dissimilarity)、均匀性(homogeneity)、能量(energy)、相关性(correlation)。程序输出的特征结果如下图所示。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第2张图片


根据依赖调用【from skimage.feature import hog】后,输入经过灰度处理的图像、特征的方向分箱数等信息,可以得到特征向量(fd)和可视化图像矩阵(hog_image)。程序输出的特征向量和hog矩阵结果如下图所示。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第3张图片

根据依赖调用【import matplotlib.pyplot as plt】后,可以绘制出灰度图像和HOG可视化图像的对比图。程序输出的对比图如下图所示。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第4张图片

2:将hog矩阵作为输入特征,实例化ANN模型(花卉)

在任务2中,将任务1的hog矩阵特征结果作为人工神经网络的输入层节点数,调用sequential模型构建隐藏层和输出层。实例化模型的结构如下图所示。   同时,损失函数采用交叉熵,优化器采用Adam且学习速率从0.001开始。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第5张图片

在迭代过程中,模型的损失函数、训练集准确率、测试集准确率等结果如下图所示。可以观察到,随着迭代次数的增加,模型的损失在不断下降,训练集的准确率在不断上升,测试集的准确率也呈现上升趋势,但是存在一定的过拟合现象。Test Accuracy的最好结果是:83.33%。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第6张图片

3:将灰度图像的像素矩阵作为特征,实例化ANN模型(花卉)

在任务3中,将经过灰度处理的图像像素矩阵结果作为人工神经网络的输入层节点数,调用sequential模型构建隐藏层和输出层。实例化模型、损失函数和优化器和任务2保持一致。

在迭代过程中,模型的损失函数、训练集准确率、测试集准确率等结果如下图所示。可以观察到,随着迭代次数的增加,模型的损失在不断下降,训练集的准确率在不断上升,测试集的准确率呈现波动趋势,并且存在一定的过拟合现象。Test Accuracy的最好结果是:58.33%。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第7张图片

经过对比分析可以得到:在Test Accuracy方面,【将hog矩阵作为特征】比【将灰度图像的像素矩阵作为特征】的模型表现更好。

4:将原始彩色图像的像素矩阵作为特征,实例化ANN模型(花卉)

在任务4中,将原始彩色图像像素矩阵结果作为人工神经网络的输入层节点数,调用sequential模型构建隐藏层和输出层。实例化模型、损失函数和优化器和任务2保持一致。

但是,ANN模型需要修改input_size,将其扩大三倍,因为之前输入的特征是单色通道,而现在输入的特征是彩色通道(RGB)。

在迭代过程中,模型的损失函数、训练集准确率、测试集准确率等结果如下图所示。可以观察到,随着迭代次数的增加,模型的损失在不断下降,训练集的准确率在不断上升,测试集的准确率也呈现上升趋势,但是存在一定的过拟合现象。Test Accuracy的最好结果是:91.67%。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第8张图片

 经过对比分析可以得到:在Test Accuracy方面,【将原始彩色图像的像素矩阵作为特征】比【将灰度图像的像素矩阵作为特征】的模型表现更好,同时也比【将hog矩阵作为特征】的模型表现更好。

5:重复任务2至任务4的操作,应用在玉米数据集上

应用任务2的结果:【将hog矩阵作为特征】

Test Accuracy的最好结果是:73.33%。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第9张图片

应用任务3的结果:【将灰度图像的像素矩阵作为特征】

Test Accuracy的最好结果是:70.00%。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第10张图片

应用任务4的结果:【将原始彩色图像的像素矩阵作为特征】

Test Accuracy的最好结果是:80.00%。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第11张图片

经过对比分析可以得到:在Test Accuracy的模型表现方面,【将原始彩色图像的像素矩阵作为特征】 > 【将hog矩阵作为特征】 > 【将灰度图像的像素矩阵作为特征】。

6:基于任务4的操作,调整人工神经网络的参数(花卉)

在任务6中,减少隐藏层的结点个数,尝试从[256, 128]减少至[128, 64],并观察模型迭代的结果。实例化模型的修改如下图所示。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第12张图片

程序输出的结果如下图所示。Test Accuracy的最好结果是:100.00%。  

【人工智能Ⅰ】实验10:人工神经网络图像分类_第13张图片

经过对比分析可以得到:在Test Accuracy方面,隐藏层为[256, 128]结构的模型表现不如隐藏层为[128, 64]结构的模型表现。


继续减少隐藏层的结点个数,尝试从[128, 64]减少至[64, 32],并观察模型迭代的结果。实例化模型的修改如下图所示。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第14张图片

程序输出的结果如下图所示。Test Accuracy的最好结果是:75.00%。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第15张图片

经过对比分析可以得到:在Test Accuracy方面,隐藏层为[64, 32]结构的模型表现不如隐藏层为[128, 64]结构的模型表现。

    综上所述,模型的隐藏层结点数并非越多越好,而是遵循一个随着结点数的增加而表现效果先上升后下降的过程。

7:基于任务4的操作,通过数据增强增加数据量(花卉)

在任务7中,对训练集数据进行数据增强,而测试集数据保持原样,并观察模型迭代的结果。添加数据增强模块的修改代码如下图所示。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第16张图片


程序输出的结果如下图所示。Test Accuracy的最好结果是:91.67%。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第17张图片

综上所述,训练集数据进行随机旋转的数据增强操作后,模型的泛化效果更好,每一次迭代的Test Accuracy效果整体优于任务4中不采用数据增强的效果。

四、遇到的问题和解决方法

问题1:data_set 列表中的每个元素(即每张图像的特征向量)长度不一致。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第18张图片

解决1:确保所有图像在加载之前都被调整到相同的尺寸,通过 resize 函数确保每个图像都被统一调整到相同的大小。同时,在将数据添加到 data_set 之前,检查每个图像的特征向量长度是否一致。修改后的代码如下所示。

def getImage(file, size=(28, 28)):

def getDataSet(data_path, image_size=(28, 28)):

问题2:实验指导中给出的getDataSet并没有传参,调用函数时会报错。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第19张图片

解决2:调用函数时进行传参。修改后的代码如下所示。

# 数据集读取路径

data_path = r"/home/ubuntu/exp11/data1"

# 数据集构建

X, y = getDataSet(data_path)

问题3:神经网络中有一个矩阵乘法因为矩阵的形状不匹配而操作失败。在一个线性(全连接)层中,输入张量的形状与该层的权重矩阵形状不兼容。

【人工智能Ⅰ】实验10:人工神经网络图像分类_第20张图片

解决3:首先,确定 HOG 特征的实际长度,可以通过对一个样本图像计算 HOG 特征并查看返回的特征向量的长度。然后,更新模型的输入层尺寸,根据计算出的 HOG 特征长度,更新ANN中输入层的特征数。修改后的代码如下所示。

# 示例,计算单个图像的 HOG 特征长度

sample_image = skio.imread(os.path.join(data_path, os.listdir(data_path)[0], os.listdir(os.path.join(data_path, os.listdir(data_path)[0]))[0]), as_gray=True)

sample_image_resized = resize(sample_image, (228, 228))

sample_hog_features = hog(sample_image_resized, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(2, 2), block_norm='L2-Hys')

hog_feature_length = len(sample_hog_features)

print("HOG feature length:", hog_feature_length)

# 更新模型的输入层尺寸

model = nn.Sequential(

    nn.Linear(hog_feature_length, hidden_sizes[0]),  # 使用计算出的 HOG 特征长度

    nn.ReLU(),

    nn.Linear(hidden_sizes[0], hidden_sizes[1]),

    nn.ReLU(),

    nn.Linear(hidden_sizes[1], output_size),

    nn.LogSoftmax(dim=1)

)

五、实验总结

1:方向梯度直方图 (HOG) 通过计算图像局部区域的梯度方向直方图来捕捉形状信息。HOG 特征适用于形状和轮廓的特征提取。

2:灰度共生矩阵(GLCM)是一种用于纹理分析的统计方法,通过考察像素对(按照特定的空间关系)的灰度级联合分布来量化纹理。

3:数据增强:通过对训练数据应用各种变换来增加数据多样性的技术。在深度学习中,数据增强有助于提高模型的泛化能力,减少过拟合。

4:彩色图像处理:处理彩色图像需要考虑多个通道(通常是RGB通道),并根据需要进行通道分离、合并或处理。

5:人工神经网络的步骤流程图:

【人工智能Ⅰ】实验10:人工神经网络图像分类_第21张图片

六、程序源代码

1:方向梯度直方图 & 灰度共生矩阵 在单张图片上的测试

from skimage.feature import hog

from skimage import io, color

import matplotlib.pyplot as plt

from skimage.feature import graycomatrix, graycoprops

import numpy as np

# 读取图像并转换为灰度图

image = io.imread(r"/home/ubuntu/exp11/data1/1/55.jpg")

gray_image = color.rgb2gray(image)

# 将灰度图像转换为整数类型(GLCM 需要整数类型)

gray_image = (gray_image * 255).astype(np.uint8)

# 计算 GLCM

# distances 表示像素对之间的距离,angles 表示像素对之间的角度

glcm = graycomatrix(gray_image, distances=[1], angles=[0, np.pi/4, np.pi/2, 3*np.pi/4], levels=256, symmetric=True, normed=True)

# 计算 GLCM 的各种特征

contrast = graycoprops(glcm, 'contrast')

dissimilarity = graycoprops(glcm, 'dissimilarity')

homogeneity = graycoprops(glcm, 'homogeneity')

energy = graycoprops(glcm, 'energy')

correlation = graycoprops(glcm, 'correlation')

# 打印结果

print()

print("Contrast【对比度】:", contrast)

print("Dissimilarity【不相似度】:", dissimilarity)

print("Homogeneity【均匀性】:", homogeneity)

print("Energy【能量】:", energy)

print("Correlation【相关性】:", correlation)

# 计算 HOG 特征

fd, hog_image = hog(gray_image, orientations=9, pixels_per_cell=(8, 8),

                    cells_per_block=(2, 2), visualize=True, block_norm='L2-Hys')

# fd 是特征向量,hog_image 是可视化的 HOG 图像

print()

print("特征向量:")

print(fd)

print()

print("hog矩阵:")

print(hog_image)

print()

# 显示原始图像

plt.figure(figsize=(8, 4))

plt.subplot(121)

plt.imshow(gray_image, cmap='gray')

plt.title('Original Image')

plt.axis('off')

# 显示 HOG 可视化图像

plt.subplot(122)

plt.imshow(hog_image, cmap='gray')

plt.title('HOG Visualization')

plt.axis('off')

plt.savefig(r"/home/ubuntu/hot.png")

2:不提取特征的ANN模型

import os

import numpy as np

from skimage import io as skio

from skimage.transform import resize

import torch

from torch import nn

from torch.utils.data import DataLoader, TensorDataset

from torchvision import transforms

import torch.optim as optim

from sklearn.model_selection import train_test_split

# 定义图像读取和处理函数

def getImage(file, size=(228, 228)):

    image = skio.imread(file, as_gray=True)

    image_resized = resize(image, size)

    return image_resized.flatten()

def getDataSet(data_path, image_size=(228, 228)):

    data_set = []

    for label, class_dir in enumerate(os.listdir(data_path)):

        class_path = os.path.join(data_path, class_dir)

        for file in os.listdir(class_path):

            img = getImage(os.path.join(class_path, file), image_size)

            img = np.append(img, label)

            data_set.append(img)

    data_set = np.array(data_set)

    X, y = data_set[:, :-1], data_set[:, -1]

    return X, y

# 数据集路径

data_path = r"/home/ubuntu/exp11/data2"

# 获取数据

X, y = getDataSet(data_path, image_size=(228, 228))

# 划分数据集

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 转换为torch张量

X_train = torch.Tensor(X_train)

y_train = torch.Tensor(y_train).long()

X_test = torch.Tensor(X_test)

y_test = torch.Tensor(y_test).long()

# 创建数据加载器

train_data = TensorDataset(X_train, y_train)

test_data = TensorDataset(X_test, y_test)

train_loader = DataLoader(train_data, batch_size=64, shuffle=True)

test_loader = DataLoader(test_data, batch_size=64, shuffle=False)

# 实例化模型

input_size = 228*228

# hidden_sizes = [128, 64]

hidden_sizes = [256, 128]

output_size = 3  # 类别数量

model = nn.Sequential(

    nn.Linear(input_size, hidden_sizes[0]),

    nn.ReLU(),

    nn.Linear(hidden_sizes[0], hidden_sizes[1]),

    nn.ReLU(),

    nn.Linear(hidden_sizes[1], output_size),

    nn.LogSoftmax(dim=1)

)

# 定义损失函数和优化器

criterion = nn.CrossEntropyLoss()

optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练模型并计算准确率

epochs = 30

for epoch in range(epochs):

    running_loss = 0

    correct_train = 0

    total_train = 0

    # 训练过程

    model.train()

    for images, labels in train_loader:

        optimizer.zero_grad()

        outputs = model(images)

        loss = criterion(outputs, labels)

        loss.backward()

        optimizer.step()

        running_loss += loss.item()

        _, predicted = torch.max(outputs.data, 1)

        total_train += labels.size(0)

        correct_train += (predicted == labels).sum().item()

    train_accuracy = 100 * correct_train / total_train

    # 测试过程

    correct_test = 0

    total_test = 0

    model.eval()

    with torch.no_grad():

        for images, labels in test_loader:

            outputs = model(images)

            _, predicted = torch.max(outputs.data, 1)

            total_test += labels.size(0)

            correct_test += (predicted == labels).sum().item()

    test_accuracy = 100 * correct_test / total_test

    print(f'Epoch {epoch+1}, Loss: {running_loss/len(train_loader)}, '

          f'Train Accuracy: {train_accuracy}%, Test Accuracy: {test_accuracy}%')

3:提取特征的ANN模型

import os

import numpy as np

from skimage import io as skio

from skimage.transform import resize

import torch

from torch import nn

from torch.utils.data import DataLoader, TensorDataset

from torchvision import transforms

import torch.optim as optim

from sklearn.model_selection import train_test_split

from skimage.feature import hog

# 修改 getImage 函数以提取 HOG 特征

def getImage(file, size=(228, 228)):

    image = skio.imread(file, as_gray=True)

    image_resized = resize(image, size)

    hog_features = hog(image_resized, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(2, 2), block_norm='L2-Hys')

    return hog_features

def getDataSet(data_path, image_size=(228, 228)):

    data_set = []

    for label, class_dir in enumerate(os.listdir(data_path)):

        class_path = os.path.join(data_path, class_dir)

        for file in os.listdir(class_path):

            img = getImage(os.path.join(class_path, file), image_size)

            img = np.append(img, label)

            data_set.append(img)

    data_set = np.array(data_set)

    X, y = data_set[:, :-1], data_set[:, -1]

    return X, y

# 数据集路径

data_path = r"/home/ubuntu/exp11/data2"

# 获取数据集,使用 HOG 特征

X, y = getDataSet(data_path, image_size=(228, 228))

# 划分数据集,转换为 torch 张量

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

X_train = torch.Tensor(X_train)

y_train = torch.Tensor(y_train).long()

X_test = torch.Tensor(X_test)

y_test = torch.Tensor(y_test).long()

# 创建数据加载器

train_data = TensorDataset(X_train, y_train)

test_data = TensorDataset(X_test, y_test)

train_loader = DataLoader(train_data, batch_size=64, shuffle=True)

test_loader = DataLoader(test_data, batch_size=64, shuffle=False)

# 实例化模型

input_size = 228*228

# hidden_sizes = [128, 64]

hidden_sizes = [256, 128]

output_size = 3  # 类别数量

# 示例,计算单个图像的 HOG 特征长度

sample_image = skio.imread(os.path.join(data_path, os.listdir(data_path)[0], os.listdir(os.path.join(data_path, os.listdir(data_path)[0]))[0]), as_gray=True)

sample_image_resized = resize(sample_image, (228, 228))

sample_hog_features = hog(sample_image_resized, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(2, 2), block_norm='L2-Hys')

hog_feature_length = len(sample_hog_features)

print("HOG feature length:", hog_feature_length)

# 更新模型的输入层尺寸

model = nn.Sequential(

    nn.Linear(hog_feature_length, hidden_sizes[0]),  # 使用计算出的 HOG 特征长度

    nn.ReLU(),

    nn.Linear(hidden_sizes[0], hidden_sizes[1]),

    nn.ReLU(),

    nn.Linear(hidden_sizes[1], output_size),

    nn.LogSoftmax(dim=1)

)

# 定义损失函数和优化器

criterion = nn.CrossEntropyLoss()

optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练模型并计算准确率

epochs = 30

for epoch in range(epochs):

    running_loss = 0

    correct_train = 0

    total_train = 0

    # 训练过程

    model.train()

    for images, labels in train_loader:

        optimizer.zero_grad()

        outputs = model(images)

        loss = criterion(outputs, labels)

        loss.backward()

        optimizer.step()

        running_loss += loss.item()

        _, predicted = torch.max(outputs.data, 1)

        total_train += labels.size(0)

        correct_train += (predicted == labels).sum().item()

    train_accuracy = 100 * correct_train / total_train

    # 测试过程

    correct_test = 0

    total_test = 0

    model.eval()

    with torch.no_grad():

        for images, labels in test_loader:

            outputs = model(images)

            _, predicted = torch.max(outputs.data, 1)

            total_test += labels.size(0)

            correct_test += (predicted == labels).sum().item()

    test_accuracy = 100 * correct_test / total_test

    print(f'Epoch {epoch+1}, Loss: {running_loss/len(train_loader)}, '

          f'Train Accuracy: {train_accuracy}%, Test Accuracy: {test_accuracy}%')

你可能感兴趣的:(人工智能,人工智能,分类,数据挖掘)