写python脚本:#!/usr/bin/env python
写bash脚本:#!/bin/bash 或#!/usr/bin/env sh  其后常加set e 

对于深度学习网络的训练任务中一般会需要三组数据库: 
训练集,验证集及测试集。这里训练集中主要是用于训练网络,而验证集中主要是在训练网络中验证测试部分网络超参数,而测试集是用于考察网络的精度。因此,虽然三组数据集都是带标签的数据集,但训练集中的标签是网络可以已知的,也就是说网络会利用标签信息进行梯度更新,而验证集中的标签对于网络本身是未知的,但对于实验者是已知的,也就是说实验者可以通过验证集来验证一些网络在训练中不可改变的超参数。而测试集的标签对于实验者和网络都是未知的,其是用于考察实验者所设计的网络本身的有效性。

有时,我们也可以将训练集和验证集合二为一trainval.txt,但必须要有测试集test.txt,如果没有测试集,将无法考察网络的泛化能力(也即真实的检测精度)。因此在得到的大量的图像中,我们一般会随机抽取的一组图像作为测试集数据,而其他数据作为训练验证数据。

对于分类任务来说,数据列表文件中每一行包含图像地址及该图像对应的分类标号
对于目标检测数据集来说,其中每一行包含图像地址及该图像标记文件xml的地址
对于目标检测任务来说,每张图像中可以会有多个目标,每个目标都有一组位置信息和分类信息,因此通常是通过xml文件来表示。这里推荐使用labelImg来进行图像标记,该软件可以直接通过pip install labelImg来进行安装,在Anaconda中安装完成后,在使用时可能会提示PyQt4错误,可以将所有import PyQt4的部分及使用PyQt4的部分删除。
If you're using Anaconda to manage Python on your system, you can install it with:

$ conda install pyqt=4

Omit the =4 to install the most current version.


Caffe上有很多使用了Google Protocol Buffer的东西,从网上来看,这“是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式”。作为caffe模型定义的数据格式,看懂caffe.proto对caffe的理解会有很大帮助。在 protobuf 的术语中,结构化数据被称为 Message,message中有不同成员。proto 文件非常类似 java 或者 C 语言的数据定义,string、int32这种类型我们已经见得多了。支持类型包括数字(整数或浮点), 布尔值,,字符串,原始字节(raw bytes),或者是其他的message类型 (如上例) 。除了这些类型,其前后多了一些“修饰”。类型前是field rules,有可选(optional)、必填(required)、重复(repeated)三种。后面是message中的ID,同一message下ID随成员递增。
对于一个完整的proto文件,在文件前还应该加上:
syntax = "proto2";//说明语法是2还是3
package caffe;    //包名,通常与文件名相同
使用写好的proto就可以用编译器将文件编译为目标语言了。在protobuf V3.0网站上可以下载 Protobuf V3.0的源代码,V2.6版本在网页上比较靠后,更新到2.6.1。然后解压编译安装便可以使用它了。从caffe文件上看用的还是2的语法。2和3的区别可以从网上搜到,如Google Protobuf 3版本介绍。其实变化也是不少,比如只保留repeated标记数组类型,optional和required都被去掉了;字段default标记不能使用了
关于solver的一切,都在caffe.proto文件中message SolverParameter 这一部分,必须为每个test_net指定一个test_iter。还可以为每个test_net指定test_level和/或test_stage。注意的是:文件的路径要从caffe的根目录开始,其它的所有配置都是这样。 
可以看到这几行的标签序号并不是顺序的,也说明caffe在不断地修改,下一个可用的序号是41。网络状态必须是未指定的或者只能在一个网络中指定一次。 执行完一次全部数据,称之为一个epoch,iter_size是迭代器大小,梯度的计算是通过iter_size x batch_size决定的。

在prototxt文件中,层都是用layer{}的结构表示,而里面包含的层的参数可以在caffe.proto文件中找到,比如说Data类型的结构由message DataParameter所定义,Convolution类型的结构由message ConvolutionParameter所定义。 具体说明下:
  name表示该层的名称
  type表示该层的类型,如Data或者Convolution类型
  top表示该层后接的Blob结构的名称
  bottom表示该层前接的Blob数据结构的名称
  *_param表示该层的参数,比如对于某卷积层conv1来说,convolution_param中 
  num_output表示输出通道数
  pad表示卷积pad
  kernel_size表示卷积核的大小
