PyTorch中三角函数与特殊运算详解和实战场景示例

发布于:2025-08-07 ⋅ 阅读:(13) ⋅ 点赞:(0)

在 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 控制数据范围,避免梯度爆炸或损失异常


网站公告

今日签到

点亮在社区的每一天
去签到