看完这篇,你基本上可以自定义前向与反向传播,可以自己定义自己的算子

文章目录

  • Tanh
    • 公式
    • 求导过程
    • 优点:
    • 缺点:
    • 自定义Tanh
    • 与Torch定义的比较
    • 可视化
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F%matplotlib inlineplt.rcParams['figure.figsize'] = (7, 3.5)
plt.rcParams['figure.dpi'] = 150
plt.rcParams['axes.unicode_minus'] = False  #解决坐标轴负数的铅显示问题

Tanh

公式

tanh⁡(x)=sinh⁡(x)cosh⁡(x)=ex−e−xex+e−x\tanh(x) = \frac{\sinh(x)}{\cosh(x)} = \frac{e^x - e^{-x}}{e^x + e^{-x}}tanh(x)=cosh(x)sinh(x)​=ex+e−xex−e−x​

tanh⁡(x)=2σ(2x)−1\tanh(x) = 2 \sigma(2x) - 1 tanh(x)=2σ(2x)−1

求导过程

tanh⁡′(x)=(ex−e−xex+e−x)′=[(ex−e−x)(ex+e−x)−1]′=(ex+e−x)(ex+e−x)−1+(ex−e−x)(−1)(ex+e−x)−2(ex−e−x)=1−(ex−e−x)2(ex+e−x)−2=1−(ex−e−x)2(ex+e−x)2=1−tanh⁡2(x)\begin{aligned} \tanh'(x) =& \big(\frac{e^x - e^{-x}}{e^x + e^{-x}}\big)' \\ =& \big[(e^x - e^{-x})(e^x + e^{-x})^{-1}\big]' \\ =& (e^x + e^{-x})(e^x + e^{-x})^{-1} + (e^x - e^{-x})(-1)(e^x + e^{-x})^{-2} (e^x - e^{-x}) \\ =& 1-(e^x - e^{-x})^2(e^x + e^{-x})^{-2} \\ =& 1 - \frac{(e^x - e^{-x})^2}{(e^x + e^{-x})^2} \\ =& 1- \tanh^2(x) \\ \end{aligned}tanh′(x)======​(ex+e−xex−e−x​)′[(ex−e−x)(ex+e−x)−1]′(ex+e−x)(ex+e−x)−1+(ex−e−x)(−1)(ex+e−x)−2(ex−e−x)1−(ex−e−x)2(ex+e−x)−21−(ex+e−x)2(ex−e−x)2​1−tanh2(x)​

优点:

Tanh也称为双切正切函数,取值范围为[-1,1]。tanh在特征相差明显时的效果会很好,在循环过程中会不断扩大特征效果。与 sigmoid 的区别是,tanh 是 0 均值的,因此实际应用中 tanh 会比 sigmoid 更好。文献 [LeCun, Y., et al., Backpropagation applied to handwritten zip code recognition. Neural computation, 1989. 1(4): p. 541-551.] 中提到tanh 网络的收敛速度要比sigmoid快,因为tanh 的输出均值比 sigmoid 更接近 0,SGD会更接近 natural gradient[4](一种二次优化技术),从而降低所需的迭代次数。非常优秀,几乎适合所有的场景

缺点:

  • 该导数在正负饱和区的梯度都会接近于0值,会造成梯度消失。还有其更复杂的幂运算。

自定义Tanh

class SelfDefinedTanh(torch.autograd.Function):@staticmethoddef forward(ctx, inp):exp_x = torch.exp(inp)exp_x_ = torch.exp(-inp)result = torch.divide((exp_x - exp_x_), (exp_x + exp_x_))ctx.save_for_backward(result)return result@staticmethoddef backward(ctx, grad_output):# ctx.saved_tensors is tuple (tensors, grad_fn)result, = ctx.saved_tensorsreturn grad_output * (1 - result.pow(2))class Tanh(nn.Module):def __init__(self):super().__init__()def forward(self, x):out = SelfDefinedTanh.apply(x)return out
def tanh_sigmoid(x):"""according to the equation"""# 2 * torch.sigmoid(2 * x) -1 return torch.mul(torch.sigmoid(torch.mul(x, 2)), 2) - 1