对于深度网络,一般都是通过梯度下降法训练的,因此在Blob结构中除了包含一个存储数据或者权重值的4维数组外,而需要包含一个存储权重增量(diff)的4维数组。
Caffe的所有数据(各层的参数、及各层输入及输出)都是以Blob数据结构形式存在于内存中的,其是Caffe的基本存储单元,这同Torch、Theano和Tensorflow中的Tensor结构是一致的。
对于层(Layer),其至少会有一个输入Blob或者输出Blob,当然也可以有多个输入或输出Blob。一些层的内部还会有权重值(Weight)和偏置值(Bias)两个Blob结构。
前向传播中,Layer主要是将输入Blob进行某种处理(比如卷积操作)得到输出Blob,而在后向传播中,主要是对输出Blob的diff进行处理得到输入Blob的diff(这也就是损失梯度的反向传播过程),对于需要进行参数更新的层,还会计算权重值Blob及偏置Blob的diff,并用于参数更新(对于批量训练法,会在根据一个批量的累积diff来进行参数更新,而并不是在每次反向传播中都进行参数更新)。
Net中包含了两个部分结构:Layer结构和Blob结构。其中Blob对象主要用于存放每个Layer层的输入及输出的中间结果,而Layer结构即为对Blob对象进行计算处理的层(比如卷积、全连接、池化、softmax等)。注意的是Blob对象和Layer对象可能重名,但两者是完全不一样的。如:用于图像分类的网络的最后一层一般是一个名为’prob’的SoftMax网络,这个名为’prob’层的输出即为反应该图像在各分类下的概率向量。而prob层的输出Blob也名为prob
layer { name: "prob" type: "Softmax" bottom: "ip2" top: "prob" # 输出Blob }

Blob:存储和传递(communication):
以行为主顺序(Row-major order)的存储方式,简单的说就是把一行存完,再存下一行,把第一个通道(channel)的所有行写完后写完再写下一个通道。例如对一批(batches)图像,用4维blob存储,表示为number N(数据批量大小) x channel K(通道、维度特征) x height H (高)x width W(宽),对于索引 (n, k, h, w) 的物理地址就是:((n * K + k) * H + h) * W + w,注意区分大小写,大写是总的,小写是索引值。对于图像是4D的,当然也可以不用4D。具体参数需要根据层类型和数据大小配置。 
blob使用了两块存储区域,为data(数据)和diff(网络梯度),实际值可以存储在CPU或GPU上,访问也可以不变(const)访问或者可变(mutable)访问。 
const Dtype* cpu_data() const; 
Dtype* mutable_cpu_data(); 
同理可得GPU上diff类型数据操作。官网上有一个example,展示了数据在CPU和GPU上流动操作。

Layer计算和连接:
每层须有三个关键计算:setup, forward, and backward
setup:初始化层和连接。
forward:底部向顶部计算。
backward:给定梯度,从top计算传回
使用GPU会因为数据需要从CPU复制到GPU上,因此会有数据传输成本,但GPU跑的还是快一些,所以是quick experiments

Net定义和操作:
Net由Layer组成(The net is a set of layers connected in a computation graph有向无环图)。模型初始化由Net :: Init()处理:主要是创建blob和layer,并调用layer里的setup,同时会输出INFO。

模型格式:
模型定义在.prototxt文件中,训练好的模型在model目录下.binaryproto格式的文件中,模型的格式由caffe.proto定义。
这里摘取DeepLearning中文版中的一段话:
我们几乎总是初始化模型的权重为高斯或均匀分布中随机抽取的值。高斯或均匀分布的选择似乎不会有很大的差别,但也没有被详尽地研究。然而,初始分布的 大小确实对优化过程的结果和网络泛化能力都有很大的影响
随着bn等新的层的提出对于初始化的方法现在网络有更强的容忍度了,不过还是有影响的。
主要介绍几种常用的初始化方法:
Gaussian,高斯初始化给定均值与标准差 比如均值一般为0,标准差为 0.01 或0.001
uniform,取均匀分布的数值比如从0到1之间随机取 Xavier也是属于均匀分布的一种
Xavier,为了保证前传和反传过程中不会遇到输出方差越来越大或者越来越小的情况,将其初始化为均匀分布:U(-sqrt(6/(m+n)),sqrt(6/(m+n)))
MSRA
除此之外也有很多对于初始化的探索,比如将权重初始化为正交矩阵等等

1. sigmoid在压缩数据幅度方面有优势,对于深度网络,使用sigmoid可以保证数据幅度不会有问题,这样数据幅度稳住了就不会出现太大的失误。 
2. 但是sigmoid存在梯度消失的问题,在反向传播上有劣势,所以在优化的过程中存在不足 
3. relu不会对数据做幅度压缩,所以如果数据的幅度不断扩张,那么模型的层数越深,幅度的扩张也会越厉害,最终会影响模型的表现。 
4. 但是relu在反向传导方面可以很好地将“原汁原味”的梯度传到后面,这样在学习的过程中可以更好地发挥出来。(这个“原汁原味”只可意会,不必深究)这么来看,sigmoid前向更靠谱,relu后向更强。

输入:n * c_i * h_i * w_i
输出:n * c_o * h_o * w_o, where h_o = (h_i + 2 * pad_h - kernel_h) / stride_h + 1 and w_o likewise。

stride (or stride_h and stride_w) [default 1]: 卷积核的移动步长,默认为1。
group (g) [default 1]: 分组,默认为1组。如果大于1,我们限制卷积的连接操作在一个子集内。如果我们根据图像的通道来分组,那么第i个输出分组只能与第i个输入分组进行连接。groups是代表filter 组的个数。引入gruop主要是为了选择性的连接卷基层的输入端和输出端的channels,否则参数会太多。当group=2时,前半部分filter与输入的前半部分通道连接,后半部分filter与后半部分输入通道连接(alexnet是以通道分组)。
Pooling 层一般在网络中是跟在Conv卷积层之后,做采样操作,其实是为了进一步缩小feature map,同时也能增大神经元的视野。
可选参数: 
pool [default MAX]: 池化方法,默认为MAX,还有 AVE, or STOCHASTIC。
pad (or pad_h and pad_w) [default 0]:填零。
stride (or stride_h and stride_w) [default 1]:步长。

局部响应归一化层LRN层:通过对局部输入区域进行归一化来执行一种“横向抑制”。具体作用感觉和特征缩放有点像,使梯度下降在所有方向上具有相同的曲率。而RNL这种方法的计算相比对每个神经元输入归一化要简单。
可选参数 
local_size [default 5]:需要求和的通道数数目(对于跨通道LRN),或者是方形区域求和的变长(对于通道内LRN)。
alpha [default 1]: 比例参数。
beta [default 5]: 指数参数。
norm_region [default ACROSS_CHANNELS]:ACROSS_CHANNELS表示在相邻的通道间求和归一化,但没有空间延伸,即大小为local_size x 1 x 1;WITHIN_CHANNEL表示在一个通道内部特定的区域内进行求和归一化,其大小为:1 x local_size x local_size。每个输入值被除以(1+(α/n)∑ix2i)β,n是每个局部区域的大小。
ReLU层支持in-place计算,bottom输入和top输出可以相同避免内存消耗。Sigmoid层激活函数表达式为y=(1+exp(−x))−1,由于收敛速度问题现在用的不多了。当然其他的层不能使用重复的blob名称
卷积层中:先后两个lr_mults是对本层可学习参数的速率调整,权重学习率与solver中的学习率相同,而偏置学习率为其两倍,这往往导致更好的收敛率
化层表示采用最大池化的方法,进行大小为2,步长为2的非重叠池化
##############################caffe常用参考#####################################
含有的模型:
caffenet 
fc-rcnn 
googlenet 
alexnet 
caffenet-based-finetuning-flickr-style
LogisticRegressionNet
LeNet
MNISTAutoencoder
CaffeNetConv(Fully convolutional network version of CaffeNet)
mnist_siamese_train_test net

输出训练日志到指定文件并放后台运行:
nohup ./build/tools/caffe train --solver=examples/mnist/lenet_solver.prototxt > /home/sunlibo/Desktop/log.txt 2>&1 &

编写train_val.prototxt常用到!
include {
    phase: TRAIN
  }
include {
    phase: TEST
  }

layer-type:
Slice,Data(ldmb,levb),HDF5Data,WindowData,ImageData,MemoryData,DummyData,Reshape,Convolution,Pooling,InnerProduct,Dropout,ContrastiveLoss,SigmoidCrossEntropyLoss,BatchNorm,EuclideanLoss,Input,LRN,Softmax,SoftmaxWithLoss,Accuracy,Python,ContrastiveLoss ,BN,ReLU,Rectified-Linear and Leaky-ReLU,Sigmoid,TanH、AbsVal、BNLL,Power(幂运算函数为f(x)=(shift+scale∗x)p)
affe中的激活层还有很多,也有一些是加速的层。比如DropoutLayer现在是非常常用的一种网络层,只用在训练阶段,一般用在网络的全连接层中,可以减少网络的过拟合问题。
Softmax(with loss):SoftmaxWithLoss概念上等同于softmax layer+多项对数损失层(multinomial logistic loss layer),但提供了更稳定的梯度。softmax只是输出每一类的概率,并没有与label做比较。
Sum-of-Squares / Euclidean:EuclideanLoss 这是比较传统的求偏差的方法,直接计算欧氏距离
Hinge / Margin: HingeLoss 可选参数 norm [default L1]:应该是正则化方法,目前只有L1、L2。Hinge loss主要用于SVM
输入: 
n * c * h * w Predictions预测值
n * 1 * 1 * 1 Labels标签
输出:1 * 1 * 1 * 1 Computed Loss
Accuracy:只有test阶段才有,因此需要加入include参数。它实际上不是损失并且没有后退步骤,输入:n * c_i * h_i * w_i;输出:n * c_o * 1 * 1
Reshape层:输入:单独的blob,输出:变形后的blob,示例:
layer {
    name: "reshape"
    type: "Reshape"
    bottom: "input"
    top: "output"
    reshape_param {
          shape {
            dim: 0  # copy the dimension from below
            dim: 2
            dim: 3
            dim: -1 # infer it from the other dimensions
          }
    }
}
这一操作不改变数据,只改变维度,也没有在过程中拷贝数据。输出的尺寸有shape参数的值规定,正数是对应的维度,除此外还有两个特殊值:0表示复制底层对应的维度,-1表示从其他维度推断,特别的,当时用参数:reshape_param { shape { dim: 0 dim: -1 } }时,reshape层相当于flatten层,将n * c * h * w的数据变为n * (c*h*w)。

级联层类型: Concat,参数 (ConcatParameter concat_param): 
可选参数 
axis [default 1]: 0表示沿着数量(n),1表示沿着通道(C)。
输入:n_i * c_i * h * w 对于每个blob输入,i= 1 到 K。
输出: 
当 axis = 0: (n_1 + n_2 + … + n_K) * c_1 * h * w, 所有的c_i应该相同。
当 axis = 1: n_1 * (c_1 + c_2 + … + c_K) * h * w, 所有的n_i 应该相同。
这个层把多个blob连接为一个blob。


caffe中支持下面几种梯度下降:Solver类型
SGD stochastic gradient descent
AdaDelta
Adam
Nesterov
RMSProp

lr_policy: "step" "fixed" "poly"
fixed: 总是返回base_lr(学习率不变)
step: 返回 base_lr * gamma ^ (floor(iter / step)) 
还需要设置stepsize参数以确定step,iter表示当前迭代次数。
exp: 返回base_lr * gamma ^ iter, iter为当前迭代次数
inv: 如果设置为inv,还需要设置一个power, 返回base_lr * (1 + gamma * iter) ^ (- power)
multistep: 如果设置为multistep,则还需要设置一个stepvalue。这个参数和step很相似,step是均匀等间隔变化,而multistep则是根据stepvalue值变化。
poly: 学习率进行多项式误差, 返回 base_lr (1 - iter/max_iter) ^ (power)
sigmoid: 学习率进行sigmod衰减,返回 base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))。
multistep示例::step是均匀等间隔变化,而multistep则是根据stepvalue值变化
base_lr: 0.01
momentum: 0.9
weight_decay: 0.0005
# The learning rate policy
lr_policy: "multistep"
gamma: 0.9
stepvalue: 5000
stepvalue: 7000
stepvalue: 8000
stepvalue: 9000
stepvalue: 9500#在第5000步,7000步。。。分别改变学习率,regularization_type正则化方式默认为L2

