科大讯飞智能硬件语音控制的时频图分类挑战赛82.9%解决方案分享:基于PaddleX的分类实现

本次赛题使用的是基于PaddleX的快速开发套件,通过PaddleX取得了赛事7月2日排名第四的成绩。

1、赛事背景

2014年11月,亚马逊推出了一款全新概念的智能音箱Echo,通过语音指令交互控制硬件设备。截止2016年4月,Echo的累计销量已经突破300万台。2017年12月累计数千万台。亚马逊Echo音箱的推出标志着以语音交互为实用化的落地方案。

以智能音箱为代表的声控智能硬件在我国已经得到了商业化的大规模推广。2020年我国占有全球智能音箱销售量的51%,位居全球第一,而同期美国的份额从44%下降到了24%。

赛题提供具有24句语音交互指令的语音时频谱数据集(spectrogram dataset),选手需要完成搭建网络模型,基于密集多层网络、卷积网络和循环网络等基本结构的组合,进行有效预测。

本次比赛为参赛选手提供了语音信号及其对应的语句标签。出于数据安全保证的考虑,所有数据均为脱敏处理后的数据。

本模型依据提交的结果文件,采用Macro-F1进行评价。

1、初赛和复赛均提供下载数据,选手在本地进行算法调试,在比赛页面提交结果。

2、每支团队每天最多提交3次。

3、排行按照得分从高到低排序,排行榜将选择团队的历史最优成绩进行排名。

2、任务描述

赛题提供具有24句语音交互指令的语音时频谱数据集(spectrogram dataset),选手需要完成搭建网络模型,基于密集多层网络、卷积网络和循环网络等基本结构的组合,进行有效预测。

3、方案说明

本次比赛是图像的分类任务。因此可以使用PaddleX进行快速开发来验证模型的效果。

PaddleX套件在处理图像分类的问题上会大量节省开发效率,相关文档如下:

PaddleX项目官网:

https://www.paddlepaddle.org.cn/paddle/paddlex

PaddleX Github地址:

https://github.com/PaddlePaddle/PaddleX

PaddleX API开发模式快速上手:

https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/quick_start_API.md

PaddleX指标及日志:

https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/appendix/metrics.md

4、方案实现

4.1 引入依赖库

# 引入依赖库
import paddle
import cv2
import os 
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# 设定GPU,如果使用的是基础版本,可以忽略这个代码块
paddle.device.set_device("gpu:0")

4.2 数据集解压与查看

数据集已经在本项目中提前挂载好了,直接解压即可

# 解压数据集到loadta中
!unzip  data/data155487/data.zip -d data/loaddata/

为了更好了解数据集的结构,可以使用tree命令来查看数据集的结构情况

# 显示数据集的结构
!tree data/loaddata/

在这里对图片进行抽样,查看图片的原始状态

# 图片抽样

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
%matplotlib inline

# 读取数据集中一个文件夹的路径
file_dir = 'data/loaddata/data/train/'
# 设立列表存储图片名
filesum = []
# 读取图片名
for root, dirs, files in os.walk(file_dir): 
    filesum.append(files)
filesum = filesum[0]
# 打印图片名看看效果符不符合预期
# print(filesum)
# 定义画布大小
plt.figure(figsize=(8, 8))
# 循环读取图片并显示
for i in range(1,5):
    plt.subplot(2,2,i)
    plt.title(filesum[i])
    image = file_dir+filesum[i]
    # print(f">>>{image}")
    plt.imshow(cv2.imread(image,1))
plt.tight_layout()
plt.show()

在这里插入图片描述

4.3 安装PaddleX

在这里,我们使用pip来安装PaddleX

# 使用pip安装方式安装2.1.0版本PaddleX:
!pip install paddlex==2.1.0 -i https://mirror.baidu.com/pypi/simple

4.4 读取训练集的数据表并处理

官方给了训练集的数据表,数据晒处理,根据数据表的顺序来读取即可。

# 读取训练集的数据表
traincsv = pd.read_csv("data/loaddata/data/train.csv")
traincsv

通过数据表来计算分类的类别有多少

# 提取标签数据,并把标签数据存入集合中,计算出标签的种类一共多少
traincsv['label']
# 这里用到了集合的概念
labelname = set(traincsv['label'])
len(labelname)
labelname
新建一个空的文件夹来存放处理后的数据集,防止对原始数据进行改动,导致不能回退操作
# 新建一个空文件夹来存放处理后的数据集
os.mkdir('data/loaddata/processedimage')

PaddleX 很有特色的一个点就是:需要将不同类别的照片按类别放到各自的类别文件夹中。

解释起来可能比较拗口。

举个例子就是:

假如,花朵图片有A,B,C三个类别

那么我们需要:

将A类别的花朵图片放到名字为A的文件夹中

B类别的花朵图片放到名字为B的文件夹中

C类别的花朵图片放到名字为C的文件夹中

这样处理后,PaddleX处理会自动生成训练测试的标签文件,极其方便

接下来就是处理的过程:

# 以标签名来创建文件夹
import os
for i in labelname:
    os.mkdir('data/loaddata/processedimage/'+str(i))
# 将对应标签的图片放入对应的文件夹
import shutil
for i in range(traincsv.shape[0]):
    filename = traincsv.iloc[i,0]
    # print(filename)
    src = 'data/loaddata/data/train/'
    des = 'data/loaddata/processedimage/'+str(traincsv.iloc[i,1]) +'/'
    shutil.copy(os.path.join(src, filename), os.path.join(des))

4.5 使用PaddleX划分训练集,验证集和测试集

PaddleX命令可以一键生成labels.txt, train_list.txt, val_list.txt, test_list.txt四个文件

