如何利用自己的数据训练一个分类网络

从零开始学会如何利用自己的数据训练一个分类网络

1、准备训练数据和测试数据

下载地址如下:
animal:
http://www.robots.ox.ac.uk/~vgg/data/pets/
flower:
http://www.robots.ox.ac.uk/~vgg/data/flowers/
plane:
http://www.robots.ox.ac.uk/~vgg/data/airplanes_side/airplanes_side.tar
house:
http://www.robots.ox.ac.uk/~vgg/data/houses/houses.tar
guitar:
http://www.robots.ox.ac.uk/~vgg/data/guitars/guitars.tar

数据文档结构如下:

└── data
    ├── test
    │   ├── animal
    │   ├── flower
    │   ├── guitar
    │   ├── house
    │   └── plane
    └── train
        ├── animal
        ├── flower
        ├── guitar
        ├── house
        └── plane

数量:以花为例,800+的图片,测试300+,训练500张。在剩下的不包含在test和train的图片中,每一类选择2张,共计10张图片作为demon测试图片。

2、制作标签

格式:文件路径+标签
代码如下,注意修改路径:

import os
#定义Caffe根目录
caffe_root = 'E:/Caffe-windows/caffe-windows/'

#制作训练标签数据
i = 0 #标签
with open(caffe_root + 'models/my_models_recognition/labels/train.txt','w') as train_txt: 
    for root,dirs,files in os.walk(caffe_root+'models/my_models_recognition/data/train/'): #遍历文件夹
        for dir in dirs:
            for root,dirs,files in os.walk(caffe_root+'models/my_models_recognition/data/train/'+str(dir)): #遍历每一个文件夹中的文件 
                for file in files:
                    image_file = str(dir) + '\\' + str(file)
                    label = image_file + ' ' + str(i) + '\n'       #文件路径+空格+标签编号+换行 
                    train_txt.writelines(label)                   #写入标签文件中
                i+=1 #编号加1


#制作测试标签数据
i=0 #标签
with open(caffe_root + 'models/my_models_recognition/labels/test.txt','w') as test_txt:
    for root,dirs,files in os.walk(caffe_root+'models/my_models_recognition/data/test/'): #遍历文件夹
        for dir in dirs:
            for root,dirs,files in os.walk(caffe_root+'models/my_models_recognition/data/test/'+str(dir)): #遍历每一个文件夹中的文件
                for file in files:
                    image_file = str(dir) + '\\' + str(file)
                    label = image_file + ' ' + str(i) + '\n'       #文件路径+空格+标签编号+换行 
                    test_txt.writelines(label)                   #写入标签文件中
                i+=1#编号加1

print "成功生成文件列表" 

3、数据转换,将图片转为LMDB格式

参考这个博客

代码如下:

# convert_imageset路径
# 重新修改图片的分辨率位256\*256
# 打乱图片顺序shuffle
# 设置转换为lmdb格式
# 图片路径
# 图片标签
# lmdb文件的输出路径
./build/tools/convert_imageset --resize_height=256 --resize_width=256 --shuffle --backend="lmdb" models/classification_CNN/data/train models/classification_CNN/dlabels/train.txt models/classification_CNN/lmdb/train

4、修改网络模型文件

  • 修改均值文件使用方法,不使用均值文件,使用通用均值文件
#   transform_param {
#     mirror: true
#     crop_size: 227
#     mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
#   }
# mean pixel / channel-wise mean instead of mean image
  transform_param {
    crop_size: 227  # 传入的图片是256*256,现在在其中框出一个227*227的小图片 以此来增大训练集
    mean_value: 104  # 通用均值
    mean_value: 117
    mean_value: 123
    mirror: true  # 镜像操作 扩大数据集
  }
  • 修改数据输入层的数据来源路径以及batch_size,需要适当调小一点。
data_param {
  source: "/home/weijian/caffe/models/classification_CNN/lmdb/train"
  batch_size: 100
  backend: LMDB
}
  • 修改中间fc6、fc7这两个全连接层的特征平面数量为512,原来的4000+的特征平面数量会造成过拟合。
fc6
layer {
  name: "fc6"
  type: "InnerProduct"
  bottom: "pool5"
  top: "fc6"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 512 # 这里改成512
    weight_filler {
      type: "gaussian"
      std: 0.005
    }
    bias_filler {
      type: "constant"
      value: 1
    }
  }
}

fc7
layer {
  name: "fc7"
  type: "InnerProduct"
  bottom: "fc6"
  top: "fc7"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 512  # 这里改成512
    weight_filler {
      type: "gaussian"
      std: 0.005
    }
    bias_filler {
      type: "constant"
      value: 1
    }
  }
}
  • 修改最后一个全连接层的输出为5种类型,因为设置了house、flower、animal、guitar、plane五种数据。
