首页 > 其他分享 >Simple Neural Network

Simple Neural Network

时间:2024-04-27 23:57:54浏览次数:25  
标签:partial matrix Neural Simple 函数 神经网络 Output frac Network

神经网络——从 PLA 到 BP 神经网络

0. 推荐阅读

B 站白板推导系列二十三(没有任何数学推导,能够看得很舒服)

李沐-动手学深度学习

1. 感知机学习算法(Perceptron Learning Algorithm)

相信能看到神经网络的朋友对于机器学习的基础算法已经了解了个大概了,如果你没有听说过感知机算法,那么你可以将它简单理解为你很熟悉的一个算法的弱化版:支持向量机。

感知机学习算法的原始形态就是对于一个线性可分二分类类别标签,如何找出一个分离超平面去区分这两类数据。

说人话:对于二维坐标轴上的一堆散点,你能不能找出来一条线,依据类别标签把它们分成两类。

假设输入空间\(X = \{(x_1, x_2)\}\),特征空间\(Y=\{(+1/-1)\}\),我们有如下几个例子:

  1. 与关系
    20230504235225

  2. 或关系
    20230504235405

有了这两个我画的非常抽象的图,你可能已经理解什么叫线性可分,那么单层感知机算法的学习模型是什么呢?

其实就是寻找到\(wx + b = 0\)(这里的\(w x b\)均是向量)这样一个分离超平面,是不是非常简单?

那对于机器学习算法,跟模型同等重要的是学习策略,即如何取得我们想要的那个最优的模型,由于这章主要讲的是神经网络,所以损失函数的推导我就不细说了。最终会得到一个感知机模型的损失函数

\[L(w,b) = -\sum_{误分类的x}y_i(wx_i + b) \]

而我们的目的是求出 w 与 b,所以可以转化成一个最优化问题(让损失函数最小化)

\[w,b = argmin_{w,b}L(w,b) \]

那么这个最优化问题,我们可以用梯度下降的算法(这个有需求我再讲,因为我也不懂原理,只知道这样可以)来求,这边用的是随机梯度下降。

\[w \leftarrow w + \eta y_ix_i \\ b \leftarrow b + \eta y_i \]

这样我们就能求出最优解了!

那么问题来了,感知机模型要求线性可分线性不可分又是什么样的情况?看下面的异或问题

  1. 异或关系
    20230505001701
    从图上可以看出,你没有办法找到一条直线将正负类分离开来,但是存在一条曲线能够分离。在 1969 有人证明了感知机没有办法解决异或问题,这就引出了接下来的多层感知机(神经网络)。

2. 神经网络(多层感知机)

线性不可分的问题,我们有带核方法的 SVM(Kernel SVM)和神经网络两种处理手段,Kernel SVM 是出现在神经网络之后的,这个我们不多讲,因为我也不懂。

在具体讲神经网络为什么有用之前,我们先理解一下神经网络是如何工作的。

  1. 神经元

神经元其实就是一个感知机,有输入\(x\),有权值\(w\),有偏置(bias)\(b\)当然你也可以叫它阈值(threshold)\(\theta\),有输出\(y\),最后就是你可能不太熟悉的激活函数\(f\)。

它的最终表达形式是这样的:

\[y = f(wx+b) \]

或者

\[y = f(wx-\theta) \]

图片形式:
20230505002714

这里的激活函数,在单层感知机里就是符号函数,大于 0 取+1,小于 0 取-1。但是由于符号函数不可导,所以激活函数可以由各种 S 型曲线代替,比如 Sigmoid 函数:
20230505002904

也能起到符号函数的作用,只不过是大于 0.5 取+1,小于 0.5 取-1。

这个激活函数有什么作用?就是将线性的作用转成非线性的作用,这样多层叠加起来就不再可以被合并为一个线性的作用了,比如:

\[z = f(w_2f(w_1x+b_1) + b_2) \]

如果两个\(f\)均为\(y=x\),不难得出 z 与 x 是线性的关系。

  1. 神经元叠加

