0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Relu算子的介绍

jf_pmFSk4VX 来源:GiantPandaCV 2023-01-11 17:07 次阅读

Relu算子的介绍

Relu是一种非线性激活函数,它的特点有运算简单,不会在梯度处出现梯度消失的情况,而且它在一定程度上能够防止深度学习模型在训练中发生的过拟合现象。Relu的公式表达如下所示,「如果对于深度学习基本概念不了解的同学,可以将Relu当作一个公式进行对待,可以不用深究其背后的含义。」

我们今天的任务就是来完成这个公式中的操作,「值得注意的是,在我们的项目中,x和y可以理解为我们在第二、第三节中实现的张量类(tensor).」

Operator类

Operator类就是我们在第一节中说过的计算图中「节点」的概念,计算图的另外一个概念是数据流图,如果同学们忘记了这个概念,可以重新重新翻看第一节课程。

在我们的代码中我们先定义一个「Operator」类,它是一个父类,其余的Operator,包括我们本节要实现的ReluOperator都是其派生类,「Operator中会存放节点相关的参数。」例如在「ConvOperator」中就会存放初始化卷积算子所需要的stride, padding, kernel_size等信息,本节的「ReluOperator」就会带有「thresh」值信息。

我们从下方的代码中来了解Operator类和ReluOperator类,它们是父子关系,Operator是基类,OpType记录Operator的类型。

enumclassOpType{
kOperatorUnknown=-1,
kOperatorRelu=0,
};

classOperator{
public:
OpTypekOpType=OpType::kOperatorUnknown;

virtual~Operator()=default;

explicitOperator(OpTypeop_type);
};

ReluOperator实现:

classReluOperator:publicOperator{
public:
~ReluOperator()override=default;

explicitReluOperator(floatthresh);

voidset_thresh(floatthresh);

floatget_thresh()const;

private:
floatthresh_=0.f;
};

Layer类

我们会在operator类中存放从「计算图结构文件」得到的信息,例如在ReluOperator中存放的thresh值作为一个参数就是我们从计算图结构文件中得到的,计算图相关的概念我们已经在第一节中讲过。

下一步我们需要根据ReLuOperator类去完成ReluLayer的初始化,「他们的区别在于ReluOperator负责存放从计算图中得到的节点信息,不负责计算」,而ReluLayer则「负责具体的计算操作」,同样,所有的Layer类有一个公共父类Layer. 我们可以从下方的代码中来了解两者的关系。

classLayer{
public:
explicitLayer(conststd::string&layer_name);

virtualvoidForwards(conststd::vector>>&inputs,
std::vector>>&outputs);

virtual~Layer()=default;
private:
std::stringlayer_name_;
};

其中Layer的Forwards方法是具体的执行函数,负责将输入的inputs中的数据,进行relu运算并存放到对应的outputs中。

classReluLayer:publicLayer{
public:
~ReluLayer()override=default;

explicitReluLayer(conststd::shared_ptr&op);

voidForwards(conststd::vector>>&inputs,
std::vector>>&outputs)override;

private:
std::shared_ptrop_;
};

这是集成于Layer的ReluLayer类,我们可以看到其中有一个op成员,是一个ReluOperator指针,「这个指针中负责存放ReluLayer计算时所需要用到的一些参数」。此处op_存放的参数比较简单,只有ReluOperator中的thresh参数。

我们再看看是怎么使用ReluOperator去初始化ReluLayer的,先通过统一接口传入Operator类,再转换为对应的ReluOperator指针,最后再通过指针中存放的信息去初始化「op_」.

ReluLayer::ReluLayer(conststd::shared_ptr&op):Layer("Relu"){
CHECK(op->kOpType==OpType::kOperatorRelu);
ReluOperator*relu_op=dynamic_cast(op.get());
CHECK(relu_op!=nullptr);
this->op_=std::make_shared(relu_op->get_thresh());
}

我们来看一下具体ReluLayer的Forwards过程,它在执行具体的计算,完成Relu函数描述的功能。

