从头推导与实现 BP 网络

回归模型

目标

学习 \(y = 2x\)

模型

单隐层、单节点的 BP 神经网络

策略

Mean Square Error 均方误差
\[ MSE = \frac{1}{2}(\hat{y} - y)^2 \]

模型的目标是 \(\min \frac{1}{2} (\hat{y} - y)^2\)

算法

朴素梯度下降。在每个 epoch 内,使模型对所有的训练数据都误差最小化。

网络结构

Forward Propagation Derivation

\[ E = \frac{1}{2}(\hat{Y}-Y)^2 \\ \hat{Y} = \beta \\ \beta = W b \\ b = sigmoid(\alpha) \\ \alpha = V x \]

Back Propagation Derivation

模型的可学习参数为 \(w,v\) ,更新的策略遵循感知机模型:

参数 w 的更新算法
\[ w \leftarrow w + \Delta w \\ \Delta w = - \eta \frac{\partial E}{\partial w} \\ \frac{\partial E}{\partial w} = \frac{\partial E}{\partial \hat{Y}} \frac{\partial \hat{Y}}{\partial \beta} \frac{\partial \beta}{\partial w} \\ = (\hat{Y} - Y) \cdot 1 \cdot b \]

参数 v 的更新算法
\[ v \leftarrow v + \Delta v \\ \Delta v = -\eta \frac{\partial E}{\partial v} \\ \frac{\partial E}{\partial v} = \frac{\partial E}{\partial \hat{Y}} \frac{\partial \hat{Y}}{\partial \beta} \frac{\partial \beta}{\partial b} \frac{\partial \beta}{\partial \alpha} \frac{\partial \alpha}{\partial v} \\ = (\hat{Y} - Y) \cdot 1 \cdot w \cdot \frac{\partial \beta}{\partial \alpha} \cdot x \\ \frac{\partial \beta}{\partial \alpha} = sigmoid(\alpha) [ 1 - sigmoid(\alpha) ] \\ sigmoid(\alpha) = \frac{1}{1+e^{-\alpha}} \]

代码实现

C++ 实现

#include <iostream>
#include <cmath>using namespace std;class Network {
public :Network(float eta) :eta(eta) {}float predict(int x) {  // forward propagationthis->alpha = this->v * x;this->b = this->sigmoid(alpha);this->beta = this->w * this->b;float prediction = this->beta;return prediction;}void step(int x, float prediction, float label) {this->w = this->w - this->eta * (prediction - label) * this->b;this->alpha = this->v * x;this->v = this->v - this->eta * (prediction - label) * this->w * this->sigmoid(this->alpha) * (1 - this->sigmoid(this->alpha)) * x;}
private:float sigmoid(float x) {return (float)1 / (1 + exp(-x));}float v = 1, w = 1, alpha = 1, beta = 1, b = 1, prediction, eta;
};int main() {  // Going to learn the linear relationship y = 2*xfloat loss, pred;Network model(0.01);cout << "x is " << 3 << " prediction is " << model.predict(3) << " label is " << 2*3 << endl;for (int epoch = 0; epoch < 500; epoch++) {loss = 0;for (int i = 0; i < 10; i++) {pred = model.predict(i);loss += pow((pred - 2*i), 2) / 2;model.step(i, pred, 2*i);}loss /= 10;cout << "Epoch: " << epoch << "  Loss:" << loss << endl;}cout << "x is " << 3 << " prediction is " << model.predict(3) << " label is " << 2*3 << endl;return 0;
}

C++ 运行结果

初始网络权重,对数据 x=3, y=6的 预测结果为 \(\hat{y} = 0.952534\) 。

训练了 500 个 epoch 以后,平均损失下降至 7.82519,对数据 x=3, y=6的 预测结果为 \(\hat{y} = 11.242\) 。

PyTorch 实现

