图像分类是计算机视觉的重要领域,它的目标是将图像分类到预定义的标签。近期,许多研究者提出很多不同种类的神经网络,并且极大的提升了分类算法的性能。本文以自己创建的数据集:青春有你2中选手识别为例子,介绍如何使用PaddleHub进行图像分类任务。
#CPU环境启动请务必执行该指令
%set_env CPU_NUM=1
#安装paddlehub
!pip install paddlehub==1.6.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
加载数据文件
导入python包
利用前天的爬虫案例爬取五位选手照片。我是在本地pycharm环境爬取的,随后把数据打包上传到平台
import re
import requests
from urllib import error
from bs4 import BeautifulSoup
import os
## name:选手名称 basepath:图片下载目录 pn: 百度图片分页参数 pic_num:下载图片数量
def crawl_pic_urls(name,basepath,pn,pic_num):
pic_urls=[]
# 数据源主要是通过百度
url = 'http://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=' + name+' 青春有你 高清' + '&pn='
tmp = url
num = 0
while num < pic_num:
try:
url = tmp + str(pn)
print(url)
result = requests.get(url, timeout=10)
pic_url = re.findall('"objURL":"(.*?)",', result.text, re.S) # 先利用正则表达式找到图片url
if len(pic_url)>pic_num:
pic_url=pic_url[0:pic_num]
down_pic(name,pic_url,basepath)
num+=len(pic_url)
pn+=60
except error.HTTPError as e:
print('网络错误,请调整网络后重试')
def down_pic(name,pic_urls,basepath):
'''
根据图片链接列表pic_urls, 下载所有图片,保存在以name命名的文件夹中,
'''
path = basepath + name + '/'
if not os.path.exists(path):
os.makedirs(path)
# print("正在下载:%s" %(str(name)))
for i, pic_url in enumerate(pic_urls):
try:
pic = requests.get(pic_url, timeout=15)
string = str(i + 1) + '.jpg'
with open(path+string, 'wb') as f:
f.write(pic.content)
# 生成训练集
print('成功下载第%s张图片: %s' % (str(i + 1), str(pic_url)))
except Exception as e:
print('下载第%s张图片时失败: %s' % (str(i + 1), str(pic_url)))
print(e)
continue
label_list = ['yushuxin', 'xujiaqi', 'zhaoxiaotang', 'anqi', 'wangchengxuan']
for name in label_list:
crawl_pic_urls(name, 'dataset/train/', 0, 50)
crawl_pic_urls(name, 'dataset/validate/', 0, 5)
上传数据集,然后解压。可以根据自己创建的路径修改下面的解压命令。
!unzip -o /home/aistudio/dataset/dataset.zip -d /home/aistudio/dataset/
这样数据集就导入了,下面导入python包
import paddlehub as hub
到这一步基本没有什么问题报错
下面是填写txt文件,主要是test_list.txt 和 validate_list.txt
为了防止粗心出错,遍些了程序写入内容,然后粘贴复制即可。
下面是验证集validate_list.txt ,
file_object = open('yushuxin.txt', 'w')
for i in range(1, 6):
file_object.write('validate/yushuxin/'+ str(i) + '.jpg 0\n')
file_object = open('xujiaqi.txt', 'w')
for i in range(1, 6):
file_object.write('validate/xujiaqi/'+ str(i) + '.jpg 1\n')
file_object = open('zhaoxiaotang.txt', 'w')
for i in range(1, 6):
file_object.write('validate/zhaoxiaotang/'+ str(i) + '.jpg 2\n')
file_object = open('anqi.txt', 'w')
for i in range(1, 6):
file_object.write('validate/anqi/'+ str(i) + '.jpg 3\n')
file_object = open('wangchengxuan.txt', 'w')
for i in range(1, 6):
file_object.write('validate/wangchengxuan/'+ str(i) + '.jpg 4\n')
复制写好内容的文件到平台文件上,如下图所示。
需要注意的是: !!!
写入后不要有空行多余的行!!!踩过这样的坑,特此提醒。
相应的测试集train_list.txt,讲上面程序里面的validate改成train, range改成(0,51)
做相应调整后,按照上面的要求复制粘贴即可,同样!!!不要有空行和多余行!!!
接下来我们要在PaddleHub中选择合适的预训练模型来Finetune,由于是图像分类任务,因此我们使用经典的ResNet-50作为预训练模型。PaddleHub提供了丰富的图像分类预训练模型,包括了最新的神经网络架构搜索类的PNASNet,我们推荐您尝试不同的预训练模型来获得更好的性能。
module = hub.Module(name="resnet_v2_50_imagenet")
接着需要加载图片数据集。我们使用自定义的数据进行体验,请查看适配自定义数据
from paddlehub.dataset.base_cv_dataset import BaseCVDataset
class DemoDataset(BaseCVDataset):
def __init__(self):
# 数据集存放位置
self.dataset_dir = "dataset"
super(DemoDataset, self).__init__(
base_path=self.dataset_dir,
train_list_file="train_list.txt",
validate_list_file="validate_list.txt",
test_list_file="test_list.txt",
label_list_file="label_list.txt",
)
dataset = DemoDataset()
到这里应该还是也没有什么报错
在进行Finetune前,我们可以设置一些运行时的配置,例如如下代码中的配置,表示:
use_cuda
:设置为False表示使用CPU进行训练。如果您本机支持GPU,且安装的是GPU版本的PaddlePaddle,我们建议您将这个选项设置为True;
epoch
:迭代轮数;
batch_size
:每次训练的时候,给模型输入的每批数据大小为32,模型训练时能够并行处理批数据,因此batch_size越大,训练的效率越高,但是同时带来了内存的负荷,过大的batch_size可能导致内存不足而无法训练,因此选择一个合适的batch_size是很重要的一步;
log_interval
:每隔10 step打印一次训练日志;
eval_interval
:每隔50 step在验证集上进行一次性能评估;
checkpoint_dir
:将训练的参数和数据保存到cv_finetune_turtorial_demo目录中;
strategy
:使用DefaultFinetuneStrategy策略进行finetune;
更多运行配置,请查看RunConfig
同时PaddleHub提供了许多优化策略,如AdamWeightDecayStrategy
、ULMFiTStrategy
、DefaultFinetuneStrategy
等,详细信息参见策略
config = hub.RunConfig(
use_cuda=False, #是否使用GPU训练,默认为False;
num_epoch=3, #Fine-tune的轮数;
checkpoint_dir="cv_finetune_turtorial_demo",#模型checkpoint保存路径, 若用户没有指定,程序会自动生成;
batch_size=3, #训练的批大小,如果使用GPU,请根据实际情况调整batch_size;
eval_interval=10, #模型评估的间隔,默认每100个step评估一次验证集;
strategy=hub.finetune.strategy.DefaultFinetuneStrategy()) #Fine-tune优化策略;
有了合适的预训练模型和准备要迁移的数据集后,我们开始组建一个Task。
由于该数据设置是一个二分类的任务,而我们下载的分类module是在ImageNet数据集上训练的千分类模型,所以我们需要对模型进行简单的微调,把模型改造为一个二分类模型:
input_dict, output_dict, program = module.context(trainable=True)
img = input_dict["image"]
feature_map = output_dict["feature_map"]
feed_list = [img.name]
task = hub.ImageClassifierTask(
data_reader=data_reader,
feed_list=feed_list,
feature=feature_map,
num_classes=dataset.num_labels,
config=config)
这是很重要的一个步骤,检验前面的步骤是否正确完成。
在这里有几个需要注意的地方
可能会报错说一个文件找不到,或者说文件找不到,原因可能是下载的照片有问题,或者是路径不正确,或者前面填写的文件里有空行等等,这些是常见的,而且也很容易忽略,需要特别注意。
当然也有可能出现其他错,认真解决吧!谁没踩过那么些个神奇搞怪的坑呢
当运行成功后,你的loss值从大到越来越小,acc值从小到越来越大的时候说明数据训练效果不错。
如果有些波动可能是数据集的问题,比如照片特征差异较大等等。
当Finetune完成后,我们使用模型来进行预测,先通过以下命令来获取测试的图片
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
with open("dataset/test.txt","r") as f:
filepath = f.readlines()
data = [filepath[0].split(" ")[0], filepath[1].split(" ")[0],filepath[2].split(" ")[0],filepath[3].split(" ")[0],filepath[4].split(" ")[0]]
label_map = dataset.label_dict()
index = 0
run_states = task.predict(data=data)
results = [run_state.run_results for run_state in run_states]
for batch_result in results:
print(batch_result)
batch_result = np.argmax(batch_result, axis=2)[0]
print(batch_result)
for result in batch_result:
index += 1
result = label_map[result]
print("input %i is %s, and the predict result is %s" %
(index, data[index - 1], result))
不能不说,走到这一步已经挺难了。如果一次运行成功了,那么恭喜你,真是幸运儿!
当然我要说的是,在这一步还是会报错的,信息如下:
直接来说就是,在测试时没有找到路径里的照片。
因此,创建了一个test.txt,如下
最后保存运行一下