voidReluLayer::Forwards(conststd::vector>>&inputs,
std::vector>>&outputs){
CHECK(this->op_!=nullptr);
CHECK(this->op_->kOpType==OpType::kOperatorRelu);

constuint32_tbatch_size=inputs.size();
for(inti=0;i< batch_size; ++i) {
    CHECK(!inputs.at(i)->empty());
conststd::shared_ptr>&input_data=inputs.at(i);

input_data->data().transform([&](floatvalue){
floatthresh=op_->get_thresh();
if(value>=thresh){
returnvalue;
}else{
return0.f;
}
});
outputs.push_back(input_data);
}
}

在for循环中,首先读取输入input_data, 再对input_data使用armadillo自带的transform按照我们给定的thresh过滤其中的元素,如果「value」的值大于thresh则不变,如果小于thresh就返回0.

最后,我们写一个测试函数来验证我们以上的两个类,节点op类,计算层layer类的正确性。

先判断Forwards返回的outputs是否已经保存了relu层的输出,输出大小应该assert为1. 随后再进行比对,我们应该知道在thresh等于0的情况下,第一个输出index(0)和第二个输出index(1)应该是0,第三个输出应该是3.f.

TEST(test_layer,forward_relu){
usingnamespacekuiper_infer;
floatthresh=0.f;
std::shared_ptrrelu_op=std::make_shared(thresh);
std::shared_ptr>input=std::make_shared>(1,1,3);
input->index(0)=-1.f;
input->index(1)=-2.f;
input->index(2)=3.f;
std::vector>>inputs;
std::vector>>outputs;
inputs.push_back(input);
ReluLayerlayer(relu_op);
layer.Forwards(inputs,outputs);
ASSERT_EQ(outputs.size(),1);
for(inti=0;i< outputs.size(); ++i) {
    ASSERT_EQ(outputs.at(i)->index(0),0.f);
ASSERT_EQ(outputs.at(i)->index(1),0.f);
ASSERT_EQ(outputs.at(i)->index(2),3.f);
}
}

本期代码仓库位置

gitclonehttps://gitee.com/fssssss/KuiperCourse.git
gitcheckoutfouth





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • ARM芯片
    +关注

    关注

    1

    文章

    126

    浏览量

    21499

原文标题:自制深度学习推理框架-实现我们的第一个算子Relu-第三课

