Julia:用多层感知机解决异或问题

简介: 异或问题就是当两个输入的布尔值不一致时,输出为 True(可以用 1 代表),如果两个输入的布尔值一致的时候,输出为 False(可以用 0 代表)。

1/ 异或问题(XOR Problem)

异或问题就是当两个输入的布尔值不一致时,输出为 True(可以用 1 代表),如果两个输入的布尔值一致的时候,输出为 False(可以用 0 代表)。

据说多层感知机(MLP)是很难处理异或问题的,就好比下面的问题。

首先由一个问题引入,来自邱锡鹏老师的书《神经网络与深度学习》第四章的习题 4-2:

习题 4-2 试设计一个前馈神经网络来解决 XOR 问题,要求该前馈神经网络具有两个隐藏神经元和一个输出神经元,并使用 ReLU 作为激活函数。

一个可行的结果如下,

$$ \boldsymbol{W}^{(1)}=\left[\begin{array}{ll}1 & 1 \\ 1 & 1\end{array}\right], \boldsymbol{b}^{(1)}=\left[\begin{array}{c}0 \\ -1\end{array}\right]\\ \boldsymbol{w}^{(2)}=\left[\begin{array}{c}1 \\ -2\end{array}\right], b^{(2)}=\left[0\right] \tag{1} $$

故整个网络的计算为:

$$ \boldsymbol{y}=\left(\boldsymbol{w}^{(2)}\right)^{\mathrm{T}}\left(\operatorname{ReLU}\left(\left(\boldsymbol{W}^{(1)}\right)^{\mathrm{T}} \boldsymbol{X}+\boldsymbol{b}^{(1)}\right)\right)+b^{(2)} $$

代入:

$$ \boldsymbol{X}=\left[\begin{array}{llll}0 & 0 & 1 & 1 \\ 0 & 1 & 0 & 1\end{array}\right] $$

可以算得:$\boldsymbol{y}=\left[\begin{array}{llll}0 & 1 & 1 & 0\end{array}\right]$

2/ 使用 Flux 训练

2.1/ 两个隐含神经元

实际上这样的一个网络结构,如果使用随机初始化的方式去训练,是训练不好的,原因在于中间要求的是一个 ReLU 激活函数,如果换成其他的激活函数就能够训练好。

使用如下代码:

using Flux

function loss()
    ŷ = mlp(data)
    Flux.mse(ŷ, y)
end

cb = function ()
    println(loss())
end

data = Array([[0 1 0 1];
              [0 0 1 1]]);
y = Array([[0 1 1 0];]);

mlp = Chain(Dense(2, 2, relu), Dense(2, 1));
ps = Flux.params(mlp);

opt = ADAM(0.01)
@time Flux.train!(loss, ps, Iterators.repeated((), 1000), opt, cb=cb)

训练完之后会发现,损失依然很高,输出的结果会是全部都很接近 $0.5$.

如果我们将隐含层的参数设置为 (1) 式的结果,然后只训练输出层的权重 $\boldsymbol{w}^{(2)}$,那么会得到相同的结果:

# 自定义权重,将权重都初始化为全 1 的矩阵
mlp = Chain(Dense(2, 2, relu, bias=[0; -1], init=ones),
            Dense(2, 1, bias=zeros(1), init=ones))
# 只拿出第三个参数,即输出层的权重训练
ps = Flux.params(Flux.params(mlp)[3])
opt = ADAM(0.1)
@time Flux.train!(loss, ps, Iterators.repeated((), 1000), opt, cb=cb)

结果会得到 $\boldsymbol{w}^{(2)}=[0.9999... -1.9999...]$,与题目设计的是一样的。

2.2/ 三个隐含神经元

但实际上,如果我们在隐含层上使用三个神经元,就能够解决这个问题。这证明只使用两个隐含神经元,模型的能力并不够,加多了一个就能够解决了:

mlp = Chain(Dense(2, 3, relu), Dense(3, 1));
ps = Flux.params(mlp)
opt = ADAM(0.01)
@time Flux.train!(loss, ps, Iterators.repeated((), 1000), opt, cb=cb)
# loss = 0.22230548
# loss = 0.21818444
# ...
# loss = 0.0
ŷ = mlp(data)

最后的解是对的,查看各层的参数可以知道

