text caffe深度学习#caffe

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了text caffe深度学习#caffe相关的知识,希望对你有一定的参考价值。

# 安装

基于Ubuntu16下的caffe安装教程

链接: https://blog.csdn.net/muzilinxi90/article/details/53673184

** 但有一处需要修改,我在make的时候遇到“找不到lhdf5”的问题。

处理方法:把/usr/lib/x86_64-linux-gnu/hdf5/serial下的所有文件复制到上两级目录下

=============================================================================
本文是第一次在Ubuntu 16.04上安装Caffe(CPU Only)的过程。主要参考了以下链接:

官方安装文档:http://caffe.berkeleyvision.org/installation.html

官方Ubuntu安装文档:http://caffe.berkeleyvision.org/install_apt.html

博客:http://www.linuxidc.com/Linux/2016-09/135034.htm

           http://www.linuxdiyf.com/linux/23093.html

1、安装依赖库
切换到root权限,依次安装:
apt-get install libprotobuf-dev 
apt-get install libleveldb-dev 
apt-get install libsnappy-dev 
apt-get install libopencv-dev 
apt-get install libhdf5-serial-dev 
apt-get install protobuf-compiler
apt-get install --no-install-recommends libboost-all-dev
CPU Only的情况下,跳过了CUDA相关的安装;
接下来是BLAS:
apt-get install libatlas-base-dev
使用默认Python来建立pycaffe接口,需要安装:
apt-get install python-dev
一些兼容性依赖库:
apt-get install libgflags-dev
apt-get install libgoogle-glog-dev 
apt-get install liblmdb-dev
2、下载Caffe源码
没有安装git的话需要先装一下git
apt-get install git
下载Caffe源码
git clone https://github.com/BVLC/caffe.git
如果需要Caffe的Python接口,切换到caffe下的python目录下,输入以下命令下载python依赖库(先安装pip):
apt-get install python-pip
for req in $(cat requirements.txt); do pip install $req; done
3、编译Caffe
到Caffe文件夹中,拷贝一份Makefile.config.example并重命名成Makefile.config,修改该配置文件:
cp Makefile.config.example Makefile.config
使用文本编辑器打开Makefile.config,因为这里没有配置GPU,所以去掉CPU_ONLY := 1前面的注释;
由于Ubuntu16.04文件结构的变化,#Whatever else you find you need goes here.处要改成下面这样:
# Whatever else you find you need goes here.
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu/hdf5/serial
设置到这里开始编译,make pycaffe,结果报错,错误和numpy相关,重新打开Makefile.config目录,又查找了一下numpy的安装目录,发现对应不上,需要重新设置,需要把原本如下的内容:
# NOTE: this is required only if you will compile the python interface.
# We need to be able to find Python.h and numpy/arrayobject.h.
PYTHON_INCLUDE := /usr/include/python2.7 \
		/usr/lib/python2.7/dist-packages/numpy/core/include
更改为:
# NOTE: this is required only if you will compile the python interface.
# We need to be able to find Python.h and numpy/arrayobject.h.
PYTHON_INCLUDE := /usr/include/python2.7 \
		/usr/local/lib/python2.7/dist-packages/numpy/core/include
之后就是编译:
make pycaffe
make all
make test
make runtest
make默认单核运算,如果想加快速度,我这里是4核,可以在每条命令后面加上-j4,如果有报错,建议最好make clean重新开始。
如果所有测试都通过,则说明安装好了。

4、测试
测试Caffe的Python接口,切换到caffe/python文件目录下,记录下来当前路径,输入以下命令:
export PYTHONPATH=/path/to/caffe/python:$PYTHONPATH
进入python环境,输入:
import caffe
如果没有报错,证明安装成功。
上面的方法,一旦关闭终端或者打开新终端则失效,如果放到配置文件中,可以永久有效果,命令操作如下:
#A.把环境变量路径放到 ~/.bashrc文件中
sudo echo export PYTHONPATH="~/caffe/python" >> ~/.bashrc
#B.使环境变量生效
source ~/.bashrc
5、结束语
配置Caffe环境还是要仔细阅读官方文档的步骤,另外配置文件的注释也很详细。装完了才发现了一个更靠谱的教程,在Caffe的Github的Wiki里面,附上链接:
https://github.com/BVLC/caffe/wiki/Ubuntu-16.04-or-15.10-Installation-Guide
下一步再入坑GPU相关的安装~
1. ADAMA  Solver may be better than 

