【caffe-Windows】以mnist为例的hdf5单标签处理——matlab实现
2017-06-21 11:10
363 查看
前言
主要是想尝试看一下多标签的caffe是如何进行输入输出的,但是目前还未找到基于原始caffe做多标签输入的代码,大部分都是基于源码做了一部分修改实现多标签分类,caffe官网倒是有一个多标签的Python程序,这个我慢慢研究研究,此篇博客先看看单标签的数据格式制作与训练,以hdf5和mnist数据集为例吧【注】使用hdf5的好处有三个:①相对于前面制作的lmdb和leveldb数据集,用convert的那个代码转换前,一般都要求一张图片一个标签,也就是说猫图片的标签必须是“猫”,而不是”绿“、“猫”,而hdf5的数据格式就能支持后者,一张图片可有多个标签描述。②当我们的数据是非图片类型的,比如一维声音数据,也能用hdf5制作满足caffe输入的数据集。③当程序无法一次性读取太大的数据集,我们可以将数据集分别放到不同的hdf5文件
国际惯例,参考博客:
caffe HDF5Data 层使用及数据生成
解读创建hdf5的matlab程序
在caffe中自带了hdf5的处理程序,我们先来研究研究,然后再套入mnist数据集。前面说过一个数据集可以放入不同的hdf5文件中,那么我们肯定要现指定当前的数据存在哪个hdf5文件中
filename='trial.h5';
由于自带的程序中没有调用指定数据集,所以事先随机生成了一系列样本
num_total_samples=10000; % to simulate data being read from disk / generated etc. data_disk=rand(5,5,1,num_total_samples); label_disk=rand(10,num_total_samples);
需要注意的是这个数据集的格式,
data_disk的每个维度分别代表宽、高、通道数、样本数,刚好符合opencv的读取方式,而matlab读取图片的方式是高、宽,与这个刚好相反,所以用自己的数据集记得要翻转前两个维度,待会再说。此外
label_disk的两个维度分别是标签的单热度编码、样本数,与我们的习惯也相反,我们习惯一行一个标签,而这里是一列是一个样本的标签。
然后我们看看到底是怎么写入文件的?
定义了三个变量,分别是每次读取的数据大小,是否覆盖写入原来的hdf5文件(1/0)
chunksz=100; created_flag=false; totalct=0;
看不懂没关系,接着往下读代码
fprintf('batch no. %d\n', batchno); last_read=(batchno-1)*chunksz; % to simulate maximum data to be held in memory before dumping to hdf5 file batchdata=data_disk(:,:,1,last_read+1:last_read+chunksz); batchlabs=label_disk(:,last_read+1:last_read+chunksz);
这里就是按照事先设置的
chunksz分批读取数据。比如第一次读取第1-100个数据,第二次就是101-200,以此类推,当然读取数据的时候,虽然从每批的第一个数据(1/101/201…)开始读,但是有时候我们需要从这个数据的第m个样本的第n行第m列开始读,所以提供了这样一个结构体,用于指示读取数据的开始位置
startloc=struct('dat',[1,1,1,totalct+1], 'lab', [1,totalct+1]);
也就是从
totalct+1个数据的第1行第1列第1个通道开始读取,标签同理
接下来就是存储每批数据到最开始指定的
trial.h5文件中了
curr_dat_sz=store2hdf5(filename, batchdata, batchlabs, ~created_flag, startloc, chunksz);
有兴趣可以看看
store2hdf5的源码,这里分别介绍一下几个参数的含义:
filename:存储的hdf5文件名称
batchdata:读取的数据,一般是四个维度(宽、高、通道、批大小)
batchlabs:读取的批数据对应的输出,可以是标签也可以是其它的东东,两维(类别、批大小)
created_flag:是否覆盖写入(0不覆盖,1覆盖),一般来说第一个批次肯定是覆盖写入(
~false=1)
startloc:前面说的第一个数据开始位置
chunksz:批大小
curr_dat_sz:返回值,四维(宽、高、通道、已写入样本数)
接下来两个就是重置3中的下一个读取数据的位置
totalct和4中的是否覆盖写入为否(0=
~true)
created_flag=true;% flag set so that file is created only once totalct=curr_dat_sz(end);% updated dataset size (#samples)
【注】代码灵活多变,请不要循环类似于“为什么函数
store2hdf5用
~created_flag而不把非号去掉?”诸如此类的问题。
后面有一行代码用于展示存储的
hdf5数据情况
h5disp(filename);
自带的程序输出如下,一般我们核对核对大小和样本数就行咯:
HDF5 trial.h5 Group '/' Dataset 'data' Size: 5x5x1x10000 MaxSize: 5x5x1xInf Datatype: H5T_IEEE_F32LE (single) ChunkSize: 5x5x1x100 Filters: none FillValue: 0.000000 Dataset 'label' Size: 10x10000 MaxSize: 10xInf Datatype: H5T_IEEE_F32LE (single) ChunkSize: 10x100 Filters: none FillValue: 0.000000
这样还不够,我们还得检测一下数据是不是真的是我们输入的数据,也就是一致性
data_rd=h5read(filename, '/data', [1 1 1 1000], [5, 5, 1, 1000]); label_rd=h5read(filename, '/label', [1 1000], [10, 1000]); fprintf('Testing ...\n'); try assert(isequal(data_rd, single(data_disk(:,:,:,1000:1999))), 'Data do not match'); assert(isequal(label_rd, single(label_disk(:,1000:1999))), 'Labels do not match'); fprintf('Success!\n'); catch err fprintf('Test failed ...\n'); getReport(err) end
可以发现读取了存储的
trial.h5文件中从第
[1 1 1 1000]个数据开始的随后1000个每个大小
[5,5,1]的数据。其实也就是按照[5,5,1]从第1000个样本的第一个数值读,总共读1000个就行了,即完成了读取第1000-1999的样本数据和标签。随后在
try catch语句中判断这读出来的和我们原始数据
data_disk和
label_disk是不是对应的,是就返回
Success!,错误的话不仅返回
Test failed ...而且还有错误原因,非常便于调试。
最后,当然就是指示一下我们的
hdf5文件名字是什么,为什么用
txt文档存?因为前面已经说了,一个大的数据集一般存在多个
hdf5中,换行存储就行。自带源码只存储到了一个
hdf5文件中,因而对应的
list.txt存储只有一行,那就是:
trial.h5
在prototxt中使用
hdf5的方法,其实也就是换掉了type类型和指定
hdf5存储的
txt位置
layer { name: "data" type: "HDF5Data" top: "data" top: "labelvec" hdf5_data_param { source: "/path/to/list.txt" batch_size: 64 } }
以mnist为实例创建hdf5文件
制作训练集
去显示mnist手写数字这一博文中copy一下loadMNISTImages和
loadMNISTLabels这两个文件,用于读取存储mnist的四个二进制文件,哪四个就不说了吧
t10k-images-idx3-ubyte、
t10k-labels-idx1-ubyte、
train-images-idx3-ubyte、
train-labels-idx1-ubyte
然后按照上面介绍的基本流程分别进行如下修改:
数据集的读取
data = loadMNISTImages('t10k-images-idx3-ubyte')'; labels = loadMNISTLabels('t10k-labels-idx1-ubyte'); num_total_samples=size(data,1); data_disk=reshape(data,[28,28,1,num_total_samples]);%将数据集读取出来(高*宽*通道*样本数)
图片宽高翻转和标签的行列变换
data_disk=permute(data_disk,[2 1 3 4]);%翻转matlab读取的高宽 label_disk=permute(labels,[2 1]);%转换为caffe标签的输入格式(类别数*总样本数)
验证一致性
data_rd=h5read(filename, '/data', [1 1 1 1000], [28, 28, 1, 1000]); label_rd=h5read(filename, '/label', [1 1000], [1, 1000]);
附上
train.h5制作的完整代码,注意
test.h5的制作相同,只需替换代码中的
train为
test以及测试数据对应的二进制文件即可。
%% WRITING TO HDF5
clear
clc
filename='train.h5';%可改test.h5
% data = loadMNISTImages('train-images-idx3-ubyte')';%可改test的数据集
% labels = loadMNISTLabels('train-labels-idx1-ubyte');%可改test的标签
data = loadMNISTImages('train-images-idx3-ubyte')';
labels = loadMNISTLabels('train-labels-idx1-ubyte');
num_total_samples=size(data,1);
data_disk=reshape(data,[28,28,1,num_total_samples]);%将数据集读取出来(高*宽*通道*样本数)
%由于caffe正常的处理方法是opencv读取图片,与matlab的高宽相反
data_disk=permute(data_disk,[2 1 3 4]);%翻转matlab读取的高宽 label_disk=permute(labels,[2 1]);%转换为caffe标签的输入格式(类别数*总样本数)
% num_total_samples=10000;
% to simulate data being read from disk / generated etc.
% data_disk=rand(5,5,1,num_total_samples);
% label_disk=rand(10,num_total_samples);
chunksz=100; created_flag=false; totalct=0;
for batchno=1:num_total_samples/chunksz
fprintf('batch no. %d\n', batchno); last_read=(batchno-1)*chunksz; % to simulate maximum data to be held in memory before dumping to hdf5 file batchdata=data_disk(:,:,1,last_read+1:last_read+chunksz); batchlabs=label_disk(:,last_read+1:last_read+chunksz);
% store to hdf5
startloc=struct('dat',[1,1,1,totalct+1], 'lab', [1,totalct+1]);
curr_dat_sz=store2hdf5(filename, batchdata, batchlabs, ~created_flag, startloc, chunksz);%1代表新建,0代表附加
created_flag=true;% flag set so that file is created only once
totalct=curr_dat_sz(end);% updated dataset size (#samples)
end
% display structure of the stored HDF5 file
h5disp(filename);
%% READING FROM HDF5
% Read data and labels for samples #1000 to 1999
data_rd=h5read(filename, '/data', [1 1 1 1000], [28, 28, 1, 1000]); label_rd=h5read(filename, '/label', [1 1000], [1, 1000]);
fprintf('Testing ...\n');
try
assert(isequal(data_rd, single(data_disk(:,:,:,1000:1999))), 'Data do not match');
assert(isequal(label_rd, single(label_disk(:,1000:1999))), 'Labels do not match');
fprintf('Success!\n');
catch err
fprintf('Test failed ...\n');
getReport(err)
end
%delete(filename);
% CREATE list.txt containing filename, to be used as source for HDF5_DATA_LAYER
FILE=fopen('train.txt', 'w');%可改test.txt
fprintf(FILE, '%s', filename);
fclose(FILE);
fprintf('HDF5 filename listed in %s \n', 'list.txt');
% NOTE: In net definition prototxt, use list.txt as input to HDF5_DATA as:
% layer {
% name: "data"
% type: "HDF5Data"
% top: "data"
% top: "labelvec"
% hdf5_data_param {
% source: "/path/to/list.txt"
% batch_size: 64
% }
% }
运行结果,总共600个batch:
HDF5 test.h5 Group '/' Dataset 'data' Size: 28x28x1x60000 MaxSize: 28x28x1xInf Datatype: H5T_IEEE_F32LE (single) ChunkSize: 28x28x1x100 Filters: none FillValue: 0.000000 Dataset 'label' Size: 1x60000 MaxSize: 1xInf Datatype: H5T_IEEE_F32LE (single) ChunkSize: 1x100 Filters: none FillValue: 0.000000 Testing ... Success! HDF5 filename listed in list.txt
同理制作
test.h5文件。
以hdf5为输入进行训练
把原始的lenet_train_test.prototxt的前两个’layer’改一下:
name: "LeNet" layer { name: "mnist" type: "HDF5Data" top: "data" top: "label" include { phase: TRAIN } hdf5_data_param { source: "train.txt" batch_size: 64 } } layer { name: "mnist" type: "HDF5Data" top: "data" top: "label" include { phase: TEST } hdf5_data_param { source: "test.txt" batch_size: 100 } }
写个
bat文件训练试试
E:\caffeDEV1\caffe-master\Build\x64\Release\caffe.exe train --solver=lenet_solver.prototxt pause
截取了部分运行过程
I0621 11:01:55.571880 10520 solver.cpp:244] Train net output #0: loss = 2.29 63 (* 1 = 2.2963 loss) I0621 11:01:55.571880 10520 sgd_solver.cpp:106] Iteration 6600, lr = 0.00683784 I0621 11:01:56.463932 10520 solver.cpp:228] Iteration 6700, loss = 2.29493 I0621 11:01:56.464931 10520 solver.cpp:244] Train net output #0: loss = 2.29 493 (* 1 = 2.29493 loss) I0621 11:01:56.464931 10520 sgd_solver.cpp:106] Iteration 6700, lr = 0.00680711 I0621 11:01:57.424986 10520 solver.cpp:228] Iteration 6800, loss = 2.28502 I0621 11:01:57.425987 10520 solver.cpp:244] Train net output #0: loss = 2.28 502 (* 1 = 2.28502 loss) I0621 11:01:57.425987 10520 sgd_solver.cpp:106] Iteration 6800, lr = 0.0067767 I0621 11:01:58.465046 10520 solver.cpp:228] Iteration 6900, loss = 2.29951 I0621 11:01:58.466047 10520 solver.cpp:244] Train net output #0: loss = 2.29 951 (* 1 = 2.29951 loss) I0621 11:01:58.466047 10520 sgd_solver.cpp:106] Iteration 6900, lr = 0.0067466 I0621 11:01:59.259091 10520 solver.cpp:337] Iteration 7000, Testing net (#0) I0621 11:01:59.883127 10520 solver.cpp:404] Test net output #0: accuracy = 0 .1049 I0621 11:01:59.884127 10520 solver.cpp:404] Test net output #1: loss = 2.385 52 (* 1 = 2.38552 loss) I0621 11:01:59.889127 10520 solver.cpp:228] Iteration 7000, loss = 2.29426 I0621 11:01:59.889127 10520 solver.cpp:244] Train net output #0: loss = 2.29 426 (* 1 = 2.29426 loss) I0621 11:01:59.889127 10520 sgd_solver.cpp:106] Iteration 7000, lr = 0.00671681
好了,附件打包:
程序和
prototxt以及
bat下载地址: 链接:http://pan.baidu.com/s/1hr4UM2o 密码:bqiy
mnist手写数字:链接:http://pan.baidu.com/s/1jHYCQJ8 密码:vaeo
后续研究将扩展到多标签中,预先参考文献戳这里
相关文章推荐
- 深度学习Caffe实战(9)Windows 平台caffe用MATLAB接口实现训练网络和测试
- Windows玩转Caffe(五): mnist模型可视化探知,Matlab绘制其Accuracy和Loss曲线
- 【caffe-Windows】mnist实例编译之model的使用-matlab
- 【caffe-Windows】识别率批量输出——matlab实现
- Windows下Matlab使用G++ DLL实现图像处理
- MATLAB图像处理与计算机视觉(3):实现Carsten Steger 的曲线检测算法(1)
- C或C++调用Windows系统函数 实现延时 或 获取当前时间的处理
- 使用cwRsync实现windows下服务器文件定时同步备份(附错误处理方法)
- 图像边沿平滑处理的matlab实现
- windows计划任务+批处理文件实现oracle数据库的定时备份与恢复
- 在windows开发环境下写bat脚本实现对erlang项目的并行编译处理
- Matlab中图像处理实例:灰度变换,空域滤波,频域滤波,傅里叶变换的实现
- 利用System.Windows.Interactivity.dll实现View时间在ViewModel中处理(可带sender、EventArgs参数)
- 如何快糙好猛地在Windows下编译CAFFE并使用其matlab和python接口
- 数字图像处理,经典滤波算法去噪对比实验(Matlab实现)
- Windows计划任务+批处理文件实现oracle数据库的定时备份与恢复
- [数字图像处理]常见噪声的分类与Matlab实现
- matlab实现分水岭算法处理图像分割
- java调用windows DLL实现底层处理(C++编程)
- 细说windows的异常处理和实现——结构化异常