前言
学习是一个实践与认知的反复过程,所以要不停地去实践代码,因此本人习惯在写代码的过程中封一些方法用在实践中使用,能够更方便自己调用。但是也难免遇到些问题。
一、记录下遇见的一个小问题
“鱼叔”的第四章有一个梯度计算公式,其书中代码如下:
def numerical_gradient(f, x)
h = le-4 #0.0001
grad = np.zeros_like(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
该段代码被我学完,测试完,封起来后没有举一反三就过去了,结果后续学习就出问题了。
二、问题分析
封装后的代码如下:
class LossFunction:
-----snip--------
@staticmethod
def numerical_gradient2(f, x):
"""梯度"""
h = 1e-4 # 0.0001
grad = np.zeros_like(x)
for idx in range(x.size):
tmp_val = x[idx]
x[idx] = tmp_val+ h
fxh1 = f(x) # f(x+h)
x[idx] = tmp_val - h
fxh2 = f(x) # f(x-h)
grad[idx] = (fxh1 - fxh2) / (2 * h)
x[idx] = tmp_val # 还原值
return grad
直到后续的神经网络的梯度学习(p108),测试的时候发现问题了,索引超界了,回头找问题才发现,封装的这个方法只适合单个向量,有些粗心了。同时在练习书本代码时,最好也要参考下作者的例程,不然可能会漏掉一些书本上没有的知识点。
附录
由函数中我们可以看到其做了一个判断,即当输入为向量时就按照原有的函数,如果超过了一维,则将其变成“多个一维数组计算”再按照idx组成该数组。
def _numerical_gradient_no_batch(f, x):
h = 1e-4 # 0.0001
grad = np.zeros_like(x)
for idx in range(x.size):
tmp_val = x[idx]
x[idx] = float(tmp_val) + h
fxh1 = f(x) # f(x+h)
x[idx] = tmp_val - h
fxh2 = f(x) # f(x-h)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 还原值
return grad
def numerical_gradient(f, X):
if X.ndim == 1:
return _numerical_gradient_no_batch(f, X)
else:
grad = np.zeros_like(X)
for idx, x in enumerate(X):
grad[idx] = _numerical_gradient_no_batch(f, x)
return grad