./scripts/download_model_binary.py models/bvlc_reference_caffenet
sh ./data/ilsvrc12/get_ilsvrc_aux.sh
python examples/finetune_flickr_style/assemble_data.py --workers=-1 --images=2000 --seed 831486


快照可以将训练出来的model和solver状态进行保存,snapshot用于设置训练多少次后进行保存,默认为0,不保存。snapshot_prefix设置保存路径。还可以设置snapshot_diff,是否保存梯度值,保存有利于调试,但需要较大空间存储,默认为false,不保存。也可以设置snapshot_format,保存的类型。有两种选择:HDF5 和BINARYPROTO ,默认为BINARYPROTO。
snapshot: 10000
snapshot_format: HDF5,如生成caffenet_train_iter_10000.solverstate.h5
snapshot_prefix: "examples/cifar10/cifar10_full"

杂项:debug_info用于输出调试信息。snapshot_after_train用于训练后是否输出快照
./build/tools/caffe train --solver=models/bvlc_reference_caffenet/solver.prototxt或:
./build/tools/caffe train -solver models/bvlc_reference_caffenet/solver.prototxt

运行模式:设置CPU或GPU模式,在GPU下还可以指定使用哪一块或所有GPU运行。random_seed用于初始生成随机数种子。
#使用GPU训练
./build/tools/caffe train -solver models/finetune_flickr_style/solver.prototxt -weights models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel -gpu 0
./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt -gpu 0,1
#使用所有GPU训练
./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt -gpu all 或
./build/tools/caffe train --solver=examples/mnist/lenet_solver.prototxt --gpu=all
./build/tools/extract_features.bin models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel examples/_temp/imagenet_val.prototxt fc7 examples/_temp/features 10 leveldb

./build/examples/cpp_classification/classification.bin \
  models/bvlc_reference_caffenet/deploy.prototxt \
  models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel \
  data/ilsvrc12/imagenet_mean.binaryproto \
  data/ilsvrc12/synset_words.txt \
  examples/images/cat.jpg
#ctrl+c终止训练,会生成类似mnist_siamese_iter_21915.solverstate用于开机继续训练,
./build/tools/caffe train --solver=examples/siamese/mnist_siamese_solver.prototxt --snapshot=examples/siamese/mnist_siamese_iter_21915.solverstate
./build/tools/caffe train --solver=models/bvlc_reference_caffenet/solver.prototxt --snapshot=models/bvlc_reference_caffenet/caffenet_train_iter_10000.solverstate

