自己的数据在caffe上训练识别遇到的问题及解决方案

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/anxuxiao/article/details/72802796

网上有很多教程,文中的源码大多都是借用别人的,但在自动动手做的时候出现了很多问题,自己查了很多资料,把相关问题记录下,给新手的你一些启示:
如果你是第一次使用caffemodel,建议你参考
http://www.cnblogs.com/denny402/p/5111018.html这个博客,它使用了caffe里自带的生成模型来识别,在caffe/examples/images的目录下,有一张自带的cat.jpg,可以使用上面博客中的代码跑一下,大概了解下流程。
在此之后,我们来系统的构架下用自己数据训练识别的过程:
1. 建数据两个分别是train 和val两个文件夹在,space是自建的他们两个的上层目录,下同,并在train中按类放好你的训练数据,而val中的则不用分类存放
2. 生成val 和 train路径文档。我找到另一个博客(地址实在找不到了,先谢过这位客主大神)找到一个写的很精悍的编译代码
这里注意下路径问题:很多人说caffe里面的程序是要在主目录下运行,其实哪里运行都没关系,只要你写程序的时候注意就行。比如这个程序要在你train目录中运行才行。后执行sudo python train.py即可生成train.txt,同里生成val.txt

import os  
#将其保存为train.py 
root = os.getcwd()  
data = 'train'  
path = os.listdir(root+'/'+ data) 
path.sort()  
file = open('train.txt','w')  

i = 0  

for line in path:  
  str = root+'/'+ data +'/'+line  
  for child in os.listdir(str):  
    str1 = data+'/'+line+'/'+child;  
    d = ' %s' %(i)  
    t = str1 + d  
    file.write(t +'\n')  
  i=i+1  

file.close()  

3 将train和val生成lmdb格式的数据,因为在caffe网络训练时只认识这种格式的数据。进行转化的脚本文件在caffe中自带有,根据自己需要的进行修下即可
这里的坑就是:最容易出现的问题是No such file or directory,这个问题的出现肯定是路径问题。比如下面的程序必需要在主目下即caffe/目录下执行才不会错,其他目录是找不到的。如果相在其加目录下都能执行,只需要加上全路径或绝对路径,比如EXAMPLE=/home/xxx/caffe/examples/myself即可。
执行sudo python mk_lmdb.py生成space_val_lmdb。

#!/usr/bin/env sh
# Create the imagenet lmdb inputs
# N.B. set the path to the imagenet train + val data dirs
set -e
#将该程序存为mk_lmdb.py
EXAMPLE=examples/myself
DATA=data/space
TOOLS=build/tools

#TRAIN_DATA_ROOT=data/space/
VAL_DATA_ROOT=data/space/

# Set RESIZE=true to resize the images to 256x256. Leave as false if images have
# already been resized using another tool.
RESIZE=false
if $RESIZE; then
  RESIZE_HEIGHT=256
  RESIZE_WIDTH=256
else
  RESIZE_HEIGHT=0
  RESIZE_WIDTH=0
fi

if [ ! -d "$VAL_DATA_ROOT" ]; then
  echo "Error: VAL_DATA_ROOT is not a path to a directory: $TRAIN_DATA_ROOT"
  echo "Set the TRAIN_DATA_ROOT variable in create_imagenet.sh to the path" \
       "where the ImageNet training data is stored."
  exit 1
fi


echo "Creating train lmdb..."

GLOG_logtostderr=1 $TOOLS/convert_imageset \
    --resize_height=$RESIZE_HEIGHT \
    --resize_width=$RESIZE_WIDTH \
    --shuffle \
    $VAL_DATA_ROOT \
    $DATA/val.txt \
    $EXAMPLE/space_val_lmdb

echo "Done."

4 再将上面生成lmdb转化成二进制文件,代码如下:
这些源代码都在caffe/build/tools下
注意路径,最后生成imagenet_mean.binaryproto文件

#!/usr/bin/env sh
# Compute the mean image from the imagenet training lmdb
# N.B. this is available in data/ilsvrc12

EXAMPLE=examples/myself
DATA=data/space
TOOLS=build/tools

$TOOLS/compute_image_mean $EXAMPLE/space_train_lmdb \
  $DATA/imagenet_mean.binaryproto

echo "Done."

5.再python中最后训练网络要中要将其转化为.npy格式的均值文件才行。源代码来自
http://blog.csdn.net/may0324/article/details/52316967

import numpy as np
import caffe
import sys