# encoding:utf8
# 极简的神经网络,单隐层、单节点、单输入、单输出import torch as t
import torch.nn as nn
import torch.optim as optimclass Model(nn.Module):def __init__(self, in_dim, out_dim):super(Model, self).__init__()self.hidden_layer = nn.Linear(in_dim, out_dim)def forward(self, x):out = self.hidden_layer(x)out = t.sigmoid(out)return outif __name__ == '__main__':X, Y = [[i] for i in range(10)], [2*i for i in range(10)]X, Y = t.Tensor(X), t.Tensor(Y)model = Model(1, 1)optimizer = optim.SGD(model.parameters(), lr=0.01)criticism = nn.MSELoss(reduction='mean')y_pred = model.forward(t.Tensor([[3]]))print(y_pred.data)for i in range(500):optimizer.zero_grad()y_pred = model.forward(X)loss = criticism(y_pred, Y)loss.backward()optimizer.step()print(loss.data)y_pred = model.forward(t.Tensor([[3]]))print(y_pred.data)

PyTorch 运行结果

初始网络权重,对数据 x=3, y=6的 预测结果为 $\hat{y} =0.5164 $ 。

训练了 500 个 epoch 以后,平均损失下降至 98.8590,对数据 x=3, y=6的 预测结果为 \(\hat{y} = 0.8651\) 。

结论

居然手工编程的实现其学习效果比 PyTorch 的实现更好,真是奇怪!但是我估计差距就产生于学习算法的不同,PyTorch采用的是 SGD。

分类模型

目标

目标未知,因为本实验的数据集是对 iris 取前两类样本,然后把四维特征降维成两维,得到本实验的数据集。

数据简介:

-1.653443 0.198723 1 0  # 前两列为特正,最后两列“1 0”表示第一类
1.373162 -0.194633 0 1  # "0 1",第二类

模型

单隐层双输入输入节点的分类 BP 网络

策略

在整个模型的优化过程中,使得在整个训练集上交叉熵最小:
\[ \mathop{\arg\min}_{\theta} H(Y, \hat{Y}) \]

交叉熵:
\[ \begin{align} H(y, \hat y) & = -\sum_{i=1}^{2} y_i \log \hat{y}_i \\ & = - (y_1 \log \hat{y}_1 + y_2 \log \hat{y}_2) \end{align} \]

算法

梯度下降,也即在每个 epoch 内,使模型对所有的训练数据都误差最小。

网络结构

如图

Forward Propagation

公式推导如下

\[ a_1 = w_{11}x_1 + w_{21}x_2 \\ a_2 = w_{12}x_1 + w_{22}x_2 \\ b_1 = sigmoid(a_1) \\ b_2 = sigmoid(a_2) \\ \hat{y_1} = \frac{\exp(b_1)}{\exp(b_1) + \exp(b_2)} \\ \hat{y_2} = \frac{\exp(b_2)}{\exp(b_1) + \exp(b_2)} \\ \]

\[ \begin{align} E^{(k)} & = H(y^{(k)}, \hat{y}^{(k)}) \\ & =- (y_1 \log\hat{y}_1 + y_2 \log\hat{y}_2) \end{align} \]

Back Propagation

\[ \frac{\partial E}{\partial w_{11}} = ( \frac{\partial E}{\partial\hat{y}_1} \frac{\partial\hat{y}_1}{\partial b_1} + \frac{\partial E}{\partial\hat{y}_2} \frac{\partial\hat{y}_2}{\partial b_1}) \frac{\partial b_1}{\partial a_1} \frac{\partial a_1}{\partial w_{11}} \]

其中,
\[ \frac{\partial E}{\partial\hat{y}_1} = \frac{-y_1}{\hat{y}_1} \\ \frac{\partial E}{\partial\hat{y}_2} = \frac{-y_2}{\hat{y}_2} \\ \frac{\partial \hat{y}_1}{\partial b_1} = \hat{y}_1 (1- \hat{y}_1) \\ \frac{\partial \hat{y}_2}{\partial b_1} = - \hat{y}_1 \hat{y}_2 \\ \frac{\partial b1}{\partial a1} = sigmoid(a_1) [1 - sigmoid(a_1)] \\ \frac{\partial a_1}{\partial w_{11}} = x_1 \]
所以,
\[ \frac{\partial E}{\partial w_{11}} = (\hat{y}_1 - y_1) sigmoid(a_1) [ 1 - sigmoid(a_1)] x_1 \]
类似的,可得
\[ \frac{\partial E}{\partial w_{21}} = (\hat{y}_1 - y_1) sigmoid(a_1) [ 1 - sigmoid(a_1)] x_2 \\ \frac{\partial E}{\partial w_{12}} = (\hat{y}_2 - y_2) sigmoid(a_2) [ 1 - sigmoid(a_2)] x_1 \\ \frac{\partial E}{\partial w_{22}} = (\hat{y}_2 - y_2) sigmoid(a_2) [ 1 - sigmoid(a_2)] x_2 \]