与Torch定义的比较

# self defined
torch.manual_seed(0)tanh = Tanh()  # SelfDefinedTanh
inp = torch.randn(5, requires_grad=True)
out = tanh((inp + 1).pow(2))print(f'Out is\n{out}')out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nFirst call\n{inp.grad}")out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nSecond call\n{inp.grad}")inp.grad.zero_()
out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nCall after zeroing gradients\n{inp.grad}")
Out is
tensor([1.0000, 0.4615, 0.8831, 0.9855, 0.0071],grad_fn=<SelfDefinedTanhBackward>)First call
tensor([ 5.0889e-05,  1.1121e+00, -5.1911e-01,  9.0267e-02, -1.6904e-01])Second call
tensor([ 1.0178e-04,  2.2243e+00, -1.0382e+00,  1.8053e-01, -3.3807e-01])Call after zeroing gradients
tensor([ 5.0889e-05,  1.1121e+00, -5.1911e-01,  9.0267e-02, -1.6904e-01])
# self defined tanh_sigmoid
torch.manual_seed(0)inp = torch.randn(5, requires_grad=True)
out = tanh_sigmoid((inp + 1).pow(2))print(f'Out is\n{out}')out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nFirst call\n{inp.grad}")out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nSecond call\n{inp.grad}")inp.grad.zero_()
out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nCall after zeroing gradients\n{inp.grad}")
Out is
tensor([1.0000, 0.4615, 0.8831, 0.9855, 0.0071], grad_fn=<SubBackward0>)First call
tensor([ 5.0889e-05,  1.1121e+00, -5.1911e-01,  9.0267e-02, -1.6904e-01])Second call
tensor([ 1.0178e-04,  2.2243e+00, -1.0382e+00,  1.8053e-01, -3.3807e-01])Call after zeroing gradients
tensor([ 5.0889e-05,  1.1121e+00, -5.1911e-01,  9.0267e-02, -1.6904e-01])
# torch defined
torch.manual_seed(0)inp = torch.randn(5, requires_grad=True)
out = torch.tanh((inp + 1).pow(2))print(f'Out is\n{out}')out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nFirst call\n{inp.grad}")out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nSecond call\n{inp.grad}")inp.grad.zero_()
out.backward(torch.ones_like(inp), retain_graph=True)
print(f"\nCall after zeroing gradients\n{inp.grad}")
Out is
tensor([1.0000, 0.4615, 0.8831, 0.9855, 0.0071], grad_fn=<TanhBackward>)First call
tensor([ 5.0283e-05,  1.1121e+00, -5.1911e-01,  9.0267e-02, -1.6904e-01])Second call
tensor([ 1.0057e-04,  2.2243e+00, -1.0382e+00,  1.8053e-01, -3.3807e-01])Call after zeroing gradients
tensor([ 5.0283e-05,  1.1121e+00, -5.1911e-01,  9.0267e-02, -1.6904e-01])

从上3个结果,可以看出,不管是经过sigmoid来计算,还是公式定义都可以得到一样的output与gradient。但在输入的值较大时,torch应该是减去一个小值,使得梯度更小。

可视化

# visualization
inp = torch.arange(-8, 8, 0.1, requires_grad=True)
out = tanh(inp)
out.sum().backward()inp_grad = inp.gradplt.plot(inp.detach().numpy(),out.detach().numpy(),label=r"$\tanh(x)$",alpha=0.7)
plt.plot(inp.detach().numpy(),inp_grad.numpy(),label=r"$\tanh'(x)$",alpha=0.5)
plt.grid()
plt.legend()
plt.show()

