MXNet 定义新激活函数(Custom new activation function)

https://blog.csdn.net/weixin_34260991/article/details/87106463

这里使用比较简单的定义方式,只是在原有的激活函数调用中加入。

准备工作
下载MXNet源代码,确认可以顺利编译通过。推荐在Linux下进行此操作:

https://mxnet.incubator.apache.org/get_started/install.html

编写激活函数先前和先后传递
在src/operator/mshadow_op.h里面,加入新的激活函数向前传递和向后的函数:

/*!
* \brief RBF Unit
* \author Yuzhong Liu
*/
struct rbf {
template<typename DType>
MSHADOW_XINLINE static DType Map(DType x) {
return DType(expf(-x*x));
}
};

struct rbf_grad {
template<typename DType>
MSHADOW_XINLINE static DType Map(DType x, DType a) {
return DType(-2 * x * a);
}
};
添加调用方法
在src/operator/leaky_relu-inl.h里面,激活函数的调用方式:

namespace leakyrelu {
enum LeakyReLUOpInputs {kData, kGamma};
enum LeakyReLUOpOutputs {kOut, kMask};
# 定义新的激活函数名称
enum LeakyReLUOpType {kLeakyReLU, kPReLU, kRReLU, kELU, kRBF};
enum LeakyReLUOpResource {kRandom};
} // namespace leakyrelu

struct LeakyReLUParam : public dmlc::Parameter<LeakyReLUParam> {
// use int for enumeration
int act_type;
float slope;
float lower_bound;
float upper_bound;
DMLC_DECLARE_PARAMETER(LeakyReLUParam) {
DMLC_DECLARE_FIELD(act_type).set_default(leakyrelu::kLeakyReLU)
.add_enum("rrelu", leakyrelu::kRReLU)
.add_enum("leaky", leakyrelu::kLeakyReLU)
.add_enum("prelu", leakyrelu::kPReLU)
.add_enum("elu", leakyrelu::kELU)
# 添加激活函数枚举
.add_enum("rbf", leakyrelu::kRBF)
.describe("Activation function to be applied.");
DMLC_DECLARE_FIELD(slope).set_default(0.25f)
.describe("Init slope for the activation. (For leaky and elu only)");
DMLC_DECLARE_FIELD(lower_bound).set_default(0.125f)
.describe("Lower bound of random slope. (For rrelu only)");
DMLC_DECLARE_FIELD(upper_bound).set_default(0.334f)
.describe("Upper bound of random slope. (For rrelu only)");
}
};