caffe test -model examples/mnist/lenet_train_test.prototxt -weights examples/mnist/lenet_iter_10000.caffemodel -gpu 0 -iterations 100意思是利用训练好了的权重(-weight),输入到测试模型中(-model),用编号为0的gpu(-gpu)测试100次(-iteration)。
caffe time -model examples/mnist/lenet_train_test.prototxt -iterations 10这个例子用来在屏幕上显示lenet模型迭代10次所使用的时间。包括每次迭代的forward和backward所用的时间,也包括每层forward和backward所用的平均时间。


####################caffe之python接口常用库:########################
import cv2            ##class OpenCVResizeCrop for resize_and_crop_images.py
from PIL import Image ##class PILResizeCrop for resize_and_crop_images.py

from __future__ import print_function
from __future__ import division
import json
import sys#if os.path.exists(model_filename) and model_checks_out():....sys.exit(0),sys.exit(1)
import os
import os.path as osp
import time
import random
import datetime #datetime.datetime.now()
import matplotlib.pyplot as plt
import matplotlib.cm as cmx
import matplotlib.colors as colors
import matplotlib.legend as lgd
import matplotlib.markers as mks

from collections import OrderedDict
from collections import OrderedDict, Counter
import six
import skimage.io
from scipy.ndimage import zoom
from skimage.transform import resize
from caffe.proto import caffe_pb2

%matplotlib inline  #jupyter notebook才用,用于图形显示的嵌入

import yaml
import hashlib
import argparse#parser = argparse.ArgumentParser(...) ...parser.add_argument...args = parser.parse_args()
import pickle
import cPickle
import scipy.misc

import skimage.io
from PIL import Image

# Make sure that caffe is on the python path:
caffe_root = '../'  # this file is expected to be in {caffe_root}/examples/

sys.path.insert(0, caffe_root + 'python')
import caffe
from caffe import layers as L, params as P, to_proto

from caffe import layers as L
from caffe import params as P
from caffe.proto import caffe_pb2
import caffe.draw
import tempfile

import pandas as pd
import numpy as np


from xml.dom import minidom
from random import shuffle
from threading import Thread

import cStringIO as StringIO
import urllib
import logging #logging.info('Uploaded image open error: %s', err)
import flask #app = flask.Flask(__name__)
import werkzeug
import optparse #参数解析
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
import tornado.wsgi
import tornado.httpserver

from tools import SimpleTransformer
from google.protobuf import text_format
from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2



####################caffe之python接口常用API:########################
Packages导入:
import caffe
from caffe import layers as L
from caffe import params as P

Layers定义:
Data层--lmdb/leveldb Data层定义
L.Data( 
        source=lmdb,
        backend=P.Data.LMDB,
        batch_size=batch_size, ntop=2,
        transform_param=dict(
                              crop_size=227,
                              mean_value=[104, 117, 123],
                              mirror=True
                              )
        )
Data层--HDF5 Data层定义
L.HDF5Data(
            hdf5_data_param={
                            'source': './training_data_paths.txt',  
                            'batch_size': 64
                            },
            include={
                    'phase': caffe.TRAIN
                    }
            )

Data层--ImageData Data层定义
适用于txt文件一行记录一张图片的数据源
L.ImageData(
                source=list_path,
                batch_size=batch_size,
                new_width=48,
                new_height=48,
                ntop=2,
                ransform_param=dict(crop_size=40,mirror=True)
                )

Convloution层定义:
L.Convolution(  
                bottom, 
                kernel_size=ks, 
                stride=stride,
                num_output=nout, 
                pad=pad, 
                group=group
                )

LRN层定义:
L.LRN(
        bottom, 
        local_size=5, 
        alpha=1e-4, 
        beta=0.75
        )
Activation层定义--ReLU层定义
L.ReLU(
        bottom, 
        in_place=True
        )

Pooling层定义:
L.Pooling(
            bottom,
            pool=P.Pooling.MAX, 
            kernel_size=ks, 
            stride=stride
            )

FullConnect层定义:
L.InnerProduct(
                bottom, 
                num_output=nout
                )

Dropout层定义:
L.Dropout(
            bottom, 
            in_place=True
            )
Loss层定义:
L.SoftmaxWithLoss(
                    bottom, 
                    label
                    )

Accuracy层定义:
L.Accuracy(
            bottom,
            label
            )

转换为proto文本:
caffe.to_proto(
                loss, 
                acc     #训练阶段可以删去Accuracy层
                )


Solver定义:
from caffe.proto import caffe_pb2
s = caffe_pb2.SolverParameter()
path='/home/xxx/data/'
solver_file=path+'solver.prototxt'     #solver文件保存位置
s.train_net = path+'train.prototxt'     # 训练配置文件
s.test_net.append(path+'val.prototxt')  # 测试配置文件
s.test_interval = 782                   # 测试间隔
s.test_iter.append(313)                 # 测试迭代次数
s.max_iter = 78200                      # 最大迭代次数
s.base_lr = 0.001                       # 基础学习率
s.momentum = 0.9                        # momentum系数
s.weight_decay = 5e-4                   # 权值衰减系数
s.lr_policy = 'step'                    # 学习率衰减方法
s.stepsize=26067                        # 此值仅对step方法有效
s.gamma = 0.1                           # 学习率衰减指数
s.display = 782                         # 屏幕日志显示间隔
s.snapshot = 7820
s.snapshot_prefix = 'shapshot'
s.type = “SGD”                          # 优化算法
s.solver_mode = caffe_pb2.SolverParameter.GPU
with open(solver_file, 'w') as f:
    f.write(str(s))


Model训练:
# 训练设置
# 使用GPU
caffe.set_device(gpu_id) # 若不设置,默认为0
caffe.set_mode_gpu()
# 使用CPU
caffe.set_mode_cpu()
# 加载Solver,有两种常用方法
# 1. 无论模型中Slover类型是什么统一设置为SGD
solver = caffe.SGDSolver('/home/xxx/data/solver.prototxt') 
# 2. 根据solver的prototxt中solver_type读取,默认为SGD
solver = caffe.get_solver('/home/xxx/data/solver.prototxt')
# 训练模型
# 1.1 前向传播
solver.net.forward()  # train net
solver.test_nets[0].forward()  # test net (there can be more than one)
# 1.2 反向传播,计算梯度
solver.net.backward()
# 2. 进行一次前向传播一次反向传播并根据梯度更新参数
solver.step(1)
# 3. 根据solver文件中设置进行完整model训练
solver.solve()
如果想在训练过程中保存模型参数,调用solver.net.save('mymodel.caffemodel')