$$ \boldsymbol{W}^{(1)}=\left[\begin{array}{ll} 0.574309 & -0.574309\\ 0.92754 & -0.966212\\ 1.12378 & -1.12138\end{array}\right], \boldsymbol{b}^{(1)}=\left[\begin{array}{c} 0.5743128\\ -0.00046141824\\ -0.0034916808\end{array}\right]\\ \boldsymbol{w}^{(2)}=\left[\begin{array}{c} -1.74122 \\ 0.60053 \\ 1.2883\end{array}\right], b^{(2)}=\left[1.0000067\right] $$

当使用两个隐含神经元的时候,使用随机初始化权重的方式去训练,会非常难以求解,但是如果使用三个隐含神经元,那么其能力就足以解决异或问题了。

不过实际上,在使用两个隐含神经元的时候,不使用 ReLU 作为激活函数,而是在隐含层使用 Sigmoid 函数,那么只有两个隐含神经元的情况下,也可以解决异或问题。

主要的问题应该还是在 ReLU 会把小于零的部分直接截断,相当于这个神经元没有被激活,会容易造成神经元「死亡」无法再继续训练。

目录
相关文章
vxe-table表格校验失败后保持可以编辑状态
vxe-table表格校验失败后保持可以编辑状态
vxe-table表格校验失败后保持可以编辑状态
|
人工智能 JavaScript 前端开发
【Vue2从入门到精通】详解Vue数据双向绑定原理及手动实现双向绑定
Vue是采用数据劫持结合发布者-订阅者模式的方式,通过使用ES5中的Object.defineProperty()方法来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。
802 0
【Vue2从入门到精通】详解Vue数据双向绑定原理及手动实现双向绑定
|
Linux Docker 容器
在anolis 8.4上安装docker-ce
在anolis的软件仓库中并没有docker-ce套件,那么该如何安装docker-ce呢?
3371 1
在anolis 8.4上安装docker-ce
|
前端开发
antd中table组件中如何进行换行操作(react中)
antd中table组件中如何进行换行操作(react中)
antd中table组件中如何进行换行操作(react中)
|
4月前
|
运维 监控 数据可视化
故障定位48小时→5分钟:靠的不是玄学,是“全网透视眼”
在多云部署的网络架构下,企业需要全方位监控全链路网络,解决故障定位难题。 Fusion WAN可视化平台提供实时监控和故障定位能力,帮助企业实现业务畅通。
故障定位48小时→5分钟:靠的不是玄学,是“全网透视眼”
|
11月前
|
存储 缓存 安全
只会“有序无序”?面试官嫌弃的List、Set、Map回答!
小米,一位热衷于技术分享的程序员,通过与朋友小林的对话,详细解析了Java面试中常见的List、Set、Map三者之间的区别,不仅涵盖了它们的基本特性,还深入探讨了各自的实现原理及应用场景,帮助面试者更好地准备相关问题。
235 20
|
机器学习/深度学习 5G
5G中的调制技术:从QPSK到256QAM,赋能高速率通信
5G中的调制技术:从QPSK到256QAM,赋能高速率通信
3161 5
|
9月前
|
人工智能 关系型数据库 分布式数据库
PolarDB 开源基础教程系列 7.4 应用实践之 AI大模型外脑
PolarDB向量数据库插件通过实现通义大模型AI的外脑,解决了通用大模型无法触达私有知识库和产生幻觉的问题。该插件允许用户将新发现的知识和未训练的私有知识分段并转换为向量,存储在向量数据库中,并创建索引以加速相似搜索。当用户提问时,系统将问题向量化并与数据库中的向量进行匹配,找到最相似的内容发送给大模型,从而提高回答的准确性和相关性。此外,PolarDB支持多种编程语言接口,如Python,使数据库具备内置AI能力,极大提升了数据处理和分析的效率。
353 4
|
数据可视化 数据处理 开发者
构建高效的数据流图:Python与PyGraphviz的实践
【9月更文挑战第13天】在本文中,我们将探索如何利用Python和PyGraphviz库来创建和操作数据流图。我们将通过一个具体示例,展示如何从零开始构建一张数据流图,并讨论如何优化图表以提高可读性。文章旨在为初学者提供一个清晰的入门指南,同时为有经验的开发者提供一些高级技巧。
|
12月前
昇腾910A部署Qwen2-7B教程
Qwen2-7BS适配昇腾910A教程。