caffe 中 python 数据层
caffe中大多数层用C++写成。 但是对于自己数据的输入要写对应的输入层,比如你要去图像中的一部分,不能用LMDB,或者你的label 需要特殊的标记。 这时候就需要用python 写一个输入层。
如在fcn 的voc_layers.py 中 有两个类:
VOCSegDataLayer
SBDDSegDataLayer
分别包含:setup,reshape,forward, backward, load_image, load_label. 不需要backward 没有参数更新。
import caffe import numpy as np
from PIL import Image import random class VOCSegDataLayer(caffe.Layer):
"""
Load (input image, label image) pairs from PASCAL VOC
one-at-a-time while reshaping the net to preserve dimensions. Use this to feed data to a fully convolutional network.
""" def setup(self, bottom, top):
"""
Setup data layer according to parameters: - voc_dir: path to PASCAL VOC year dir
- split: train / val / test
- mean: tuple of mean values to subtract
- randomize: load in random order (default: True)
- seed: seed for randomization (default: None / current time) for PASCAL VOC semantic segmentation. example params = dict(voc_dir="/path/to/PASCAL/VOC2011",
mean=(104.00698793, 116.66876762, 122.67891434),
split="val")
"""
# config
params = eval(self.param_str)
self.voc_dir = params['voc_dir']
self.split = params['split']
self.mean = np.array(params['mean'])
self.random = params.get('randomize', True)
self.seed = params.get('seed', None) # two tops: data and label
if len(top) != 2:
raise Exception("Need to define two tops: data and label.")
# data layers have no bottoms
if len(bottom) != 0:
raise Exception("Do not define a bottom.") # load indices for images and labels
split_f = '{}/ImageSets/Segmentation/{}.txt'.format(self.voc_dir,
self.split)
self.indices = open(split_f, 'r').read().splitlines()
self.idx = 0 # make eval deterministic
if 'train' not in self.split:
self.random = False # randomization: seed and pick
if self.random:
random.seed(self.seed)
self.idx = random.randint(0, len(self.indices)-1) def reshape(self, bottom, top):
# load image + label image pair
self.data = self.load_image(self.indices[self.idx])
self.label = self.load_label(self.indices[self.idx])
# reshape tops to fit (leading 1 is for batch dimension)
top[0].reshape(1, *self.data.shape)
top[1].reshape(1, *self.label.shape) def forward(self, bottom, top):
# assign output
top[0].data[...] = self.data
top[1].data[...] = self.label # pick next input
if self.random:
self.idx = random.randint(0, len(self.indices)-1)
else:
self.idx += 1
if self.idx == len(self.indices):
self.idx = 0 def backward(self, top, propagate_down, bottom):
pass def load_image(self, idx):
"""
Load input image and preprocess for Caffe:
- cast to float
- switch channels RGB -> BGR
- subtract mean
- transpose to channel x height x width order
"""
im = Image.open('{}/JPEGImages/{}.jpg'.format(self.voc_dir, idx))
in_ = np.array(im, dtype=np.float32)
in_ = in_[:,:,::-1]
in_ -= self.mean
in_ = in_.transpose((2,0,1))
return in_ def load_label(self, idx):
"""
Load label image as 1 x height x width integer array of label indices.
The leading singleton dimension is required by the loss.
"""
im = Image.open('{}/SegmentationClass/{}.png'.format(self.voc_dir, idx))
label = np.array(im, dtype=np.uint8)
label = label[np.newaxis, ...]
return label class SBDDSegDataLayer(caffe.Layer):
"""
Load (input image, label image) pairs from the SBDD extended labeling
of PASCAL VOC for semantic segmentation
one-at-a-time while reshaping the net to preserve dimensions. Use this to feed data to a fully convolutional network.
""" def setup(self, bottom, top):
"""
Setup data layer according to parameters: - sbdd_dir: path to SBDD `dataset` dir
- split: train / seg11valid
- mean: tuple of mean values to subtract
- randomize: load in random order (default: True)
- seed: seed for randomization (default: None / current time) for SBDD semantic segmentation. N.B.segv11alid is the set of segval11 that does not intersect with SBDD.
Find it here: https://gist.github.com/shelhamer/edb330760338892d511e. example params = dict(sbdd_dir="/path/to/SBDD/dataset",
mean=(104.00698793, 116.66876762, 122.67891434),
split="valid")
"""
# config
params = eval(self.param_str)
self.sbdd_dir = params['sbdd_dir']
self.split = params['split']
self.mean = np.array(params['mean'])
self.random = params.get('randomize', True)
self.seed = params.get('seed', None) # two tops: data and label
if len(top) != 2:
raise Exception("Need to define two tops: data and label.")
# data layers have no bottoms
if len(bottom) != 0:
raise Exception("Do not define a bottom.") # load indices for images and labels
split_f = '{}/{}.txt'.format(self.sbdd_dir,
self.split)
self.indices = open(split_f, 'r').read().splitlines()
self.idx = 0 # make eval deterministic
if 'train' not in self.split:
self.random = False # randomization: seed and pick
if self.random:
random.seed(self.seed)
self.idx = random.randint(0, len(self.indices)-1) def reshape(self, bottom, top):
# load image + label image pair
self.data = self.load_image(self.indices[self.idx])
self.label = self.load_label(self.indices[self.idx])
# reshape tops to fit (leading 1 is for batch dimension)
top[0].reshape(1, *self.data.shape)
top[1].reshape(1, *self.label.shape) def forward(self, bottom, top):
# assign output
top[0].data[...] = self.data
top[1].data[...] = self.label # pick next input
if self.random:
self.idx = random.randint(0, len(self.indices)-1)
else:
self.idx += 1
if self.idx == len(self.indices):
self.idx = 0 def backward(self, top, propagate_down, bottom):
pass def load_image(self, idx):
"""
Load input image and preprocess for Caffe:
- cast to float
- switch channels RGB -> BGR
- subtract mean
- transpose to channel x height x width order
"""
im = Image.open('{}/img/{}.jpg'.format(self.sbdd_dir, idx))
in_ = np.array(im, dtype=np.float32)
in_ = in_[:,:,::-1]
in_ -= self.mean
in_ = in_.transpose((2,0,1))
return in_ def load_label(self, idx):
"""
Load label image as 1 x height x width integer array of label indices.
The leading singleton dimension is required by the loss.
"""
import scipy.io
mat = scipy.io.loadmat('{}/cls/{}.mat'.format(self.sbdd_dir, idx))
label = mat['GTcls'][0]['Segmentation'][0].astype(np.uint8)
label = label[np.newaxis, ...]
return label
对于 最终的loss 层:
在prototxt 中定义的layer:
layer {
type: 'Python' #python
name: 'loss' # loss 层
top: 'loss'
bottom: 'ipx'
bottom: 'ipy'
python_param { module: 'pyloss' # 写在pyloss 文件中 layer: 'EuclideanLossLayer' # 对应此类的名字
}
# set loss weight so Caffe knows this is a loss layer
loss_weight: 1
}
loss 层的实现 :
import caffe
import numpy as np class EuclideanLossLayer(caffe.Layer):
"""
Compute the Euclidean Loss in the same manner as the C++ EuclideanLossLayer
to demonstrate the class interface for developing layers in Python.
""" def setup(self, bottom, top):# top是最后的loss, bottom 中有两个值,一个网络的输出, 一个是label。
# check input pair
if len(bottom) != 2:
raise Exception("Need two inputs to compute distance.") def reshape(self, bottom, top):
# check input dimensions match
if bottom[0].count != bottom[1].count:
raise Exception("Inputs must have the same dimension.")
# difference is shape of inputs
self.diff = np.zeros_like(bottom[0].data, dtype=np.float32)
# loss output is scalar
top[0].reshape(1) def forward(self, bottom, top):
self.diff[...] = bottom[0].data - bottom[1].data
top[0].data[...] = np.sum(self.diff**2) / bottom[0].num / 2. def backward(self, top, propagate_down, bottom):
for i in range(2):
if not propagate_down[i]:
continue
if i == 0:
sign = 1
else:
sign = -1
bottom[i].diff[...] = sign * self.diff / bottom[i].num
caffe 中 python 数据层的更多相关文章
- caffe添加python数据层
caffe添加python数据层(ImageData) 在caffe中添加自定义层时,必须要实现这四个函数,在C++中是(LayerSetUp,Reshape,Forward_cpu,Backward ...
- caffe中python接口的使用
下面是基于我自己的接口,我是用来分类一维数据的,可能不具通用性: (前提,你已经编译了caffe的python的接口) 添加 caffe塻块的搜索路径,当我们import caffe时,可以找到. 对 ...
- caffe中关于数据进行预处理的方式
caffe的数据层layer中再载入数据时,会先要对数据进行预处理.一般处理的方式有两种: 1. 使用均值处理 transform_param { mirror: true crop_size: me ...
- (原)torch和caffe中的BatchNorm层
转载请注明出处: http://www.cnblogs.com/darkknightzh/p/6015990.html BatchNorm具体网上搜索. caffe中batchNorm层是通过Batc ...
- 【撸码caffe 五】数据层搭建
caffe.cpp中的train函数内声明了一个类型为Solver类的智能指针solver: // Train / Finetune a model. int train() { -- shared_ ...
- caffe中添加local层
下载caffe-local,解压缩; 修改makefile.config:我是将cuudn注释掉,去掉cpu_only的注释; make all make test(其中local_test出错,将文 ...
- caffe中全卷积层和全连接层训练参数如何确定
今天来仔细讲一下卷基层和全连接层训练参数个数如何确定的问题.我们以Mnist为例,首先贴出网络配置文件: name: "LeNet" layer { name: "mni ...
- 3. caffe中 python Notebook
caffe官网上的example中的例子,如果环境配对都能跑出来,接下来跑Notobook Example中的程序,都是python写的,这些程序会让你对如何使用caffe解决问题有个初步的了解(ht ...
- caffe中的BatchNorm层
在训练一个小的分类网络时,发现加上BatchNorm层之后的检索效果相对于之前,效果会有提升,因此将该网络结构记录在这里,供以后查阅使用: 添加该层之前: layer { name: "co ...
随机推荐
- pandas创建一个日期
1.通过指定周期和频率,使用date.range()函数就可以创建日期序列. 默认情况下,范围的频率是天. 2.bdate_range()用来表示商业日期范围,不同于date_range(),它不包括 ...
- 一步步分析为什么B+树适合作为索引的结构
在MySQL中,主要有四种类型的索引,分别为:B-Tree索引,Hash索引,Fulltext索引和R-Tree索引,本文讲的是B-Tree索引. 什么是索引 索引(Index)是帮助数据库高效获取数 ...
- 【转载】JAVA消息服务JMS规范及原理详解
转载:https://www.cnblogs.com/molao-doing/articles/6557305.html 作者: moyun- 一.简介 JMS即Java消息服务(Java Messa ...
- Git提交代码失败: empty ident name (for <>) not allowed
使用git提交代码,报错如下: 下午2:56 Commit failed with error 0 files committed, 1 file failed to commit: 升级 empty ...
- servlet生成验证码代码
package forward; import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import java.awt ...
- linux 环境下 firefox乱码问题解决
https://blog.csdn.net/wlwlwlwl015/article/details/51482065
- day28 反射 属性操作 getattr hasattr setattr delattr
反射 用字符串来对应其同名的属性或者方法,通过某种方法调用这个字符串来执行方法或者获取属性 网络编程的时候非常好用,是很重要的内容 先看个示例吧: class Teather: dic = { &qu ...
- 自学Linux Shell11.4-重定向输入输出
点击返回 自学Linux命令行与Shell脚本之路 11.4-重定向输入输出 Linux 命令默认从标准输入设备(stdin)获取输入,将结果输出到标准输出设备(stdout)显示.一般情况下,标准输 ...
- 【转】Context Switches上下文切换性能详解
http://blog.csdn.net/aiai5251/article/details/50015745 Context Switches 上下文切换,有时也被称为进程切换(process swi ...
- (转)Java程序员的面试经历和题库
背景:最近我在找工作,前期就像打了鸡血的一样,隔一段时间没有面试,就又松懈了下来,看到别人写的面经,感觉就像打脸一般,以后要多多总结前人的经验,时刻保持压力状态才是. 作者:nuaazhaofeng2 ...