当前位置:   article > 正文

目标检测——线性分类 (模型及训练模型)_基于深度学习的图像线性分类器实验

基于深度学习的图像线性分类器实验

 

一、线性分类

1.1 实验介绍

  • 关于线性分类的相关知识
  • 基本的数据集知识
  • 如何使用 Scikit-image 中的模块对数据集进行训练和分类

 

1.2 知识点

  • 图像分类
  • 数据集基本知识
  • 分类模型训练流程
  • 构建线性分类器

 
 

二、图像分类的基本知识

  • 回顾 ——通过前面的三节实验:
  1. 如何使用图像金字塔和滑动窗口在图片中寻找目标
  2. 通过方向梯度直方图的方法对图像进行特征描述

但是光靠这些方法还不足以实现一个目标检测项目

  • 对一张图片进行目标检测还需要判断滑动窗口寻找的物体是否是想要检测到?
  • 这就涉及到图像分类问题。

 

2.1 图像分类

计算机视觉中的图像分类:

  • 简单来说就是为一张图片赋予一个标签(Label)
  • 一个标签就是人为定义的集合中的一个元素

例如:下面公式表示我们定义了一个集合 D D D c a t cat cat d o g dog dog 则被称为集合 D D D 的 2 个不同标签

D = { c a t ,   d o g } D = \{cat,\ dog\} D={cat, dog}


以下图为例,图像分类任务就是:

  1. 希望给计算机提供左边的图片,则计算机将赋予其 c a t cat cat 标签
  2. 提供右边的图片,则赋予其 d o g dog dog 标签
    图片描述

