从零开始训练自己的数据模型超详细教程(以caffenet为例)带你熟悉整个过程(数据准备,均值文件,训练,测试)

背景:我要解决的是一个二分类问题,分类出正脸和非正脸,从而过滤人脸质量较差的图片,如低头,侧脸或者是戴口罩的人脸,而分类出正脸中对正脸进行一个评分。好的,下面正式进入实验过程。

(1)模型准备**

如果你没有还没有装好caffe,那请参考:
1.caffe安装系列——史上最详细的安装步骤
2,Ubuntu 16.04+CUDA8.0+Caffe安装教程
3.windows下安装caffe
4.caffe官网安装教程
安装好caffe之后,一般不会自带模型,可以从model zoo中下载 ,使用方法:
下载meta数据到当前目录:

./get_ilsvrc_aux.sh

下载caffenet模型:

cd ../../models/nclv_reference_caffenet/

wget http://dl.caffe.berkeleyvision.org/bvlc_reference_caffenet.caffemodel

回到根目录
./build/examples/cpp_classification/classification.bin models/bvlc_reference_caffenet/deploy.prototxt models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel data/ilsvrc12/imagenet_mean.binaryproto data/ilsvrc12/synset_words.txt examples/images/cat.jpg

输出如下所示:
———- Prediction for examples/images/cat.jpg ———-
0.3134 - “n02123045 tabby, tabby cat”
0.2380 - “n02123159 tiger cat”
0.1235 - “n02124075 Egyptian cat”
0.1003 - “n02119022 red fox, Vulpes vulpes”
0.0715 - “n02127052 lynx, catamount”
zoo的使用还可以参看博客
model还可以在这里下载,更直接。但是还的自己上传就是。
可以直接在浏览器里输入地址下载,也可以运行脚本文件下载。下载地址为:http://dl.caffe.berkeleyvision.org/bvlc_reference_caffenet.caffemodel
输入命令:wget http://dl.caffe.berkeleyvision.org/bvlc_reference_caffenet.caffemodel
文件名称为:bvlc_reference_caffenet.caffemodel,文件大小为230M左右,为了代码的统一,将这个caffemodel文件下载到caffe根目录下的 models/bvlc_reference_caffenet/ 文件夹下面。也可以运行脚本文件进行下载:

sudo ./scripts/download_model_binary.py models/bvlc_reference_caffenet

2.准备数据

(1)生成带标签文件
如果有自己的数据最好,如果没有,可以从kaggle中搜索猫狗大战数据(cat vs dog)
获取训练图片集与验证图片集,并产生train.txt与val.txt,内容为图片路径与分类标签;将图片进行大小重设,设置为256*256大小;使用create_imagenet.sh脚本将2组图片集转换为lmbp格式。(注意这里的256*256可以根据自己的需求进行更改,更改之后后续中的模型输入同步修改,不然会报错)
产生train.txt 方法,可以参考:
1.caffe 使用shell自动生成train.txt & val.txt
2.官网的教程
如果你的数据文件夹本来分好类,只需要自己写一个脚本,读取文件名,文件名后面添加“ 0”.注意标签一定要从0开始,便签前面需要加一个英文字符空格 。
在这里推荐一个神器,caffe图形化操作工具digits的安装与运行
我的数据路径为:/home/xxx/caffe/data/peng_data/
我的脚本和模型路径为:/home/xxx/caffe/exampels/peng_task/
(2)生成lmdb数据库,用于caffe训练的数据来源。
这里写图片描述
将/caffe/examples/imagenet/文件夹下的所有文件复制到/home/xxx/caffe/exampels/peng_task/目录下,然后打开create_imagenet.sh文件。按照下图标注的进行修改,最好是填完整路径。
这里写图片描述
EXAMPLE :是模型是生成的lmdb存放的路径
DATA:是存放train.txt 和val.txt路径,不然会提示错误
TRAIN_DATA_ROOT:train数据集所在路径
VAL_DATA_ROOT:val数据集所在路径
RESIZE_HEIGHT RESIZE_WDTH是输入模型时的图片大小。
这里写图片描述
可以修改生成lmdb文件的名称。
修改之后保存退出。
运行:

./create_imagenet.sh

3.生成mean.binaryproto文件

需要对应的均值文件,在测试阶段,需要把测试数据减去均值。这个文件我们用脚本来下载
打开make_imagenet_mean.sh文件,作如下修改:
这里写图片描述
每个代表什么我这里就不解释了,记得名称对应就好。然后运行:./make_imagenet_mean.sh
在生成过程中遇到了如下问题:

1、如果文件夹下含有lmdb格式的文件,那么生成时会出现错误,所以在生成之前需要对create_imagenet.sh 所在文件夹进行检查,删除之前的 lmdb 文件。代码中添加了代码,来辅助完成此检查:

[python] view plain copy
在CODE上查看代码片派生到我的代码片
rm -rf EXAMPLE/trainlmdbrmrf EXAMPLE/val_lmdb #删除已存在的lmdb格式文件,若在已存在lmdb格式的文件夹下再添加lmdb文件,会出现错误

2、在生成lmdb过程中,出现 can not find or open …//////…….jpg 这个错误时,这个错误中会给出相应的图像路径:
首先,查看路径是否正确,若路径不正确,则需要更改相应的图像路径。再运行,看问题是否解决。

若问题还没有解决,则检查train.txt中,路径和标签之间是否只有一个空格!

在一些程序中,在对图像加标签时,标签与路径之间的空格使用转义字符 “ \t ”来生成,可是在生成txt中,路径与标签之间的距离往往多于一个空格,所以在生成标签文档时,程序中用空格代替转义字符 \t 。如下方程序所示:

[python] view plain copy
在CODE上查看代码片派生到我的代码片
str1=img+’ ‘+’1’+’\n’

(4)设置网络

1)train_val.prototxt
caffenet的网络配置文件,放在 caffe/models/bvlc_reference_caffenet/ 这个文件夹里面,名字叫train_val.prototxt。
将文件夹下的文件都复制到/home/xxx/caffe/example./peng_task/目录下

cp *.prototxt /home/xxx/caffe/example./peng_task/

打开这个文件,将里面的内容复制到上图的Custom Network文本框里,然后进行修改,主要修改这几个地方:

1、mean_file:修改为你的均值文件路径(两个)
2.train 和test层的source:修改为你的训练集和验证集的lmdb路径(两个)

这里写图片描述
3.修改你分类的数据,在最后一层全链接层(fc8)的num output修改你要分类的类数。
这里写图片描述
4.修改你的batch_size
如果你的内存或者GPU显存不够时,把batch_size改小,训练时不会报out of memery的错误
保存退出。
2.deploy.prototxt
这个文件跟上个文件类似,修改的地方都差不多。但是注意的是如果修改后出现错误,注意修改下面几个地方。
这里写图片描述
把第一层修改成图片所示
参数分别表示:输入图数量,维数,图片的长,图片的宽
5.修改solver.prototxt文件
如下图(注意着张图和之前的不是匹配的,这是另一个项目拿过来的)
这里写图片描述
参数的含义可以参考这里。

5.训练网络

1.修改train_caffenet.sh
这里写图片描述
将划线部分修改为自己solver.prototxt路径
然后回到caffe根目录下输入:./examples/peng_task/train_caffenet.sh
开始训练。
这里写图片描述

训练时容易遇到的问题:
1.out of memery 显存不够 更改batch_size大小等方法
2.输入不匹配 ,更改输入图片的大小,crop size 维数等方法
这里写图片描述

静静等待,然后看看loss是否收敛,准确率是否上升。到了准确率来回震荡时,说明基本上已经可以停止训练了。
(6)测试
测试部分直接帖代码。

#coding:utf-8
#!/usr/bin/python
import os  
import sys  
reload(sys)  
sys.setdefaultencoding("utf-8")
import sys
caffe_root='/home/zzl/caffe/' #修改成你的Caffe项目路径
sys.path.append(caffe_root+'python')
import caffe
caffe.set_mode_gpu() #设置为GPU运行
from pylab import *
import time


#测试训练后的模型性能
#准备好test.txt文件,包含图片名称和标签
#保存预测的result
#输出测试100张图的时间及平均时间
#输出测试的图片总数量 正确率 正确数量和错误数量
#


# 修改成你的deploy.prototxt文件路径
model_def = '/home/zzl/caffe/examples/peng_task/live_detection/deploy.prototxt' 
#model_weights = '/home/zzl/caffe/examples/peng_task/caffenet_train_256/_iter_16000.caffemodel' # 修改成你的caffemodel文件的路径
model_weights = '/home/zzl/caffe/examples/peng_task/live_detection/train_result_model/_iter_20000.caffemodel' # 修改成你的caffemodel文件的路径

result_dir = '/home/zzl/caffe/examples/peng_task/live_detection/process_test_result/process_test_result2.txt' #预测结果保存路径 结果如 img.jpg 0 1

