深度学习入门——神经网络的学习

神经网络的学习

从数据中学习

神经网络的特征就是可以从数据中学习。所谓“从数据中学习”,是指可以由数据自动决定权重参数的值。在实际的神经网络中,参数的数量成千上万,在层数更深的深度学习中,参数的数量甚至可以上亿,想要人工决定这些参数的值是不可能的。

在神经网络中,机器可以学习图像中的重要特征量,神经网络的优点是对所有的问题都可以用同样的流程来解决。

训练数据和测试数据

机器学习中,一般将数据分为训练数据和测试数据两部分来进行学习和实验等。首先,使用训练数据进行学习,寻找最优的参数;然后,使用测试数据评价训练得到的模型的实际能力。为什么需要将数据分为训练数据和测试数据呢?因为我们追求的是模型的泛化能力。为了正确评价模型的泛化能力,就必须划分训练数据和测试数据。另外,训练数据也可以称为监督数据。

泛化能力是指处理未被观察过的数据(不包含在训练数据中的数据)的能力。获得泛化能力是机器学习的最终目标。

过拟合是可以顺利地处理某个数据集,但无法处理其他数据集的情况,是只对某个数据集过度拟合的状态。

损失函数

损失函数是表示神经网络性能的“恶劣程度”的指标,即当前的神经网络对监督数据在多大程度上不拟合,在多大程度上不一致。以“性能的恶劣程度”为指标可能会使人感到不太自然,但是如果给损失函数乘上一个负值,就可以解释为“在多大程度上不坏”,即“性能有多好”。常见的有均方误差和交叉熵误差。

均方误差

公式如下:
E = 1 2 ∑ k ( y k − t k ) 2 E=\frac{1}{2}\sum_{k}(y_k-t_k)^2 E=21k(yktk)2
这里, y k y_k yk表示神经网络的输出, t k t_k tk表示监督数据,k表示数据的维度。

python实现代码:

def mean_squared_error(y, t):
    return 0.5 * np.sum((y - t)**2)

交叉熵误差

公式如下:
E = − ∑ k t k l o g y k E=-\sum_{k}t_klogy_k E=ktklogyk
这里,log表示以e为底数的自然对数( l o g e log_e loge)。 y k y_k yk是神经网络的输出, t k t_k tk是正确解标签。并且, t k t_k tk中只有正确解标签的索引为1,其他均为0。交叉熵误差的值是由正确解标签所对应的输出结果决定的。

python实现代码:

def cross_entropy_error(y, t):
    delta = 1e-7
    return -np.sum(t * np.log(y + delta))

这里,参数y和t是NumPy数组。函数内部在计算np.log时,加上了一个微小值delta。这是因为,当出现np.log(0)时,np.log(0)会变为负无限大的-inf,这样一来就会导致后续计算无法进行。作为保护性对策,添加一个微小值可以防止负无限大的发生。

使用批次进行训练

在深度学习中,Batch(批次)是指一次性输入到神经网络的一组训练样本。相比于逐个样本- 进行训练,以批次方式处理数据可以带来一些优势。

  • 训练效率:批次训练可以利用并行计算的优势,加速整个训练过程。通过同时处理多个样本,可以有效地利用计算资源,例如GPU的并行计算能力,加快模型的训练速度。

  • 模型更新:使用批次训练可以在一次前向传播和反向传播中计算所有样本的梯度,并在批次结束时对模型参数进行一次更新。这样可以使模型参数的更新更加平滑和稳定,减少训练过程中的波动性。

  • 内存使用:批次训练可以有效地利用内存,尤其是当处理大规模数据集时。通过将多个样本组合成批次进行处理,可以减少内存的使用量,使得模型可以处理更大规模的数据。

  • 泛化性能:使用批次训练可以提供更多的样本信息,使得模型能够更好地学习数据的统计特征,从而提高模型的泛化能力。

利用损失函数调参原理

假设有一个神经网络,现在我们来关注这个神经网络中的某一个权重参数。此时,对该权重参数的损失函数求导,表示的是“如果稍微改变这个权重参数的值,损失函数的值会如何变化”。如果导数的值为负,通过使该权重参数向正方向改变,可以减小损失函数的值;反过来,如果导数的值为正,则通过使该权重参数向负方向改变,可以减小损失函数的值。不过,当导数的值为0时,无论权重参数向哪个方向变化,损失函数的值都不会改变,此时该权重参数的更新会停在此处。

之所以不能用识别精度作为指标,是因为这样一来绝大多数地方的导数都会变为0,导致参数无法更新。识别精度对微小的参数变化基本上没有什么反应,即便有反应,它的值也是不连续地、突然地变化。作为激活函数的阶跃函数也有同样的情况。出于相同的原因,如果使用阶跃函数作为激活函数,神经网络的学习将无法进行。所以损失函数必须是连续平滑的。

数值微分

导数

定义公式:
d f ( x ) d x = lim ⁡ x → 0 f ( x + h ) − f ( x ) h \frac{df(x)}{dx}=\lim_{x \to 0} \frac{f(x+h)-f(x)}{h} dxdf(x)=x0limhf(x+h)f(x)

向h中赋入一个微小值即可程序实现:

def numerical_diff(f, x):
    h = 10e-50
    return (f(x+h) - f(x)) / h

上述程序表示x到x-h之间的斜率,真的倒数是x处的斜率,可以通过求x-h到x+h之间的斜率来减小误差。

def numerical_diff(f, x):
    h = 10e-50
    return (f(x+h) - f(x-h)) / h

偏导数和梯度

上述中讲了一个变量的倒数求法,对于多个变量求导则称为偏导数,求偏导数的方法是令一个变量为目标变量,其他变量固定为常量,从而对那一个目标变量求导。的由全部变量的偏导数汇总而成的向量称为梯度(gradient),梯度实现方法如下:

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

机器学习的主要任务是在学习时寻找最优参数。同样地,神经网络也必须在学习时找到最优参数(权重和偏置)。这里所说的最优参数是指损失函数取最小值时的参数。通过使用梯度来寻找函数最小值的方法就是梯度法。

注意:在一些复杂的函数中,梯度为0的点不一定是最值点,函数的极值,最值以及称为鞍点的地方梯度为0,极值为局部最值,鞍点是从某个方向看是极大值,从另一个方向看则是极小值的点,此外,当函数很复杂且呈扁平状时,学习可能会进入一个(几乎)平坦的地区,陷入被称为“学习高原”的无法前进的停滞期。

梯度法数学式:
x 0 = x 0 − η ∂ f ∂ x 0 x_0=x_0- \eta \frac{\partial f}{\partial x_0} x0=x0ηx0f
x 1 = x 1 − η ∂ f ∂ x 1 x_1=x_1- \eta \frac{\partial f}{\partial x_1} x1=x1ηx1f
η表示更新量,在神经网络的学习中,称为学习率。学习率决定在一次学习中,应该学习多少,以及在多大程度上更新参数。

python程序实现梯度下降法:

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

参数f是要进行最优化的函数,init_x是初始值,lr是学习率learning rate,step_num是梯度法的重复次数。numerical_gradient(f,x)会求函数的梯度,用该梯度乘以学习率得到的值进行更新操作,由step_num指定重复的次数。

学习率这样的参数称为超参数。这是一种和神经网络的参数(权重和偏置)性质不同的参数。相对于神经网络的权重参数是通过训练数据和学习算法自动获得的,学习率这样的超参数则是人工设定的。一般来说,超参数需要尝试多个值,以便找到一种可以使学习顺利进行的设定。

你可能感兴趣的:(深度学习,神经网络,学习)