代码实现

Python 3 实现

# encoding:utf8from math import exp, log
import numpy as npdef load_data(fname):X, Y = list(), list()with open(fname, encoding='utf8') as f:for line in f:line = line.strip().split()X.append(line[:2])Y.append(line[2:])return X, Yclass Network:eta = 0.5w = [[0.5, 0.5], [0.5, 0.5]]b = [0.5, 0.5]a = [0.5, 0.5]pred = [0.5, 0.5]def __sigmoid(self, x):return 1 / (1 + exp(-x))def forward(self, x):self.a[0] = self.w[0][0] * x[0] + self.w[1][0] * x[1]self.a[1] = self.w[0][1] * x[0] + self.w[1][1] * x[1]self.b[0] = self.__sigmoid(self.a[0])self.b[1] = self.__sigmoid(self.a[1])self.pred[0] = self.__sigmoid(self.b[0]) / (self.__sigmoid(self.b[0]) + self.__sigmoid(self.b[1]))self.pred[1] = self.__sigmoid(self.b[1]) / (self.__sigmoid(self.b[0]) + self.__sigmoid(self.b[1]))return self.preddef step(self, x, label):g = (self.pred[0] - label[0]) * self.__sigmoid(self.a[0]) * (1-self.__sigmoid(self.a[0])) * x[0]self.w[0][0] = self.w[0][0] - self.eta * gg = (self.pred[0] - label[0]) * self.__sigmoid(self.a[0]) * (1 - self.__sigmoid(self.a[0])) * x[1]self.w[1][0] = self.w[1][0] - self.eta * gg = (self.pred[1] - label[1]) * self.__sigmoid(self.a[1]) * (1 - self.__sigmoid(self.a[1])) * x[0]self.w[0][1] = self.w[0][1] - self.eta * gg = (self.pred[1] - label[1]) * self.__sigmoid(self.a[1]) * (1 - self.__sigmoid(self.a[1])) * x[1]self.w[1][1] = self.w[1][1] - self.eta * gif __name__ == '__main__':X, Y = load_data('iris.txt')X, Y = np.array(X).astype(float), np.array(Y).astype(float)model = Network()pred = model.forward(X[0])print("Label: %d %d, Pred: %f %f" % (Y[0][0], Y[0][1], pred[0], pred[1]))epoch = 100loss = 0for i in range(epoch):loss = 0for j in range(len(X)):pred = model.forward(X[j])loss = loss - Y[j][0] * log(pred[0]) - Y[j][1] * log(pred[1])model.step(X[j], Y[j])print("Loss: %f" % (loss))pred = model.forward(X[0])print("Label: %d %d, Pred: %f %f" % (Y[0][0], Y[0][1], pred[0], pred[1]))

网络在训练之前,预测为:

Label: 1 0, Pred: 0.500000 0.500000
Loss: 55.430875

学习率 0.5, 训练 100 个 epoch 以后:

Label: 1 0, Pred: 0.593839 0.406161
Loss: 52.136626

结论

训练后损失减小,模型预测的趋势朝着更贴近标签的方向前进,本次实验成功。

只不过模型的参数较少,所以学习能力有限。

Reference

Derivative of Softmax Loss Function

转载于:https://www.cnblogs.com/fengyubo/p/10554040.html