test_labels_file = '/home/zzl/caffe/examples/peng_task/live_detection/process_data/test.txt' #包含路径和标签的文件
test_image_dir = '/home/zzl/caffe/data/peng_data/livedetection/test/'  #需要测试的图片路径
# caffenet_train_256/_iter_20000.caffemodel  0.997401  caffenet_test_result3    0.996
# caffenet_train/_iter_16000.caffemodel      0.9981 caffenet_test_result        0.993
# caffenet_train/_iter_20000.caffemodel    0.9982  caffenet_test_result2    0.996
# caffenet_train_256/_iter_16000.caffemodel  0.997401  caffenet_test_result4  0.993

net = caffe.Net(model_def,      # defines the structure of the model
                model_weights,  # contains the trained weights
                caffe.TEST)     # use test mode (e.g., don't perform dropout)

#这是一个由mean.binaryproto文件生成mean.npy文件的函数
def convert_mean(binMean,npyMean):
    blob = caffe.proto.caffe_pb2.BlobProto()
    bin_mean = open(binMean, 'rb' ).read()
    blob.ParseFromString(bin_mean)
    arr = np.array( caffe.io.blobproto_to_array(blob) )
    npy_mean = arr[0]
    np.save(npyMean, npy_mean )
binMean='/home/zzl/caffe/data/peng_data/livedetection/imagenet_mean.binaryproto' #修改成你的mean.binaryproto文件的路径
npyMean='/home/zzl/caffe/examples/peng_task/live_detection/process_test_result/mean.npy' #你想把生成的mean.npy文件放在哪个路径下
convert_mean(binMean,npyMean)

transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
transformer.set_transpose('data', (2,0,1))  # 通道变换,例如从(530,800,3) 变成 (3,530,800)
transformer.set_mean('data', np.load(npyMean).mean(1).mean(1)) #如果你在训练模型的时候没有对输入做mean操作,那么这边也不需要
transformer.set_raw_scale('data', 112)  # rescale from [0, 1] to [0, 255]
transformer.set_channel_swap('data', (2, 1, 0))  # swap channels from RGB to BGR

with open(test_labels_file) as image_list: # 修改成你要测试的txt文件的路径,这个txt文件的内容一般是:每行表示图像的路径,然后空格,然后是标签,也就是说每行都是两列
    with open(result_dir,'w') as result: # 如果你想把预测的结果写到一个txt文件中,那么把这个路径修改成你想保存这个txt文件的路径
        count_right=0
        count_all=0
        count_100 = 0
        sum_time = 0.0
        start = time.clock()

        while 1:
            list_name=image_list.readline()
            if list_name == '\n' or list_name == '': #如果txt文件都读完了则跳出循环
                break
            image_type=list_name[0:-3].split('.')[-1]
            if image_type == 'gif': #这里我对gif个数的图像直接跳过
                continue

            image = caffe.io.load_image(test_image_dir+list_name[:-3]) 
            # 这里要添加你的图像所在的路径,根据你的list_name灵活调整,总之就是图像路径
            #imshow(image)
            transformed_image = transformer.preprocess('data', image)

            #用转换后的图像代替net.blob中的data
            net.blobs['data'].data[...] = transformed_image
            net.blobs['data'].reshape(1, 3, 256, 256)  #根据模型输入要求reshape图片大小
            ### perform classification
            output = net.forward()

        # 读取预测结果和真实label
            output_prob = net.blobs['prob'].data[0]
            #print net.blobs['prob'].data[0].flatten()  #取出最后一层(prob)属于某个类别的概率值,并打印,'prob'为最后一层的名称
            #order=prob.argsort()[4]  #将概率值排序,取出最大值所在的序号 ,9指的是分为0-9十类 
            true_label = int(list_name[-2:-1])
    # 如果预测结果和真实label一样,则count_right+1
            if(output_prob.argmax()==true_label):
                count_right=count_right+1
            count_all=count_all+1

    # 保存预测结果,这个可选
            result.writelines(list_name[0:-1]+' '+str(output_prob.argmax())+'\n')
    #可以每预测完100个样本就打印一些,这样好知道预测的进度,尤其是要预测几万或更多样本的时候,否则你还以为代码卡死了
            if(count_all%100==0):
                end = time.clock()
                each_100_time = end - start  #测试100张所需要的时间
                sum_time = sum_time + each_100_time 
                count_100 += 1
                #print 'test 100 images need time:' + str(each_100_time)

                #print count_all
                start = time.clock()
                end = 0

       # 打印总的预测结果
        print 'test 100 images need avg time:' + str(sum_time/count_100)
        print 'Accuracy: '+ str(float(count_right)/float(count_all))
        print 'count_all: ' + str(count_all)
        print 'count_right: ' + str(count_right)
        print 'count_wrong: ' + str(count_all-count_right)

就写到这里,有问题可以私聊我,大家一起交流。谢谢!

猜你喜欢

转载自blog.csdn.net/fengzhongluoleidehua/article/details/80043803