任务描述
近年来,随着人工智能的发展,其在语音识别、自然语言处理、图像与视频分析等诸多领域取得了巨大成功。如何将人工智能技术应用到更广泛的领域成为了重要目标,本次竞赛将聚焦蝴蝶图片的细粒度图像分类,利用人工智能技术,对蝴蝶的类别、属性进行识别分类,以便相关工作者快速识别蝴蝶种类,进行科学研究,提高效率和精度。要求参赛者给出一个算法或模型,对于给定的图片,检测出图片中的蝴蝶类别和属。给定图片数据,选手据此训练模型,为每张测试数据预测出最正确的类别。
数据说明
本竞赛所用训练和测试图片均来自网络(和鲸社区)。总共有9个属,20个物种,文件genus.txt中描述了9个属名,species.txt描述了20个物种名。
数据文件包括训练集(有标注)和测试集(无标注),训练集和验证集的所有图片分别保存在Butterfly20文件夹下面的20个文件夹中,文件名即属-物种标签,测试集共有200张待分类的蝴蝶图片在test文件夹下,名称为:图片ID.jpg。
提交答案
本赛题任务是对蝴蝶图片进行物种分类,要求提交结果的格式如下:
1.每个类别的行数和测试集原始数据行数应一一对应,不可乱序。
2.输出结果应检查是否为200行数据,否则成绩无效。
3.输出结果文件命名为result.txt,一行一个物种标签(物种标号 + . +属+ _ +物种名),样例如下:
‘’’’’’
006.Graphium_agamemnon
014.Meandrusa_sciron
012.Losaria_coon
006.Graphium_agamemnon
011.Lamproptera_meges
018.Papilio_bianor
014.Meandrusa_sciron
017.Papilio_arcturus
003.Byasa_alcinous
001.Atrophaneura_horishanus
‘’’’’’
解决办法
是不是有时候你也为不会高新算法发愁,别担心,飞桨都为你实现好了,下面请看如何用飞桨解决图像分类问题。
采用端到端的PaddleClas来解决
https://github.com/PaddlePaddle/PaddleClas
PaddleClas有多好用就不讲了,大家自己体会体会。
PaddleClas
简介
飞桨图像分类套件PaddleClas是飞桨为工业界和学术界所准备的一个图像分类任务的工具集,助力使用者训练出更好的视觉模型和应用落地。
环境准备
# 克隆PaddleClas并安装依赖项,本notebook已安装
%cd work
!git clone https://gitee.com/PaddlePaddle/PaddleClas.git
%cd /home/aistudio/work/PaddleClas/
# !pip install --upgrade -r requirements.txt
#导入一些图像处理的包
%cd /home/aistudio
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import os, shutil, cv2, random
%matplotlib inline
/home/aistudio
!unzip -q data/data66509/Butterfly20_test.zip -d dataset
!unzip -q data/data66509/Butterfly20.zip -d dataset
!rm -rf dataset/__MACOSX/
定义数据集
# 读取label配置
%cd ~
import os
import random
import cv2
import numpy as np
import shutil
import json
with open("dataset/Butterfly20_dict.json",'r') as load_f:
label_map = json.load(load_f)
print(label_map)
/home/aistudio
{'0': '001.Atrophaneura_horishanus', '1': '002.Atrophaneura_varuna', '2': '003.Byasa_alcinous', '3': '004.Byasa_dasarada', '4': '005.Byasa_polyeuctes', '5': '006.Graphium_agamemnon', '6': '007.Graphium_cloanthus', '7': '008.Graphium_sarpedon', '8': '009.Iphiclides_podalirius', '9': '010.Lamproptera_curius', '10': '011.Lamproptera_meges', '11': '012.Losaria_coon', '12': '013.Meandrusa_payeni', '13': '014.Meandrusa_sciron', '14': '015.Pachliopta_aristolochiae', '15': '016.Papilio_alcmenor', '16': '017.Papilio_arcturus', '17': '018.Papilio_bianor', '18': '019.Papilio_dialis', '19': '020.Papilio_hermosanus'}
import numpy as np
from PIL import Image
from paddle.vision.transforms import functional as F
for (root , dirs, files ) in os.walk("dataset/Butterfly20", topdown=False):
for name in files:
abs_name=os.path.join(root, name)
print(abs_name)
img = Image.open(abs_name)
rotated_img = F.rotate(img, 180)
print(rotated_img.size)
fake_name=os.path.join(root,"rotate_"+ name)
print(fake_name)
rotated_img.save(fake_name)
import numpy as np
from PIL import Image
from paddle.vision.transforms import ColorJitter
# brightness(float) - 亮度调整范围大小,会从给定参数后的均匀分布[max(0,1 - brightness), 1 + brightness]中随机选择进行实际调整,不能是负数。
# contrast(float) - 对比度调整范围大小,,会从给定参数后的均匀分布[max(0,1 - contrast), 1 + contrast]中随机选择进行实际调整,不能是负数。
# saturation(float) - 饱和度调整范围大小,,会从给定参数后的均匀分布[max(0,1 - saturation), 1 + saturation]中随机选择进行实际调整,不能是负数。
# hue(float) - 色调调整范围大小,,会从给定参数后的均匀分布[-hue, hue]中随机选择进行实际调整,参数值需要在0到0.5之间。
# keys (list[str]|tuple[str], optional) - 与 BaseTransform 定义一致。默认值: None。
# ColorJitter随机调整图像的亮度,对比度,饱和度和色调。
transform = ColorJitter(0.4, 0.4, 0.4, 0.4)
for (root , dirs, files ) in os.walk("dataset/Butterfly20", topdown=False):
for name in files:
abs_name=os.path.join(root, name)
print(abs_name)
img = Image.open(abs_name)
rotated_img = transform(img)
print(rotated_img.size)
fake_name=os.path.join(root,"ColorJitter_"+ name)
print(fake_name)
rotated_img.save(fake_name)
# 将所有训练集的数据都写进一个列表中
# 训练集和测试集路径
data_path = "/home/aistudio/dataset"
train_folder = "Butterfly20"
test_folder = "Butterfly20_test"
data_list = []
for index in range(20):
# print(index,label_map[str(index)])
sub_folder=label_map[str(index)]
abs_sub_folder=os.path.join(data_path, train_folder,sub_folder)
sub_list=os.listdir(abs_sub_folder)
for sub_name in sub_list:
data_list.append(os.path.join(train_folder, sub_folder, sub_name) + ' ' + str(index) + '\n')
print("Finished train_folder: {}".format(sub_folder))
print("Finished data_list length: {}".format(len(data_list)))
# import os
# import random
# import cv2
# import numpy as np
# 训练集和测试集路径
val_ratio = 0.1
# save file
def save_file(list, txt):
myfile=os.path.join('dataset',txt)
if os.path.exists(myfile):
os.remove(myfile)
with open(myfile, "a") as f:
f.writelines(list)
random.shuffle(data_list)
val_number = int(val_ratio * len(data_list))
train_list = data_list[val_number:]
val_list = data_list[0:val_number]
print("full data size: {} train_list size: {} val_list size: {}".format(len(data_list), len(data_list)-val_number,val_number))
save_file(train_list, 'train_list.txt')
save_file(val_list, 'test_list.txt')
开始训练
# 选择GPU
%cd /home/aistudio/work/PaddleClas/
%env PYTHONPATH=$PYTHONPATH:.
%env CUDA_VISIBLE_DEVICES=0
/home/aistudio/work/PaddleClas
env: PYTHONPATH=$PYTHONPATH:.
env: CUDA_VISIBLE_DEVICES=0
模型选取
# 由于数据集划分、数据增强的随机性,可能有一些波动,在测试集上>92,最好的模型在验证集大于96应该就没问题
# 配置文件见 ./configs/EfficientNet/EfficientNetB0.yaml
!python -m paddle.distributed.launch \
--gpus="0" \
tools/train.py \
-c ./configs/EfficientNet/EfficientNetB0.yaml \
--vdl_dir='./scalar'
# 充分利用验证集,学习一些没见过的样本,用全部的训练数据微调1个epoch,去掉label smooth和一些数据增强操作.有一定随机性.
!rm -rf ./scalar_finetune/*
!python -m paddle.distributed.launch \
--selected_gpus="0" \
tools/train.py \
-c ./configs/EfficientNet/EfficientNetB0_finetune.yaml \
-o pretrained_model='./output/EfficientNetB0/best_model_train/ppcls' \
--vdl_dir='./scalar_finetune'
You are using Paddle compiled with TensorRT, but TensorRT dynamic library is not found. Ignore this if TensorRT is not needed.
usage: launch.py [-h] [--log_dir LOG_DIR] [--nproc_per_node NPROC_PER_NODE]
[--gpus GPUS] [--ips IPS] [--servers SERVERS]
[--workers WORKERS] [--heter_workers HETER_WORKERS]
[--worker_num WORKER_NUM] [--server_num SERVER_NUM]
[--heter_worker_num HETER_WORKER_NUM] [--http_port HTTP_PORT]
training_script ...
launch.py: error: unrecognized arguments: --selected_gpus=0
验证\导出模型
此处修复了一些小BUG。PaddleClas的EfficientNet(网络结构位于work/PaddleClas/ppcls/modeling/architectures/efficientnet.py)在验证和导出模型的时候,缺少一个is_test=True参数,默认是False,这会让模型在验证和推理的时候也按设定的概率随机drop_connect,导致产生结果是随机的。
在./tools/export_model.py和./tools/program.py中,为EfficientNet在验证和推理创建模型的时候传入is_test=True即可。
!python -m paddle.distributed.launch \
--gpus="0" \
tools/eval.py \
-o ARCHITECTURE.name="EfficientNetB0" \
-o pretrained_model='./output/EfficientNetB0/best_model_train/ppcls'
# 导出模型
!python tools/export_model.py \
--model='EfficientNetB0' \
--pretrained_model='./output_finetune/EfficientNetB0/best_model_finetune/ppcls' \
--output_path='./output_finetune/EfficientNetB0_infer'
You are using Paddle compiled with TensorRT, but TensorRT dynamic library is not found. Ignore this if TensorRT is not needed.
export model for EfficientNet
预测\推理
修改./tools/infer/predict.py ,通过for循环读取ID,生成key结果到 /home/aistudio/result_id.txt
大约1min20s
!python tools/infer/predict.py \
-m=./output_finetune/EfficientNetB0_infer/model \
-p=./output_finetune/EfficientNetB0_infer/params \
-i=/home/aistudio/dataset/Butterfly20_test \
# -i=./dataset/sgt/test/jpg \
inetune/EfficientNetB0_infer/params \
-i=/home/aistudio/dataset/Butterfly20_test \
# -i=./dataset/sgt/test/jpg \
--use_gpu=1
结果处理
通过key查找value,结果保存到home/aistudio/result_id.txt
# 读取,并转换为value,
%cd /home/aistudio
import fileinput
value_list = []
for line in fileinput.input("/home/aistudio/result_id.txt"):
value_list.append(label_map[line.strip('\n')])
print(len(value_list))
/home/aistudio
200
# 保存
savename = '/home/aistudio/result.txt'
with open(savename, 'w', newline='') as f:
for line in value_list:
f.write(line+"\n")
个人总结
给大家打个样,开拓下视野,可以选择多种模型,也可以多种参数调整,分分钟准确率上去了。
由于系统保存版本文件限制,修改过的work/PaddleClas/tools/infer/predict.py文件,以及work/PaddleClas/configs/EfficientNet/EfficientNetB0.yaml单独存放于/home/aistudio即当前用户目录下了,请自提。
aistudio项目地址
用PaddleClas解决蝴蝶分类https://aistudio.baidu.com/aistudio/projectdetail/1415075