# 在模型进行训练时,我们需要划分训练集,验证集和测试集
# 因此需要对如上数据进行划分,直接使用paddlex命令即可将数据集随机划分成70%训练集,20%验证集和10%测试集
# 划分好的数据集会额外生成labels.txt, train_list.txt, val_list.txt, test_list.txt四个文件,之后可直接进行训练。
!paddlex --split_dataset --format ImageNet --dataset_dir data/loaddata/processedimage/ --val_value 0.2 --test_value 0.1

4.6 图像增强

图像增强是图像分类的必要环节,也是图像处理的最基本手段, 它往住是各种图像分析与处理时的预处理过程。

图像增强就是增强图像中用户感兴趣的信息, 其主要目的有两个:

一是改善图像的视觉效果, 提高图像成分的清晰度;

二是使图像变得更有利于计算机处理。

# 在训练和验证过程中,数据的处理
# 图像增强:https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/apis/transforms/transforms.md
from paddlex import transforms as T
train_transforms = T.Compose([
    #图片自由裁剪
    T.MixupImage(),#对图像进行 mixup 操作
    T.RandomExpand(),#随机扩张图像
    T.RandomDistort(),#以一定的概率对图像进行随机像素内容变换,可包括亮度、对比度、饱和度、色相角度、通道顺序的调整
    T.Resize(target_size=400),#随机选取目标尺寸调整图像大小
    T.RandomCrop(crop_size=224),#随机裁剪图像
    T.Resize(255, interp='LINEAR', keep_ratio=False),#随机选取目标尺寸调整图像大小。
    T.RandomHorizontalFlip(prob=0.7),#以一定的概率对图像进行随机水平翻转
    T.RandomVerticalFlip(prob=0.7),#以一定的概率对图像进行随机垂直翻转
    T.RandomBlur(prob=0.1),#以一定的概率对图像进行高斯模糊
    T.Normalize()])#对图像进行标准化。

eval_transforms = T.Compose([
    T.ResizeByShort(short_size=256),#以一定的概率对图像进行随机像素内容变换,可包括亮度、对比度、饱和度、色相角度、通道顺序的调整
    T.Normalize()#对图像进行标准化。
])

4.7 定义数据集,标签等路径

在这里,我们将PaddleX生成的4个文件一一对应的相应的路径中

import paddlex as pdx
# 定义数据集,pdx.datasets.ImageNet表示读取ImageNet格式的分类数据集:
train_dataset = pdx.datasets.ImageNet(
    data_dir='data/loaddata/processedimage/',
    file_list='data/loaddata/processedimage/train_list.txt',
    label_list='data/loaddata/processedimage/labels.txt',
    transforms=train_transforms,
    shuffle=True)
eval_dataset = pdx.datasets.ImageNet(
    data_dir='data/loaddata/processedimage/',
    file_list='data/loaddata/processedimage/val_list.txt',
    label_list='data/loaddata/processedimage/labels.txt',
    transforms=eval_transforms)

4.8 模型训练

接下来就是使用PaddleX预训练模型训练,一路写到这里,整个流程就快结束啦

# 模型库参考:https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/appendix/model_zoo.md
# 训练参数调整:https://github.com/PaddlePaddle/PaddleX/blob/develop/docs/parameters.md
# 使用百度基于蒸馏方法得到的预训练模型,模型结构与原来一致,但精度更高。
# num_classes 是类别数,需要自定义,默认是1000
num_classes = len(train_dataset.labels)
model = pdx.cls.ResNet200_vd(num_classes=num_classes)

model.train(num_epochs=120,
            train_dataset=train_dataset,
            train_batch_size=64,
            eval_dataset=eval_dataset,
            save_interval_epochs=80,
            learning_rate = 0.01,
            save_dir='output/ResNet200_vd',
            #训练的输出保存在output/mobilenetv3_small
            use_vdl=True)
            #use_vdl=True表示可以启动visualdl并查看可视化的指标变化情况。

4.9 模型预测并生成结果文件

模型训练好后,就可以进行模型预测

官方给的提交样例,其csv中照片顺序是从小到大的,所以在预测的时候按照片名从小到大的顺序来预测,避免提交时候由于格式不正确导致出错

fileList=os.listdir("data/loaddata/data/test/")
fileList.sort()
for i in fileList:
    # 序列解包
    *_,b = i.split(".")
    if b != "jpg":
        fileList.remove(i)
fileList.sort(key=lambda x:int(x.split('test_')[1].split('.jpg')[0]))
#print(fileList)
# 模型预测
import paddlex as pdx
import paddle
ans = pd.DataFrame(columns=['image','label'])
# 调用GPU
paddle.device.set_device('gpu:0')
# 加载模型
model = pdx.load_model('output/ResNet200_vd/best_model')
# 设定图片地址
path = 'data/loaddata/data/test/'
anspre = []
for i in fileList:
    src = path + i
    result = model.predict(src)[0]
    print(result['category'])
    anspre.append(str(i))
    anspre.append(result['category'])
    print(anspre)
    ans.loc[i] = pd.Series({'image': str(i), 'label': result['category']})
    anspre = []
    #print(f"i == {i}")
# 结果保存为csv文件
ans.to_csv("answer.csv",index=0)

5、提交结果

在这里插入图片描述

6、比赛心得

本次得到的分数是0.82922,但是loss的下降实际上还有优化的空间,后续的优化可以按以下的思路来进行:

  • 参数调优
  • 对数据集的特征进行进一步的提取(特征工程极其重要!)
  • 更换更好的深度学习算法等

此项目为搬运,原项目地址:https://aistudio.baidu.com/aistudio/projectdetail/4294493

Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