在 PyTorch 中,三角函數(如 sin
, cos
, tan
等)和一些特殊數學運算(如雙曲函數、反三角函數、hypot
, atan2
, clamp
, lerp
, sigmoid
, softplus
, special
模塊等)被廣泛用于科學計算、機器學習、深度學習中的前向推理或梯度計算中。
PyTorch 中的三角函數與特殊運算詳解
1. 常見三角函數
torch.sin(input)
- 定義:對輸入張量每個元素計算正弦值
- 參數:
input (Tensor)
– 輸入張量(角度以弧度為單位) - 返回值:返回一個和
input
同形狀的張量,每個元素是sin(x)
- 示例:
import torch
x = torch.tensor([0, torch.pi/2, torch.pi])
y = torch.sin(x)
print(y) # tensor([0.0000, 1.0000, 0.0000])
torch.cos(input)
- 類似于
sin
,返回余弦值
torch.tan(input)
- 返回正切值(注意:
tan(π/2)
會出現無窮大)
torch.asin(input)
, torch.acos(input)
, torch.atan(input)
- 反三角函數,輸出的是角度(單位:弧度)
- 輸入值需在定義域內(
asin/acos
的輸入必須在[-1, 1]
)
torch.atan2(input, other)
-
定義:返回
atan(input / other)
,但能處理分母為 0 的情形,按象限返回正確角度 -
參數:
input
: 分子other
: 分母
-
示例:
a = torch.tensor([1.0])
b = torch.tensor([1.0])
print(torch.atan2(a, b)) # 輸出 π/4 ≈ 0.7854
torch.hypot(x, y)
- 定義:計算
sqrt(x2 + y2)
- 常用于二維向量的模長(歐幾里得范數)
x = torch.tensor([3.0])
y = torch.tensor([4.0])
print(torch.hypot(x, y)) # 輸出 tensor([5.])
2. 雙曲函數
torch.sinh
, torch.cosh
, torch.tanh
x = torch.tensor([0.0, 1.0])
print(torch.sinh(x)) # tensor([0.0000, 1.1752])
print(torch.tanh(x)) # tensor([0.0000, 0.7616])
3. 特殊數學函數(常用于神經網絡中)
torch.sigmoid(input)
- 返回:
1 / (1 + exp(-x))
- 常用于二分類模型輸出層
x = torch.tensor([-1.0, 0.0, 1.0])
print(torch.sigmoid(x)) # tensor([0.2689, 0.5000, 0.7311])
torch.nn.functional.softplus(input)
- 類似于平滑版的 ReLU:
log(1 + exp(x))
- 可用于避免 ReLU 的非可導性問題
import torch.nn.functional as F
x = torch.tensor([-1.0, 0.0, 1.0])
print(F.softplus(x)) # tensor([0.3133, 0.6931, 1.3133])
torch.lerp(start, end, weight)
- 線性插值:
(1 - weight) * start + weight * end
a = torch.tensor([0.0])
b = torch.tensor([10.0])
print(torch.lerp(a, b, 0.3)) # tensor([3.])
torch.clamp(input, min, max)
- 限制張量的最小最大范圍
x = torch.tensor([-2.0, 0.5, 3.0])
print(torch.clamp(x, min=0.0, max=1.0)) # tensor([0.0, 0.5, 1.0])
4. torch.special
模塊(高級特殊函數)
import torch.special as S# gamma 函數:S.gamma(x) = (x-1)!
x = torch.tensor([1.0, 2.0, 3.0])
print(S.gamma(x)) # tensor([1., 1., 2.])# erf 函數(高斯誤差函數)
print(S.erf(torch.tensor([0.0, 1.0]))) # tensor([0.0000, 0.8427])
常用 torch.special
函數包括:
函數名 | 功能 |
---|---|
special.erf | 高斯誤差函數 |
special.gammaln | gamma 函數的對數 |
special.logit | sigmoid 的反函數 |
special.expit | sigmoid 函數(別名) |
special.i0 | 第一類貝塞爾函數 |
special.digamma | gamma 函數的導數 |
總結對比表
函數 | 作用 | 說明 |
---|---|---|
torch.sin/cos/tan | 三角函數 | 輸入為弧度,輸出 [-1, 1] |
torch.asin/acos/atan | 反三角函數 | 返回弧度 |
torch.atan2 | atan(y/x) 并考慮象限 | 更安全的除法處理 |
torch.hypot | 計算 √(x2 + y2) | 常用于距離計算 |
torch.sigmoid | S型函數 | 常用于分類神經網絡 |
torch.softplus | 平滑 ReLU | 輸出始終 > 0 |
torch.clamp | 限定區間 | 防止梯度爆炸或數值異常 |
torch.lerp | 線性插值 | 用于圖像插值或平滑過渡 |
torch.special | 特殊函數模塊 | 包含 gamma、貝塞爾等高級函數 |
使用 PyTorch 計算三角函數的梯度(自動求導演示)
PyTorch 中只要一個張量啟用了 .requires_grad=True
,就可以使用 .backward()
自動求導。
示例 1:sin(x)
的梯度(導數為 cos(x)
)
import torchx = torch.tensor([torch.pi / 4], requires_grad=True) # 45度,sin(π/4) ≈ 0.7071
y = torch.sin(x) # y = sin(x)
y.backward() # 計算 dy/dx
print("y =", y.item())
print("dy/dx =", x.grad.item()) # 應該為 cos(π/4) ≈ 0.7071
輸出(大約):
y = 0.7071
dy/dx = 0.7071
示例 2:tanh(x)
的梯度(導數為 1 - tanh2(x)
)
x = torch.tensor([1.0], requires_grad=True)
y = torch.tanh(x)
y.backward()
print("y =", y.item())
print("dy/dx =", x.grad.item()) # 約為 1 - tanh(x)^2 ≈ 0.4199
輸出:
y = 0.7616
dy/dx = 0.4199
示例 3:sigmoid(x)
的梯度(導數為 s(x)*(1-s(x))
)
x = torch.tensor([0.0], requires_grad=True)
y = torch.sigmoid(x)
y.backward()
print("y =", y.item()) # 0.5
print("dy/dx =", x.grad.item()) # 0.5 * (1 - 0.5) = 0.25
示例 4:組合函數 + 多元素求導
x = torch.tensor([0.1, 0.2, 0.3], requires_grad=True)
y = torch.sin(x) + torch.cos(x)
z = y.sum() # 標量才能 .backward()
z.backward()
print("x.grad =", x.grad)
輸出大約為:
x.grad ≈ tensor([cos(0.1) - sin(0.1),cos(0.2) - sin(0.2),cos(0.3) - sin(0.3)])
注意事項
條件 | 說明 |
---|---|
requires_grad=True | 啟用自動求導 |
輸出必須是標量才能 .backward() | 否則需手動傳入梯度向量 |
.grad 只能用于葉子節點變量 | 中間變量(如 y)無 .grad |
多次 .backward() 需使用 retain_graph=True | 否則計算圖會被釋放 |
示例 5:對 special.erf()
求梯度
import torch.special as Sx = torch.tensor([0.5], requires_grad=True)
y = S.erf(x)
y.backward()
print("dy/dx =", x.grad.item()) # d/dx erf(x) = 2 / sqrt(pi) * exp(-x^2)
梯度驗證工具(額外推薦)
可以使用 torch.autograd.gradcheck
做數值梯度驗證(需要使用 double
類型):
from torch.autograd import gradcheckx = torch.tensor([0.5], dtype=torch.double, requires_grad=True)
test = gradcheck(torch.sin, (x,), eps=1e-6, atol=1e-4)
print("Sin gradcheck:", test)
實際神經網絡中使用示例
下面我們深入介紹 在實際神經網絡中如何使用 PyTorch 的三角函數和特殊函數(如 sin、sigmoid、softplus 等),特別是它們在 loss 函數、自定義激活、周期性建模等場景中的實際用法。
場景 1:周期性數據建模(比如時間、角度)用 sin/cos
應用背景:
對于 角度、時間(24小時) 等周期性輸入,用 sin/cos
編碼能避免 0° 和 360° 被認為相差很遠的問題。
示例:用 sin/cos
編碼輸入 + 簡單回歸網絡
import torch
import torch.nn as nn
import torch.nn.functional as Fclass SinCosNet(nn.Module):def __init__(self):super().__init__()self.fc = nn.Linear(2, 1) # 輸入是 sin 和 cos,輸出是預測值def forward(self, x_deg):x_rad = x_deg * torch.pi / 180x = torch.stack([torch.sin(x_rad), torch.cos(x_rad)], dim=1) # [N, 2]out = self.fc(x)return out# 模擬輸入:角度(以度為單位)
x_deg = torch.tensor([0.0, 90.0, 180.0, 270.0]).reshape(-1, 1)
y_true = torch.tensor([0.0, 1.0, 0.0, -1.0]).reshape(-1, 1) # 例如正弦值作為目標model = SinCosNet()
loss_fn = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)# 前向 + 反向 + 更新
for epoch in range(200):pred = model(x_deg)loss = loss_fn(pred, y_true)optimizer.zero_grad()loss.backward()optimizer.step()print("預測值:", model(x_deg).detach().squeeze())
場景 2:使用 softplus
替代 ReLU 防止死神經
class SoftplusNet(nn.Module):def __init__(self):super().__init__()self.fc1 = nn.Linear(10, 64)self.fc2 = nn.Linear(64, 1)def forward(self, x):x = F.softplus(self.fc1(x)) # 使用 softplus 而不是 ReLUreturn self.fc2(x)
適用場景:
- 高穩定性訓練
- 避免 ReLU 導致的神經元“死亡”
- 和
sigmoid
搭配時,數值更平滑
場景 3:自定義 Loss 函數中使用 torch.atan2
, sin
, cos
示例:角度差異損失(用于姿態估計、旋轉預測)
def angular_loss(pred_angle, target_angle):"""計算兩個角度之間的最小差(結果范圍在 [-pi, pi])"""diff = pred_angle - target_anglediff = torch.atan2(torch.sin(diff), torch.cos(diff)) # wrap 到 [-pi, pi]return torch.mean(diff ** 2) # MSE 損失
應用背景:
- 預測角度(如相機旋轉、姿態)
- 避免直接使用
pred - target
導致 359° 和 0° 差異非常大
場景 4:使用 sigmoid
+ torch.special.logit
實現穩定反向函數 Loss
import torch.special as Sdef binary_target_loss(pred, target):pred = torch.clamp(pred, 1e-6, 1 - 1e-6) # 避免 logit 無窮大loss = torch.mean((S.logit(pred) - S.logit(target)) ** 2)return loss
應用背景:
- 對于二分類輸出,可以用 logit 空間計算差異,更穩定、更敏感
場景 5:周期函數的擬合(神經網絡擬合 sin 函數)
import matplotlib.pyplot as pltclass SineFitter(nn.Module):def __init__(self):super().__init__()self.net = nn.Sequential(nn.Linear(1, 64),nn.Tanh(),nn.Linear(64, 64),nn.Tanh(),nn.Linear(64, 1))def forward(self, x):return self.net(x)x = torch.linspace(-2*torch.pi, 2*torch.pi, 200).unsqueeze(1)
y = torch.sin(x)model = SineFitter()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
loss_fn = nn.MSELoss()for epoch in range(1000):pred = model(x)loss = loss_fn(pred, y)optimizer.zero_grad()loss.backward()optimizer.step()# 可視化
plt.plot(x.detach(), y, label="Ground Truth")
plt.plot(x.detach(), model(x).detach(), label="Predicted")
plt.legend()
plt.title("Sine Function Fitting")
plt.show()
總結:三角函數/特殊函數在神經網絡中的常見用途
應用領域 | 使用的函數 | 說明 |
---|---|---|
角度建模 | sin , cos , atan2 | 編碼/解碼周期性角度 |
激活函數 | softplus , tanh , sigmoid | 平滑激活、避免死神經 |
自定義損失函數 | atan2 , logit , erf | 更穩定地處理周期性/概率性誤差 |
函數擬合 | sin , special.* | 網絡學習任意復雜函數,特別是周期/光波類 |
數據歸一化或變換 | clamp , lerp , special.logit | 控制數據范圍,避免梯度爆炸或損失異常 |