caffe代码阅读4:LayerRegistry的介绍与实现_caffe layerregistry-程序员宅基地

技术标签: caffe  

一、LayerRegistry的作用简介

LayerResistry的功能很简单,就是将类和对应的字符串类型放入到一个map当中去,以便灵活调用。主要就是注册类的功能

二、LayerRegistry类的详细介绍


1)构造函数和析构函数

构造函数 
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. // 禁止实例化,因为该类都是静态函数,所以是私有的  
  2.   LayerRegistry() {}  

2)类型定义

[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1.  // 函数指针Creator,返回的是Layer<Dtype>类型的指针  
  2. typedef shared_ptr<Layer<Dtype> > (*Creator)(const LayerParameter&);  
  3. // CreatorRegistry是字符串与对应的Creator的映射  
  4. typedef std::map<string, Creator> CreatorRegistry;  

3)成员函数

3-1 加入一个Creator到注册表

[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. // 给定类型,以及函数指针,加入到注册表  
  2. static void AddCreator(const string& type, Creator creator) {  
  3.   CreatorRegistry& registry = Registry();  
  4.   CHECK_EQ(registry.count(type), 0)  
  5.       << "Layer type " << type << " already registered.";  
  6.   registry[type] = creator;  
  7. }  

3-2 给定层的类型,创建层

这个创建层在net.cpp中会用到,在初始化整个网络的时候会根据参数文件中的层的类型去创建该层的实例
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. static shared_ptr<Layer<Dtype> > CreateLayer(const LayerParameter& param) {  
  2.   if (Caffe::root_solver()) {  
  3.     LOG(INFO) << "Creating layer " << param.name();  
  4.   }  
  5.   // 从参数中获得类型字符串  
  6.   const string& type = param.type();  
  7.   // 获得注册表指针  
  8.   CreatorRegistry& registry = Registry();  
  9.   // 测试是否查找到给定type的Creator  
  10.   CHECK_EQ(registry.count(type), 1) << "Unknown layer type: " << type  
  11.       << " (known types: " << LayerTypeListString() << ")";  
  12.   // 调用对应的层的Creator函数  
  13.   return registry[type](param);  
  14. }  

3-3 返回层的类型列表

[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. static vector<string> LayerTypeList() {  
  2.   // 获得注册表  
  3.   CreatorRegistry& registry = Registry();  
  4.   vector<string> layer_types;  
  5.   // 遍历注册表压入layer_types字符串容器  
  6.   for (typename CreatorRegistry::iterator iter = registry.begin();  
  7.        iter != registry.end(); ++iter) {  
  8.     layer_types.push_back(iter->first);  
  9.   }  
  10.   return layer_types;  
  11. }  

3-4 返回一个string,就是把所有的类型都拼起来用逗号分隔形成一个字符串

[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1.   static string LayerTypeListString() {  
  2.     vector<string> layer_types = LayerTypeList();  
  3.     string layer_types_str;  
  4.     for (vector<string>::iterator iter = layer_types.begin();  
  5.          iter != layer_types.end(); ++iter) {  
  6.       if (iter != layer_types.begin()) {  
  7.         layer_types_str += ", ";  
  8.       }  
  9.       layer_types_str += *iter;  
  10.     }  
  11.     return layer_types_str;  
  12.   }  
  13. };  

3-5 获取注册表(静态的,第一次的时候才new,以后都是直接return的)

[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. // 产生一个CreatorRegistry映射的的实例赋值给g_registry_  
  2.   // 表示内部的注册表  
  3.   // 静态函数,第一次的时候会new然后return,其余时间都是return  
  4.   static CreatorRegistry& Registry() {  
  5.     static CreatorRegistry* g_registry_ = new CreatorRegistry();  
  6.     return *g_registry_;  
  7.   }  

3-6此外还定义了一个层注册器

[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. // LayerRegisterer  
  2. // 自己定义层的注册器  
  3. // 以供后面的宏进行使用  
  4. template <typename Dtype>  
  5. class LayerRegisterer {  
  6.  public:  
  7.   // 层的注册器的构造函数  
  8.   LayerRegisterer(const string& type,  
  9.                   shared_ptr<Layer<Dtype> > (*creator)(const LayerParameter&)) {  
  10.     // LOG(INFO) << "Registering layer type: " << type;  
  11.     // 还是调用的层注册表中的加入Creator函数加入注册表  
  12.     LayerRegistry<Dtype>::AddCreator(type, creator);  
  13.   }  
  14. };  

三、其他:

为了方便作者还弄了个宏便于注册自己写的层类

[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. #define REGISTER_LAYER_CREATOR(type, creator)                                  \  
  2.   static LayerRegisterer<float> g_creator_f_##type(#type, creator<float>);     \  
  3.   static LayerRegisterer<double> g_creator_d_##type(#type, creator<double>)    \  
  4. #define REGISTER_LAYER_CLASS(type)                                             \  
  5.   template <typename Dtype>                                                    \  
  6.   shared_ptr<Layer<Dtype> > Creator_##type##Layer(const LayerParameter& param) \  
  7.   {                                                                            \  
  8.     return shared_ptr<Layer<Dtype> >(new type##Layer<Dtype>(param));           \  
  9.   }                                                                            \  
  10.   REGISTER_LAYER_CREATOR(type, Creator_##type##Layer)  
下面对该宏进行详细解释:
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. // 生成g_creator_f_type(type, creator<Dtype>)的两个函数 (double和float类型)  
  2. #define REGISTER_LAYER_CREATOR(type, creator)                                  \  
  3.   static LayerRegisterer<float> g_creator_f_##type(#type, creator<float>);     \  
  4.   static LayerRegisterer<double> g_creator_d_##type(#type, creator<double>)    \  
  5.   
  6. // 注册自己定义的类,类名为type,  
  7. // 假设比如type=bias,那么生成如下的代码  
  8. // 下面的函数直接调用你自己的类的构造函数生成一个类的实例并返回  
  9. // CreatorbiasLayer(const LayerParameter& param)  
  10. // 下面的语句是为你自己的类定义了LayerRegisterer<float>类型的静态变量g_creator_f_biasLayer(float类型,实际上就是把你自己的类的字符串类型和类的实例绑定到注册表)  
  11. // static LayerRegisterer<float> g_creator_f_biasLayer(bias, CreatorbiasLayer)  
  12. // 下面的语句为你自己的类定义了LayerRegisterer<double>类型的静态变量g_creator_d_biasLayer(double类型,实际上就是把你自己的类的字符串类型和类的实例绑定到注册表)  
  13. // static LayerRegisterer<double> g_creator_d_biasLayer(bias, CreatorbiasLayer)  
  14. #define REGISTER_LAYER_CLASS(type)                                             \  
  15.   template <typename Dtype>                                                    \  
  16.   shared_ptr<Layer<Dtype> > Creator_##type##Layer(const LayerParameter& param) \  
  17.   {                                                                            \  
  18.     return shared_ptr<Layer<Dtype> >(new type##Layer<Dtype>(param));           \  
  19.   }                                                                            \  
  20.   REGISTER_LAYER_CREATOR(type, Creator_##type##Layer)  

四、Layer_factory.cpp中的实现

首先给出卷积层的参数
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. message ConvolutionParameter {  
  2.   optional uint32 num_output = 1; // The number of outputs for the layer  
  3.   optional bool bias_term = 2 [default = true]; // whether to have bias terms  
  4.   
  5.   // Pad, kernel size, and stride are all given as a single value for equal  
  6.   // dimensions in all spatial dimensions, or once per spatial dimension.  
  7.   repeated uint32 pad = 3; // The padding size; defaults to 0  
  8.   repeated uint32 kernel_size = 4; // The kernel size  
  9.   repeated uint32 stride = 6; // The stride; defaults to 1  
  10.   
  11.   // For 2D convolution only, the *_h and *_w versions may also be used to  
  12.   // specify both spatial dimensions.  
  13.   optional uint32 pad_h = 9 [default = 0]; // The padding height (2D only)  
  14.   optional uint32 pad_w = 10 [default = 0]; // The padding width (2D only)  
  15.   optional uint32 kernel_h = 11; // The kernel height (2D only)  
  16.   optional uint32 kernel_w = 12; // The kernel width (2D only)  
  17.   optional uint32 stride_h = 13; // The stride height (2D only)  
  18.   optional uint32 stride_w = 14; // The stride width (2D only)  
  19.   
  20.   optional uint32 group = 5 [default = 1]; // The group size for group conv  
  21.   
  22.   optional FillerParameter weight_filler = 7; // The filler for the weight  
  23.   optional FillerParameter bias_filler = 8; // The filler for the bias  
  24.   enum Engine {  
  25.     DEFAULT = 0;  
  26.     CAFFE = 1;  
  27.     CUDNN = 2;  
  28.   }  
  29.   optional Engine engine = 15 [default = DEFAULT];  
  30.   
  31.   // The axis to interpret as "channels" when performing convolution.  
  32.   // Preceding dimensions are treated as independent inputs;  
  33.   // succeeding dimensions are treated as "spatial".  
  34.   // With (N, C, H, W) inputs, and axis == 1 (the default), we perform  
  35.   // N independent 2D convolutions, sliding C-channel (or (C/g)-channels, for  
  36.   // groups g>1) filters across the spatial axes (H, W) of the input.  
  37.   // With (N, C, D, H, W) inputs, and axis == 1, we perform  
  38.   // N independent 3D convolutions, sliding (C/g)-channels  
  39.   // filters across the spatial axes (D, H, W) of the input.  
  40.   optional int32 axis = 16 [default = 1];  
  41.   
  42.   // Whether to force use of the general ND convolution, even if a specific  
  43.   // implementation for blobs of the appropriate number of spatial dimensions  
  44.   // is available. (Currently, there is only a 2D-specific convolution  
  45.   // implementation; for input blobs with num_axes != 2, this option is  
  46.   // ignored and the ND implementation will be used.)  
  47.   optional bool force_nd_im2col = 17 [default = false];  
  48. }  
注册卷积层、注册池化层、注册ReLU层注册Tanh层,注册python层(如果开始python绑定的话)
代码如下:
[cpp]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. // Make sure we include Python.h before any system header  
  2. // to avoid _POSIX_C_SOURCE redefinition  
  3. #ifdef WITH_PYTHON_LAYER  
  4. #include <boost/python.hpp>  
  5. #endif  
  6. #include <string>  
  7.   
  8. #include "caffe/layer.hpp"  
  9. #include "caffe/layer_factory.hpp"  
  10. #include "caffe/proto/caffe.pb.h"  
  11. #include "caffe/vision_layers.hpp"  
  12.   
  13. #ifdef WITH_PYTHON_LAYER  
  14. #include "caffe/python_layer.hpp"  
  15. #endif  
  16.   
  17. namespace caffe {  
  18.   
  19. // 写一个获取卷积层实例的函数  
  20. // Get convolution layer according to engine.  
  21. template <typename Dtype>  
  22. shared_ptr<Layer<Dtype> > GetConvolutionLayer(  
  23.     const LayerParameter& param) {  
  24.    // 从参数中获取是使用什么引擎进行计算CUDNN还是CAFFE还是DEFAULT  
  25.    // engine可从caffe.proto中看出是枚举类型的  
  26.   ConvolutionParameter_Engine engine = param.convolution_param().engine();  
  27.   if (engine == ConvolutionParameter_Engine_DEFAULT) {  
  28.     engine = ConvolutionParameter_Engine_CAFFE;  
  29. #ifdef USE_CUDNN  
  30.     engine = ConvolutionParameter_Engine_CUDNN;  
  31. #endif  
  32.   }  
  33.   if (engine == ConvolutionParameter_Engine_CAFFE) {  
  34.     //  直接初始化Caffe的卷积层  
  35.     return shared_ptr<Layer<Dtype> >(new ConvolutionLayer<Dtype>(param));  
  36. #ifdef USE_CUDNN  
  37.   } else if (engine == ConvolutionParameter_Engine_CUDNN) {  
  38.     // 初始化CUDNN的卷积层  
  39.     return shared_ptr<Layer<Dtype> >(new CuDNNConvolutionLayer<Dtype>(param));  
  40. #endif  
  41.   } else { // 否则就是出错了  
  42.     LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";  
  43.   }  
  44. }  
  45. // 注册该卷积层,类型名为Convolution,获取卷积层的实例为GetConvolutionLayer函数  
  46. REGISTER_LAYER_CREATOR(Convolution, GetConvolutionLayer);  
  47.   
  48. // 获取池化层的实例,同卷积层的逻辑  
  49. // Get pooling layer according to engine.  
  50. template <typename Dtype>  
  51. shared_ptr<Layer<Dtype> > GetPoolingLayer(const LayerParameter& param) {  
  52.   PoolingParameter_Engine engine = param.pooling_param().engine();  
  53.   if (engine == PoolingParameter_Engine_DEFAULT) {  
  54.     engine = PoolingParameter_Engine_CAFFE;  
  55. #ifdef USE_CUDNN  
  56.     engine = PoolingParameter_Engine_CUDNN;  
  57. #endif  
  58.   }  
  59.   if (engine == PoolingParameter_Engine_CAFFE) {  
  60.     return shared_ptr<Layer<Dtype> >(new PoolingLayer<Dtype>(param));  
  61. #ifdef USE_CUDNN  
  62.   } else if (engine == PoolingParameter_Engine_CUDNN) {  
  63.     PoolingParameter p_param = param.pooling_param();  
  64.     if (p_param.pad() || p_param.pad_h() || p_param.pad_w() ||  
  65.         param.top_size() > 1) {  
  66.       LOG(INFO) << "CUDNN does not support padding or multiple tops. "  
  67.                 << "Using Caffe's own pooling layer.";  
  68.       return shared_ptr<Layer<Dtype> >(new PoolingLayer<Dtype>(param));  
  69.     }  
  70.     return shared_ptr<Layer<Dtype> >(new CuDNNPoolingLayer<Dtype>(param));  
  71. #endif  
  72.   } else {  
  73.     LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";  
  74.   }  
  75. }  
  76.   
  77. // 注册池化层  
  78. REGISTER_LAYER_CREATOR(Pooling, GetPoolingLayer);  
  79.   
  80. // 注册ReLU层  
  81. // Get relu layer according to engine.  
  82. template <typename Dtype>  
  83. shared_ptr<Layer<Dtype> > GetReLULayer(const LayerParameter& param) {  
  84.   ReLUParameter_Engine engine = param.relu_param().engine();  
  85.   if (engine == ReLUParameter_Engine_DEFAULT) {  
  86.     engine = ReLUParameter_Engine_CAFFE;  
  87. #ifdef USE_CUDNN  
  88.     engine = ReLUParameter_Engine_CUDNN;  
  89. #endif  
  90.   }  
  91.   if (engine == ReLUParameter_Engine_CAFFE) {  
  92.     return shared_ptr<Layer<Dtype> >(new ReLULayer<Dtype>(param));  
  93. #ifdef USE_CUDNN  
  94.   } else if (engine == ReLUParameter_Engine_CUDNN) {  
  95.     return shared_ptr<Layer<Dtype> >(new CuDNNReLULayer<Dtype>(param));  
  96. #endif  
  97.   } else {  
  98.     LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";  
  99.   }  
  100. }  
  101.   
  102. REGISTER_LAYER_CREATOR(ReLU, GetReLULayer);  
  103.   
  104. // 注册sigmoid层  
  105. // Get sigmoid layer according to engine.  
  106. template <typename Dtype>  
  107. shared_ptr<Layer<Dtype> > GetSigmoidLayer(const LayerParameter& param) {  
  108.   SigmoidParameter_Engine engine = param.sigmoid_param().engine();  
  109.   if (engine == SigmoidParameter_Engine_DEFAULT) {  
  110.     engine = SigmoidParameter_Engine_CAFFE;  
  111. #ifdef USE_CUDNN  
  112.     engine = SigmoidParameter_Engine_CUDNN;  
  113. #endif  
  114.   }  
  115.   if (engine == SigmoidParameter_Engine_CAFFE) {  
  116.     return shared_ptr<Layer<Dtype> >(new SigmoidLayer<Dtype>(param));  
  117. #ifdef USE_CUDNN  
  118.   } else if (engine == SigmoidParameter_Engine_CUDNN) {  
  119.     return shared_ptr<Layer<Dtype> >(new CuDNNSigmoidLayer<Dtype>(param));  
  120. #endif  
  121.   } else {  
  122.     LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";  
  123.   }  
  124. }  
  125.   
  126. REGISTER_LAYER_CREATOR(Sigmoid, GetSigmoidLayer);  
  127.   
  128. // 注册softmax层  
  129. // Get softmax layer according to engine.  
  130. template <typename Dtype>  
  131. shared_ptr<Layer<Dtype> > GetSoftmaxLayer(const LayerParameter& param) {  
  132.   SoftmaxParameter_Engine engine = param.softmax_param().engine();  
  133.   if (engine == SoftmaxParameter_Engine_DEFAULT) {  
  134.     engine = SoftmaxParameter_Engine_CAFFE;  
  135. #ifdef USE_CUDNN  
  136.     engine = SoftmaxParameter_Engine_CUDNN;  
  137. #endif  
  138.   }  
  139.   if (engine == SoftmaxParameter_Engine_CAFFE) {  
  140.     return shared_ptr<Layer<Dtype> >(new SoftmaxLayer<Dtype>(param));  
  141. #ifdef USE_CUDNN  
  142.   } else if (engine == SoftmaxParameter_Engine_CUDNN) {  
  143.     return shared_ptr<Layer<Dtype> >(new CuDNNSoftmaxLayer<Dtype>(param));  
  144. #endif  
  145.   } else {  
  146.     LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";  
  147.   }  
  148. }  
  149.   
  150. REGISTER_LAYER_CREATOR(Softmax, GetSoftmaxLayer);  
  151.   
  152. // 注册tanh层  
  153. // Get tanh layer according to engine.  
  154. template <typename Dtype>  
  155. shared_ptr<Layer<Dtype> > GetTanHLayer(const LayerParameter& param) {  
  156.   TanHParameter_Engine engine = param.tanh_param().engine();  
  157.   if (engine == TanHParameter_Engine_DEFAULT) {  
  158.     engine = TanHParameter_Engine_CAFFE;  
  159. #ifdef USE_CUDNN  
  160.     engine = TanHParameter_Engine_CUDNN;  
  161. #endif  
  162.   }  
  163.   if (engine == TanHParameter_Engine_CAFFE) {  
  164.     return shared_ptr<Layer<Dtype> >(new TanHLayer<Dtype>(param));  
  165. #ifdef USE_CUDNN  
  166.   } else if (engine == TanHParameter_Engine_CUDNN) {  
  167.     return shared_ptr<Layer<Dtype> >(new CuDNNTanHLayer<Dtype>(param));  
  168. #endif  
  169.   } else {  
  170.     LOG(FATAL) << "Layer " << param.name() << " has unknown engine.";  
  171.   }  
  172. }  
  173.   
  174. REGISTER_LAYER_CREATOR(TanH, GetTanHLayer);  
  175.   
  176. // 注册PYTHON层  
  177. #ifdef WITH_PYTHON_LAYER  
  178. template <typename Dtype>  
  179. shared_ptr<Layer<Dtype> > GetPythonLayer(const LayerParameter& param) {  
  180.   Py_Initialize();  
  181.   try {  
  182.     bp::object module = bp::import(param.python_param().module().c_str());  
  183.     bp::object layer = module.attr(param.python_param().layer().c_str())(param);  
  184.     return bp::extract<shared_ptr<PythonLayer<Dtype> > >(layer)();  
  185.   } catch (bp::error_already_set) {  
  186.     PyErr_Print();  
  187.     throw;  
  188.   }  
  189. }  
  190.   
  191. REGISTER_LAYER_CREATOR(Python, GetPythonLayer);  
  192. #endif  
  193.   
  194. // Layers that use their constructor as their default creator should be  
  195. // registered in their corresponding cpp files. Do not register them here.  
  196. }  // namespace caffe  

五、总结

作者还真是煞费苦心,弄了个宏,一下子就注册了类。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/boon_228/article/details/54909561

智能推荐

GoF23 建造者模式学习笔记_gof23 笔记-程序员宅基地

文章浏览阅读119次。GoF23 建造者模式学习笔记 1. 建造者模式也属于创建型模式 2. 定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 3. 主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象优点: 1. 产品的建造和表示分离,实现了解耦;使用建造者模式可以使客户端不必知道内部组成细节 2. 将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰 3. 具体的建造者类之间相互独立(下面例子中表现为可以存在多种Worker),这有利于系统的扩 展_gof23 笔记

mysql索引视图-程序员宅基地

文章浏览阅读363次,点赞9次,收藏7次。> Ssex varchar(20)check (Ssex='男' or Ssex='女'),-> Ssept varchar(20) default '计算机');

C语言--输入一个数字判断是否是素数(详细解答+代码优化)_输入一个数判断是不是素数-程序员宅基地

文章浏览阅读4.7k次,点赞10次,收藏19次。判断一个数是否是素数(详细解析+代码优化)_输入一个数判断是不是素数

测试环境搭建_搭建测试环境是什么意思-程序员宅基地

文章浏览阅读1.5w次,点赞61次,收藏695次。一、什么是测试环境测试环境是指测试运行其上的软件和硬件环境的描述,以及任何其它与测试软件交互的软件,包括驱动和桩测试环境是指为了完成软件测试工作所必需的计算机硬件,软件,网络设备,历史数据的总称测试环境=软件+硬件+网络+数据准备+测试工具(硬件和网络一般由公司运维考虑,历史数据由开发或者运维考虑,测试主要做软件的搭建和测试工具的搭建)二、测试环境的分类开发环境:开发环境是程序员们专门..._搭建测试环境是什么意思

【华为OD】C卷真题 200分:查找一个有向网络的头节点和尾节点 有向图的构建及环的判断 C++源码实现-程序员宅基地

文章浏览阅读575次,点赞12次,收藏4次。查找一个有向网络的头节点和尾节点 给定一个有向图,图中可能包含有环,图使用二维矩阵表示,每一行的第一列表示起始节点,第二列表示终止节点,如[0, 1]表示从0到1的路径。每个节点用正整数表示。求这个数据的首节点与尾节点,题目给的用例会是一个首节点,但可能存在多个尾节点。同时,图中可能含有环。如果图中含有环,返回[-1]。说明:入度为0是首节点,出度为0是尾节点。输入描述第一行为后续输入的键值对数量N>=0,第二行为2N个数字。每两个为一个起点,一个终点。如:输出描述输出一行头节点和尾节点。如果有多个尾节点,_查找一个有向网络的头节点和尾节点

Myeclipse调试_myeclipse运行点甲壳虫-程序员宅基地

文章浏览阅读667次。F6很简单就是从断点处向下走一行表达式;F5如果当前行有方法则进入次方法,通俗点说就是F5按照程序的执行顺序走一步F7从F5中跳出,记F5+F7相当于一个F6F8就是跳过当前断点,跳到下一个断点,如果没有断点了则执行完。_myeclipse运行点甲壳虫

随便推点

GCC编译过程_在gcc的目录下不能编译-程序员宅基地

文章浏览阅读2.7k次,点赞3次,收藏30次。1. GCC定义目前 Linux 下最常用的 C 语言编译器是 GCC ( GNU Compiler Collection ),它是 GNU 项目中符合 ANSI C 标准的编译系统,能够编译用 C 、 C++ 和 Object C 等语言编写的程序。 GCC 不仅功能非常强大,结构也异常灵活。最值得称道的一点就是它可以通过不同的前端模块来支持各种语言,如Java 、 Fortran 、 Pas..._在gcc的目录下不能编译

接口调用-【3】讯飞离线命令词识别Windows/Linux_java调用讯飞离线版语音识别 linux-程序员宅基地

文章浏览阅读1k次,点赞3次,收藏4次。1、离线命令词识别调用主函数package com.iflytek;import com.iflytek.util.Step2_asr_thread;import com.iflytek.util.Step3_audioFormat;import java.util.Scanner;import javax.sound.sampled.AudioFormat;import javax.sound.sampled.AudioSystem;import javax.sound.sampled._java调用讯飞离线版语音识别 linux

关于BIOS的那些事----不要老整三岁的脑筋急转弯,咱们来整点五岁的(中)_整点五岁以下的-程序员宅基地

文章浏览阅读1.8k次。 现在来看第二部分,第二部分其实是把要用的模块文件压缩了一个接一个放在一起就行了。压缩算法的名字叫lh5,一提到算法,国内研究这种“低层次”东西的人就少了(大家都搞往窗体上拖放几个控件就能实现功能的高层次的应用程序)。好在我在国外的网站上无意中发现了lh5压缩算法的源码,用TC写的,我又从网上把TC这个老古董下载下来,最后居然编译成功了(当然做过一些修改),编译生成的文件名叫ar.exe(文中_整点五岁以下的

微信小程序 uniapp+vue课程教学在线学习考试系统-程序员宅基地

文章浏览阅读574次,点赞21次,收藏12次。本在线学习系统使用的框架为开源框架,在开发部署上具有一定的优势,可以帮助程序开发者快速构建基本的程序框架出来,通过调用开源框架可以减少程序开发者编写的代码量,从而提升在线学习系统的安全性和稳定性,这有益于程序开发者完成功能模块的处理和数据调用。本文设计目标为设计在线学习系统,在线学习系统是一种创新的系统,创新点包含了系统框架进行结合,在仔细研究了前后端开源框架之后,最后选择使用开源框架SpringBoot,且在开源框架的基础上实现了在线学习系统。(1)确定项目名称、项目研究内容,开题报告提交及修改。

Cortex-M内核知识点总结_cortex内核-程序员宅基地

文章浏览阅读714次,点赞2次,收藏11次。我们使用外部中断的高电平触发方式来解释中断的过程 , 如上图中断请求表示外部输入引脚高电平持续的时间 ,内核检测到中断请求后,将悬起对应的中断(中断标志置位) , 中断悬起后,可能不是立马执行服务程序 , 比如当前在临界区,退出临界区后,处理器模式切换成Handler 模式,并开始执行中断服务程序,清除中断标志,执行完成后 ,退出服务,处理器模式切换成线程模式。sp我们知道是栈指针 , 每次使用 push 指令,sp都将自动生长(减小,栈是向低地址方向生长),每次使用pop指令时,sp都将增大。_cortex内核

即构SDK新增变声、立体声(3D环绕)、混响三大功能_fmod 低音-程序员宅基地

文章浏览阅读2.1k次。近日,即构SDK完成了新的迭代,新增变声、立体声(3D环绕)、混响三大功能,让玩家能体验到更多新鲜的玩法。 第一,变声功能现在流行的吃鸡游戏中,萌妹子开语音玩,只要稍微撒个娇,就能收获队友送来的福利,如果是壮汉,就没这个待遇了。有些壮汉就想了各种办法,比如另外安装一个变声软件,伪装成萌妹子。如果游戏自带变声功能,是不是就不用这么麻烦? 又比如,在语聊房、私聊、在线K歌、连麦直播..._fmod 低音

推荐文章

热门文章

相关标签