20230505003416

实际上神经元的叠加就是将前一个神经元的输出作为后一个神经元的输入,继续进行加权求和、加偏置、激活的流程。

图中的 input layer 即是输入空间\(X = \{(x_1,x_2,x_3)\}\), hidden layer 为隐藏层,可以不只有一层,就是神经元叠加的层。output layer 为输出空间,图上所指为\(Y = \{(y_1,y_2)\}\)。

有证明指出超过一层隐藏层的神经网络可以拟合任意函数,这就是神经网络强大的原因。

至于为什么现在发展的是深度学习(增加隐藏层),而不是广度学习(增加神经元个数),这就是另外一个问题了。

3. BP 神经网络

在介绍完多层感知机之后,朋友们对神经网络有了个感性认知。第三节讲讲计算规则简单的前馈反向传播(Back Propagation)神经网络

我们知道,感知机学习算法是基于 Loss Function 的随机梯度下降法,这也是机器学习的核心思想(应该是)。经典的损失函数就是线性回归中的最小二乘法和逻辑回归中的交叉熵损失函数(与高斯噪声 MLE 等价),

而在神经网络中,依赖 Loss Function 的梯度下降依旧是学习算法的核心,而损失函数的选择则是依据模型而选择,在此不详细说明。

那么对于具有复杂网络结构的神经网络如何对损失函数梯度下降从而求出参数呢,这就是 BP 神经网络的作用。

BP 神经网络的思想很简单,就是求导的链式法则,目的就是得到 loss function 关于参数 weight 与 bias 的梯度,小例子如下。

第一阶段-前向传播过程
20230505233746

(这张图与前面的图不太一样,不过应该也能看明白)

此图对应的函数为

\[z = f(wx) \]

z 作为输出

在向前计算的时候,同步计算好导数\(\frac{\partial z}{\partial x}\)以及\(\frac{\partial z}{\partial \omega}\),并将其保存下来。(在计算完 loss 有用)

第二阶段-反向传播过程

20230505234518

\[loss = L(\hat{z} - z) \]

在继续向前得到损失值 loss 的时候,前面的神经元会将\(\frac{\partial loss}{\partial z}\)的值反向传播给原先的神经元,在计算单元\(f(x,\omega)\)中,将得到的\(\frac{\partial loss}{\partial x}\)与之前存储的导数相乘,即可得到损失值对于权重以及输入层的导数,即\(\frac{\partial loss}{\partial x}\),以及\(\frac{\partial loss}{\partial \omega}\)。

基于该梯度才进行权重的调整

\[\frac{\partial loss}{\partial w} = \frac{\partial loss}{\partial z} \times \frac{\partial z}{\partial w} \]

更新策略为

\[w \leftarrow w - \eta \frac{\partial loss}{\partial w} \]

其中\(\eta\)为学习率,\(0<\eta<1\)。

4. 手工计算 BP

如果你看懂了一个神经元的更新,那么恭喜你学会了 BP 神经网络!让我们来做一个练习题(源自 play 老师的 ppt):

请你更新一下权重
20230505234925

20230505235021

20230505235030

真实值

\[Y = \left[\begin{matrix} 0.01 \\ 0.99 \end{matrix} \right] \]

这个图实际上有些问题,比如\(W_{input-hidden}\)的第一行第三列是 0.4,但是实际上第三个输入和隐藏层第一个结点没有连线,我们以权重矩阵为准。

前向

\[X_{hidden} = W_{input-hidden}X = \left[ \begin{matrix} 0.9 & 0.3 & 0.4 \\ 0.2 & 0.8 & 0.2 \\ 0.8 & 0.1 & 0.9 \end{matrix} \right] \left[ \begin{matrix} 0.9 \\ 0.1 \\ 0.8 \end{matrix} \right] = \left[ \begin{matrix} 1.16 \\ 0.42 \\ 0.62 \end{matrix} \right] \]