Pytorch 自定义激活函数前向与反向传播 Tanh相关推荐

  1. Pytorch 自定义激活函数前向与反向传播 sigmoid

    文章目录 Sigmoid 公式 求导过程 优点: 缺点: 自定义Sigmoid 与Torch定义的比较 可视化 import matplotlib import matplotlib.pyplot a ...

  2. Pytorch 自定义激活函数前向与反向传播 ReLu系列 含优点与缺点

    文章目录 ReLu 公式 求导过程 优点: 缺点: 自定义ReLu 与Torch定义的比较 可视化 Leaky ReLu PReLu 公式 求导过程 优点: 缺点: 自定义LeakyReLu 与Tor ...

  3. 4.6 前向和反向传播-深度学习-Stanford吴恩达教授

    ←上一篇 ↓↑ 下一篇→ 4.5 搭建深层神经网络快 回到目录 4.7 参数 vs. 超参数 前向和反向传播 (Forward and Backward Propagation) 之前我们学习了构成深 ...

  4. 卷积神经网络前向及反向传播过程数学解析

    卷积神经网络前向及反向传播过程数学解析 文章目录 <center>卷积神经网络前向及反向传播过程数学解析 1.卷积神经网络初印象 2.卷积神经网络性质 3.前向传播 3.1.卷积层层级间传 ...

  5. meanpool maxpool 前向和反向传播

    mean max 前向和反向传播 感觉平均迟化对值不太公平,应该加个权重,让算法自动去决定哪个 cnn中关于平均池化和最大池化的理解 接触到pooling主要是在用于图像处理的卷积神经网络中,但随着深 ...

  6. numpy实现简单的二层网络------前向和反向传播

    会推导神经网络的前向和反向传播是深度学习的基础,也许大家在实验使用Tensorflow框架,只需要调用某一个损失函数,传入参数就可以得到损失,或者Mxnet框架,你都不需要调用任何函数,给个标志就可以 ...

  7. 神经网络的前向和反向传播

    1.前向传播 前向传播的作用就是为了获取误差损失:现在以示例来说明: 上图是一个典型的神经网络结构,包括了输入层.隐含层和输出层,为了更好的讲解,现在对其进行赋值: 目标:给出输入数据i1,i2(0. ...

  8. 4.2 前向和反向传播

  9. 前向传播、反向传播(后向传播)、梯度下降、导数、链式法则

    日萌社 人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新) 2.4 神经网络最优化过程 2.4.1 最优化(Optimiz ...

最新文章

  1. SQL入门经典(第5版)学习笔记(三)
  2. RecyclerView上拉加载Demo
  3. element upload预览_vue+element上传图片并显示预览图
  4. oracle11g AUD$维护
  5. Joseph Problem(解约瑟夫问题)
  6. 程序员面试金典 - 面试题 05.08. 绘制直线(位运算)
  7. 【LeetCode笔记】34. 在排序数组中查找元素的第一个和最后一个位置(Java、二分)
  8. servlet实现新闻控制
  9. swift 二进制读写_Swift二进制搜索树
  10. linux用户批量修改密码,Linux 命令详解 chpasswd 批量修改用户密码
  11. 10分钟学会spring代理模式以及应用原理,个人专用,不适合借鉴,请关闭文章
  12. spring boot-html和templates
  13. 【同态加密算法的学习日记】
  14. java毕业设计—— 基于java+JSP+SSH的网上购物系统设计与实现(毕业论文+程序源码)——网上购物系统
  15. js特效 jQuery特效 网页特效网站 web网站模板下载推荐
  16. 剑指offer第二版面试题46:把数字翻译成字符串(java)
  17. WAS6.1JNDI数据源配置测试代码
  18. Unsafe code may only appear if compiling with /unsafe. Enable “Allow ‘unsafe‘ code“
  19. win8计算机不显示视频图标,如何解决Win8.1桌面图标显示不正常的问题?
  20. 无依赖单机尝鲜 Nebula Exchange 的 SST 导入

热门文章

  1. js(Dom+Bom)第六天(1)
  2. GitHub笔记(二)——远程仓库的操作
  3. Android:日常学习笔记(8)———探究UI开发(5)
  4. spring -mvc 将对象封装json返回时删除掉对象中的属性注解方式
  5. shell命令tree
  6. EFI BIOS下的磁盘管理工具Diskpart,Efifmt与Efichk(转)
  7. Linux进程线程学习笔记:运行新程序
  8. 【linux】 -设备名称与文件目录
  9. IPython 使用记录
  10. 如何寻回xp盘符丢失的数据