跑出结果对应的记录
修改过程
- 起初我怀疑是由于图像生成错误导致的,但是那个实在找不出来错误了!标签也是从0开始了!图像存放位置肯定也没有问题!图像本身也就是灰色图像,感觉也翻不起大浪啊!
- 为何会出现连续多个
Restarting data prefetching from start
?大概连续8个,然后还会出现loss为87.33?
- 将batch_size改为1就好了,原先为64等,我这个显卡的显存还是忒小,不能忒大!
- batch_size减小后还不行咋办?图像还是大,那么就调一下crop_size,我将其改到180了!
- 修改成以上的结果后,发现:
Restarting data prefetching from start
不会连续出现了- loss前两次迭代为8、7,然后又变成87.33了!
- 根据以上情况,我怀疑学习率太高了,所以降低学习率,从0.01改成0.0001,发现:
- loss不会变成87.33了,但是最终会变成0,后面还带着
(* 1 =0 loss)
- loss不会变成87.33了,但是最终会变成0,后面还带着
最终修改
- 生成LMDB的时候并不resize到256x256,所以图像大小仍然是160x120。这样图像明显小了很多,batch_size可以稍微大一点!
- 用的是lenet网络、并不采用imagenet_mean.binaryproto的方式进行归一化!因为我们是用的是灰度图像,所以归一化的方式就是除以255,也就是:
scale: 1/255 (0.0039625)
- 最终效果不错!准确率为100%,这个结果不难理解,图像忒简单、干扰很少、种类也很少。
reference
LMDB文件的生成,程序如下,这个文件可以在CAFFE_ROOT\examples\imagenet下面找到!
#!/usr/bin/env sh
# Create the imagenet lmdb inputs
# N.B. set the path to the imagenet train + val data dirs
# reference: http://blog.csdn.net/u013534498/article/details/51387517
# --resize_height=$RESIZE_HEIGHT \
# --resize_width=$RESIZE_WIDTH \
set -e
EXAMPLE=examples/chanchi/data
DATA=examples/chanchi/data
TOOLS=build/tools
TRAIN_DATA_ROOT=examples/chanchi/data/train/
VAL_DATA_ROOT=examples/chanchi/data/val/
# Set RESIZE=true to resize the images to 256x256. Leave as false if images have
# already been resized using another tool.
RESIZE=true
if $RESIZE; then # if部分没有用,当前程序我没准备resize,放这儿无非就是无聊而已
RESIZE_HEIGHT=256
RESIZE_WIDTH=256
else
RESIZE_HEIGHT=0
RESIZE_WIDTH=0
fi
if [ ! -d "$TRAIN_DATA_ROOT" ]; then
echo "Error: TRAIN_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
if [ ! -d "$VAL_DATA_ROOT" ]; then
echo "Error: VAL_DATA_ROOT is not a path to a directory: $VAL_DATA_ROOT"
echo "Set the VAL_DATA_ROOT variable in create_imagenet.sh to the path" \
"where the ImageNet validation data is stored."
exit 1
fi
echo "Creating train lmdb..."
GLOG_logtostderr=1 $TOOLS/convert_imageset \
--shuffle \
$TRAIN_DATA_ROOT \
$DATA/train.txt \
$EXAMPLE/chanchi_train_lmdb
# --backend=leveldb \ # 如果需要将格式改为leveldb,则需要加上当前条件!
echo "Creating val lmdb..."
GLOG_logtostderr=1 $TOOLS/convert_imageset \
--shuffle \ # 如果需要resize,需要加上--resize_height=... --resize_width=...
$VAL_DATA_ROOT \ # 测试图片存放地址!
$DATA/val.txt \ # 定义标签文件在哪儿!
$EXAMPLE/chanchi_val_lmdb # LMDB文件存放地址!
echo "Done."
只要提示Processed就没有多大问题!
数据存放方式:
data目录下:存放训练样本、测试样本、训练标签、测试标签。
标签格式:
0normal/train_0normal_001.bmp 0
0normal/train_0normal_002.bmp 0
0normal/train_0normal_003.bmp 0
0normal/train_0normal_004.bmp 0
0normal/train_0normal_005.bmp 0
0normal/train_0normal_006.bmp 0
0normal/train_0normal_007.bmp 0
.
.
.
标签需要从0开始,因为采用了sigmodloss!不然容易出现loss为87.3365!
我这标签的生成采用的是matlab生成的,其实也是使用了批处理中的
rename
命令,(ps:如果出现名称中有空格,记着在文件名称两边加双引号,例如:rename "ni hao.txt" wozhenshuai.txt
)以下为我的matlab程序:
%% 重命名文件
% for i=1:250
% Image_source_name_normal0=['.\0normal\',num2str(i,'%03d'),'.bmp'];
% Image_source_name_normal1=['.\1normal\',num2str(i,'%03d'),'.bmp'];
% Image_source_name_normalh=['.\hnormal\',num2str(i,'%03d'),'.bmp'];
%
% Image_changed_name_normal0=['train_0normal_',num2str(i,'%03d'),'.bmp'];
% Image_changed_name_normal1=['train_1normal_',num2str(i,'%03d'),'.bmp'];
% Image_changed_name_normalh=['train_hnormal_',num2str(i,'%03d'),'.bmp'];
%
% eval(['!rename' , ',',Image_source_name_normal0 , ',',Image_changed_name_normal0]);
% eval(['!rename' , ',',Image_source_name_normal1 , ',',Image_changed_name_normal1]);
% eval(['!rename' , ',',Image_source_name_normalh , ',',Image_changed_name_normalh]);
% end
%
% % for i=251:500
% % Image_source_name_normal0=['.\0normal\',num2str(i,'%03d'),'.bmp'];
% % Image_source_name_normal1=['.\1normal\',num2str(i,'%03d'),'.bmp'];
% % Image_source_name_normalh=['.\hnormal\',num2str(i,'%03d'),'.bmp'];
% %
% % Image_changed_name_normal0=['0normal_',num2str(i,'%03d'),'.bmp'];
% % Image_changed_name_normal1=['1normal_',num2str(i,'%03d'),'.bmp'];
% % Image_changed_name_normalh=['hnormal_',num2str(i,'%03d'),'.bmp'];
% %
% % eval(['!rename' , ',',Image_source_name_normal0 , ',',Image_changed_name_normal0]);
% % eval(['!rename' , ',',Image_source_name_normal1 , ',',Image_changed_name_normal1]);
% % eval(['!rename' , ',',Image_source_name_normalh , ',',Image_changed_name_normalh]);
% % end
%% 训练标签生成
Fid_train_0normal_1normal_hNormal=fopen('.\train.txt','w+');
for i =1:250
fprintf(Fid_train_0normal_1normal_hNormal,'%s %d\r\n',['0normal/','train_0normal_',num2str(i,'%03d'),'.bmp'],0);
end
for i =1:250
fprintf(Fid_train_0normal_1normal_hNormal,'%s %d\r\n',['1normal/','train_1normal_',num2str(i,'%03d'),'.bmp'],1);
end
for i =1:250
fprintf(Fid_train_0normal_1normal_hNormal,'%s %d\r\n',['hnormal/','train_hnormal_',num2str(i,'%03d'),'.bmp'],2);
end
fclose(Fid_train_0normal_1normal_hNormal);
%% 测试标签生成
Fid_test_0Normal_1Normal_hNormal=fopen('.\val.txt','w+');
for i=251:500
fprintf(Fid_test_0Normal_1Normal_hNormal,'%s %d\r\n',['0normal/0normal_',num2str(i,'%03d'),'.bmp'],0);
end
for i=251:500
fprintf(Fid_test_0Normal_1Normal_hNormal,'%s %d\r\n',['1normal/1normal_',num2str(i,'%03d'),'.bmp'],1);
end
for i=251:500
fprintf(Fid_test_0Normal_1Normal_hNormal,'%s %d\r\n',['hnormal/hnormal_',num2str(i,'%03d'),'.bmp'],2);
end
fclose(Fid_test_0Normal_1Normal_hNormal);
- 当然也可以直接采用批处理来实现,命令行中:
dir/s/on/b>d:/train.txt
就可以在d盘下面生成train.txt,里面记录当前目录下面有什么东西!再根据替换啥的直接弄吧。也可以采用写bat文件或者sh文件来实现,并不难哈!
归一化方式:计算图像均值
彩色图像可以通过计算图像均值再除以的方式来归一化!至于为何归一化?防止梯度消失!
计算图像均值可以仿照以下程序来写:CAFFE_ROOT/examples/imagenet。
此处采用的是除以255的方式来归一化的,因为我们是被转化成灰度图像的!
以下为我的模型文件*prototxt中数据的定义:
layer {
name: "chanchi"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
scale: 0.00390625
}
data_param {
source: "examples/chanchi/data/chanchi_train_lmdb"
batch_size: 8
backend: LMDB
}
}
layer {
name: "chanchi"
type: "Data"
top: "data"
top: "label"
include {
phase: TEST
}
transform_param {
scale: 0.00390625
}
data_param {
source: "examples/chanchi/data/chanchi_val_lmdb"
batch_size: 8
backend: LMDB
}
}
读取每一层输出对应的记录
deploy如何写
首先,deploy是干什么的?
- 就是部署下网络结构,输入是咋样的?输出是咋样的?每一层的网络结构是咋样的?
- 只有确定了这些参数,才可以根据caffe_model往里面填参数啊!
其次,如何写
- 其和train_test.prototxt文件很像,网络层数与参数都是一样的!主要区别就在于输入与输出!
- 其主要就是告诉caffemodel,你那个里面的参数都是怎么放的,我只需要告诉你放哪儿就行了,怎么放、放什么都不归我管。本着这个宗旨,我这个delpoy压根不需要自己定weight与bias的初始值也不需要定学习率!
重点
- 输入怎么定?这个要参考你的debug文件,里面有一层层的参数,看清楚了!!
总得来说,deploy.prototxt就是在lenet_train_test.prototxt的基础上稍作改动,input_param { shape: { dim: 1 dim: 1 dim: 120 dim: 160 } } 这四个dim参数分别是
第一个:对待识别样本图片进行数据增广的数量,一个图片会变成10个,之后输入到网络进行识别。如果不进行数据增广,可以设置成1。
第二个:图片的通道数,一般灰度图片为单通道,则值为1,如果为非灰度图3通道图片则为3。这个要看你的LMDB文件是怎么生成的了,默认生成LMDB就是3通道的,如果你是灰度图像,并且不想生成3通道,那么需要在使用convert_imageset
的时候加上--gray
选项!!!!!!切记 我们默认图像是长x高哈~~~
第三个:图片的高度,单位像素。
第四个:图片的宽度,单位像素。- 输入怎么定?这个要参考你的debug文件,里面有一层层的参数,看清楚了!!
- 综上,我们的输入的定义应该是:
input_param { shape: { dim: 1 dim: 1 dim: 120 dim: 160 } }
,我们matlab自己定义输入的时候应该是:160x120x1x1!! - 我才开始错了那么长时间主要是忽略了,转换成LMDB时默认转换为3通道的,即使是灰度图像,且没有通过debug文件来及时发现错误!!(以上部分参考,不过别像他一样用py文件来弄,不麻烦吗??)
- 此外,当有crop的时候,输入的定义又不一样了。crop的定义是:当图像大于它时会自动剪裁(caffe默认是随机剪裁,我的笔记有介绍),是一种增加样本与减小图像的一种方式。比如当图像为256x256、crop为226x226时,会自动剪裁掉30x30。(测试的时候caffe默认是减掉中间部分!具体怎么减的看原始程序吧!!!!!)
- 所以这个时候该怎么办呢?需要自己进行crop抽样处理:参考,也就是deploy输入大小与crop大小保持一致,且自己进行抽样处理,抽样数的多少可以自己定义!我看他们都是定义10!
- 以下为我的deloy:(根据lenet改的!对比mnist的那个lenet例子看就可以! ps:我的图像是160x120,高是120,灰度图像,LMDB是1通道的)
name: "LeNet"
layer {
name: "data"
type: "Input"
top: "data"
input_param { shape: { dim: 8 dim: 1 dim: 120 dim: 160 } }
}
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
convolution_param {
num_output: 20
kernel_size: 5
stride: 1
}
}
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "conv2"
type: "Convolution"
bottom: "pool1"
top: "conv2"
convolution_param {
num_output: 50
kernel_size: 5
stride: 1
}
}
layer {
name: "pool2"
type: "Pooling"
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "ip1"
type: "InnerProduct"
bottom: "pool2"
top: "ip1"
inner_product_param {
num_output: 500
}
}
layer {
name: "relu1"
type: "ReLU"
bottom: "ip1"
top: "ip1"
}
layer {
name: "ip2"
type: "InnerProduct"
bottom: "ip1"
top: "ip2"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 3
}
}
layer {
name: "prob"
type: "Softmax"
bottom: "ip2"
top: "prob"
}
读取每一层的输出对应的matlab程序
- 主程序:
clear
i1= imread('.\chanchi\0.data\0normal\0normal_251.bmp');
i2= imread('.\chanchi\0.data\0normal\0normal_252.bmp');
i3= imread('.\chanchi\0.data\0normal\0normal_253.bmp');
i4= imread('.\chanchi\0.data\0normal\0normal_254.bmp');
i5= imread('.\chanchi\0.data\0normal\0normal_255.bmp');
i6= imread('.\chanchi\0.data\0normal\0normal_256.bmp');
i7= imread('.\chanchi\0.data\0normal\0normal_257.bmp');
i8= imread('.\chanchi\0.data\0normal\0normal_258.bmp');
%imshow(I);
crops_data = zeros(160,120,1,8, 'single');
for i=1:8
eval(['crops_data(:,:,1,i)=single(i',num2str(i),')'';']);
end
crops_data=crops_data./255; % 相当于归一化
feature_each_name=[2,3,4,5,6,7,8];
feature_chanchi=cell(1,7);
for feature_num=1:7
mapnum=feature_each_name(feature_num);
feature_chanchi{feature_num}=Extract_features_chanchi(crops_data,mapnum);
end
- 读取模型的数据
function [y] = Extract_features_chanchi(data,mapnum)
addpath('..') %加入+caffe路径
caffe.set_mode_cpu();%设置CPU模式
model_dir = './chanchi/1.lenet/';
model = [model_dir 'chanchi_deploy.prototxt']; %模型
weights = [model_dir 'lenet_chanchi_new_iter_1500.caffemodel']; %参数
net=caffe.Net(model,'test'); %测试
net.copy_from(weights); %得到训练好的权重参数
res=net.forward({data});
names=net.blob_names;
featuremap=net.blobs(names{mapnum}).get_data(); %读取输出
y=featuremap;
end
尚存在的问题
- 为啥我输入到模型时,必须一次性输入8个图像呢?也就是上述deploy文件中
input_param
参数必须为8x1x160x120? - 后来我把batchsize改成1了;又或者输入的时候仅输入1张图像,其余为0.