2. Relu是最好的非线性激活函数,比sigmoid要好。

	Relu快速,简单,而且在训练过程中不会逐渐减少梯度。

3. 不要在输出层使用激活函数。

4. 在每一层中增加一个偏置,其本质是可以把直线移動到最佳拟合的位置。

5. 使用方差缩放进行初始化。variance_scaling_initializer()。这个方法比常规的高斯分布初始化的效果更好。

6. 输入数据要进行归一化。在训练时,减去数据集的均值,然后处理标准差。这样可以减少权重在每个方向上的拉伸,更好更快地学习。并且,在进行归一化之前,要合理缩放数据,神经网络在(0,1)范围内学习地更好。

7. 如果你的卷积层有64/128个滤波器,可能就有些多余了。

8. 池化是为了最大程度保持变换的不变性,本质上是为了使神经网络学习图像中一部分的整体特征。比如,max pooling可以使图像在卷积中经过位移/旋转和缩放等变换之后仍然保持特征的不变性。

调试神经网络

	如果你的网络不收敛,第一件做的事是去过拟合一个训练点。
	精度应该达到100%,或99.99%,或误差接近0.
	如果你的网络不能过拟合一个数据点,那么你的架构有问题。

	如果你的网络可以过拟合一个数据点,但大数据集时不能收敛,尝试:
	
	1.降低学习速度。
	这样可能慢点,但能够下降到最小值,之前可能是你的学习步长设置大了

	2. 提高学习率
	较大的学习率可以缩短时间,很快判断网络模型是不是可行。但结果可能不会理想,甚至会有较大的振荡。
	我们发现,对于ADAM优化器,0.001的学习率效果较好。

	3. 减少批处理的样本数
	使用样本数为1的批处理能够获取更细粒度的权重以更新反馈

	4 去掉批处理规范化
	在批处理样本数减少到1,去掉批处理规范化,可以暴露梯度消失或者梯度爆炸的问题

	可能第二代迭代的输出就已经是NAN

	5. 增加批处理的样本数
	较大样本的批处理,比如使用整个数据集,可以减少梯度更新的方差,使每轮迭代的结果更精确。但受物理内存的限制。不如3,4常用。

	6.检查损失函数
	如果使用的是较复杂的损失函数,可以先试一下L1,L2损失函数。我们发现L1对异常值没那么敏感。
	
	7. 检查可视化
	是不是你的值域有限制等

	8. 我们把每代的损失值画出来,看看到底有没有收敛。如果曲线上下抖动,很杂乱,可能是学习率设置大了。可以尝试衰减学习率,并只用一个样本点进行训练。可以发现在某个区间下降地太快,可以放缓迭代速率。发现损失还没有降到0,然后我们停止了学习率的衰减,并尝试了将数值压缩到更小的区间,并取代了tanh函数,虽然这样可以将损失降到了1,但仍然不能达到过拟合(因为我们的样本数为1)。
	然后去掉了批处理规范化,网络输出很快在1-2次迭代后变成了NAN
	因此,我们停止了批处理规范化,并使用方差标准化进行初始化。
 
在深度学习的实际应用中,我们经常用到的原始数据是图片文件,如jpg,jpeg,png,tif等格式的,而且有可能图片的大小还不一致。而在caffe中经常使用的数据类型是lmdb或leveldb,因此就产生了这样的一个问题:如何从原始图片文件转换成caffe中能够运行的db(leveldb/lmdb)文件?

在caffe中,作者为我们提供了这样一个文件:convert_imageset.cpp,存放在根目录下的tools文件夹下。编译之后,生成对应的可执行文件放在 buile/tools/ 下面,这个文件的作用就是用于将图片文件转换成caffe框架中能直接使用的db文件。

该文件的使用格式:

 convert_imageset [FLAGS] ROOTFOLDER/ LISTFILE DB_NAME