\[Output_{hidden} = Sigmoid(X_{hidden}) = Sigmoid( \left[ \begin{matrix} 1.16 \\ 0.42 \\ 0.62 \end{matrix} \right]) = \left[ \begin{matrix} 0.761 \\ 0.603 \\ 0.650 \end{matrix} \right] \]

\[X_{output} = W_{hidden-output}Output_{hidden} = \left[ \begin{matrix} 0.3 & 0.7 & 0.5 \\ 0.6 & 0.5 & 0.2 \end{matrix} \right] \left[ \begin{matrix} 0.761 \\ 0.603 \\ 0.650 \end{matrix} \right] = \left[ \begin{matrix} 0.975 \\ 0.888 \end{matrix} \right] \]

\[Output_{output} = Sigmoid(X_{output}) = \left[ \begin{matrix} 0.726 \\ 0.708 \end{matrix} \right] \]

反向
简单起见,我们只做一个权重值的更新(挑个简单的,第二层的\(w_{1,1} = 0.3\))

损失函数:

\[L(W) = (Output - Y)^T(Output - Y) = 0.59218 \]

我们的目标是:

\[\frac{\partial L(W)}{\partial w_{1,1}} = \frac{\partial L(W)}{\partial Output_{1}} \frac{\partial Output_{1}}{\partial X_{output1}}\frac{\partial X_{output1}}{\partial w_{1,1}} \]

更清晰一点(指矩阵形式转成求和形式),对应函数为:

\[L(W) = (Output_1 - Y_1)^2 + (Output_2 - Y_2)^2 \]

\[Output_1 = Sigmoid(X_{output1}) \]

这里\(w_{1,1}\)指第一个隐藏层输出对应第一个输出的权值,实际上权值矩阵是转置后的

\[X_{output1} = w_{1,1} * Output_{hidden1} + w_{2,1} * Output_{hidden2} + w_{3,1} * Output_{hidden3} \]

计算偏导

\[\frac{\partial L(W)}{\partial Output_{1}} = 2(Output_1 - Y_1) = 1.432 \]

\[\frac{\partial Output_{1}}{\partial X_{output1}} = Output_1(1 - Output_1) = 0.1989 \]

\[\frac{\partial X_{output1}}{\partial w_{1,1}} = Output_{hidden1} = 0.761 \]

最后得出答案

\[\frac{\partial L(W)}{\partial w_{1,1}} = 1.432 \times 0.1989 \times 0.761 = 0.217 \]

更新一下权重

\[\eta = 0.5 \\ w_{1,1} = w_{1,1} - \eta \frac{\partial L(W)}{\partial w_{1,1}} = 0.3 - 0.5 \times 0.217 = 0.1915 \]

大功告成!是不是很简单(我知道不简单),不过好在你只要知道怎么算就行了,具体调包就完事了。

5. 调包实现 BP

包介绍

在 R 语言中可以用 nnet 和 neuralnet 包实现,前者参数简单,后者参数复杂。

看看就好,看例子就会了

单层的前向神经网络模型在包 nnet 中的 nnet 函数,其调用格式为:

nnet(formula, data, weights, size, Wts, linout = F, entropy = F, softmax = F, skip = F, rang = 0.7,decay = 0, maxit = 100, trace = T)

拟合

predict(model, data)

参数说明:
size, 隐层结点数;

decay(就是学习率), 表明权值是递减的(可以防止过拟合);

linout, 线性输出单元开关;

skip,是否允许跳过隐层;

maxit, 最大迭代次数;

Hess, 是否输出 Hessian 值(似乎是用来判断函数凹凸性的,Hessian(半)正定则为凸函数)

可多层的 neuralnet 包

neuralnet(formula, data, hidden = 1, threshold = 0.01,stepmax = 1e+05, rep = 1, startweights = NULL,learningrate.limit = NULL,learningrate.factor = list(minus = 0.5, plus = 1.2),learningrate=NULL, lifesign = "none",lifesign.step = 1000, algorithm = "rprop+",err.fct = "sse", act.fct = "logistic",linear.output = TRUE, exclude = NULL,constant.weights = NULL, likelihood = FALSE)

