在 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(x² + y²)
- 常用于二维向量的模长(欧几里得范数)
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 |
计算 √(x² + y²) | 常用于距离计算 |
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 torch
x = 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 - tanh²(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 S
x = 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 gradcheck
x = 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 F
class 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 / 180
x = 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 而不是 ReLU
return self.fc2(x)
适用场景:
- 高稳定性训练
- 避免 ReLU 导致的神经元“死亡”
- 和
sigmoid
搭配时,数值更平滑
场景 3:自定义 Loss 函数中使用 torch.atan2
, sin
, cos
示例:角度差异损失(用于姿态估计、旋转预测)
def angular_loss(pred_angle, target_angle):
"""
计算两个角度之间的最小差(结果范围在 [-pi, pi])
"""
diff = pred_angle - target_angle
diff = 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 S
def 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 plt
class 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 |
控制数据范围,避免梯度爆炸或损失异常 |