需要带四个参数:

FLAGS: 图片参数组
		-gray: 是否以灰度图的方式打开图片。程序调用opencv库中的imread()函数来打开图片,默认为false
		-shuffle: 是否随机打乱图片顺序。默认为false
		-backend:需要转换成的db文件格式,可选为leveldb或lmdb,默认为lmdb
		-resize_width/resize_height: 改变图片的大小。
			在运行中,要求所有图片的尺寸一致,因此需要改变图片大小。 
			程序调用opencv库的resize()函数来对图片放大缩小,默认为0,不改变
		-check_size: 检查所有的数据是否有相同的尺寸。默认为false,不检查
		-encoded: 是否将原图片编码放入最终的数据中,默认为false
		-encode_type: 与前一个参数对应,将图片编码为哪一个格式:‘png','jpg'......

ROOTFOLDER/: 图片存放的绝对路径,从linux系统根目录开始

LISTFILE: 图片文件列表清单,一般为一个txt文件,一行一张图片
	如下的一个train.txt文件:
	cat.jpg 1
	fish-bike.jpg 2

DB_NAME: 最终生成的db文件存放目录

Usage:

	build/tools/convert_imageset --shuffle --resize_height=256 --resize_width=256 \
		/home/feng/caffe/examples/images/ examples/images/train.txt  examples/images/img_train_lmdb

	就会在examples/images/ 目录下生成一个名为 img_train_lmdb的文件夹,里面的文件就是我们需要的db文件了。



EXTENDED(1) 

	由于参数比较多,因此我们可以编写一个sh脚本来执行命令:

	首先,创建sh脚本文件:

	# sudo vi examples/images/create_lmdb.sh
	编辑,输入下面的代码并保存

	#!/usr/bin/en sh
	DATA=examples/images
	rm -rf $DATA/img_train_lmdb
	build/tools/convert_imageset --shuffle \
	--resize_height=256 --resize_width=256 \
	/home/xxx/caffe/examples/images/ $DATA/train.txt  $DATA/img_train_lmdb
	
	设置参数-shuffle,打乱图片顺序。设置参数-resize_height和-resize_width将所有图片尺寸都变为256*256.
	
	最后,运行这个脚本文件

	# sudo sh examples/images/create_lmdb.sh


EXTENDED(2)

	本文以caffe程序中自带的图片为例,进行讲解,图片目录是  example/images/, 两张图片,一张为cat.jpg, 另一张为fish_bike.jpg,表示两个类别。

	我们创建一个sh脚本文件,调用linux命令来生成图片清单:

	# sudo vi examples/images/create_filelist.sh
	编辑这个文件,输入下面的代码并保存

	# /usr/bin/env sh
	DATA=examples/images
	echo "Create train.txt..."
	rm -rf $DATA/train.txt
	find $DATA -name *cat.jpg | cut -d '/' -f3 | sed "s/$/ 1/">>$DATA/train.txt
	find $DATA -name *bike.jpg | cut -d '/' -f3 | sed "s/$/ 2/">>$DATA/tmp.txt
	cat $DATA/tmp.txt>>$DATA/train.txt
	rm -rf $DATA/tmp.txt
	echo "Done.."

	这个脚本文件中,用到了rm,find, cut, sed,cat等linux命令。

	rm: 删除文件

	find: 寻找文件

	cut: 截取路径

	sed: 在每行的最后面加上标注。本例中将找到的*cat.jpg文件加入标注为1,找到的*bike.jpg文件加入标注为2

	cat: 将两个类别合并在一个文件里。

	最终生成如下的一个train.txt文件:

	cat.jpg 1
	fish-bike.jpg 2

	当然,图片很少的时候,手动编写这个列表清单文件就行了。但图片很多的情况,就需要用脚本文件来自动生成了。在以后的实际应用中,还需要生成相应的val.txt和test.txt文件,方法是一样的。

	生成的这个train.txt文件,就可以作为第三个参数,直接使用了。
 