拟合

compute(model, data(without output column))

参数说明:
formula :公式

data :建模的数据

hidden :每个隐藏层的单元个数(可以用向量添加隐层数目,如 c(6,4))

threshold :误差函数的停止阈值

stepmax :最大迭代次数

rep :神经网络训练的重复次数

startweights :初始权值,不会随机初始权值

learningrate.limit :学习率的上下限,只针对学习函数为 RPROP 和 GRPROP

learningrate.factor :同上,不过可以是针对多个

learningrate :算法的学习速率,只针对 BP 算法

lifesign :神经网络计算过程中打印多少函数{none、minimal、full}

lifesign.stepalgorithm :计算神经网络的算法{ backprop , rprop+ , rprop- , sag , slr }

err.fct :计算误差,’{sse,se}

act.fct :激活函数,{logistic,tanh}

linear.output :是否线性输出,即是回归还是分类

exclude :一个用来指定在计算中将要排除的权重的向量或矩阵,如果给的是一个向量,则权重的位置很明确,如果是一个 n*3 的矩阵,则会排除 n 个权重,第一列表示层数,第二列,第三列分别表示权重的输入单元和输出单元

constant.weights :指定训练过程中不需要训练的权重,在训练中看做固定值

likelihood :逻辑值,如果损失函数使负对数似然函数,那么信息标准 AIC 和 BIC 将会被计算

实例

数据:混凝土强度数据集

Pre

concrete <- read.csv("concrete.csv")
str(concrete)

# 没有证据表明归一化会有效,但确实有点效
normalize <- function(x) {
  return((x - min(x)) / (max(x) - min(x)))
}

# apply normalization to entire data frame
concrete_norm <- as.data.frame(sapply(concrete, normalize))

# confirm that the range is now between zero and one
summary(concrete_norm$strength)

# compared to the original minimum and maximum
summary(concrete$strength)

# create training and test data
set.seed(20021119)
index <- sample(x=c(1,2),nrow(concrete_norm),replace=T, prob=c(0.75,0.25))
concrete_train <- concrete_norm[index==1, ] #75%
concrete_test <- concrete_norm[index==2, ] #25%
summary(concrete_train$strength)

nnet

library(nnet)
nnet <- nnet(concrete_train$strength~., data=concrete_train,
             size = 10,decay = 5e-4, maxit = 200)
summary(nnet)
pred = predict(nnet, concrete_test)
cor(pred, concrete_test$strength)
plot(pred, concrete_test$strength)

neuralnet

无参数

library(neuralnet)

# simple ANN with only a single hidden neuron
set.seed(20021119) # to guarantee repeatable results
concrete_model <- neuralnet(strength ~ cement + slag +
                              ash + water + superplastic +
                              coarseagg + fineagg + age,
                            data = concrete_train)

# visualize the network topology
plot(concrete_model)

## Step 4: Evaluating model performance ----

# obtain model results
model_results <- compute(concrete_model, concrete_test[1:8])

# obtain predicted strength values
predicted_strength <- model_results$net.result

# examine the correlation between predicted and actual values
cor(predicted_strength, concrete_test$strength)
plot(predicted_strength, concrete_test$strength)

调参数

concrete_model2 <- neuralnet(strength ~ cement + slag +
                               ash + water + superplastic +
                               coarseagg + fineagg + age,
                             data = concrete_train, hidden =c(10,5))
# 通过hidden的向量化控制隐层数目
# plot the network
plot(concrete_model3)

# evaluate the results as we did before
model_results3 <- compute(concrete_model3, concrete_test[1:8])
predicted_strength3 <- model_results3$net.result
cor(predicted_strength3, concrete_test$strength)
plot(predicted_strength3, concrete_test$strength)

模型网络结构
20230506232814