文章出处:【微信号:GiantPandaCV,微信公众号:GiantPandaCV】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    什么是PRelu算子?PRelu算子调优经历-先行篇

    一个叫做PRelu的算子,想要运行在RT170上。 本来小编是信心满满的答应客户说: 速度上放心,我们这主频1GHz的CPU绝对没问题,包您满意。 没想到跑分结果出炉直接给了小编沉重一击。 直接依赖
    的头像 发表于 08-24 08:50 1414次阅读
    什么是PRelu<b class='flag-5'>算子</b>?PRelu<b class='flag-5'>算子</b>调优经历-先行篇

    基于GFO算子的图像增强算法如何去实现?

    基于GFO算子(广义模糊算子)的图像增强算法如何去实现?怎样对图像增强算法进行分析?
    发表于 06-04 06:24

    边缘检测的几种微分算子

    一、边缘检测边缘检测的几种微分算子:一阶微分算子:Roberts、Sobel、Prewitt二阶微分算子:Laplacian、Log/Marr非微分算子:Canny一阶微分
    发表于 07-26 08:29

    bottom-up多层规约图融合策略资料介绍

    (例如Conv+ReLU)则受限于供应商API的支持程度。  随着AI模型在各领域的发展、成熟和落地,模型推理在具体设备上的性能变得越发重要,17年到18年,业界出现了大量面向DL模型推理的计算框架,算子
    发表于 11-09 17:33

    LOG算子在FPGA中的实现

    介绍了一种高斯拉普拉斯LOG算子在FPGA中的实现方案!并通过对一幅BMP图像的处理!论证了在FPGA中实现的LOG算子的图像增强效果
    发表于 05-16 17:12 50次下载
    LOG<b class='flag-5'>算子</b>在FPGA中的实现

    边缘检测算子在汽车牌照区域检测中的应用

    文中介绍了常用的几种 边缘检测 算子,不同的微分算子对不同边缘检测的敏感程度是不同的,因此对不同类型的边缘提取,应该采用对此类边缘敏感的算子进行边缘提取。针对车辆牌
    发表于 07-25 16:13 22次下载
    边缘检测<b class='flag-5'>算子</b>在汽车牌照区域检测中的应用

    基于修正的直觉模糊集成算子

    已有的一些直觉模糊集成算子在处理一些特殊直觉模糊数时会出现反直觉现象。首先介绍了两个直觉模糊集成算子和直觉模糊数的比较方法。接着,举例说明了这些集成算子在某些情况下出现的反直觉现象。然
    发表于 11-17 14:36 9次下载

    深度ReLU网络的训练动态过程及其对泛化能力的影响

    基于这个框架,我们试图用统一的观点来解释这些令人费解的经验现象。本文使用师生设置,其中给过度参数化的深度学生ReLU网络的标签,是具有相同深度和未知权重的固定教师ReLU网络的输出(图1(a))。在这个角度来看,隐藏的学生节点将随机初始化为不同的激活区域。(图2(a))
    的头像 发表于 06-15 10:48 3361次阅读
    深度<b class='flag-5'>ReLU</b>网络的训练动态过程及其对泛化能力的影响

    在PyTorch中使用ReLU激活函数的例子

    PyTorch已为我们实现了大多数常用的非线性激活函数,我们可以像使用任何其他的层那样使用它们。让我们快速看一个在PyTorch中使用ReLU激活函数的例子:
    的头像 发表于 07-06 15:27 2556次阅读

    Sobel算子原理介绍与实现方法

    索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量Sobel 卷积因子为:
    的头像 发表于 07-21 17:27 1.3w次阅读

    自定义算子开发

    一个完整的自定义算子应用过程包括注册算子算子实现、含自定义算子模型转换和运行含自定义op模型四个阶段。在大多数情况下,您的模型应该可以通过使用hb_mapper工具完成转换并顺利部署
    的头像 发表于 04-07 16:11 2822次阅读
    自定义<b class='flag-5'>算子</b>开发

    深度ReLU网络的对应浅层网络

      只要你用了ReLU,我们就是好朋就是“浅度学习”。 最近有研究证明,所有基于ReLU的深度神经网络都可以重写为功能相同的3层神经网络。   基于这个证明,伦敦国王学院的研究团队还提出一种为任意
    的头像 发表于 07-03 14:13 574次阅读
    深度<b class='flag-5'>ReLU</b>网络的对应浅层网络

    机器学习算法的5种基本算子

    自主决策的方法和插件,其中包含了一系列常用的基本算子。在本文中,我们将会介绍机器学习算法的五种基本算子。 一、 求值算子 求值算子是常用的机
    的头像 发表于 08-17 16:11 1812次阅读

    Dynamic ReLU:根据输入动态确定的ReLU

    这是我最近才看到的一篇论文,它提出了动态ReLU (Dynamic ReLU, DY-ReLU),可以将全局上下文编码为超函数,并相应地调整分段线性激活函数。
    的头像 发表于 09-01 17:28 716次阅读
    Dynamic <b class='flag-5'>ReLU</b>:根据输入动态确定的<b class='flag-5'>ReLU</b>

    图像锐化的Sobel、Laplacian算子基础知识介绍

    Sobel 算子是一种用于边缘检测的离散微分算子,它结合了高斯平滑和微分求导
    的头像 发表于 09-13 09:52 1467次阅读
    图像锐化的Sobel、Laplacian<b class='flag-5'>算子</b>基础知识<b class='flag-5'>介绍</b>