日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/10 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Pytorch 自定义激活函数前向与反向传播 sigmoid 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • Sigmoid
      • 公式
      • 求導過程
      • 優點:
      • 缺點:
      • 自定義Sigmoid
      • 與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 #解決坐標軸負數的鉛顯示問題

Sigmoid

公式

sigmoid(x)=σ(x)=11+e?x\text{sigmoid}(x)= \sigma(x) = \frac{1}{1+e^{-x}}sigmoid(x)=σ(x)=1+e?x1?

求導過程

σ′(x)=[(1+e?x)?1]′=(?1)(1+e?x)?2(?1)e?x=(1+e?x)?2e?x=e?x(1+e?x)2=1+e?x?1(1+e?x)2=1+e?x(1+e?x)2?1(1+e?x)2=1(1+e?x)(1?1(1+e?x))=σ(x)(1?σ(x))\begin{aligned} \sigma'(x) =&[(1+e^{-x})^{-1}]' \\ =&(-1)(1+e^{-x})^{-2}(-1)e^{-x}\\ =&(1+e^{-x})^{-2}e^{-x}\\ =&\frac{e^{-x}}{(1+e^{-x})^2} \\ =&\frac{1+e^{-x}-1}{(1+e^{-x})^2} \\ =&\frac{1+e^{-x}}{(1+e^{-x})^2} - \frac{1}{(1+e^{-x})^2} \\ =&\frac{1}{(1+e^{-x})}(1-\frac{1}{(1+e^{-x})}) \\ =&\sigma(x)(1-{\sigma(x)}) \end{aligned}σ(x)========?[(1+e?x)?1](?1)(1+e?x)?2(?1)e?x(1+e?x)?2e?x(1+e?x)2e?x?(1+e?x)21+e?x?1?(1+e?x)21+e?x??(1+e?x)21?(1+e?x)1?(1?(1+e?x)1?)σ(x)(1?σ(x))?

用于隱層神經元輸出,取值范圍為(0,1),它可以將一個實數映射到(0,1)的區間,可以用來做二分類。在特征相差比較復雜或是相差不是特別大時效果比較好。Sigmoid作為激活函數有以下優缺點:

優點:

  • 輸出范圍有限,數據在傳遞的過程中不容易發散。
  • 輸出范圍為(0,1),所以可以用作輸出層,輸出表示概率。
  • 抑制兩頭,對中間細微變化敏感,對分類有利。
  • 在特征相差比較復雜或是相差不是特別大時效果比較好。

缺點:

  • 梯度消失(Gradient Vanishing)會導致backpropagate時,w的系數太小,w更新很慢。所以對初始化時要特別注意,避免過大的初始值使神經元進入飽和區。
  • 輸出不是zero-center 這會導致后層的神經元的輸入是非0均值的信號,這會對梯度產生影響:假設后層神經元的輸入都為正(e.g. x>0 elementwise in ),那么對w求局部梯度則都為正,這樣在反向傳播的過程中w要么都往正方向更新,要么都往負方向更新,導致有一種捆綁的效果,使得收斂緩慢。 如果你是按batch去訓練,那么每個batch可能得到不同的符號(正或負),那么相加一下這個問題還是可以緩解
  • 指數運算耗時,計算效率低

自定義Sigmoid

class SelfDefinedSigmoid(torch.autograd.Function):@staticmethoddef forward(ctx, inp):result = torch.divide(torch.tensor(1), (1 + torch.exp(-inp)))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 * result * (1 - result)class Sigmoid(nn.Module):def __init__(self):super().__init__()def forward(self, x):out = SelfDefinedSigmoid.apply(x)return out

與Torch定義的比較

# self defined torch.manual_seed(0)sigmoid = Sigmoid() # SelfDefinedSigmoid inp = torch.randn(5, requires_grad=True) out = 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([0.9984, 0.6223, 0.8005, 0.9213, 0.5018],grad_fn=<SelfDefinedSigmoidBackward>)First call tensor([ 0.0080, 0.3322, -0.3765, 0.2275, -0.0423])Second call tensor([ 0.0159, 0.6643, -0.7530, 0.4549, -0.0845])Call after zeroing gradients tensor([ 0.0080, 0.3322, -0.3765, 0.2275, -0.0423]) # torch defined torch.manual_seed(0) inp = torch.randn(5, requires_grad=True) out = torch.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([0.9984, 0.6223, 0.8005, 0.9213, 0.5018], grad_fn=<SigmoidBackward>)First call tensor([ 0.0080, 0.3322, -0.3765, 0.2275, -0.0423])Second call tensor([ 0.0159, 0.6643, -0.7530, 0.4549, -0.0845])Call after zeroing gradients tensor([ 0.0080, 0.3322, -0.3765, 0.2275, -0.0423])

從上面結果,可以看出與torch定義sigmoid得到是一樣的結果

可視化

# visualization inp = torch.arange(-8, 8, 0.1, requires_grad=True) out = sigmoid(inp) out.sum().backward()inp_grad = inp.gradplt.plot(inp.detach().numpy(),out.detach().numpy(),label=r"$\sigma(x)=\frac{1}{1+e^{-x}} $",alpha=0.7) plt.plot(inp.detach().numpy(),inp_grad.numpy(),label=r"$\sigma'(x)$",alpha=0.5) plt.grid() plt.legend() plt.show()

總結

以上是生活随笔為你收集整理的Pytorch 自定义激活函数前向与反向传播 sigmoid的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。