layer {
  name: "fc8"
  type: "InnerProduct"
  bottom: "fc7"
  top: "fc8"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 5  # 这里哟
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}

5、修改超参数文件

  • 修改net(网络结构文件的位置)
net: "/home/weijian/caffe/models/classification_CNN/train_val.prototxt"
  • 修改test_iter(在测试的时候,需要迭代的次数。) test_iter = 测试图片的数量 / Test layer的batch_size
test_iter: 30  # 测试集一共1500张图片,Test layer的batch_size是50,则在测试的时候,需要迭代30次,即每30次完成一次对所有测试集的测试。
  • 修改test_interval(每训练多少次,开始一次测试。) test_interval = 训练图片数量 / Train layer的batch_siz
test_interval: 250 # 一共2500张训练图片,Train_layer的batch_size是100,则每250次iterration完成一次对所有训练图片的测试。实际上,也可以随便设置,200,210都可以。
  • 修改训练策略参数stepsize、max_iter、snapshot、snapshot_prefix
lr_policy: "step"
gamma: 0.1
stepsize: 1000
display: 50
max_iter: 10000
momentum: 0.9
weight_decay: 0.0005
snapshot: 5000
snapshot_prefix: "/home/weijian/caffe/models/classification_CNN/caffenet_train"
solver_mode: GPU

6、训练模型

vim train.sh

#!/usr/bin/env sh
set -e

log_path="logs/"
mkdir -p $log_path

save_model_path="caffemodel/"
mkdir -p $save_model_path

# training log
file_prefix="classification_CNN"
log_file=$(date -d "today" +"%Y-%m-%d-%H:%M:%S")
log_file=$log_path$file_prefix$log_file".log"

# caffe execute file path
caffe_bin="/home/weijian/caffe/build/tools/caffe"

# trainning
# $caffe_bin train --solver=solver.prototxt  2>&1  | tee -a $log_file
$caffe_bin train --solver=solver.prototxt 2>&1 | tee ./logs/classification_CNN.log

7、测试模型

按照labels中的test.txt和train.txt的图片分类规则在labels文件夹中编辑label.txt,在test.txt和train.txt中,animal是0,guitar是1,以此类推,得到label.txt如下所示:

animal
guitar
flower
house
plane

vim testDemo.py

import caffe
import numpy as np
import matplotlib.pyplot as plt
import os
import PIL
from PIL import Image
import sys

#定义Caffe根目录
caffe_root = '/home/weijian/caffe/'
#网络结构描述文件
deploy_file = caffe_root+'models/classification_CNN/deploy.prototxt'
#训练好的模型
model_file = caffe_root+'models/classification_CNN/caffenet_train/solver_iter_10000.caffemodel'

#gpu模式
caffe.set_device(0)  # 如果你有多个GPU,那么选择第一个
caffe.set_mode_gpu()
# caffe.set_mode_gpu()

#定义网络模型
net = caffe.Classifier(deploy_file, #调用deploy文件
                       model_file,  #调用模型文件
                       channel_swap=(2,1,0),  #caffe中图片是BGR格式,而原始格式是RGB,所以要转化
                       raw_scale=255,         #python中将图片存储为[0, 1],而caffe中将图片存储为[0, 255],所以需要一个转换
                       image_dims=(227, 227)) #输入模型的图片要是227*227的图片


#分类标签文件
imagenet_labels_filename = caffe_root +'models/classification_CNN/labels/label.txt'
#载入分类标签文件
labels = np.loadtxt(imagenet_labels_filename, str)

#对目标路径中的图像,遍历并分类
for root,dirs,files in os.walk(caffe_root+'models/classification_CNN/demo_test_image/'):
    for file in files:
        #加载要分类的图片
        image_file = os.path.join(root,file)
        input_image = caffe.io.load_image(image_file)

        #打印图片路径及名称
        image_path = os.path.join(root,file)
        print(image_path)

        #显示图片
        img=Image.open(image_path)
        plt.imshow(img)
        plt.axis('off')
        plt.show()

        #预测图片类别
        prediction = net.predict([input_image])
        print 'predicted class:',prediction[0].argmax()

        # 输出概率最大的前5个预测结果
        top_k = prediction[0].argsort()[::-1]
        for node_id in top_k:     
            #获取分类名称
            human_string = labels[node_id]
            #获取该分类的置信度
            score = prediction[0][node_id]
            print('%s (score = %.5f)' % (human_string, score))

运行testDemo.py

你可能感兴趣的:(caffe)