data_layer 数据层

	数据通过数据层进入Caffe,数据层在整个网络的底部。
	数据可以来自高效的数据库(LevelDB 或者 LMDB),直接来自内存。
	如果不追求高效性,可以以HDF5或者一般图像的格式从硬盘读取数据。
	
	LevelDB 谷歌一高性能key/value储存库
	LMDB 与LevelDB类似,但性能更快

	一些基本的操作,
	如:mean subtraction, scaling, random cropping, and mirroring均可以直接在数据层上进行指定。
如:

layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    mirror: true
    crop_size: 227
    mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
  }
  data_param {
    source: "examples/imagenet/ilsvrc12_train_lmdb"
    batch_size: 256
    backend: LMDB
  }
}

=================================================================
1 Database
    类型:Data
    
    必须参数:
    
    source: 包含数据的目录名称
    
    batch_size: 一次处理的输入的数量
    
    可选参数:
    
    rand_skip: 在开始的时候从输入中跳过这个数值,这在异步随机梯度下降(SGD)的时候非常有用
    
    backend [default LEVELDB]: 选择使用 LEVELDB 或者 LMDB

2 In-Memory
    类型: MemoryData
    
    必需参数:
    
    batch_size, channels, height, width: 指定从内存读取数据的大小
    MemoryData层直接从内存中读取数据,而不是拷贝过来。因此,要使用它的话,你必须调用MemoryDataLayer::Reset (from C++)或者Net.set_input_arrays (from Python)以此指定一块连续的数据(通常是一个四维张量)。
    
    3 HDF5 Input
    类型: HDF5Data
    
    必要参数:
    
    source: 需要读取的文件名
    
    batch_size:一次处理的输入的数量
    
4 HDF5 Output
    类型: HDF5Output
    
    必要参数:
    
    file_name: 输出的文件名
    HDF5的作用和这节中的其他的层不一样,它是把输入的blobs写到硬盘
    
5 Images
    类型: ImageData
    
    必要参数:
    
    source: text文件的名字,每一行给出一张图片的文件名和label
    
    batch_size: 一个batch中图片的数量
    
    可选参数:
    
    rand_skip:在开始的时候从输入中跳过这个数值,这在异步随机梯度下降(SGD)的时候非常有用
    
    shuffle [default false]
    
    new_height, new_width: 把所有的图像resize到这个大小
    
6 Windows
	类型:WindowData

7 Dummy
	类型:DummyData

	Dummy 层用于development 和debugging。具体参数DummyDataParameter。
