2.4微分
用微分解决问题的思想,把一个比较大(或者无法用常规方法解决)的问题无限分割,直到问题缩小到能够比较简单的解决。深度学习中,我们训练模型,不断更新他们,使他们的效果变得更好。衡量模型有多好的标准,是损失函数。
2.4.1 导数与微分
关于导数的例子:
import matplotlib.pyplot as plt
import numpy as np
from IPython import display
from d2l import torch as d2l
def f(x): # 定义函数
return 3 * x ** 2 - 4 * x
def numberical_lim(f, x, h):
return (f(x + h) - f(x)) / h
h = 0.1
for i in range(5):
print(f'h={h:.5f},numberical lim={numberical_lim(f, 2, h):.5f}') # 当x=2时,计算其导数
h *= 0.1
def use_svg_display(): # 使用svg格式在调用显示绘图
display.set_matplotlib_formats('svg')
def set_figsize(figzize=(3.5, 2.5)): # 设置matplotlib图表的大小。
use_svg_display()
d2l.plt.rcParams['figure.figsize'] = figzize
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend): # 设置matplotlib的轴
axes.set_xlabel(xlabel)
axes.set_ylabel(ylabel)
axes.set_xscale(xscale)
axes.set_yscale(yscale)
axes.set_xlim(xlim)
axes.set_ylim(ylim)
if legend:
axes.legend(legend)
axes.grid()
def plot(X, Y=None, xlabel=None, ylabel=None, legend=None, xlim=None,
ylim=None, xscale='linear', yscale='linear',
fmts=('-', 'm--', 'g-.', 'r:'), figsixe=(3.5, 2.5), axes=None):
if legend is None:
legend = []
set_figsize(figsixe)
axes = axes if axes else d2l.plt.gca()
# 如果 “X”有一个轴,则输出Ture
def has_one_axis(X):
return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list) and not hasattr(X[0], "__len__"))
if has_one_axis(X):
X = [X]
if Y is None:
X, Y = [[]] * len(X), X
elif has_one_axis(Y):
Y = [Y]
if len(X) != len(Y):
X = X * len(Y)
axes.cla()
for x, y, fmt in zip(X, Y, fmts):
if len(x):
axes.plot(x, y, fmt)
else:
axes.plot(y, fmt)
set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
x = np.arange(0, 3, 0.1)
plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)'])
plt.show()
2.4.2 偏导数
将导数的概念扩展到多元函数上,就有了偏导数的概念。
2.4.3 梯度
我们可以连结一个多元函数对其所有变量的偏导数,以得到该函数的梯度向量。梯度在深度学习模型训练的作用是提供一个正确的方向,梯度的方向即变化率最大的方向,更够更加快的找到目标,实现模型的优化。
2.2.4 链式法则
在很多时候,多元函数都是复合的,链式法则能使我们能够微分复合函数,即复合函数求导.
2.5 自动求导
深度学习框架可以自动计算求导,即自动求导,来加快这项工作。
实际中,根据我们设计的模型,系统会构建一个计算图,来跟踪计算是那些数据通过哪些操作组合产生的数据通过哪些操作组合起来产生输出。
2.5.1 grad()和backwark()函数
首先要先把张量的.requires_grad 属性设置为True
backward()是求导,会记录在grad中,grad的值会不断累加,使用之前需要清零
# 对函数y = 2x.T*x关于列向量x求导
import torch
x=torch.arange(4.0)
print(x)
x.requires_grad_(True)
print(x.grad) # 默认是None
y=2 *torch.dot(x,x) #函数y
print(y)
print(y.backward()) #y.backward 对函数y自动求梯度
print(x.grad)
print(x.grad==4*x)
#默认情况下,pytorch会累计梯度,我们需要清除之前的值
x.grad.zero_()
print(x.grad)
y=x.sum()
print(y)
y.backward() ## 标量才能使用backward()函数,如果是矩阵,需要.sum().backward
print(x.grad)
# 计算偏导数之和
x.grad.zero_()
y=x*x
print(torch.ones(len(x)))
y.sum().backward() #等价于y.backward(torch.ones(len(x))) 调用原矩阵和维度为1相乘,结果是原矩阵的和 相当于.sum()
print(x.grad)
x.grad.zero_()
y=x*x
u=y.detach() #分离出一个不需要梯度的变量
z=u*x
print(z)
print(z.sum())
z.sum().backward()
print(x.grad==u)
x.grad.zero_()
y.sum().backward()
print(x.grad)
print(x.grad==2*x)