Autograd自动微分库使用教程:从基础到实战
为什么需要Autograd?
在机器学习和科学计算领域,我们经常需要计算复杂函数的导数。传统方法主要有两种:
- 手动推导并实现导数计算
- 使用Theano或TensorFlow等框架的限制性语法
Autograd提供了第三种选择:使用标准的Numpy库编写函数,Autograd会自动计算其梯度。这种方法既保持了编程的灵活性,又省去了手动推导的麻烦。
Autograd基础用法
Autograd的核心是grad
函数,它接收一个函数并返回该函数的导数计算函数。需要注意的是,目标函数的输出必须是标量值(单个浮点数)。
基本示例:泰勒展开近似正弦函数
import autograd.numpy as np # Autograd封装的Numpy
from autograd import grad
def taylor_sine(x): # 使用泰勒级数近似正弦函数
ans = currterm = x
i = 0
while np.abs(currterm) > 0.001:
currterm = -currterm * x**2 / ((2 * i + 3) * (2 * i + 2))
ans = ans + currterm
i += 1
return ans
grad_sine = grad(taylor_sine)
print("π处的梯度是:", grad_sine(np.pi))
这个例子展示了Autograd的强大之处:它能正确处理循环和条件判断等控制流结构。
实战案例:逻辑回归
让我们通过一个完整的逻辑回归示例来展示Autograd的实际应用:
import autograd.numpy as np
from autograd import grad
def sigmoid(x):
return 0.5 * (np.tanh(x / 2.) + 1)
def logistic_predictions(weights, inputs):
# 计算逻辑回归模型的预测概率
return sigmoid(np.dot(inputs, weights))
def training_loss(weights):
# 训练损失是训练标签的负对数似然
preds = logistic_predictions(weights, inputs)
label_probabilities = preds * targets + (1 - preds) * (1 - targets)
return -np.sum(np.log(label_probabilities))
# 构建小型数据集
inputs = np.array([[0.52, 1.12, 0.77],
[0.88, -1.08, 0.15],
[0.52, 0.06, -1.30],
[0.74, -2.49, 1.39]])
targets = np.array([True, True, False, True])
# 使用Autograd创建梯度计算函数
training_gradient_fun = grad(training_loss)
# 梯度下降优化权重
weights = np.array([0.0, 0.0, 0.0])
print("初始损失:", training_loss(weights))
for i in range(100):
weights -= training_gradient_fun(weights) * 0.01
print("训练后损失:", training_loss(weights))
Autograd工作原理
Autograd通过以下步骤实现自动微分:
- 计算图构建:在执行函数时记录所有操作
- 反向模式微分:从输出向输入反向传播梯度
- 向量-雅可比积:高效计算梯度而不显式构造雅可比矩阵
反向模式微分的优势
对于输入维度高、输出为标量的函数(如机器学习中的损失函数),反向模式微分比正向模式或有限差分法更高效。在机器学习中,这被称为"反向传播"。
支持的Numpy/Scipy功能
Autograd支持大多数Numpy操作,包括:
- 数学运算
- 数组和矩阵操作
- 线性代数函数
- 快速傅里叶变换
- 复数运算
- N维卷积
使用限制
- 不支持数组赋值操作(如
A[i,j] = x
) - 不支持
A.dot(B)
语法(应使用np.dot(A,B)
) - 避免原地操作(如
a += b
) - 某些
isinstance
检查需要使用Autograd提供的版本
扩展Autograd:自定义原语
当Autograd不支持某个函数时,可以自定义其梯度计算:
from autograd.extend import primitive, defvjp
@primitive
def logsumexp(x):
"""数值稳定的log(sum(exp(x)))"""
max_x = np.max(x)
return max_x + np.log(np.sum(np.exp(x - max_x)))
def logsumexp_vjp(ans, x):
x_shape = x.shape
return lambda g: np.full(x_shape, g) * np.exp(x - np.full(x_shape, ans))
defvjp(logsumexp, logsumexp_vjp)
复数支持
Autograd采用特定约定支持复数运算:
- 对于全纯函数,得到常规复导数
- 对于复参数的实值损失函数,结果可用于基于梯度的优化器
- 对于内部使用复数运算的实值函数,结果与纯实数实现一致
性能优化建议
- 避免不必要的计算图构建
- 对于重复计算,考虑缓存梯度函数
- 使用Autograd提供的
builtins
模块进行类型检查 - 对于性能关键部分,考虑自定义原语
Autograd将自动微分的能力带入了标准的Python和Numpy编程环境中,使研究人员能够快速实验新模型而无需手动推导梯度或学习新的框架语法。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考