1. Caffe C++ code is locate in caffe/tools
	caffe/tools
		caffe.cpp   train,test,time,device_query(show GPU) 
					-cpu, -solver, -model,-level, -stage

			train:
					build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt


			test:
					参数用在测试阶段,用于最终结果的输出,要模型配置文件中我们可以设定需要输入accuracy还是loss. 假设我们要在验证集中验证已经训练好的模型,就可以这样写

					# ./build/tools/caffe test -model examples/mnist/lenet_train_test.prototxt -weights examples/mnist/lenet_iter_10000.caffemodel -gpu 0 -iterations 100
					这个例子比较长,不仅用到了test参数,还用到了-model, -weights, -gpu和-iteration四个参数。
					意思是利用训练好了的权重(-weight),输入到测试模型中(-model),用编号为0的gpu(-gpu)测试100次(-iteration)。

			time:
					time参数用来在屏幕上显示程序运行时间。如:

					# ./build/tools/caffe time -model examples/mnist/lenet_train_test.prototxt -iterations 10
					这个例子用来在屏幕上显示lenet模型迭代10次所使用的时间。包括每次迭代的forward和backward所用的时间,也包括每层forward和backward所用的平均时间。

					# ./build/tools/caffe time -model examples/mnist/lenet_train_test.prototxt -gpu 0
					这个例子用来在屏幕上显示lenet模型用gpu迭代50次所使用的时间。

					# ./build/tools/caffe time -model examples/mnist/lenet_train_test.prototxt -weights examples/mnist/lenet_iter_10000.caffemodel -gpu 0 -iterations 10
					利用给定的权重,利用第一块gpu,迭代10次lenet模型所用的时间。

			device_query:
					device_query参数用来诊断gpu信息。

					# ./build/tools/caffe device_query -gpu 0
					最后,我们来看两个关于gpu的例子

					# ./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt -gpu 0,1
					# ./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt -gpu all
					这两个例子表示: 用两块或多块GPU来平行运算,这样速度会快很多。但是如果你只有一块或没有gpu, 就不要加-gpu参数了,加了反而慢。

					最后,在linux下,本身就有一个time命令,因此可以结合进来使用,因此我们运行mnist例子的最终命令是(一块gpu):

					$ sudo time ./build/toos/caffe train -solver examples/mnist/lenet_solver.prototxt
			-solver:
					必选参数。一个protocol buffer类型的文件,即模型的配置文件。如:

					# ./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt

			-gpu:
					可选参数。该参数用来指定用哪一块gpu运行,根据gpu的id进行选择,如果设置为'-gpu all'则使用所有的gpu运行。如使用第二块gpu运行

					# ./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt -gpu 2
					
			-snapshot:
					可选参数。该参数用来从快照(snapshot)中恢复训练。可以在solver配置文件设置快照,保存solverstate。如:

					# ./build/tools/caffe train -solver examples/mnist/lenet_solver.prototxt -snapshot examples/mnist/lenet_iter_5000.solverstate

			-weights:
					可选参数。用预先训练好的权重来fine-tuning模型,需要一个caffemodel,不能和-snapshot同时使用。如:

					# ./build/tools/caffe train -solver examples/finetuning_on_flickr_style/solver.prototxt -weights models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel

			-iterations: 
					可选参数,迭代次数,默认为50。 如果在配置文件文件中没有设定迭代次数,则默认迭代50次。

			-model:
					可选参数,定义在protocol buffer文件中的模型。也可以在solver配置文件中指定。

			-sighup_effect:
					可选参数。用来设定当程序发生挂起事件时,执行的操作,可以设置为snapshot, stop或none, 默认为snapshot

			-sigint_effect: 
					可选参数。用来设定当程序发生键盘中止事件时(ctrl+c), 执行的操作,可以设置为snapshot, stop或none, 默认为stop

1. Get the Image

	download images
	scrapy web images
	
	Put them all in one folder.	

2. Create the Imagelist
	
	you will see such names: cat1.jpg cat2.jpg cat3.jpg
	
	And then, you can write a script to create train.txt, such as

	I write a create_imagelist.sh to create lists easily.
	
	You can put the script at the same directory of the images.
	=============================================================
	1 # /usr/bin/env sh
  	2 DATA=$(cd `dirname $0`; pwd)
  	3 
  	4 rm -rf ./train.txt
  	5 
  	6 echo "Create train.txt..."
  	7 
  	8 touch train.txt
  	9 
 	10 find . -name 'cat*' | cut -d '/' -f2  | sed  's/$/& 1/' > trai
 	11 find . -name 'fish*' | cut -d '/' -f2 | sed  's/$/& 2/' >> tra
 	12 echo "Done.."
	============================================================		
	And you can run  sh create_imagelist.sh, you will get a train.txt at the present directory.
	
3. Convert Image data to Imdb
	
 	build/tools/convert_imageset \
		--shuffle \
		--resize_height=256 \
		--resize_width=256 \
		/home/xxx/caffe/data/re/ \
		$MY/train.txt \
		$MY/img_train_lmdb
 
4. Compute_Image_mean
	计算均值并保存,	图片减去均值再训练,会提高训练速度和精度。因此,一般都会有这个操作。

	sudo build/tools/compute_image_mean examples/myfile/img_train_lmdb examples/myfile/mean.binaryproto

	compute_image_mean带两个参数,第一个参数是lmdb训练数据位置,第二个参数设定均值文件的名字及保存路径。
	运行成功后,会在 examples/myfile/ 下面生成一个mean.binaryproto的均值文件。

5. Edit Model Net  Configures 

	(1) Copy the default config
	模型就用程序自带的caffenet模型,位置在 models/bvlc_reference_caffenet/文件夹下, 
	将需要的两个配置文件,复制到myfile文件夹内	
	
	sudo cp models/bvlc_reference_caffenet/train_val.prototxt examples/myfile/

	(2) Modify config

