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 数据层的更多相关文章

  1. caffe添加python数据层

    caffe添加python数据层(ImageData) 在caffe中添加自定义层时,必须要实现这四个函数,在C++中是(LayerSetUp,Reshape,Forward_cpu,Backward ...

  2. caffe中python接口的使用

    下面是基于我自己的接口,我是用来分类一维数据的,可能不具通用性: (前提,你已经编译了caffe的python的接口) 添加 caffe塻块的搜索路径,当我们import caffe时,可以找到. 对 ...

  3. caffe中关于数据进行预处理的方式

    caffe的数据层layer中再载入数据时,会先要对数据进行预处理.一般处理的方式有两种: 1. 使用均值处理 transform_param { mirror: true crop_size: me ...

  4. (原)torch和caffe中的BatchNorm层

    转载请注明出处: http://www.cnblogs.com/darkknightzh/p/6015990.html BatchNorm具体网上搜索. caffe中batchNorm层是通过Batc ...

  5. 【撸码caffe 五】数据层搭建

    caffe.cpp中的train函数内声明了一个类型为Solver类的智能指针solver: // Train / Finetune a model. int train() { -- shared_ ...

  6. caffe中添加local层

    下载caffe-local,解压缩; 修改makefile.config:我是将cuudn注释掉,去掉cpu_only的注释; make all make test(其中local_test出错,将文 ...

  7. caffe中全卷积层和全连接层训练参数如何确定

    今天来仔细讲一下卷基层和全连接层训练参数个数如何确定的问题.我们以Mnist为例,首先贴出网络配置文件: name: "LeNet" layer { name: "mni ...

  8. 3. caffe中 python Notebook

    caffe官网上的example中的例子,如果环境配对都能跑出来,接下来跑Notobook Example中的程序,都是python写的,这些程序会让你对如何使用caffe解决问题有个初步的了解(ht ...

  9. caffe中的BatchNorm层

    在训练一个小的分类网络时,发现加上BatchNorm层之后的检索效果相对于之前,效果会有提升,因此将该网络结构记录在这里,供以后查阅使用: 添加该层之前: layer { name: "co ...

随机推荐

  1. FICO基础知识(二)

    FI中的maser data: COA (Chart Of Account)  科目表 Account 科目 Vendor master dada  供应商主数据 Customer master da ...

  2. 初学者学习C++的50条忠告

    1.把C++当成一门新的语言学习(和C没啥关系!真的.); 2.看<Thinking In C++>,不要看<C++变成死相>; 3.看<The C++ Programm ...

  3. Visual Studio 2017各版本安装包离线下载、安装全解析

    关于Visual Studio 2017各版本安装包离线下载.更新和安装的方法以及通过已下载版本减少下载量的办法 微软最近发布了正式版Visual Studio 2017并公开了其下载方式,不过由于V ...

  4. Linux共享库LD_LIBRARY_PATH与ld.so.conf

    1. 往/lib和/usr/lib里面加东西,是不用修改/etc/ld.so.conf的,但是完了之后要调一下ldconfig,不然这个library会找不到 2. 想往上面两个目录以外加东西的时候, ...

  5. Codeforces960G Bandit Blues 【斯特林数】【FFT】

    题目大意: 求满足比之前的任何数小的有A个,比之后的任何数小的有B个的长度为n的排列个数. 题目分析: 首先写出递推式,设s(n,k)表示长度为n的排列,比之前的数小的数有k个. 我们假设新加入的数为 ...

  6. bzoj 2120 数颜色 (带修莫队)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2120 题意:两种操作:Q 询问区间  l - r  内颜色的种类 ,R 单点修改 思路 ...

  7. POI插入图片至Excel使用固定的长宽

    使用POI在Excel里插入图片,如何使插入的图片使用固定的大小?先介绍原有的两种方式: 一种是指定开始和结尾单元格,然后从头画到尾,相当于平铺 还有一种就是仅指定开始的单元格,图片的大小跟这个单元格 ...

  8. day8 文件操作

    文件基本操作 # 打开文件 f = open("小重山","r",encoding="utf-8") # readline 方法 只查看一行 ...

  9. 洛谷CF868F Yet Another Minimization Problem(动态规划,决策单调性,分治)

    洛谷题目传送门 貌似做所有的DP题都要先搞出暴力式子,再往正解上靠... 设\(f_{i,j}\)为前\(i\)个数分\(j\)段的最小花费,\(w_{l,r}\)为\([l,r]\)全在一段的费用. ...

  10. CodeChef题目选讲

    https://wenku.baidu.com/view/2445a0322f60ddccda38a023.html 关键点:不超过7条 根据咕咕原理,所以答案最少是N/7;(N小于49就暴力) 随机 ...