分类图片--加载Model数据
net = caffe.Net(
        deploy_prototxt_path,   # 用于分类的网络定义文件路径
        caffe_model_path,       # 训练好模型路径
        caffe.TEST              # 设置为测试阶段
        )

分类图片--中值文件转换
# 编写一个函数,将二进制的均值转换为python的均值
def convert_mean(binMean,npyMean):
    blob = caffe.proto.caffe_pb2.BlobProto()
    bin_mean = open(binMean, 'rb' ).read()
    blob.ParseFromString(bin_mean)
    arr = np.array( caffe.io.blobproto_to_array(blob) )
    npy_mean = arr[0]
    np.save(npyMean, npy_mean )
# 调用函数转换均值
binMean='examples/cifar10/mean.binaryproto'
npyMean='examples/cifar10/mean.npy'
convert_mean(binMean,npyMean)

分类图片--图片预处理
# 设定图片的shape格式为网络data层格式
transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
# 改变维度的顺序,由原始图片维度(width, height, channel)变为(channel, width, height)
transformer.set_transpose('data', (2,0,1)) 
# 减去均值,注意要先将binaryproto格式均值文件转换为npy格式[此步根据训练model时设置可选]
transformer.set_mean('data', np.load(mean_file_path).mean(1).mean(1))
# 缩放到[0,255]之间
transformer.set_raw_scale('data', 255)
# 交换通道,将图片由RGB变为BGR
transformer.set_channel_swap('data', (2,1,0))
# 加载图片
im=caffe.io.load_image(img)
# 执行上面设置的图片预处理操作,并将图片载入到blob中
net.blobs['data'].data[...] = transformer.preprocess('data',im)

分类图片--执行测试
#执行测试
out = net.forward()
labels = np.loadtxt(labels_filename, str, delimiter='\t')   #读取类别名称文件
prob= net.blobs['Softmax1'].data[0].flatten() #取出最后一层(Softmax)属于某个类别的概率值,并打印
print prob
order=prob.argsort()[0]  #将概率值排序,取出最大值所在的序号 
print 'the class is:',labels[order]   #将该序号转换成对应的类别名称,并打印
# 取出前五个较大值所在的序号
top_inds = prob.argsort()[::-1][:5]
print 'probabilities and labels:' zip(prob[top_inds], labels[top_inds])

分类图片--执行测试
#执行测试
out = net.forward()
labels = np.loadtxt(labels_filename, str, delimiter='\t')   #读取类别名称文件
prob= net.blobs['Softmax1'].data[0].flatten() #取出最后一层(Softmax)属于某个类别的概率值,并打印
print prob
order=prob.argsort()[0]  #将概率值排序,取出最大值所在的序号 
print 'the class is:',labels[order]   #将该序号转换成对应的类别名称,并打印
# 取出前五个较大值所在的序号
top_inds = prob.argsort()[::-1][:5]
print 'probabilities and labels:' zip(prob[top_inds], labels[top_inds])

分类图片--各层信息显示
# params显示:layer名,w,b
for layer_name, param in net.params.items():
    print layer_name + '\t' + str(param[0].data.shape), str(param[1].data.shape)
# blob显示:layer名,输出的blob维度
for layer_name, blob in net.blobs.items():
    print layer_name + '\t' + str(blob.data.shape)

自定义函数:参数/卷积结果可视化:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import caffe
%matplotlib inline
plt.rcParams['figure.figsize'] = (8, 8)
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
def show_data(data, padsize=1, padval=0):
"""Take an array of shape (n, height, width) or (n, height, width, 3)
       and visualize each (height, width) thing in a grid of size approx. sqrt(n) by sqrt(n)"""
    # data归一化
    data -= data.min()
    data /= data.max()

    # 根据data中图片数量data.shape[0],计算最后输出时每行每列图片数n
    n = int(np.ceil(np.sqrt(data.shape[0])))
    # padding = ((图片个数维度的padding),(图片高的padding), (图片宽的padding), ....)
    padding = ((0, n ** 2 - data.shape[0]), (0, padsize), (0, padsize)) + ((0, 0),) * (data.ndim - 3)
    data = np.pad(data, padding, mode='constant', constant_values=(padval, padval))

    # 先将padding后的data分成n*n张图像
    data = data.reshape((n, n) + data.shape[1:]).transpose((0, 2, 1, 3) + tuple(range(4, data.ndim + 1)))
    # 再将(n, W, n, H)变换成(n*w, n*H)
    data = data.reshape((n * data.shape[1], n * data.shape[3]) + data.shape[4:])
    plt.figure()
    plt.imshow(data,cmap='gray')
    plt.axis('off')
# 示例:显示第一个卷积层的输出数据和权值(filter)
print net.blobs['conv1'].data[0].shape
show_data(net.blobs['conv1'].data[0])
print net.params['conv1'][0].data.shape
show_data(net.params['conv1'][0].data.reshape(32*3,5,5))

自定义:训练过程Loss&Accuracy可视化:
import matplotlib.pyplot as plt  
import caffe   
caffe.set_device(0)  
caffe.set_mode_gpu()   
# 使用SGDSolver,即随机梯度下降算法  
solver = caffe.SGDSolver('/home/xxx/mnist/solver.prototxt')  

# 等价于solver文件中的max_iter,即最大解算次数  
niter = 10000 
# 每隔100次收集一次loss数据  
display= 100  

# 每次测试进行100次解算 
test_iter = 100
# 每500次训练进行一次测试
test_interval =500

#初始化 
train_loss = zeros(ceil(niter * 1.0 / display))   
test_loss = zeros(ceil(niter * 1.0 / test_interval))  
test_acc = zeros(ceil(niter * 1.0 / test_interval))  