在计算机视觉中我们希望构建一个系统

  1. 当给系统输入一张图片时,系统会分析该图片然后输出一系列标签的概率值(例如 c a t = 0.89 cat = 0.89 cat=0.89 d o g = 0.1 dog = 0.1 dog=0.1
  2. 而这些标签属于我们事先定义的一个类别集合(例如 c a t cat cat d o g dog dog 属于集合 D D D)。

更具体的来说:

  • 假设我们有一张宽和高分别为 W ,   H W,\ H W, H 的 3 通道的彩色图片
  • 则图片共有 W × H × 3 W\times H\times 3 W×H×3像素
  • 我们希望将所有这些像素值输入一个机器学习或深度学习模型
  • 然后该模型通过计算将图片正确的分到所属类别

 

2.2 数据集

要想通过机器学习或深度学习实现图像分类

  • 我们还需要为其提供数据集

数据集:

  • 由许多数据组成的集合
  • 数据集中的任意一个元素可以是图片、文本、音频等。

我们希望机器学习或深度学习算法

  1. 通过学习和提炼数据集中的规律
  2. 运用这些规律正确地分类它从未 ⌈ 看 ⌋ \lceil 看 \rfloor 到过的图片。

 

故机器学习和深度学习是数据驱动的方法:

  • 数据集则是不可或缺的前提。
  • 其中学习和提炼的过程我们称之为训练(Train)也可称为建模的过程
  • 最后学习得数据集中的规律表示我们已经完成了建模并获得一个模型(Model)

 
 

三、构建图像分类模型

  • 至此我们已经了解了一些基本的图像分类和数据集概念
  • 现在让我们更进一步介绍如何构建一个图像分类模型
  • 构建一个分类模型基本上可以分为下面几个步骤。

3.1 收集数据

为了构建一个图像分类模型,我们首先需要收集不同的图片创建一个数据集

  • 对于数据集中的每张图片我们都有一个对应的标签
  • 这些标签都属于一个预先定义好的集合(例如前面提到的 c a t cat cat d o g dog dog 属于集合 D D D)。

还有一点需要注意的是:我们在创建数据集时要尽量让每种类别的图片数量相差不太大

  • 例如假设我们构建一个只有猫和狗的数据集
  • 那么猫这个类别(或称为标签)的图片数量尽量不要与狗这个类别(或称为标签)的图片数量相差太大。
  • 如果数量相差太大(例如猫的图片数量是狗的图片数量的三倍,这种情况通常称为样本不均衡)则会导致模型的性能较差

 

3.2 数据集划分

收集好数据集后通常我们会将其分为三份:
训练集、验证集、测试集

  1. 训练集
    • 用于让机器学习或深度学习算法(也可称为分类器)从中学习每个类别的特征规律
    • 我们将数据输入分类器,然后分类器通过计算输出分类结果
    • 如果输出结果与输入数据所对应标签不一致则分类错误,分类器将进行自我修正,最后完成训练生成一个模型
       
  2. 训练完成后我们用测试集评估模型性能
    • 注意测试集和训练集必须是数据集中的两个没有交集的子集
    • 因为如果用于评估模型的测试集中掺杂了训练集中的样本评估的结果就不够准确。
    • 通常数据集会被按比例分为:训练集占 75%,测试集占 25%。
    • 数据集的比例划分没有明确规定,可以是 60% 和 40%、90% 和 10% 等。
    • 如果数据集中的样本数量有 100 万个,则将 25% 的样本划分为用于评估模型的测试集显然是不合理的。
       
  3. 验证集:
    • 主要用于评估模型效果以及调整超参数
    • 在机器学习和深度学习中会有一些需要设置的参数,这些参数不是通过训练过程得到的而是需要事先设定
    • 通常我们需要对这些参数调优以便提高模型的性能和效果,这些参数被称为超参数
    • 验证集不是必需的,如果不需要调参可以不划分验证集
    • 通常会从训练集中抽取 10% 到 20%作为验证集。

 

3.3 训练

有了数据集并且划分了训练集和测试集,我们就可以训练自己的模型了。

  1. 首先我们需要一个评分函数(Score Function)输入图片映射到类别标签

    • 例如,假设我们有一个评分函数 f ( x ; w ) f(x;w) f(x;w)
    • 我们将训练集中的图片作为函数的输入
    • 函数通过计算输出预测的类别标签
  2. 然后一个损失函数(Loss Function)将会被用于评估输出的结果与该数据所对应的真实标签的近似程度

    • 两个标签的相似程度越高,损失函数的值就越小
    • 我们希望通过整个训练过程最小化损失函数以提高分类的准确度。

 

3.4 评估

完成训练后我们用测试集评估获得的模型

  1. 简单来说就是:我们会将测试集中的每张图片输入模型
  2. 看看模型对每张图片分类后的标签是否正确

 
 

四、实现一个线性分类任务

  • 已经了解了图片分类和数据集的基本知识

下面我们将使用 Scikit-learn 工具教会大家使用线性分类器

  1. 训练一个模型
  2. 使用测试集评估该模型

 
我们将使用学习过的方向梯度直方图

  1. 提取数据集中每张图片的特征
  2. 然后用这些特征训练分类模型

 

4.1使用的数据集

首先我们先了解下我们将使用的数据集

  • 看到文件夹包含 peoplebackground 两个子文件夹
    • 表示两个类别

图片描述

这个文件夹内各包含两千多张图片

  1. people 文件夹内都是人的图片
  2. backgorund 内都是一些背景图片

我们将使用这个数据集训练一个用于分辨人和背景的分类模型


 

4.2 处理数据集路径的函数

首先我们将创建一个用于处理数据集路径的函数

  • 我们使用这个函数将数据集中的所有图片的路径保存在一个列表
  • 并将每张图片对应的标签保存在另一个列表中。

模型训练阶段,我们将从这两个列表读取数据集中的图片和其对应的标签

from os import listdir
from os.path import join
  • 1
  • 2

上面的代码表示从 osos.path 中导入需要的功能模块。

接着我们创建一个 preprocessing 函数

  • 这个函数用于读取数据集中所有图片的路径以及每张图片对应的标签
  • (这里标签是指数据集中图片的内容是人或图片中的内容没有人)。
  • 这个函数需要一个输入参数 datasetpath,这个参数是数据集的路径
def preprocessing(datasetpath):
    
    dataset = []
    labels = []
    
    categories = [join(datasetpath, i) for i in listdir(datasetpath)]
    
    for i in categories:
        dataset.extend([join(i, f) for f in listdir(i)])
        
    labels = [i.split("/")[1] for i in dataset]
    return (dataset, labels)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

然后我们创建两个列表 datasetlabels

  1. dataset 用于存放每张图片的路径
  2. labels 用于存放每张图片对应的标签

 

在代码中:

  • 我们使用列表解析方法在 categories 中存储数据集下的每个子文件夹的路径
  • 具体的方法是:
    1. 先使用 listdir 方法获取 datasetpath 下每个子文件夹名称
    2. 然后使用 join 方法将 datasetpath 的路径和每个子文件夹的名称拼接获取子文件夹的路径
    3. 例如,将 "pedestrian" 作为函数的输入值,则 categories 的值为:["pedestrian/people", "pedestrian/background"]

 
接着我们用一个 for 循环将每张图片的路径保存dataset 中。

  1. 具体方法是在列表解析方法中先用 listdir 获取每个子文件夹下所有图片的名称
  2. 然后使用 join 方法将子文件夹的路径和它里面的图片名称拼接
  3. 最后使用 extend 方法将每张图片的路径存储dataset 中。

在代码中,我们使用列表解析获取每张图片的标签 labels

  1. 具体方法是对于 dataset 中保存的每个路径 i
  2. 我们使用 split("/")[1] 方法获取每张图片所属的文件夹名称
  3. 然后将这些名称保存labels
  4. 最后返回一个元组 (dataset, labels)

 

执行下面的代码来看一下函数的输出结果。

  1. 我们调用 preprocessing 函数并将数据集的路径 pedestrian 作为函数的输入值
  2. 然后分别输出 datasetlabels
    图片描述

输出结果:

  1. 图片左边的一列是图片的路径
  2. 右边的一列是每张图片对应的标签

 

4.3 方向梯度直方图模块

我们已经学习了方向梯度直方图

  • 现在我们将其封装成一个模块方便在训练模型时调用提取图片的特征
  • 首先从 Scikit-image 导入 feature 模块。
from skimage import feature
  • 1

然后我们创建一个 HOG 类并初始化 __init__ 构造函数。

  • 构造函数需要 4 个参数 :
    orientationspixelsPerCellcellsPerBlocktransform
  1. orientations 表示要将梯度方向分成几个区间,这里我们设置一个默认值 9
  2. pixelsPerCell 表示每个 Cell 中有几个像素,我们设置默认值为 (8, 8)
  3. cellsPerBlock 表示每个 Block 中有几个 Cells,我们设置默认值为 (3, 3)
  4. transform 是一个布尔类型,表示是否使用伽马校正预先对图片进行归一化处理,我们设置默认值为 False
class HOG:
    def __init__(self, orientations = 9, pixelsPerCell = (8, 8),
        cellsPerBlock = (3, 3), transform = False):
        self.orienations = orientations
        self.pixelsPerCell = pixelsPerCell
        self.cellsPerBlock = cellsPerBlock
        self.transform = transform
        
    def describe(self, image):
        hist = feature.hog(image, orientations = self.orienations,
                           pixels_per_cell = self.pixelsPerCell,
                           cells_per_block = self.cellsPerBlock,
                           transform_sqrt = self.transform)
        return hist
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

接下来我们再定义一个函数 describe

  • 这个函数将用于计算 HOG 特征
  • 该函数需要输入一个参数 image,表示要进行 HOG 特征描述的图片。
  • 在函数内我们调用 feature.hog 方法计算 HOG 特征
  • 我们只需将构造函数获得的参数传递给 feature.hog 对应的参数,最后返回 feature.hog 的计算结果即可。

 
 

五、训练模型

  • 我们构建了一个处理数据路径的模块方向梯度直方图模块

现在我们将使用这两个模块编写一个训练数据集的脚本。

5.1 (dataset, labels)、整数编码

首先导入需要用到的模块

这些模块的作用我们将稍后一一为大家介绍。

from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.svm import LinearSVC
import joblib
import cv2
import numpy as np
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

接着调用 preprocessing 函数

  1. 我们用数据集的路径 pedestrian 作为函数的输入
  2. 然后获取保存数据集中所有图片路径的列表 dataset 以及图片对应的标签 labels
(dataset, labels) = preprocessing("pedestrian")
  • 1

 

下面:

  1. 使用从 sklearn.preprocessing 中导入的 LabelEncoder实例化一个对象 L
  2. 然后我们调用 .fit_transform 方法将 labels 中的字符串转换为各不相同的整数
L = LabelEncoder()
labels = L.fit_transform(labels)
  • 1
  • 2

因为 sklearn 中的算法需要整数编码的标签

  • 所以我们要将 labels 中的字符串标签 backgroundpeople 编码为不同的整数
  • 上面的代码会将 labels 自动编码为[1,1,1 ... 0,0,0] 的形式

 

5.2 提取 HOG 特征

接下来:

  1. 我们使用 HOG初始化一个 hog 实例
  2. 并将 transform 参数设为 True
hog = HOG(transform = True)
  • 1
  1. 还需要创建一个 data 列表用于存储从每张图片中提取的 HOG 特征
  2. 然后我们将用一个 for 循环将每张图片转化为 HOG 特征
  3. 然后将这些特征存储data
data = []
for i in dataset:
    image = cv2.imread(i)
    gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
    resized = cv2.resize(gray, (64, 128), interpolation = cv2.INTER_AREA)
    
    hist = hog.describe(resized)
    data.append(hist)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

 
具体的操作是:

  1. 使用 cv2.imread 读取数据集中每张图片
  2. 使用 cv2.cvtColor 方法将图片转化为灰度图
  3. 然后使用 cv2.resize 将每张图片都缩放到相同尺寸 64 × 128 64\times128 64×128

    需要注意的是如果每张图片不是相同的尺寸,那么在后面的训练模型时会产生错误。

  4. 接着我们使用 hog 实例中的 describe 函数将图片转化为 HOG 特征
  5. 最后我们将这些特征都保存data 中。

 

5.3 分为训练集和测试集

将所有特征保存好之后:

  1. 我们使用从 sklearn.model_selection 模块导入的 train_test_split 方法
  2. 将数据分为训练集和测试集
(trainData, testData, trainLabels, testLabels) = train_test_split(
    np.array(data), np.array(labels), test_size=0.15, random_state=42)
  • 1
  • 2

传入 4 个参数给该方法,其参数意义如下所示:

  1. 第一个参数 data保存的所有特征
    • 这里我们将其转换为 NumPy 数组
  2. 第二个参数 labelsdata每个特征对应的标签
    • 我们同样将其转换为 NumPy 数组
  3. 第三个参数 test_size 表示我们测试集占总样本比例
    • 这里我们将其设置为 0.15 表示数据集中的 15% 的图片将被划分为测试集
  4. 第四个参数 random_state 表示随机种子
  • 其控制数据集分割前将数据集打乱,这里我们将其设置为 42

 
执行函数我们将获得:

  • 训练集 trainData
  • 测试集 testData
  • 训练集图片的标签 trainLabels
  • 测试集图片的标签 testLabels

 

5.4 模型、训练模型

  1. 我们使用从 sklearn.svm 模块导入的 LinearSVC
  2. 然后初始化一个实例 model
print("### Training model...")
model = LinearSVC()   
model.fit(trainData, trainLabels)
  • 1
  • 2
  • 3
  • 这里我们调用 model 实例的 fit 方法训练模型
  • fit 方法需要两个参数:
    1. 第一个参数 trainData 是我们的训练集
    2. 第二个参数是训练集中图片的标签

图片描述
 

5.5 分类测试

模型训练好后我们就可以使用 model 实例的 predict 方法在测试集上进行分类测试

  • 我们只需要将测试集 testData 作为参数传入 preditct 方法即可
print("### Evaluating model...")
predictions = model.predict(testData)
  • 1
  • 2

 
接着:

  1. 我们使用从 sklearn.metrics 导入的 classification_report 方法
  2. 显示模型在测试集上分类的分析结果
print(classification_report(testLabels, predictions, target_names=L.classes_))
  • 1

我们给该方法传入 3 个参数,其参数意义如下所示:

  1. testLabels测试集中图片对应的标签
  2. predictions 是模型推理的分类标签
  3. target_names 表示类别
    • 我们使用实例 Lclass_ 属性
    • 将数据集的两个类别 peoplebackground 传递给该参数。

图片描述
可以看到我们的模型在 349 个测试图片上的准确度 (accuracy)是 99%。


 
最后我们使用 joblib 模块的 dump 方法保存训练好的模型

  • 该方法需要两个参数
    1. model 是我们训练好的模型
    2. "model"模型保存的路径
joblib.dump(model, "model")
  • 1

六、总结

  • 介绍了图像分类的基本知识
  • 训练一个分类模型的流程
  • 同时我们通过一个实例编写了一个线性分类任务
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/144971
推荐阅读
相关标签
  

闽ICP备14008679号