从头推导与实现 BP 网络相关推荐

  1. 【深一点学习】BP网络,结合数学推导的代码实现

    认识一个简单的神经网络 反向传播的推导(结合上图推导,慢慢来才比较快) E=12∑j−1l(yj^−yj)2,误差表示:f(x)=sigmoid(x)=11+e−x,激活函数对上式分别求导:∂E∂yj ...

  2. BP神经网络算法基本原理,bp网络神经算法代码

    bp神经网络的算法改进一共有多少种啊!麻烦举例一下! . 改进点主要在以下几个方面1激励函数的坡度-------误差曲面的平台和不收敛现象----------------激励函数中引入陡度因子,分段函 ...

  3. bp神经网络隐含层神经元个数_CNN,残差网络,BP网络

    (以下实验均在MNIST中实现) 一.CNN与CNN改进的对比 众所周知,对于CNN卷积神经网络而言,随着卷积层数的增加,其模型的准确度也会增加.那模型层数和准确度是无限地成正比例关系吗?显然不是的, ...

  4. 基于c语言实现bp算法,基于BP网络的自学习算法和C语言实现

    BP 维普资讯 http://doc.docsou.com <业控制计算机} 0 2年 1工 2O 5卷第 4期 1 3 基于 B P网络的自学习算法和 C语言实现 尚丽中国科学技术大学经济技术 ...

  5. 手撕BP网络,你值得拥有!

    本文货很干,自己挑的文章,含着泪也要读完! 一.认识BP神经网络        BP网络(Back-ProPagation Network)又称反向传播神经网络,分为两个过程:(1)工作信号正向传递子 ...

  6. 误差反向传播算法(BP网络)

    1.引言 误差反向传播网络(Error Back Propagtion,),简称为BP神经网络,是一种多层神经网络,与之相关的另一个概念是多层感知器(Multi-Layer Perceptron,ML ...

  7. java深度学习框架Deeplearning4j实战(一)BP网络分类器

    1.Deeplearning4j 深度学习,人工智能今天已经成了IT界最流行的词,而tensorflow,phython又是研究深度学习神经网络的热门工具.tensorflow是google的出品,而 ...

  8. 如何利用BP网络进行神经网络变量筛选

    如何利用BP网络进行神经网络变量筛选

  9. BP网络Python实现代码

    ➤00 说明 本文后面给出的BP网络Python代码主要依据 <飞浆PaddlePaddle深度学习实战> 中给出的示例进行总结而得. AC20KHz.AVI 无线充电系统 裁判系统的简介 ...

最新文章

  1. 如何配置Spring的XML文件及使用
  2. poj 2482 Stars in Your Window (线段树扫描线)
  3. wxWidgets:wxHeaderColumnSimple类用法
  4. 它成为全球最受关注度的行业之一,连续5年都提到它
  5. Python快速定位工作目录
  6. ajax怎么在html与php中使用,如何使用ajax和php将数据从数据库表放到html表
  7. sqlserver 字符串转化数值函数_Excel常见函数用法(TEXT函数)
  8. ES6字符串的扩展方法~超详细哦
  9. English vocabulary-1
  10. 【Android】Android底层开发实战
  11. 【图文详解】RE文件管理器手工精简Android系统
  12. SCCM 2012 R2部署,安装SCCM(四)
  13. grub引导项修复详解_grub2修复引导 · LINCHUAN的小站
  14. iOS仿微信录像和拍照(swift5.0)
  15. 1w+大学生在线学习,弘玑Cyclone与伯禹教育开展大学生RPA认证集训营
  16. 水果店线下营销玩法有哪些,水果店前期营销方案有哪些
  17. 恋恋有词 - 高频版
  18. 刁肥宅数据结构课设:布隆过滤器的实现和应用(v 1.1,修正非最终版)
  19. 生活随记-安心照顾母亲
  20. 复杂命令行参数gcc的-Wl的含义,注意是字母l不是数字1

热门文章

  1. HDU5086Revenge of Segment Tree(数论)
  2. linux环境 前端开发环境搭建,Linux运维知识之linux 前端环境搭建
  3. php判断是否存在http,php获取http-header来判断文件是否存在
  4. java 线程间通信方式_「转」JAVA多线程之线程间的通信方式
  5. 使用 ExMerge.exe 工具从邮箱中删除感染病毒的邮件
  6. snoopy php https_php使用snoopy与curl模拟登陆的实例分享
  7. JSP中调用java类中的方法
  8. 2019-07-10
  9. 使用QT的qmake工具生成VS工程
  10. GameJS——Game Library written in JavaScript