《深度学习入门》读书笔记3.1:Python实现导数

导数

导数表示的是某个瞬间的变化量:

d f ( x ) d x = lim h 0 f ( x + h ) f ( x ) h \frac{df(x)}{dx}=\lim_{h \to0} \frac{f(x+h)-f(x)}{h}
h 0 h \to0 怎么表示呢?
方案一:h = 1-50

def numerical_diff(f, x):
	h = 1e-50
    return (f(x+h) - f(x)) / h
问题1:
h = 1 -50这个微小值会被舍入误差,比如python用float32类型(32位浮点数)来表示即 np.float32(1e-50)输出为0.0,改为10 -4就行
问题2:
我们用上述的计算出来的导数在严格意义上并不一致,这个差异的出现是因为h不可能无限接近0
在这里插入图片描述
如图所示,数值微分含有误差。为了减小这个误差,我们可以计算函数f在(x + h)和(x − h)之间的差分。因为这种计算方法以x为中心,计算它左右两边的差分,所以也称为中心差分(而(x + h)和x之间的差分称为前向差分)。
def numerical_diff(f, x):
 h = 1e-4 # 0.0001
 return (f(x+h) - f(x-h)) / (2*h)

偏导数

偏导数和单变量的导数一样,都是求某个地方的斜率。不过,偏导数需要将多个变量中的某一个变量定为目标变量,并将其他变量固定为某个值,为了将目标变量以外的变量固定到某些特定的值上,我们定义了新函数。然后,对新定义的函数应用了之前的求数值微分的函数,得到偏导数

梯度

梯度指示的方向是各点处的函数值减小最多的方向

def numerical_gradient(f, x):
 h = 1e-4 # 0.0001
 grad = np.zeros_like(x) # 生成和x形状相同的数组
 for idx in range(x.size):
 tmp_val = x[idx]
 # f(x+h)的计算
 x[idx] = tmp_val + h
 fxh1 = f(x)
 # f(x-h)的计算
 x[idx] = tmp_val - h
 fxh2 = f(x)
 grad[idx] = (fxh1 - fxh2) / (2*h)
 x[idx] = tmp_val # 还原值
 return grad

机器学习的主要任务是在学习时寻找最优参数。同样地,神经网络也必须在学习时找到最优参数(权重和偏置)。这里所说的最优参数是指损失函数取最小值时的参数。但是,一般而言,损失函数很复杂,参数空间庞大,我们不知道它在何处能取得最小值。而通过巧妙地使用梯度来寻找函数最小值(或者尽可能小的值)的方法就是梯度法

虽然梯度的方向并不一定指向最小值,但沿着它的方向能够最大限度地减小函数的值。因此,在寻找函数的最小值(或者尽可能小的值)的位置的任务中,要以梯度的信息为线索,决定前进的方向。

此时梯度法就派上用场了。在梯度法中,函数的取值从当前位置沿着梯度方向前进一定距离,然后在新的地方重新求梯度,再沿着新梯度方向前进,如此反复,不断地沿梯度方向前进。像这样,通过不断地沿梯度方向前进,逐渐减小函数值的过程就是梯度法(gradient method)。梯度法是解决机器学习中最优化问题的常用方法,特别是在神经网络的学习中经常被使用。

def gradient_descent(f, init_x, lr=0.01, step_num=100):
 x = init_x
 for i in range(step_num):
 	grad = numerical_gradient(f, x)
 	x -= lr * grad
 return x
发布了178 篇原创文章 · 获赞 140 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_42146775/article/details/104556238
今日推荐