深度学习之神经网络(二)

深度学习之神经网络(一)

在前面文章中,我们已经系统了解了神经网络的部分概念,以及如何去搭建一个简单的神经网络模型。这篇文章我将主要讲解损失函数、反向传播等神经网络知识。


1. 损失函数

之前我们已经提到,损失函数就是用来计算我们的结果与真实值之间的误差,从而指导进一步的训练向正确的方向进行。

损失函数可以分为两大类:回归、分类。

1.1 回归损失

回归类的损失函数主要有MAE和MSE等。

1.1.1 MAE(Mean Absolute Error)

MAE为平均绝对误差,简单说就是计算输出值与真实值之间的误差绝对值大小的平均值。MAE是一种线性分数,所有个体差异在平均值上的权重都相等,比如,10和0之间的绝对误差是5和0之间绝对误差的两倍:

$$MAE(X,h)=\frac{1} {m}\sum_{i=1}^m | h(x_i)-y_i) |$$

  • 在高纬任务中表现比较好
  • 预测速度快
  • 对outliers(异常值)不敏感

1.1.2 MSE(Mean Square Error)

MSE为均方误差:

$$MSE(X,h)=\frac{1} {m}\sum_{i=1}^m (h(x_i)-y_i))^2$$

  • 比绝对误差函数得到的结果更精准
  • 对大的误差输出更敏感
  • 对outliers很敏感

1.2 分类损失

1.2.1 Cross-Entropy Loss

交叉熵损失,常在分类问题中使用,随着预测概率偏离实际标签,交叉熵会逐渐增加:

$$H(y,f)=-\sum_{i=1}^m y_i log(f(x_i))$$

  • 交叉熵能够衡量同一个随机变量中的两个不同概率分布的差异程度,在机器学习中就表示为真实概率分布与预测概率分布之间的差异。
  • 交叉熵经常搭配softmax使用,将输出的结果进行处理,使其多个分类的预测值和为1,再通过交叉熵来计算损失。


损失函数已经简单介绍完了,我们该如何训练神经网络,使得我们的损失最小呢?我们知道,梯度下降法是机器学习中一种用来“学习”参数的方法,神经网络中则可称为“反向传播”法。

2. 反向传播

前向传递输入信号直至输出产生误差,反向传播误差信息更新权重矩阵。

简单来说就是求偏导以及高数中的链式法则。(这里放个链接:反向传播,此文讲解的非常清楚)

假如我们有这样的一个数据集:

姓名 身高 体重 性别
张三 170 62
陈四 175 65
王霞 160 45
李红 165 50

 为了方便处理,对其进行一定的处理:

 我们现在的目标就是训练一个神经网络,来预测性别:深度学习之神经网络(二)

代码示例:

import numpy as np


def sigmoid(x):
    # activation function
    return 1 / (1 + np.exp(-x))


def deriv_sigmoid(x):
    # derivative of sigmoid
    z = sigmoid(x)
    return z*(1 - z)


def mse_loss(y, yhat):
    # loss functionon
    return ((y - yhat) ** 2).mean()


class my_NN(object):
    # set all weights and biases
    def __init__(self):
        self.w1, self.w2, self.w3, self.w4, self.w5, self.w6 = np.random.randn(6)
        self.b1, self.b2, self.b3 = np.random.randn(3)

    def train(self, inputs, y_true):
        learn_rate = 0.1  # learning rate
        epochs = 1000  # number of times to loop through the entire dataset

        for epoch in range(epochs):
            # feedforward
            for x, y in zip(inputs, y_true):
                out_h1 = sigmoid(self.w1 * x[0] + self.w2 * x[1] + self.b1)
                out_h2 = sigmoid(self.w3 * x[0] + self.w4 * x[1] + self.b2)
                out_o1 = self.w5 * out_h1 + self.w6 * out_h2 + self.b3
                y_pred = sigmoid(out_o1)


                # - - - Naming: d_L_d_w1 represents "partial L / partial w1"
                # start calculating the backward error

                d_L_d_ypred = -2 * (y_true - y_pred)

                # the neuron in the output layer
                d_ypred_d_w5 = out_h1 * deriv_sigmoid(out_o1)
                d_ypred_d_w6 = out_h2 * deriv_sigmoid(out_o1)
                d_ypred_d_b3 = deriv_sigmoid(out_o1)

                d_ypred_d_h1 = self.w5 * deriv_sigmoid(out_o1)
                d_ypred_d_h2 = self.w6 * deriv_sigmoid(out_o1)

                # the one neuron in the hidden layer
                d_h1_d_w1 = x[0] * deriv_sigmoid(out_h1)
                d_h1_d_w2 = x[1] * deriv_sigmoid(out_h1)
                d_h1_d_b1 = deriv_sigmoid(out_h1)

                # another one
                d_h2_d_w3 = x[0] * deriv_sigmoid(out_h2)
                d_h2_d_w4 = x[0] * deriv_sigmoid(out_h2)
                d_h2_d_b2 = deriv_sigmoid(out_h2)

                # - - - update weights and biases
                # the neuron in the output layer
                self.w5 -= learn_rate * d_L_d_ypred * d_ypred_d_w5
                self.w6 -= learn_rate * d_L_d_ypred * d_ypred_d_w6
                self.b3 -= learn_rate * d_L_d_ypred * d_ypred_d_b3

                # the one neuron in the hidden layer
                self.w1 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w1
                self.w2 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w2
                self.b1 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_b1

                # another one
                self.w3 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w3
                self.w4 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w4
                self.b2 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_b2

            if (epoch+1)% 100 == 0:
                loss = mse_loss(y_true, y_pred)
                print("第%d次,loss为 %.5f" %(epoch+1, loss))


x = np.array([[15, 22],
             [20, 25],
             [5, 5],
             [10, 10],])

y = np.array([1,
              1,
              0,
              0,
              ])

mynn=my_NN()
mynn.train(x, y)

训练结果为:

第100次,loss为 0.00252
第200次,loss为 0.00119
第300次,loss为 0.00077
第400次,loss为 0.00057
第500次,loss为 0.00045
第600次,loss为 0.00038
第700次,loss为 0.00032
第800次,loss为 0.00028
第900次,loss为 0.00025
第1000次,loss为 0.00022

小结:梯度下降法是general的优化算法,反向传播法是其在神经网络上的具体实现方式。(开始以为它们两个都是相互独立的算法...)

上一篇:H2数据库学习


下一篇:Spring Boot 和 Hibernate 的 H2 数据库配置来进行启动测试