blob = caffe.proto.caffe_pb2.BlobProto()
data = open( 'mean.binaryproto' , 'rb' ).read()
blob.ParseFromString(data)
arr = np.array( caffe.io.blobproto_to_array(blob) )
out = arr[0]
np.save( 'mean.npy' , out )

6 最后要进行训练,生成我要所需要的caffemodel文件,要完成这一件事需要三个文件。Alenet.prototxt(自己定义的网络模型,这个模型都是参考)caffe/model/train_val.protxt而来的,可以对其进行简单的修改即可变成自己想用的。
solver.prototxt学习率,秩代次数等相关参数的定义。
make_imagenet_mean.sh一个简单的脚本用来生成caffemodel,代码如下:

#!/usr/bin/env sh
# Compute the mean image from the imagenet training lmdb
# N.B. this is available in data/ilsvrc12

EXAMPLE=examples/myself
DATA=data/space
TOOLS=build/tools

$TOOLS/compute_image_mean $EXAMPLE/space_train_lmdb \
  $DATA/imagenet_mean.binaryproto

echo "Done."

最后就可生成caffemodel.
7 进行预测
这里你很可能用网上的代码做预测是碰到一个问题,对于简单的分类,输出的结果是错的,预测的结果总是第一类,其他类很少能预测到,而且很可能会报如下的错。
File “./python/caffe/classifier.py”, line 29, in init
in_ = self.inputs[0]
IndexError: list index out of range
有个大神提及了下,一下了懂了害我一整天的问题www.baidu.com/s?ie=utf-8&f=3&rsv_bp=1&tn=ubuntuu_cb&wd=csdn博客&oq=%25E5%258D%259A%25E5%25AE%25A2&rsv_pq=a24cc55e0001693e&rsv_t=a9e5xsLxj6lMEgEo%2Fed86gN9RGGWkKFBLBLrOdmw0lbCbS1Py92Y0GJ9qhSvAYAEmQ&rqlang=cn&rsv_enter=1&rsv_sug3=5&rsv_sug1=5&rsv_sug7=100&rsv_sug2=1&prefixsug=cs%25E5%258D%259A%25E5%25AE%25A2&rsp=0&inputT=2598&rsv_sug4=5597
如果你也碰到这个问题的话,那你幸运啦。其实很简单,你训练的时候用的Alenet.prototxt和预测时要用的my.protxt(自己新建的)是不一样的。
前一个的输入是

ame: "CaffeNet"
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  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
#    mean_value: 104
#    mean_value: 117
#    mean_value: 123
#    mirror: true
#  }
......

而后一个预测用的my.prototxt是输入数据是这样的

name: "mAlexNet"
input: "data"
input_shape {
  dim: 1000
  dim: 3
  dim: 224
  dim: 224
}

这里参数根据自己需要修改下。总之也们的data层是不样的,其他都一样,这样就不会报上述的错误。
由于我做的是二分类,网上找了很多程序,但最后输入的结果是两种样本输入只输出第一类。这个问题提到的很少,http://blog.csdn.net/wadqse123/article/details/44750561中提到了,对于少分类分类不准的问题终于解决了。
在解决前我们先看个网络定义的两种方式:
这两Classifier的源码定义,其中做预测的时候会用到,目前网上最多的 是后一种,相对简单,我在这里之所以提出来是因为,只是第一种才能有效解决分类不种的问题。

def __init__(self, model_file, pretrained_file, image_dims=None,  
                 mean=None, input_scale=None, raw_scale=None,  
                 channel_swap=None):  
        caffe.Net.__init__(self, model_file, pretrained_file, caffe.TEST)  

最后做预测的完整代码如下:

#!/usr/bin/python
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
root ='/home/lab/caffe1/caffe/' 
import sys
#sys.path.insert(0,caffe_root+'python')
import caffe

deploy=root + 'examples/myself/mCNN.prototxt'   
caffe_model=root + 'examples/myself_iter_400.caffemodel'
img=root+'examples/images/8.jpg'        

import os
net = caffe.Classifier(deploy, caffe_model,mean=np.load(root + 'data/space/mean.npy'),channel_swap=(2,1,0),raw_scale=255,image_dims=(224, 224))
img=filelist[i]   #获取当前图片的路径
    print filenames[i]    #打印当前图片的名称
    input_image=caffe.io.load_image(img) 
    prediction = net.predict([input_image])
    print 'prediction shape:', prediction[0].shape
    print 'predicted class:', prediction[0].argmax()

至于整个过程就完成了,我所遇到其本上问题就这些了。祝好运!

展开阅读全文

没有更多推荐了,返回首页