template<typename xpu>
class LeakyReLUOp : public Operator {
public:
explicit LeakyReLUOp(LeakyReLUParam param) {
param_ = param;
}

virtual void Forward(const OpContext &ctx,
const std::vector<TBlob> &in_data,
const std::vector<OpReqType> &req,
const std::vector<TBlob> &out_data,
const std::vector<TBlob> &aux_args) {
using namespace mshadow;
using namespace mshadow::expr;
size_t expected = param_.act_type == leakyrelu::kPReLU ? 2 : 1;
CHECK_EQ(in_data.size(), expected);
Stream<xpu> *s = ctx.get_stream<xpu>();
Tensor<xpu, 3> data;
Tensor<xpu, 3> out;
Tensor<xpu, 3> mask;
Tensor<xpu, 1> weight;
int n = in_data[leakyrelu::kData].shape_[0];
int k = in_data[leakyrelu::kData].shape_[1];
Shape<3> dshape = Shape3(n, k, in_data[leakyrelu::kData].Size()/n/k);
data = in_data[leakyrelu::kData].get_with_shape<xpu, 3, real_t>(dshape, s);
out = out_data[leakyrelu::kOut].get_with_shape<xpu, 3, real_t>(dshape, s);
if (param_.act_type == leakyrelu::kRReLU) {
mask = out_data[leakyrelu::kMask].get_with_shape<xpu, 3, real_t>(dshape, s);
}
switch (param_.act_type) {
case leakyrelu::kLeakyReLU: {
Assign(out, req[leakyrelu::kOut], F<mshadow_op::xelu>(data, param_.slope));
break;
}
case leakyrelu::kPReLU: {
weight = in_data[leakyrelu::kGamma].get<xpu, 1, real_t>(s);
Assign(out, req[leakyrelu::kOut],
F<mshadow_op::xelu>(data, broadcast<1>(weight, out.shape_)));
break;
}
case leakyrelu::kRReLU: {
if (ctx.is_train) {
Random<xpu>* prnd = ctx.requested[leakyrelu::kRandom].get_random<xpu, real_t>(s);
mask = prnd->uniform(mask.shape_);
mask = mask * (param_.upper_bound - param_.lower_bound) + param_.lower_bound;
Assign(out, req[leakyrelu::kOut], F<mshadow_op::xelu>(data, mask));
} else {
const float slope = (param_.lower_bound + param_.upper_bound) / 2.0f;
Assign(out, req[leakyrelu::kOut], F<mshadow_op::xelu>(data, slope));
}
break;
}
case leakyrelu::kELU: {
Assign(out, req[leakyrelu::kOut], F<mshadow_op::elu>(data, param_.slope));
break;
}
# RBF向前
case leakyrelu::kRBF: {
Assign(out, req[leakyrelu::kOut], F<mshadow_op::rbf>(data));
break;
}
default:
LOG(FATAL) << "Not implmented";
}
}

virtual void Backward(const OpContext & ctx,
const std::vector<TBlob> &out_grad,
const std::vector<TBlob> &in_data,
const std::vector<TBlob> &out_data,
const std::vector<OpReqType> &req,
const std::vector<TBlob> &in_grad,
const std::vector<TBlob> &aux_args) {
using namespace mshadow;
using namespace mshadow::expr;
size_t expected = param_.act_type == leakyrelu::kPReLU ? 2 : 1;
CHECK_EQ(out_grad.size(), 1U);
CHECK_EQ(req.size(), expected);
CHECK_EQ(in_data.size(), expected);
Stream<xpu> *s = ctx.get_stream<xpu>();
Tensor<xpu, 3> output;
Tensor<xpu, 3> data;
Tensor<xpu, 3> gdata;
Tensor<xpu, 3> grad;
Tensor<xpu, 3> mask;
Tensor<xpu, 1> weight;
Tensor<xpu, 1> grad_weight;
int n = out_grad[leakyrelu::kOut].shape_[0];
int k = out_grad[leakyrelu::kOut].shape_[1];
Shape<3> dshape = Shape3(n, k, out_grad[leakyrelu::kOut].Size()/n/k);
grad = out_grad[leakyrelu::kOut].get_with_shape<xpu, 3, real_t>(dshape, s);
gdata = in_grad[leakyrelu::kData].get_with_shape<xpu, 3, real_t>(dshape, s);
output = out_data[leakyrelu::kOut].get_with_shape<xpu, 3, real_t>(dshape, s);
if (param_.act_type == leakyrelu::kRReLU) {
mask = out_data[leakyrelu::kMask].get_with_shape<xpu, 3, real_t>(dshape, s);
}
if (param_.act_type == leakyrelu::kPReLU) {
data = in_data[leakyrelu::kData].get_with_shape<xpu, 3, real_t>(dshape, s);
}
switch (param_.act_type) {
case leakyrelu::kLeakyReLU: {
Assign(gdata, req[leakyrelu::kData], F<mshadow_op::xelu_grad>(output, param_.slope) * grad);
break;
}
case leakyrelu::kPReLU: {
weight = in_data[leakyrelu::kGamma].get<xpu, 1, real_t>(s);
grad_weight = in_grad[leakyrelu::kGamma].get<xpu, 1, real_t>(s);
grad_weight = sumall_except_dim<1>(F<prelu_grad>(data) * grad);
gdata = F<mshadow_op::xelu_grad>(data, broadcast<1>(weight, data.shape_)) * grad;
break;
}
case leakyrelu::kRReLU: {
Assign(gdata, req[leakyrelu::kData], F<mshadow_op::xelu_grad>(output, mask) * grad);
break;
}
case leakyrelu::kELU: {
Assign(gdata, req[leakyrelu::kData], F<mshadow_op::elu_grad>(output, param_.slope) * grad);
break;
}
# RBF向前
case leakyrelu::kRBF: {
data = in_data[leakyrelu::kData].get_with_shape<xpu, 3, real_t>(dshape, s);
Assign(gdata, req[leakyrelu::kData], F<mshadow_op::rbf_grad>(data, output) * grad);
break;
}
default:
LOG(FATAL) << "Not implmented";
}
}

private:
LeakyReLUParam param_;
}; // class LeakyReLUOp
从重新编译,并测试
import mxnet as mx
from mxnet import autograd
a = mx.nd.random_uniform(-1, 1, shape=[3, 3]) +0.5
a.attach_grad()

with autograd.record():
b = mx.nd.LeakyReLU(data=a, act_type=‘rbf‘)

print a, b
参考资料
https://mxnet.incubator.apache.org/how_to/new_op.html
http://blog.csdn.net/qq_20965753/article/details/66975622?utm_source=debugrun&utm_medium=referral
---------------------
作者:weixin_34260991
来源:CSDN
原文:https://blog.csdn.net/weixin_34260991/article/details/87106463
版权声明:本文为博主原创文章,转载请附上博文链接!

原文地址:https://www.cnblogs.com/jukan/p/10938237.html

时间: 2024-10-26 19:23:26

MXNet 定义新激活函数(Custom new activation function)的相关文章

《Noisy Activation Function》噪声激活函数(一)

