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

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

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


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. 反向传播

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

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

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

姓名身高体重性别
张三17062
陈四17565
王霞16045
李红16550

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

 我们现在的目标就是训练一个神经网络,来预测性别:

代码示例:

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 feedforward(self, x):
        h1 = sigmoid(self.w1 * x[0] + self.w2 * x[1] + self.b1)
        h2 = sigmoid(self.w3 * x[0] + self.w4 * x[1] + self.b2)
        o1 = sigmoid(self.w5 * h1 + self.w6 * h2 + self.b3)
        return o1

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

        for epoch in range(epochs):
            for x, y_true in zip(inputs, y_trues):
                # feedforward
                sum_h1 = self.w1 * x[0] + self.w2 * x[1] + self.b1
                h1 = sigmoid(sum_h1)

                sum_h2 = self.w3 * x[0] + self.w4 * x[1] + self.b2
                h2 = sigmoid(sum_h2)

                sum_o1 = self.w5 * h1 + self.w6 * h2 + self.b3
                o1 = sigmoid(sum_o1)
                y_pred = o1

                # starting calculating the backward error
                # --- Naming: d_L_d_w1 represents "partial L / partial w1"
                d_L_d_ypred = -2 * (y_true - y_pred)

                # the neuron in the output layer
                d_ypred_d_w5 = h1 * deriv_sigmoid(sum_o1)
                d_ypred_d_w6 = h2 * deriv_sigmoid(sum_o1)
                d_ypred_d_b3 = deriv_sigmoid(sum_o1)

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

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

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

                # --- Update weights and biases
                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

                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

                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

            if (epoch+1) % 100 == 0:
                y_preds = np.apply_along_axis(self.feedforward, 1, inputs)
                loss = mse_loss(y_trues, y_preds)
                print("第%d次 loss: %.3f" % (epoch+1, loss))


data = np.array([
    [5, 15],
    [10, 20],
    [-3, -3],
    [1, 0],
])

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

mynn = my_NN()
mynn.train(data, y_true)
Amy = np.array([0, 0]) # gender:F
print("predict: %.3f" %mynn.feedforward(Amy))

训练结果为:

第100次 loss: 0.115
第200次 loss: 0.032
第300次 loss: 0.012
第400次 loss: 0.007
第500次 loss: 0.005
第600次 loss: 0.004
第700次 loss: 0.003
第800次 loss: 0.002
第900次 loss: 0.002
第1000次 loss: 0.002
predict: 0.065

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

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值