6. Edit Solver Configure
		
	sudo cp models/bvlc_reference_caffenet/solver.prototxt examples/myfile/

	net: "examples/myfile/train_val.prototxt"    
	test_iter: 2
	test_interval: 50
	base_lr: 0.001
	lr_policy: "step"
	gamma: 0.1
	stepsize: 100
	display: 20    // 每训练20次,在屏幕上显示一次。如果设置为0,则不显示。
	max_iter: 500
	momentum: 0.9
	weight_decay: 0.005
	solver_mode: GPU

	Reference:
	
	net: 设置深度网络模型。每一个模型就是一个net,需要在一个专门的配置文件中对net进行配置,每个net由许多的layer所组成。	
		注意的是:文件的路径要从caffe的根目录开始,其它的所有配置都是这样。
	
	test_iter: 这个要与test layer中的batch_size结合起来理解。mnist数据中测试样本总数为10000,一次性执行全部数据效率很低,
		因此我们将测试数据分成几个批次来执行,每个批次的数量就是batch_size。假设我们设置batch_size为100,
		则需要迭代100次才能将10000个数据全部执行完。因此test_iter设置为100。执行完一次全部数据,称之为一个epoch

	test_interval: 测试间隔。也就是每训练500次,才进行一次测试。

	base_lr: 0.01
	lr_policy: "inv"
	gamma: 0.0001
	power: 0.75
			这四行可以放在一起理解,用于学习率的设置。只要是梯度下降法来求解优化,都会有一个学习率,也叫步长。
	base_lr: 用于设置基础学习率,在迭代的过程中,可以对基础学习率进行调整。
	lr_policy: 怎么样进行调整,就是调整的策略,由lr_policy来设置。
			lr_policy可以设置为下面这些值,相应的学习率的计算为:

			- fixed:   保持base_lr不变.
			- step:    如果设置为step,则还需要设置一个stepsize,  返回 base_lr * gamma ^ (floor(iter / stepsize)),其中iter表示当前的迭代次数
			- exp:     返回base_lr * gamma ^ iter, iter为当前迭代次数
			- inv:      如果设置为inv,还需要设置一个power, 返回base_lr * (1 + gamma * iter) ^ (- power)
			- multistep: 如果设置为multistep,则还需要设置一个stepvalue。这个参数和step很相似,step是均匀等间隔变化,而multistep则是根据                                 stepvalue值变化
					for example:
					base_lr: 0.01
					momentum: 0.9
					weight_decay: 0.0005
					lr_policy: "multistep"
					gamma: 0.9
					stepvalue: 5000
					stepvalue: 7000
					stepvalue: 8000
					stepvalue: 9000
					stepvalue: 9500				
			- poly:     学习率进行多项式误差, 返回 base_lr (1 - iter/max_iter) ^ (power)
			- sigmoid: 学习率进行sigmod衰减,返回 base_lr ( 1/(1 + exp(-gamma * (iter - stepsize))))

	momentum: 上一次梯度更新的权重
	 
	display: 100 每训练100次,在屏幕上显示一次。如果设置为0,则不显示。

	max_iter: 20000
				最大迭代次数。这个数设置太小,会导致没有收敛,精确度很低。设置太大,会导致震荡,浪费时间。

	snapshot: 5000
	snapshot_prefix: "examples/mnist/lenet"
				快照。将训练出来的model和solver状态进行保存,snapshot用于设置训练多少次后进行保存,默认为0,不保存。
				snapshot_prefix设置保存路径。

	还可以设置snapshot_diff,是否保存梯度值,默认为false,不保存。

	也可以设置snapshot_format,保存的类型。有两种选择:HDF5 和BINARYPROTO ,默认为BINARYPROTO

	solver_mode: CPU
			设置运行模式。默认为GPU,如果你没有GPU,则需要改成CPU,否则会出错。


以上是关于text caffe深度学习#caffe的主要内容,如果未能解决你的问题,请参考以下文章

深度学习—caffe框架训练文档

Caffe 深度学习框架介绍

Caffe深度学习计算框架

Caffe 深度学习框架上手教程

贾扬清:希望Caffe成为深度学习领域的Hadoop

开源深度学习架构Caffe