# 辅助变量  
_train_loss = 0; _test_loss = 0; _accuracy = 0  
# 进行解算  
for it in range(niter):  
    # 进行一次解算  
    solver.step(1)  
    # 统计train loss  
    _train_loss += solver.net.blobs['SoftmaxWithLoss1'].data  
    if it % display == 0:  
        # 计算平均train loss  
        train_loss[it // display] = _train_loss / display  
        _train_loss = 0  

    if it % test_interval == 0:  
        for test_it in range(test_iter):  
            # 进行一次测试  
            solver.test_nets[0].forward()  
            # 计算test loss  
            _test_loss += solver.test_nets[0].blobs['SoftmaxWithLoss1'].data  
            # 计算test accuracy  
            _accuracy += solver.test_nets[0].blobs['Accuracy1'].data  
        # 计算平均test loss  
        test_loss[it / test_interval] = _test_loss / test_iter  
        # 计算平均test accuracy  
        test_acc[it / test_interval] = _accuracy / test_iter  
        _test_loss = 0  
        _accuracy = 0  

# 绘制train loss、test loss和accuracy曲线  
print '\nplot the train loss and test accuracy\n'  
_, ax1 = plt.subplots()  
ax2 = ax1.twinx()  

# train loss -> 绿色  
ax1.plot(display * arange(len(train_loss)), train_loss, 'g')  
# test loss -> 黄色  
ax1.plot(test_interval * arange(len(test_loss)), test_loss, 'y')  
# test accuracy -> 红色  
ax2.plot(test_interval * arange(len(test_acc)), test_acc, 'r')  

ax1.set_xlabel('iteration')  
ax1.set_ylabel('loss')  
ax2.set_ylabel('accuracy')  
plt.show()


####################caffe之python接口其他用法:########################

def parse_args():
    ...
    ...
if __name__ == '__main__':
    ...
    ...

caffe_root = '/home/bnu/caffe/' 
sys.path.insert(0, caffe_root + 'python')
os.chdir(caffe_root)
caffe_root='/home/jiaxuan2/caffe-master/'   //caffe路径
//下面这三句话也是必须的,把python路径改到指定的地方
sys.path.insert(0,caffe_root+'python')
import caffe
os.chdir(caffe_root)
import sys
sys.path.append('/home/xxx/caffe/python')#手动添加路径
import caffe
import numpy as np
from skimage import io
import matplotlib.pyplot as plt
#设置求解器,和 C++/caffe 一样,需要一个 solver 配置文件。
In [2]:
# set the solver prototxt
caffe.set_device(0)
caffe.set_mode_gpu()
solver = caffe.SGDSolver('examples/cifar10/cifar10_quick_solver.prototxt')
如果不需要绘制曲线,只需要训练出一个 caffemodel,直接调用 solver.solve() 就可以了。如果要绘制曲线,就需要把迭代过程中的值保存下来,因此不能直接调用 solver.solve(), 需要迭代。在迭代过程中,每迭代200次测试一次

{
   'synset_id': l.strip().split(' ')[0], 
#split分隔后是一个列表,[0]表示取其第一个元素
#l为字符串,strip()为空,即删除删除空白符(包括'\n', '\r', '\t',  ' ')
#split(' ')即以空格为分隔符,分割字符串
   'name': ' '.join(l.strip().split(' ')[1:]).split(',')[0]
# ':'.join(seq1):连接字符串数组seq1中的元素。将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串
#os.path.join(): 将多个路径组合后返回,如os.path.join('/hello/','good/boy/','doiido') 
}

./resize_and_crop_images.py --num_clients=8 --image_lib=opencv --input=/home/user/Datasets/ImageNet/ILSVRC2010/ILSVRC2010_images.txt --input_folder=/home/user/Datasets/ImageNet/ILSVRC2010/ILSVRC2010_images_train/ --output_folder=/home/user/Datasets/ImageNet/ILSVRC2010/ILSVRC2010_images_train_resized/

with open(readme_filename) as f:
        lines = [line.strip() for line in f.readlines()]
readme_filename = os.path.join(dirname, 'readme.md')
if not os.path.exists(val):.....

img=caffe.io.load_image(caffe_root+'examples/images/cat.jpg')##skimage 这个库,caffe用于读取图像的函数caffe.io.load_image也是用的这个,具体可以在python/caffe/io.py中查看。之后我们也用这个库进行图像的保存。
//读我们需要分类的照片,那只小猫咪,下面几步是为了显示图片,caffe读完做了归一化,所以数值为0-1,要把它换位0-255
img=img[...,::-1]//将列表img倒序处理,如果img=[123],则img[::-1]=[321]。前两个冒号表示处理整个列表。
im=img*255
cv2.imwrite("./out1.jpg",im)//用poencv存放图片,前面是存放路径,后面是图片
net.blobs['data'].data[...]=transformer.preprocess('data',img)

数据格式处理:
im_input=im[np.newaxis,:,:,:].transpose(0,3,1,2)
print "data-blobs:",im_input.shape
#print "datashape:",net.blobs['data'].data.shape
net.blobs['data'].reshape(*im_input.shape)
net.blobs['data'].data[...] = im_input
图片的输入规格和caffe的blob规格并不相同。图片的维度为(360,480,3),而blob的4维数组要求通道数在前,因此需要改变顺序,并且由于仅有一张图片,需要增加一维代表图片序号,该维值为0即可。因此im_input=im[np.newaxis,:,:,:].transpose(0,3,1,2)先增加了一个维度,后改变了维的顺序,使其与输入要求相同。之后改变blobs数据层的维度,使之与图像大小相同

Image.fromarray((255 * image).astype('uint8'))
np.asarry(Image.open("图像").astype('np.float32')
Image.fromarray(img.astype(np.uint8)).show()
print("Predicted class is #{}.".format(out['prob'][0].argmax())) 
labels=np.loadtxt(imagenet_labels_filename,str,delimiter='\t')
argsort是从低到高排序,-1到-6表示反过来的1-5个的意思。[-1:-6:-1],最后一个-1表示倒序处理的意思。
top_k=net.blobs['prob'].data[0].flatten().argsort()[-1:-6:-1]




caffe.set_mode_gpu()
caffe.set_mode_cpu()

net = caffe.Classifier(
            model_def_file, pretrained_model_file,
            image_dims=(image_dim, image_dim), raw_scale=raw_scale,
            mean=np.load(mean_file).mean(1).mean(1), channel_swap=(2, 1, 0)
net = caffe.Net(MODEL_FILE, PRETRAINED_FILE, caffe.TEST)
out = net.forward_all(data=caffe_in)
net = caffe.Classifier(caffe_root + 'models/bvlc_reference_caffenet/deploy.prototxt',  
        caffe_root + 'models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel',image_dims=(256, 256))  
net.set_phase_test()  
net.set_mode_cpu()  
net.set_mean('data', np.load(caffe_root + 'python/caffe/imagenet/ilsvrc_2012_mean.npy'))  
net.set_raw_scale('data', 255)  
net.set_channel_swap('data', (2,1, 0))  
scores = net.predict([caffe.io.load_image(caffe_root + "building.jpg"), caffe.io.load_image(caffe_root + "thumb.jpg")]) 

Python下通过操作Layer结构的例子:
net = caffe.Net('deploy.prototxt', '*.caffemodel',caffe.TEST) # 打开网络 
 conv1_W = net.params['conv1'][0].data # net中的params保存各层的参数,conv1权重值 
 conv1_b = net.params['conv1'][1].data # net中的params保存各层的参数,conv1偏置值 

Python下通过操作Net结构的例子:
net = caffe.Net('deploy.prototxt', '*.caffemodel',caffe.TEST) # 打开网络 
 # 通过构造训练器得到网络 
 solver = caffe.SGDSolver('solver.prototxt') # 调用训练器 
 train_net = solver.net # 训练网络 
 test_net = solver.test_nets[0] # 测试网络 

1.通过训练超参数文件进行网络训练:
 solver = caffe.SGDSolver('solver.prototxt') # 调用训练器 
 solver.solve() # 直接训练模型

2.通过网络权重参数及网络结构配置文件调用网络:
net = caffe.Net('deploy.prototxt', '*.caffemodel',caffe.TEST) 

3.通过训练超参数文件及网络权重参数文件进行权重预设的网络训练:
 solver = caffe.SGDSolver('solver.prototxt') # 调用训练器 
 solver.net.copy_from(caffemodel) # 预设权重 
 solver.solve() # 直接训练模型 
 train_net = solver.net # 训练网络 
 test_net = solver.test_nets[0] # 测试网络


########caffe:通过三个文件完成LeNet5网络的训练及测试任务########
Tips:可以将一些常用的网络结构打包成基础体,比如在model_lib.py文件中将VGG网络、AlexNet等常用网络打包成基础网络。另外训练、测试及实施的三个网络的中间结构是一致的,只是输入层和最终输出层是不一样的,因此将可以中间相同层都用一个固定函数生成。
对于一些非常复杂的网络,很多情况下可能有成百上千的层。这样的情况下,我们能难人工一层接一层的编写prototxt文件,而且还很容易出错,因此可以通过python来直接自动生成结构文件。

在caffe目录下的example/pycaffe文件夹的caffenet.py给出了如何直接生成一个多层线性分类器的网络配置文件prototxt文件,而本节还将介绍一个直接生成mnist LeNet5网络的训练、测试及实施的三个网络配置文件prototxt。
网络训练一般是通过solver来进行的。对于caffe来说,其是通过solver文件来生成solver训练器进行网络训练及测试的,该solver文件中包含了训练及测试网络的配置文件的地址,及相关训练方法及一些训练的超参数,该文件一般不是很大,可以直接在一些solver.prototxt文件上更改。也可以通过Python结合caffe_pb2.SolverParameter()结构自动生成solver.prototxt文件
得到该文件后,进行网络的训练及测试将变得非常简单。 
在通过solver = caffe.SGDSolver(solver_proto)初始化解决器后,训练一般有两种方式,一是通过solver.solve()直接进行训练,二是通过solver.step(1)进行单步训练。当然很多情况下,我们可能需要从已经训练好的文件中重新开始训练。这种情况下,可以通过solver.net.copy_from(caffemodel)来导入已训练模型,从已知的权重连接处开始新的训练。
########caffe测试模型分类的例子########
deploy.prototxt: 网络结构配置文件
bvlc_alexnet.caffemodel: 网络权重文件
synset_words.txt: 分类名称
测试图像

加载网络:
caffe_root = '../../'
    # 网络参数(权重)文件
    caffemodel = caffe_root + 'models/bvlc_alexnet/bvlc_alexnet.caffemodel'
    # 网络实施结构配置文件
    deploy = caffe_root + 'models/bvlc_alexnet/deploy.prototxt'
    net = caffe.Net(deploy,  # 定义模型结构
                    caffemodel,  # 包含了模型的训练权值
                    caffe.TEST)  # 使用测试模式(不执行dropout)

测试图像预处理:减去均值,调整大小等
    # 加载ImageNet图像均值 (随着Caffe一起发布的)
    mu = np.load(caffe_root + 'python/caffe/imagenet/ilsvrc_2012_mean.npy')
    mu = mu.mean(1).mean(1)  # 对所有像素值取平均以此获取BGR的均值像素值

    # 图像预处理
    transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
    transformer.set_transpose('data', (2,0,1))
    transformer.set_mean('data', mu)
    transformer.set_raw_scale('data', 255)
    transformer.set_channel_swap('data', (2,1,0))

运行网络:导入输入数据,通过forward()运行结果
    # 加载图像
    im = caffe.io.load_image(img)
    # 导入输入图像
    net.blobs['data'].data[...] = transformer.preprocess('data', im)

    start = time.clock()
    # 执行测试
    net.forward()
    end = time.clock()
    print('classification time: %f s' % (end - start))

查看分类结果:
    # 查看目标检测结果
    # 加载分类名称文件
    labels = np.loadtxt(synset_words, str, delimiter='\t')
    # 得到分类网络的最终结果
    category = net.blobs['prob'].data[0].argmax() # 最大概率的分类
    # 得到分类名称
    class_str = labels[int(category)].split(',')
    class_name = class_str[0]
    # 在图像中标记分类名称
    cv2.putText(im, class_name, (0, im.shape[0]), cv2.cv.CV_FONT_HERSHEY_SIMPLEX, 1, (55, 255, 155), 2)

########caffe可视化:########
1. net.blobs.items() 存储了预测图片的网络中各层的feature map的数据。
2. net.params.items()存储了训练结束后学习好的网络参数。
3. vis_square 函数视觉化data,主要是进行数据归一化,data转换为plt可视化的square结构。
plt.imshow(net.deprocess('data', net.blobs['data'].data[4]))
这里的4是第4个crop,图片会被crop成10227*227.
#画网络结构,默认为从左到右画,默认为部分test-net和train-net,画出所有net!
#draw_net.py封装的caffe.draw.draw_net_to_file(net, args.output_image_file, args.rankdir,phase)
./python/draw_net.py \
        ./examples/siamese/mnist_siamese.prototxt \
        ./examples/siamese/mnist_siamese.png

plt.imshow(transformer.deprocess(copy(test_net.blobs['data'].data[image_index, ...])))

f = plt.figure(figsize=(16,9))
c = ['#ff0000', '#ffff00', '#00ff00', '#00ffff', '#0000ff', 
     '#ff00ff', '#990000', '#999900', '#009900', '#009999'] 
plt.plot(feat[labels==i,0].flatten(), feat[labels==i,1].flatten(), '.', c=c[i]) 
plt.legend(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'])
plt.grid()
plt.show()



########caffe调参技巧:########
Caffe 训练时loss等于87.33的原因及解决方法:oftmax是用指数函数计算的,指数函数的值都是大于零的。因此,我们有理由相信,计算过程中出现了float溢出等异常,出现了inf,nan等异常数值导致softmax输出为零最后我们发现,当softmax之前的feature值过大时,由于softmax先求指数,会超出float数据范围,成为inf。inf与其他任何数值的和都是inf,softmax在做除法时任何正常范围的数值除以inf都会变为0。然后求loss时log一下就出现了87.3356这样的值。softmax输入的feature由两部分计算得到:一部分是输入数据,另部分是各层权重参数。解决办法: 
1、观察数据中是否有异常样本或异常label导致数据读取异常 
2、调小初始化权重,以便使softmax输入的feature尽可能变小 
3、降低学习率,这样就能减小权重参数的波动范围,从而减小权重变大的可能性。这条也是网上出现较多的方法。 
4、如果有BN(batch normalization)层,finetune时最好不要冻结BN的参数,否则数据分布不一致时很容易使输出值变的很大。




































////////caffe环境配置////////

安装caffe:
第一步:
sudo apt-get install build-essential  
sudo apt-get install vim cmake git  
安装anaconda:bash ~/Downloads/Anaconda2-4.0.0-Linux-x86_64.sh   #注意这里的名字要换成自己对应版本的sh。  
在~/.bashrc,添加export PATH="/home/username/anaconda/bin:$PATH" #最下面一行添加就行,:wq保存退出。记得对应更改自己的用户名和anaconda名字,我的后面加了一个2. 
sudo vim /etc/ld.so.conf    
#添加一行,用户名改为你自己的:  
/home/your_username/anaconda/lib   #:wq 关闭并保存文件。  
$ sudo ldconfig  

sudo apt-get install build-essential libgtk2.0-dev libjpeg-dev libtiff4-dev libjasper-dev libopenexr-dev cmake python-dev python-numpy python-tk libtbb-dev libeigen2-dev yasm libfaac-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev libx264-dev libqt4-dev libqt4-opengl-dev sphinx-common texlive-latex-extra libv4l-dev libdc1394-22-dev libavcodec-dev libavformat-dev libswscale-dev  
sudo apt-get install libatlas-base-dev                #安装atlas简单易行。  
sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libboost-all-dev libhdf5-serial-dev libgflags-dev libgoogle-glog-dev liblmdb-dev protobuf-compiler  
sudo apt-get install libgflags-dev libgoogle-glog-dev liblmdb-dev  
sudo apt-get install python-dev python-pip  

第二步:
cd ~  
git clone https://github.com/BVLC/caffe.git  
打开新的终端, 用which python和which pip确定使用的是anaconda提供的python环境,然后进入caffe_root/python, 执行下列命令
for req in $(cat requirements.txt); do pip install $req; done  #python运行需要的库。  
cp Makefile.config.example Makefile.config  
vi Makefile.config              #我个人比较喜欢gedit Makefile.config,用起来方便。
编辑:Makefile.config,
CPU_ONLY := 1        #一定需要打开
GPU用到的,注释掉就可以,如cuda部分
注释掉CUDA有关的行:  
#CUDA_DIR := /usr/local/cuda  
#CUDA_ARCH := -gencode arch=compute_20,code=sm_20 \  
#        -gencode arch=compute_20,code=sm_21 \  
#        -gencode arch=compute_30,code=sm_30 \  
#        -gencode arch=compute_35,code=sm_35 \  
#        -gencode arch=compute_50,code=sm_50 \  
#        -gencode arch=compute_50,code=compute_50  
MATLAB_DIR := /usr/local/MATLAB/R2016b 
注释掉系统python路径,换成anaconda2,注意是anaconda2,不是anaconda!!!!
去掉注释WITH_PYTHON_LAYER := 1 

make all -jX           #为了提高编译速度,这里的x设成自己的cpu核数  
make pycaffe -jX  
make matcaffe -jx                
make test -jX   
make  runtest -jX      #注意,这里也可直接运行,make runtest  




总结安装要点:
1.GPU相关环境安装
2.caffe相关依赖库安装
3.anaconda环境安装,需在makefile.config中配置好为anaconda2!注意是anaconda2,不是anaconda!!!!
4.caffe的python接口编译相关依赖库安装,通过requirment.txt
5.opencv库的编译,可以用cmake gui或者cmake命令设置编译选项如debug还是release
6.修改caffe的make配置文件,然后编译,根据出现的错误百度,最好安好pycaffe和MATLAB接口,方便以后应用



遇到问题:
1./usr/include/boost/python/detail/wrap_python.hpp:50:23: fatal error: pyconfig.h: 没有那个文件或目录
解决方法:是你把makefile.config的ananconda路径设置成了ANACONDA_HOME := $(HOME)/anaconda,而实际应该为ANACONDA_HOME := $(HOME)/anaconda2
2.usr/bin/ld: warning: libpng16.so.16, needed by /home/maxkhk/anaconda/lib/libopencv_highgui.so, not found (try using -rpath or -rpath-li
解决方法:在makefile.config加入:LINKFLAGS := -Wl,-rpath,$(HOME)/anaconda2/lib



pycharm配置pycaffe接口:
在pycharm中配置caffe,如果直接import caffe/caffe2,会报错ImportError: No module named caffe/caffe2,因为pycharm启动时未加载.bashrc中的环境变量。对比在pycharm中print sys.path和在terminal中print sys.path,会发现环境的差异!
而sys.path.insert(0, caffe_root)或sys.path.append("/home/xxx/project/caffe-master/python")这种方法,有很大的弊端,就是在pycharm中不能进行代码提示和跳转,这对于开发很难受
所以,可以在pycharm的default setting的Project Interpreter的默认选择ananconda环境下,点击右侧的more,选择anaconda,再点击右侧第四个按钮可以添加额外的caffe库到pycharm的sys中区,这种方式同下:
# 在启动文件pycharm.sh中添加如下代码
export PYTHONPATH=caffe_path/caffe/python:caffe2_path/caffe2/build:$PYTHONPATH
如:export PYTHONPATH=/home/sunlibo/softwares/caffe/python:$PYTHONPATH
种方法在pycharm中可以直接import caffe/caffe2,然后可以代码提示和跳转,十分舒服




Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