本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/51736830 Noisy Activation Functions是ICML 2016年新发表的一篇关于激活函数的论文,其中对以往的激活函数进行了深入的分析,并提出了训练过程中添加噪声的新方法,效果不错,觉得很有意义,目测会在今后的深度学习领域产生比较大的影响,因此将其原论文翻译,并略作注解(计划分两篇博客来写,本文涵盖从摘要到第三节的

&lt;28&gt;【了解】10-枚举类型介绍及定义+【掌握】11-枚举变量变量定义和使用+【掌握】13-typedef定义新的类型+【掌握】15-宏的概念及无参宏定义方法+【掌握】16-有参宏定义和使用方法+【掌握】17-应用:使用有参宏求最大值+【掌握】18-typedef和#define的区别

[了解]10-枚举类型介绍及定义 枚举类型: C语言提供了一个种类型,这种类型的变量的取值被限定在一定的范围之内了 枚举类型的定义: enum 枚举类型名{ 枚举值1,枚举值2,.... }; 举例: 定义一个变量,保存一周的第几天 enum weekday{ zhouyi,zhouer,zhousan,zhousi,zhouwu ,zhouliu,zhouri }; 定义iPhone手机的颜色 关于枚举类型元素的命名习惯 enum iColor{kIcolorWhite,kIcolorBlac

iFunk,定义新基准

随着iFunk新品超极本iFunk翼的面世,iFunk官方也首次提出了"定义新基准"的概念,并以此作为自己品牌理念的整合与精髓,对于这个词相信大家都有不同的理解,今天小编就结合iFunk的产品来谈谈自己的看法. 科技的进步使得笔电行业近年来的发展更猛烈迅速,笔记本电脑不再是高高在上充满距离的高科技产品,而是更生活化的日用品,在这个过程中诞生了很多全球知名的大牌以及行业标杆,作为新兴品牌iFunk,它站在行业巨人的肩膀上又是如何定位自己的呢? 从iFunk历代产品中可以看出,iFunk非

给SharePoint页面加入自己定义页脚Custom footer

给SharePoint页面加入自己定义页脚Custom footer 在公司做站点设计项目时,须要在页面上加入页脚. 非常多人都把页脚忽视了,认为没什么多大用处,事实上它的作用还是有的,并且还越来越显得重要.页脚设计主要用来显示站点的版权和站点介绍.假设在页脚加入一些有趣的内容,能够提升用户体验,让站点变得更有趣味. 本文主要介绍怎样在SharePoint页面上加入页脚,详细样式博友能够任意尝试,公司的网站主要还是以严肃为主,就不那么花哨了.简简单单做出来显示版权就可以. 页脚当然是要放在每一个

激活函数-Activation Function

该博客的内容是莫烦大神的授课内容.在此只做学习记录作用. 原文连接:https://morvanzhou.github.io/tutorials/machine-learning/tensorflow/2-6-A-activation-function/ 非线性方程 我们为什么要使用激活函数?用简单的语句来概括,就是因为显示并没有我们想象的那么美好 ,它是残酷多变的.哈哈,开个玩笑,不过激活函数也就是为了解决我们日常生活中不能用线性方程所概括的问题. 好了,我知道你的问题来了. 什么是线性方程(

Java 8 新特性:3-函数(Function)接口

(原) 以前,在创建泛型时,是这么写的: List<String> list = new ArrayList<String>(); 现在,可以这么写了: List<String> list = new ArrayList<>(); 在java8中,这种写法被叫作diamond语法,有些书里叫他钻石语法,有些则称之为菱形语法,说的就是这种语法. 看下面的例子: package com.demo.jdk8; import java.util.ArrayList;

PowerShell-自定义函数(一) 第一个自定义Function

在PowerShell中,我们可以自定义一个函数来实现一个特定的功能,以达到重复使用的目的.准备由简单到复杂做一个小系列分享一下. 首先我们写一个非常简单的自定义函数. 目标: 输入姓名和年龄后,直接在显示 某某 今年 多少 岁 . 示例: Function Test-Function ($Name, $Age="18"){    Write-Host "$Name 今年 $Age 岁."} 说明: 以Function开头声明这是一个函数 Test-Function

c++ 11新特性之bind()与function

bind()和function()  这两个函数在std的标准库中,提供c++对函数以及对象的控制 bind()  顾名思义就是“绑定” ,而bind()是和函数有关,所以就是绑定某个函数,请看一下代码 int f(int, char, double); auto ff = bind(f, _1, 'c', 1.2); // 绑定f()函数调用的第二个和第三个参数,返回一个新的函数对象为ff,它只带有一个int类型的参数 int x = ff(7); // f(7, 'c', 1.2); 我们无

ue4 material custom node - global function and method

在ue4 material中定义全局函数 1. 背景 原文unreal-engine-4-custom-shaders-tutorial 中,提出了一种在material生成的hlsl文件中定义全局函数的方法,记录到这里以备复习. ue4 材质中的custom节点是用来使用hlsl代码的地方.一般来说都是直接编辑逻辑,最后添加return返回.类似这样: 1 float4 color = {1,0,0,1}; 2 return color; 使用ue4材质 menu window->hlsl s