食品网站首页模板欣赏,石家庄手机建网站,网站开发服务器多少钱,云南建设厅网站工程师苏的专栏 致力于学习计算机视觉、模式识别、机器学习、深度学习相关技术#xff1a;#xff1a;#xff1a;#xff1a;希望结识更多同道中人。 QQ#xff1a;2816568984 微信#xff1a;Suc1011 目录视图 摘要视图 订阅 【活动】2017 CSDN博客专栏评选 【评论送书】… 苏的专栏 致力于学习计算机视觉、模式识别、机器学习、深度学习相关技术希望结识更多同道中人。 QQ2816568984 微信Suc1011 目录视图 摘要视图 订阅 【活动】2017 CSDN博客专栏评选 【评论送书】SQL优化、深度学习、数据科学家 CSDN日报20170524 ——《2017 软件精英挑战赛总结》 Python创意编程活动结果公布 Caffe训练源码基本流程 标签 BloblayerNetSolvercaffe 2016-11-16 14:58 1362人阅读 评论(1) 收藏 举报 本文章已收录于 人工智能开发框架知识库 分类 深度学习22 作者同类文章X 目录(?)[] Caffe简介训练LeNet网络初始化训练过程 loss net_-ForwardBackwardUpdateSmoothedLossApplyUpdate Caffe简介 一般在介绍Caffe代码结构的时候大家都会说Caffe主要由Blob Layer Net 和 Solver这几个部分组成。 Blob 主要用来表示网络中的数据包括训练数据网络各层自身的参数(包括权值、偏置以及它们的梯度)网络之间传递的数据都是通过 Blob 来实现的同时 Blob 数据也支持在 CPU 与 GPU 上存储能够在两者之间做同步。 Layer 是对神经网络中各种层的一个抽象包括我们熟知的卷积层和下采样层还有全连接层和各种激活函数层等等。同时每种 Layer 都实现了前向传播和反向传播并通过 Blob 来传递数据。 Net 是对整个网络的表示由各种 Layer 前后连接组合而成也是我们所构建的网络模型。 Solver 定义了针对 Net 网络模型的求解方法记录网络的训练过程保存网络模型参数中断并恢复网络的训练过程。自定义 Solver 能够实现不同的网络求解方式。 不过在刚开始准备阅读Caffe代码的时候就算知道了代码是由上面四部分组成还是感觉会无从下手下面我们准备通过一个Caffe训练LeNet的实例并结合代码来解释Caffe是如何初始化网络然后正向传播、反向传播开始训练最终得到训练好的模型这一过程。 训练LeNet 在Caffe提供的例子里训练LeNet网络的命令为 cd $CAFFE_ROOT
./build/tools/caffe train --solverexamples/mnist/lenet_solver.prototxt1212 其中第一个参数build/tools/caffe是Caffe框架的主要框架由tools/caffe.cpp文件编译而来第二个参数train表示是要训练网络第三个参数是 solver的protobuf描述文件。在Caffe中网络模型的描述及其求解都是通过 protobuf 定义的并不需要通过敲代码来实现。同时模型的参数也是通过 protobuf 实现加载和存储包括 CPU 与 GPU 之间的无缝切换都是通过配置来实现的不需要通过硬编码的方式实现有关 protobuf的具体内容可参考这篇博文http://alanse7en.github.io/caffedai-ma-jie-xi-2/。 网络初始化 下面我们从caffe.cpp的main函数入口开始观察Caffe是怎么一步一步训练网络的。在caffe.cpp中main函数之外通过RegisterBrewFunction这个宏在每一个实现主要功能的函数之后将这个函数的名字和其对应的函数指针添加到了g_brew_map中,具体分别为train()test()device_query()time()这四个函数。 在运行的时候,根据传入的参数在main函数中通过GetBrewFunction得到了我们需要调用的那个函数的函数指针并完成了调用。 // caffe.cpp
return GetBrewFunction(caffe::string(argv[1])) ();1212 在我们上面所说的训练LeNet的例子中传入的第二个参数为train所以调用的函数为caffe.cpp中的int train()函数接下来主要看这个函数的内容。在train函数中有下面两行代码下面的代码定义了一个指向Solver的shared_ptr。其中主要是通过调用SolverRegistry这个类的静态成员函数CreateSolver得到一个指向Solver的指针来构造shared_ptr类型的solver。而且由于C多态的特性尽管solver是一个指向基类Solver类型的指针通过solver这个智能指针来调用各个成员函数会调用到各个子类(SGDSolver等)的函数。 // caffe.cpp
// 其中输入参数solver_param就是上面所说的第三个参数网络的模型及求解文件
shared_ptrcaffe::Solverfloat solver(caffe::SolverRegistryfloat::CreateSolver(solver_param);12341234 因为在caffe.proto文件中默认的优化type为SGD,所以上面的代码会实例化一个SGDSolver的对象’SGDSolver’类继承于Solver类在新建SGDSolver对象时会调用其构造函数如下所示 //sgd_solvers.hpp
explicit SGDSolver(const SolverParameter param): SolverDtype(param) { PreSolve(); }123123 从上面代码可以看出会先调用父类Solver的构造函数如下所示。Solver类的构造函数通过Init(param)函数来初始化网络。 //solver.cpp
template typename Dtype
SolverDtype::Solver(const SolverParameter param, const Solver* root_solver): net_(), callbacks_(), root_solver_(root_solver),requested_early_exit_(false)
{Init(param);
}12345671234567 而在Init(paran)函数中又主要是通过InitTrainNet()和InitTestNets()函数分别来搭建训练网络结构和测试网络结构。 训练网络只能有一个,在InitTrainNet()函数中首先会设置一些基本参数包括设置网络的状态为TRAIN确定训练网络只有一个等然会会通过下面这条语句新建了一个Net对象。InitTestNets()函数和InitTrainNet()函数基本类似不再赘述。 //solver.cpp
net_.reset(new NetDtype(net_param));1212 上面语句新建了Net对象之后会调用Net类的构造函数如下所示。可以看出构造函数是通过Init(param)函数来初始化网络结构的。 //net.cpp
template typename Dtype
NetDtype::Net(const NetParameter param, const Net* root_net): root_net_(root_net) {Init(param);
}123456123456 下面是net.cpp文件里Init()函数的主要内容(忽略具体细节)其中LayerRegistry::CreateLayer(layer_param)主要是通过调用LayerRegistry这个类的静态成员函数CreateLayer得到一个指向Layer类的shared_ptr类型指针。并把每一层的指针存放在vector //net.cpp Init()
for (int layer_id 0; layer_id param.layer_size(); layer_id) {//param是网络参数layer_size()返回网络拥有的层数const LayerParameter layer_param param.layer(layer_id);//获取当前layer的参数layers_.push_back(LayerRegistryDtype::CreateLayer(layer_param));//根据参数实例化layer//下面的两个for循环将此layer的bottom blob的指针和top blob的指针放入bottom_vecs_和top_vecs_,bottom blob和top blob的实例全都存放在blobs_中。相邻的两层前一层的top blob是后一层的bottom blob所以blobs_的同一个blob既可能是bottom blob也可能使top blob。for (int bottom_id 0; bottom_id layer_param.bottom_size();bottom_id) {const int blob_idAppendBottom(param,layer_id,bottom_id,available_blobs,blob_name_to_idx);}for (int top_id 0; top_id num_top; top_id) {AppendTop(param, layer_id, top_id, available_blobs, blob_name_to_idx);}// 调用layer类的Setup函数进行初始化输入参数每个layer的输入blobs以及输出blobs,为每个blob设置大小
layers_[layer_id]-SetUp(bottom_vecs_[layer_id], top_vecs_[layer_id]);//接下来的工作是将每层的parameter的指针塞进params_尤其是learnable_params_。const int num_param_blobs layers_[layer_id]-blobs().size();for (int param_id 0; param_id num_param_blobs; param_id) {AppendParam(param, layer_id, param_id);//AppendParam负责具体的dirtywork}}123456789101112131415161718192021222324252627123456789101112131415161718192021222324252627 经过上面的过程Net类的初始化工作基本就完成了接着我们具体来看看上面所说的layers_[layer_id]-SetUp对每一具体的层结构进行设置我们来看看Layer类的Setup()函数对每一层的设置主要由下面三个函数组成 LayerSetUp(bottom, top)由Layer类派生出的特定类都需要重写这个函数主要功能是设置权值参数(包括偏置)的空间以及对权值参数经行随机初始化。 Reshape(bottom, top)根据输出blob和权值参数计算输出blob的维数并申请空间。 //layer.hpp
// layer 初始化设置
void SetUp(const vectorBlobDtype* bottom, const vectorBlobDtype* top) {InitMutex();CheckBlobCounts(bottom, top);LayerSetUp(bottom, top);Reshape(bottom, top);SetLossWeights(top);
}1234567891012345678910 经过上述过程基本上就完成了初始化的工作总体的流程大概就是新建一个Solver对象然后调用Solver类的构造函数然后在Solver的构造函数中又会新建Net类实例在Net类的构造函数中又会新建各个Layer的实例,一直具体到设置每个Blob,大概就介绍完了网络初始化的工作当然里面还有很多具体的细节但大概的流程就是这样。 训练过程 上面介绍了网络初始化的大概流程如上面所说的网络的初始化就是从下面一行代码新建一个solver指针开始一步一步的调用SolverNet,Layer,Blob类的构造函数完成整个网络的初始化。 //caffe.cpp
shared_ptrcaffe::Solverfloat //初始化solver(caffe::SolverRegistryfloat::CreateSolver(solver_param));123123 完成初始化之后就可以开始对网络经行训练了开始训练的代码如下所示指向Solver类的指针solver开始调用Solver类的成员函数Solve()名称比较绕啊。 // 开始优化
solver-Solve();1212 接下来我们来看看Solver类的成员函数Solve(),Solve函数其实主要就是调用了Solver的另一个成员函数Step来完成实际的迭代训练过程。 //solver.cpp
template typename Dtype
void SolverDtype::Solve(const char* resume_file) {...int start_iter iter_;...// 然后调用了Step函数这个函数执行了实际的逐步的迭代过程Step(param_.max_iter() - iter_);...LOG(INFO) Optimization Done.;
}12345678910111234567891011 顺着来看看这个Step()函数的主要代码,首先是一个大循环设置了总的迭代次数在每次迭代中训练iter_size x batch_size个样本这个设置是为了在GPU的显存不够的时候使用比如我本来想把batch_size设置为128iter_size是默认为1的但是会out_of_memory借助这个方法可以设置batch_size32iter_size4那实际上每次迭代还是处理了128个数据。 //solver.cpp
template typename Dtype
void SolverDtype::Step(int iters) {...//迭代while (iter_ stop_iter) {...// iter_size也是在solver.prototxt里设置实际上的batch_sizeiter_size*网络定义里的batch_size// 因此每一次迭代的loss是iter_size次迭代的和再除以iter_size这个loss是通过调用Net::ForwardBackward函数得到的// accumulate gradients over iter_size x batch_size instancesfor (int i 0; i param_.iter_size(); i) {/** 调用了Net中的代码主要完成了前向后向的计算* 前向用于计算模型的最终输出和Loss后向用于* 计算每一层网络和参数的梯度。*/loss net_-ForwardBackward();}.../** 这个函数主要做Loss的平滑。由于Caffe的训练方式是SGD我们无法把所有的数据同时* 放入模型进行训练那么部分数据产生的Loss就可能会和全样本的平均Loss不同在必要* 时候将Loss和历史过程中更新的Loss求平均就可以减少Loss的震荡问题。*/UpdateSmoothedLoss(loss, start_iter, average_loss);...// 执行梯度的更新这个函数在基类Solver中没有实现会调用每个子类自己的实现//后面具体分析SGDSolver的实现ApplyUpdate();// 迭代次数加1iter_;...}
}1234567891011121314151617181920212223242526272829303132333435363738394012345678910111213141516171819202122232425262728293031323334353637383940 上面Step()函数主要分为三部分 loss net_-ForwardBackward(); 这行代码通过Net类的net_指针调用其成员函数ForwardBackward()其代码如下所示,分别调用了成员函数Forward(loss)和成员函数Backward()来进行前向传播和反向传播。 // net.hpp
// 进行一次正向传播一次反向传播
Dtype ForwardBackward() {Dtype loss;Forward(loss);Backward();return loss;
}1234567812345678 前面的Forward(loss)函数最终会执行到下面一段代码,Net类的Forward()函数会对网络中的每一层执行Layer类的成员函数Forward()而具体的每一层Layer的派生类会重写Forward()函数来实现不同层的前向计算功能。上面的Backward()反向求导函数也和Forward()类似调用不同层的Backward()函数来计算每层的梯度。 //net.cpp
for (int i start; i end; i) {
// 对每一层进行前向计算返回每层的loss其实只有最后一层loss不为0Dtype layer_loss layers_[i]-Forward(bottom_vecs_[i], top_vecs_[i]);loss layer_loss;if (debug_info_) { ForwardDebugInfo(i); }
}12345671234567 UpdateSmoothedLoss(); 这个函数主要做Loss的平滑。由于Caffe的训练方式是SGD我们无法把所有的数据同时放入模型进行训练那么部分数据产生的Loss就可能会和全样本的平均Loss不同在必要时候将Loss和历史过程中更新的Loss求平均就可以减少Loss的震荡问题 ApplyUpdate(); 这个函数是Solver类的纯虚函数需要派生类来实现比如SGDSolver类实现的ApplyUpdate();函数如下主要内容包括设置参数的学习率对梯度进行Normalize对反向求导得到的梯度添加正则项的梯度最后根据SGD算法计算最终的梯度最后的最后把计算得到的最终梯度对权值进行更新。 template typename Dtype
void SGDSolverDtype::ApplyUpdate() {CHECK(Caffe::root_solver());// GetLearningRate根据设置的lr_policy来计算当前迭代的learning rate的值Dtype rate GetLearningRate();// 判断是否需要输出当前的learning rateif (this-param_.display() this-iter_ % this-param_.display() 0) {LOG(INFO) Iteration this-iter_ , lr rate;}// 避免梯度爆炸如果梯度的二范数超过了某个数值则进行scale操作将梯度减小ClipGradients();// 对所有可更新的网络参数进行操作for (int param_id 0; param_id this-net_-learnable_params().size();param_id) {// 将第param_id个参数的梯度除以iter_size// 这一步的作用是保证实际的batch_sizeiter_size*设置的batch_sizeNormalize(param_id);// 将正则化部分的梯度降入到每个参数的梯度中Regularize(param_id);// 计算SGD算法的梯度(momentum等)ComputeUpdateValue(param_id, rate);}// 调用Net::Update更新所有的参数this-net_-Update();
}1234567891011121314151617181920212223242526272829303112345678910111213141516171819202122232425262728293031 等进行了所有的循环网络的训练也算是完成了。上面大概说了下使用Caffe进行网络训练时网络初始化以及前向传播、反向传播、梯度更新的过程其中省略了大量的细节。上面还有很多东西都没提到比如说Caffe中Layer派生类的注册及各个具体层前向反向的实现、Solver派生类的注册、网络结构的读取、模型的保存等等大量内容。 转自http://buptldy.github.io/2016/10/09/2016-10-09-Caffe_Code/ 顶 0 踩 0 上一篇caffe源码 之 Blob类 下一篇caffe源码 之 数据层 相关文章推荐 • win版本caffe源码libcaffe研究 • 机器学习(Machine Learning)深度学习(Deep Learning)资料集合 • 码农周刊分类整理 • 机器学习(Machine Learning)深度学习(Deep Learning)资料(Chapter 1) • 【机器学习Machine Learning】资料大全 • 机器学习深度学习 • 机器学习(Machine Learning)深度学习(Deep Learning)资料(Chapter 1) • 机器学习(Machine Learning)深度学习(Deep Learning)资料 • 深度学习如何入门 • 深度学习和机器学习的相关资料 参考知识库 人工智能规划与决策知识库 649关注|8收录 软件测试知识库 4746关注|318收录 算法与数据结构知识库 16414关注|2320收录 更多资料请参考 猜你在找 Android核心技术——Android数据存储Android之数据存储Android中的数据存储360度解析亚马逊AWS数据存储服务iOS开发高级专题—数据存储顾荣开源大数据存储系统Alluxio原Tachyon的原理分析与案例简介云端存储的基本技巧和上云实践——清宵教你玩转云存储一数据上云的基本实践Ceph—分布式存储系统的另一个选择Windows Server 2012 R2 存储和文件服务管理Windows Server 2012 存储和文件管理 Android核心技术——Android数据存储Android之数据存储Android中的数据存储360度解析亚马逊AWS数据存储服务iOS开发高级专题—数据存储 顾荣开源大数据存储系统Alluxio原Tachyon的原理分析与案例简介云端存储的基本技巧和上云实践——清宵教你玩转云存储一数据上云的基本实践Ceph—分布式存储系统的另一个选择Windows Server 2012 R2 存储和文件服务管理Windows Server 2012 存储和文件管理 关闭 查看评论 1楼 李木木乃伊 2017-03-21 18:24发表 [回复] [引用] [举报]讲的好透彻赞一个 您还没有登录,请[登录]或[注册] * 以上用户言论只代表其个人观点不代表CSDN网站的观点或立场 核心技术类目 全部主题HadoopAWS移动游戏JavaAndroidiOSSwift智能硬件DockerOpenStackVPNSparkERPIE10EclipseCRMJavaScript数据库UbuntuNFCWAPjQueryBIHTML5SpringApache.NETAPIHTMLSDKIISFedoraXMLLBSUnitySplashtopUMLcomponentsWindows MobileRailsQEMUKDECassandraCloudStackFTCcoremailOPhone CouchBase云计算iOS6Rackspace Web AppSpringSideMaemoCompuware大数据aptechPerlTornadoRubyHibernateThinkPHPHBasePureSolrAngularCloud FoundryRedisScalaDjangoBootstrap 个人资料 _苏_ 访问62214次 积分1210 等级 积分1210 排名千里之外 原创57篇 转载5篇 译文0篇 评论79条 文章搜索 文章分类 C语言学习(3) Linux学习(12) 数学算法(1) 图像处理(2) 模式识别(3) 机器学习(12) 其他(3) 深度学习(23) Python语言学习(3) 文章存档 2017年01月(7)2016年12月(8)2016年11月(14)2016年10月(8)2016年09月(7)2016年08月(3)2016年07月(6)2016年06月(1)2015年11月(2)2015年02月(1)2015年01月(4) 展开 阅读排行 caffe生成lenet-5的deploy.prototxt文件(6485)用caffe训练好的lenet_iter_10000.caffemodel测试单张mnist图片(5571)Caffe编译 Mnist训练测试(4094)用caffe训练测试自己的图片(3906)adaboost训练 之 弱分类器训练原理(2496)运动目标检测 之 Vibe背景模型算法(2373)adaboost训练 之 参数详解(2350)caffe测试单张图片(1947)ubuntu安装nvidia显卡驱动(双显卡)(1447)Caffe训练源码基本流程(1344) 评论排行 用caffe训练好的lenet_iter_10000.caffemodel测试单张mnist图片(39)caffe生成lenet-5的deploy.prototxt文件(14)Caffe图片分类(8)adaboost训练 之 参数详解(6)BP神经网络(3)编译cuda-7.5 samples文件报错(2)caffe源码 之 dropout层(2)机器学习 之 Haar特征(2)Caffe编译 Mnist训练测试(2)Caffe训练源码基本流程(1) 推荐文章 * 5月书讯流畅的Python终于等到你*【新收录】CSDN日报 —— Kotlin 专场* Android中带你开发一款自动爆破签名校验工具kstools* Android图片加载框架最全解析——深入探究Glide的缓存机制* Android 热修复 Tinker Gradle Plugin解析* Unity Shader-死亡溶解效果 最新评论 Caffe图片分类 qingdeng8127:imgsave imgsave.erase(61,2);哥哥 这句话里的61和2是怎么确定的 我... Caffe图片分类 qingdeng8127:---------- Prediction for examples/mymnist2/test_d... 用caffe训练好的lenet_iter_10000.caffemodel测试单张mnist图片 God_bless_us:作者你好我硬件有限仅仅支持cpu。所以此处应该同你有些差异我尝试过在classifymnist... BP神经网络 qq_33178422:感谢 用caffe训练好的lenet_iter_10000.caffemodel测试单张mnist图片 God_bless_us:楼主您好我想请教您的是sysnset_words.txt文件的具体生成办法是什么我参考过imag... caffe生成lenet-5的deploy.prototxt文件 zzz321year:楼主你好我为什么输出的top5正确率都是0但是label貌似正确而且train、test正确率... 用caffe训练好的lenet_iter_10000.caffemodel测试单张mnist图片 _苏_:qq_35173755:这个文件是自己创建的 用caffe训练好的lenet_iter_10000.caffemodel测试单张mnist图片 qq_35173755:请教一下您的源代码在哪里下载我从官网下载的代码训练后没有sysnset_words.txt文件 caffe源码 之 dropout层 _苏_:qq_24693721:这里是我写错了是处于训练阶段。训练时的传入参数中有个是train如果是... caffe源码 之 dropout层 qq_24693721:博主你好有个问题想问你就是网络所处的阶段是怎么判别的另外“if (this-phase_ ...