标签:partial,matrix,Neural,Simple,函数,神经网络,Output,frac,Network
From: https://www.cnblogs.com/Blackteaxx/p/18162814

相关文章

  • 论文解读(MAML)《Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks
    Note:[wechat:Y466551|可加勿骚扰,付费咨询]论文信息论文标题:Model-AgnosticMeta-LearningforFastAdaptationofDeepNetworks论文作者:ChelseaFinn、PieterAbbeel、SergeyLevine论文来源:2017 论文地址:download 论文代码:download视屏讲解:click1-摘要我们提出......
  • centos7出现网络不可达connect network is unreachable?
    centos7出现网络不可达connect:networkisunreachable?问题:在Linux系统中,用户尝试修改IP地址配置后,遇到ping命令提示connect:networkisunreachable,表明网络不可达。原因分析:IP配置错误:修改后的IP地址可能不在正确的子网内,或者与默认网关不在同一网段,导致无法正常通信......
  • 【Network Automation系列】-- 第一章
    引言:本系列是根据《MasteringPythonNetworkingThirdEdition》翻译整理出来的,原著作者:EricChou,大家可以关注一下。随着网络工程领域的快速变化,我们无疑也经历了类似的变化。随着软件开发越来越多地集成到网络的各个方面、传统的命令行接口和垂直集成中,网络堆栈方法不再是管......
  • Java面试题:SimpleDateFormat是线程安全的吗?使用时应该注意什么?
    在日常开发中,我们经常会用到时间,我们有很多办法在Java代码中获取时间。但是不同的方法获取到的时间的格式都不尽相同,这时候就需要一种格式化工具,把时间显示成我们需要的格式。最常用的方法就是使用SimpleDateFormat类。这是一个看上去功能比较简单的类,但是,一旦使用不当也有可能导......
  • SimpleCalendar 插件title显示异常
    了解到您提到的title是指日历中每个日期的标题,而不是页面的标题。在SimpleCalendar插件中,每个日期可以有一个标题或者描述,这些信息通常会显示在日历上某一天的上方或者旁边,以便用户可以知道那一天的特殊含义或者事件。根据提供的信息,SimpleCalendar插件允许用户通过mark配置项来......
  • vue启动本地服务不显示network访问链接
    在vue.config.js(或者配置config了的,就在config下的index.js)文件下设置devServer或者dev中的public属性值,需要修改为自己电脑的IPV4地址,获取IPV4地址方法,Win+R打开运行窗口,输入cmd,在命令行输入ipconfig回车后会出现一串信息,复制IPV4地址即可;module.exports={......
  • A. Simple Design
    A.SimpleDesign看来0~1000分区间还是有简单题的()就是暴力找每个数,把它每个位置分离相加找到就退出#include<iostream>usingnamespacestd;voidsolve(){intx,k;cin>>x>>k;for(inti=x;;i++){intd=i;intsum=......
  • MIT 6.5830 simpleDB Lab2
    Exercise1需要完成的是:src/java/simpledb/execution/Predicate.javasrc/java/simpledb/execution/JoinPredicate.javasrc/java/simpledb/execution/Filter.javasrc/java/simpledb/execution/Join.java这里主要实现两个功能:Filter:通过Predicate过滤一部分满足条件的Tupl......
  • perf/Simpleperf 生成火焰图
    参考:https://blog.csdn.net/weixin_43297891/article/details/137241935 https://hqber.com/archives/483/定义Simpleperf是Google随NDK一起发布的一款profile工具(注:从NDKr13开始),它是针对Android平台的一个native层性能分析工具。使用步骤本篇是分析运行在android设备......
  • 新手大白话 [SWPU 2018]SimplePHP Phar反序列化
    今天再做个Phar反序列化巩固下。进入题目发现了查看文件与上传文件,与自己的IP。利用burp抓包进行查看,先尝试index.php,发现base.php,查看base.php发现flag所在文件,再查看file.php,发现function.phpclass.php点击查看代码class.php<?phpclassC1e4r{public$t......