news 2026/8/10 12:36:23

python神经网络编程入门(二)----从XOR死穴到生物神经元——为什么单一直线搞不定,要堆一堆神经元?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python神经网络编程入门(二)----从XOR死穴到生物神经元——为什么单一直线搞不定,要堆一堆神经元?

📌 本文属于《Python神经网络入门:零基础保姆级路线图》专栏

上一篇:python神经网络编程入门(一)—— 分类器
下一篇:python神经网络编程入门(三)----矩阵乘法真是神经网络的“偷懒神器”

完整目录 & 更新记录:
《Python神经网络入门:零基础保姆级路线图(附全系列免费源码)》

这篇文章咱们接着上回说。上回我们学会了怎么让一条直线(y=kx)自己学着调整,去把两类点分开。但这一期,咱们得直面一个“残酷”的现实:一条直线,真的不够用

咱们不讲高深数学,就带大家玩一个“逻辑游戏”,看完你立马就能明白,为什么后来需要“神经网络”那么多个节点。

1. 先复习:什么是“一刀切”?

想象你是一个幼儿园老师,手里有一根长长的魔法直尺。你的任务是用这根直尺,把桌上的红色积木和绿色积木完全分开。

上期我们做的所有事,其实就是让计算机找到这根直尺最合适的位置(角度和距离)。

只要两类积木分别堆在桌子的两边,这根直尺(线性分类器)非常好使。但问题来了——生活往往没那么乖巧。

2. 两个“听话”的好学生:AND(与)和 OR(或)

在计算机的“数字世界”里(只有0和1),有两个最基本的逻辑,咱们先看看直尺能不能搞定它们。

(1)AND(与)—— 两个都要真
只有A和B同时是1(真)的时候,结果才为真(绿色)。
比如你妈说:“写完作业 AND 收拾好书包,才能看电视。”
只要有一个没做,就不能看(红色)。

(2)OR(或)—— 有一个就成
只要A或B有一个是1(真),结果就为真(绿色)。
比如你爸说:“下雨 OR 降温,就给你送外套。”
只要满足一条,外套就送来了。



你会发现一件神奇的事:对于AND和OR,你手里的魔法直尺(直线),总能轻轻松松地把绿色和红色一刀切开!(比如AND,斜着画一条线,把右上角单独框出来就行)。所以,单一直线能解决这俩问题,没毛病。

3. 大麻烦来了:XOR(异或)—— “有你没我”

现在来个刺头,叫XOR(异或)
这玩意儿很“矫情”:两个输入相同(都是0或都是1)时,输出假(红);两个输入不同(一个是0一个是1)时,输出真(绿)。

用大白话讲:“要么你请客,要么我请客,但咱俩绝不能同时掏钱!”

咱们还是把(0,0)(1,0)(0,1)(1,1)这四个点画在网格上,涂上颜色:

  • (0,0):相同 →红色

  • (1,1):相同 →红色

  • (1,0):不同 →绿色

  • (0,1):不同 →绿色

4. 拿起直尺比划一下,傻眼了!

现在,你再拿起那根“魔法直尺”(直线),试着在图上画一道线,把红色和绿色分开。

你会发现:无论你把尺子横着画、竖着画,还是斜着画(只要它是直的),你永远会误伤一个!

  • 画横线?上面有一个红一个绿,分不开。

  • 画竖线?右边有一个红一个绿,分不开。

  • 画斜线?总有一个角落的颜色不对。

这就是线性分类器的“死穴”——它天生只能处理“线性可分”的问题,而XOR是“线性不可分”的。

如果真实世界里的数据长得像XOR这样(比如判断一个人是否适合结婚:光有钱不行,光帅也不行,没钱不帅也不行,必须又有钱又帅……等等,这个逻辑好像反了,但总之,数据是交叉纠缠的),用我们上一期学的单一直线函数,算到天荒地老也算不对!

5. 怎么破局?一条不行,那就两条!

既然一条直尺一刀切不开,那咱们用两把尺子切两刀,行不行?

回到XOR图:

  • 我画第一条线(比如竖线x=0.5),把左边的(0,0)(0,1)和右边的(1,0)(1,1)分开。

  • 再画第二条线(比如横线y=0.5),把下边的(0,0)(1,0)和上边的(0,1)(1,1)分开。

然后,我把这两个结果组合起来看:
我们先看左边竖线(分出左右),再看下面横线(分出上下)。
如果两次判断的结果一结合,是不是就能把“对角线上相同”和“对角线上不同”给揪出来了?

这就是神经网络的核心思想!

6. 总结一下重点

  1. 直尺的极限:现实中有很多数据像XOR一样“纠缠不清”,单一直线(线性分类器)这辈子都解不开这类问题。

  2. 破局的法宝:既然一个不行,那就堆数量!用多个分类器(多条直线)组合起来,层层递进,就能切出各种奇形怪状的区域。

下次,当你听到“神经网络”这个名字时,别被唬住。本质上,它就是一大堆“直尺”(线性分类器)堆在一起,通过某种巧妙的方式组合起来,解决单把尺子搞不定的复杂问题



那么问题来了,这么多“尺子”堆在一起,怎么让它们学会配合呢?总得有个总指挥吧?,咱们先抛开代码,去看看大脑是怎么干这活的——因为神经网络,本来就是抄袭大脑的!

在硬着头皮写代码之前,咱们先不急着堆数字。先抬头看看自然界——因为神经网络本来就是抄袭大脑的。这一期,咱们就把它“抄袭”的原型扒个底朝天。

7. 计算机那么快,为啥连只鸽子都不如?

你可能会想:现在的电脑主频都飙到几G赫兹了,算个加减乘除快到飞起,难道还比不过一坨“肉乎乎”的大脑?

但现实很打脸:一只鸽子的大脑,比世界上任何超级计算机都更擅长识别它面前的食物是不是面包屑。一台顶级电脑要识别一张猫图,得费老大劲跑几亿次运算;而你家那只傻狗,0.1秒就认出你是主人。

为什么?

  • 电脑(传统程序):像个死心眼的会计。必须一步一步、毫不含糊地算(串行处理)。输入稍有模糊(比如图片有点模糊),它就抓瞎了。

  • 动物大脑:像个包容的居委会大妈。它同时处理一大堆信息(并行处理),而且允许模糊——哪怕只看清半张脸,它也能猜出你是谁。

所以,速度不是关键,架构(玩法)才是关键!

8. 大脑里的“最小单位”——神经元长啥样?

咱们把大脑拆开看,最基础的小零件叫神经元。它长得很像一棵倒着的树:

  • 树突(输入端):像树根或树枝,负责接收前面神经元传来的电信号。

  • 细胞体(处理器):把收到的信号汇总一下。

  • 轴突(输出端):像一根长长的电线,把汇总后的结果传给下一个神经元。


9. 几个神经元能干多大的事?(数字游戏)

你可能觉得,大脑有860亿个神经元,当然厉害。但咱们看看“小角色”:

  • 一只果蝇:只有10万个神经元。但它能飞、能躲苍蝇拍、能找烂水果吃。这10万个元件,现代计算机用传统程序至今难以完美模拟。

  • 一种线虫:只有可怜巴巴的302个神经元。但就靠这302个小零件,它能蠕动、能找到食物、能避开有害物质。用传统编程逻辑去写一个同样灵活的机器人,几十万行代码都搞不定!

这说明什么?说明神经元这种“并行+模糊”的算法架构,效率极高。所以我们学它,绝对没错!

10. 神经元的“暴脾气”——不到阈值不放电

现在咱们看单个神经元具体怎么工作。
它和咱们上期学的线性函数(y=kx)不一样。线性函数是:你给个输入,无论多小,我都给你吐个输出(哪怕是0.001)。

生物神经元很“傲娇”:如果输入信号太弱,它绝不反应,直接忽略(这叫抑制噪声)。只有输入信号累积到足够强,超过某个门槛(阈值),它才“啪”地一下放电,把信号传出去。

这就像往杯子里倒水。水没满(没到阈值),一滴都不往外溢;水装满了(超过阈值),猛地就溢出来了。

11. 改进一下:不要“冷冰冰”的台阶,要“丝滑”的S形

上面的阶跃函数虽然像生物,但在数学上太“硬”了——在门槛那里突然从0蹦到1,自然界很少有这么生硬的转折。

所以,科学家们用了下面这个S形函数(Sigmoid函数),它平滑、圆润,更像大自然的风格:

第一次看见这个公式的读者别怕,它就是个“纸老虎”。咱们把它拆开:

  • 公式里的 e 是个常数,约等于2.71828(不用记,知道是个无限不循环小数就行)。

  • −x 就是取反。假设 x=2,那么就是 e 的平方分之一。

  • 然后加1,最后用1除以它。

咱们来套个数试试
当输入 x=0 时,任何数的0次方都是1,所以=1。

代入公式:

看,当输入为0时,输出正好是0.5(正中间)。当输入很大时(比如 x=10),趋近于0,y 趋近于1。当输入很小时(比如 x=−10),巨大,分母巨大,y 趋近于0。

为什么偏要用这个S函数?除了长得像生物神经元,还有一个极其重要的原因:它求导(算斜率)特别简单!这在我们以后做“反向传播”时,能省下大量的算力。这是祖师爷赏饭吃的地方。

12. 神经元不止一个输入——它是“话痨”

咱们前面学的线性分类器只接受一个 x(横坐标)。但生物神经元有好多“树突”,它同时接收好多个信号!

比如,这个神经元同时接收来自A、B、C三个前一个细胞的信号。
那它怎么处理呢?很简单,全部加起来!

我们把所有输入信号相加,得到一个总和 x:

然后,把这个总和 x 扔进上面的 S 函数里,算出最终输出 y:

这就很有意思了!
哪怕单独一个信号很小(不够触发阈值),但是三个信号加起来很大,超过了阈值,神经元照样会“啪”地放电激发!
这就解释了为什么大脑能处理“模糊逻辑”——三个臭皮匠,顶个诸葛亮。单独看不清,凑一起就看清楚了。

13. 最重要的“调节旋钮”:连接权重(Connection Weights)

好,现在问题来了:我们搭建了这么多神经元,互相像蜘蛛网一样连着,我们到底该“调整”什么东西,才能让它学会做数学题呢?

我们不能去改生物结构吧?所以,人工神经网络里,我们调节的是连接强度,也就是权重(Weight)

想象一下,前后两层神经元之间,每一条连线上都有一个音量旋钮(权重)。

  • 如果旋钮拧得大(比如 5.3),信号通过时就放大,对下一个神经元影响巨大。

  • 如果旋钮拧得小(比如 0.1),信号通过时就衰弱,几乎不影响下一个神经元。

重点解释一下这个下标的读法(极其重要):

比如你看到一个符号:

  • 前面的数字(2):表示信号来自第2层(前一层)的节点。

  • 后面的数字(3):表示信号去往第3层(后一层)的节点。

再看一个:​,表示“第1层节点”传给“第2层节点”的那条线上的权重。

那数学上怎么算呢?下一层某个节点的输入总和 X 就等于:

也就是:前一层每个节点的输出值,乘以它们之间连线的权重,最后全部加起来。这就是神经网络最核心的“加权求和”。

14. 为什么要把“蜘蛛网”连得这么密?(全连接)

你看上面那张图,密密麻麻全是线,你可能会想:“这也太浪费了吧!很多线是不是根本没用?”

问得好!咱们之所以设计成每一层都跟下一层全部连起来(全连接),有两个偷懒又聪明的理由:

  1. 方便写代码:这种规规矩矩的“网格状”连线,用计算机的矩阵乘法算起来飞快(几行代码就搞定了)。

  2. 让它自己“断舍离”:虽然连线很多,但我们在训练的时候,会让计算机自己去调这些权重。如果某条线没用,神经网络会自动把它的权重调到接近 0

大家想想,任何数乘以 0 都得 0,信号完全传不过去。这就相当于这条连线被“物理断开了”。所以,刚开始多连几条冗余的线无所谓,反正最后没用的线会自动“失联”。这省了我们人类设计电路的大量脑细胞。

15.总结一下核心思想

  1. 计算机快但死板,大脑慢但灵活(并行 + 模糊处理)。

  2. 单个神经元:接收一堆输入(求和) -> 超过阈值 -> 通过 S 函数(Sigmoid)产生平滑的输出。

    • 公式:(其中 x 是所有输入的和)。

  3. 学习的关键:调整连接线上的权重(w)

    • 放大权重 = 放大信号;缩小权重 = 减弱信号;权重归零 = 断开连接。


好了,到这里,我们已经把“零件”认全了:

  • 一个神经元 ≈ 一个会“加权求和”再“S形压扁”的小盒子;

  • 一个神经网络 ≈ 一大堆这样的小盒子,像蜘蛛网一样连在一起;

  • 学习的“旋钮” ≈ 连接线上的权重(调大就放大信号,调小就减弱信号)。

但问题来了——如果这个“蜘蛛网”很大很大(比如3层、每层100个神经元),我们要算的东西有多少?

手动算?光是第一层传到第二层,就要做100 × 100 = 10000次乘法,再加10000次加法。这还只是一层!要命的是,第二层传到第三层还要再来10000次……手算到天黑都算不完。

那怎么办?总不能把计算机累死吧?

别怕!数学家早就发明了一个“偷懒神器”——矩阵乘法。它能把上面那一大堆密密麻麻的乘法和加法,压缩成一行字母

就这么简单!

下一期,咱们就翻开这个“偷懒神器”的使用说明书,看看怎么用一张“数字表格”,轻轻松松算出整个神经网络前向传播的结果——哪怕它有100层,我们也只写一行公式!

顺便剧透一下:算完前向传播还不算完,我们算出来的结果和正确答案有差距,这个“差距”该怎么一层一层传回去调整权重?等我们把矩阵这个工具用顺手了,就进入整个神经网络最核心的“绝活”——误差反向传播。咱们一步一步来,不着急。

代码片段1:简单神经网络 — 解决 XOR 问题(承上启下!)

还记得上一篇文章说的吗?一条直线搞不定 XOR。这里用代码搭建一个极简神经网络(3层:输入层 → 隐藏层 → 输出层),让它自己学会 XOR。

这个代码稍微长一点,但别怕——它刚好把今天讲的神经元上期讲的XOR难题串起来了。跑完你会直观看到:一个神经元不行,但多个神经元配合起来就行了!

import numpy as np # ---------- 1. 定义Sigmoid函数及其导数 ---------- def sigmoid(x): return 1 / (1 + np.exp(-x)) def sigmoid_derivative(x): return x * (1 - x) # 这是S函数求导的简化形式 # ---------- 2. 准备XOR数据 ---------- # 四个样本:输入A、输入B → 期望输出 X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) y = np.array([[0], # 0 XOR 0 = 0 [1], # 0 XOR 1 = 1 [1], # 1 XOR 0 = 1 [0]]) # 1 XOR 1 = 0 # ---------- 3. 搭建神经网络 ---------- # 输入层2个节点,隐藏层4个节点,输出层1个节点 input_size = 2 hidden_size = 4 output_size = 1 # 随机初始化权重(这就是那些"旋钮"的初始值) np.random.seed(42) # 固定随机种子,让大家跑的结果一样 W1 = np.random.randn(input_size, hidden_size) # 输入→隐藏的权重 W2 = np.random.randn(hidden_size, output_size) # 隐藏→输出的权重 # ---------- 4. 训练!让网络自己调整权重 ---------- learning_rate = 0.5 epochs = 10000 for epoch in range(epochs): # --- 前向传播(信号往前走) --- hidden_input = np.dot(X, W1) # 输入层 → 隐藏层(加权求和) hidden_output = sigmoid(hidden_input) # 过S函数 final_input = np.dot(hidden_output, W2) # 隐藏层 → 输出层(加权求和) final_output = sigmoid(final_input) # 过S函数 # --- 计算误差(看看差多少) --- error = y - final_output # --- 反向传播(把误差"传回去",调整权重) --- # (这部分是下一篇文章的重点,这里先直接给出公式) d_output = error * sigmoid_derivative(final_output) error_hidden = d_output.dot(W2.T) d_hidden = error_hidden * sigmoid_derivative(hidden_output) # 更新权重(拧动"旋钮") W2 += hidden_output.T.dot(d_output) * learning_rate W1 += X.T.dot(d_hidden) * learning_rate # ---------- 5. 看结果! ---------- print("训练完成!XOR预测结果:") for i in range(4): pred = final_output[i][0] print(f"输入 ({X[i][0]}, {X[i][1]}) → 期望 {y[i][0]} → 网络预测 {pred:.4f}")


看到没?四个预测值都非常接近正确答案(0或1)。虽然我们还没有正式讲“反向传播”,但代码已经跑通了——这就是神经网络的力量:多个神经元配合,搞定了单一直线搞不定的XOR!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/10 12:35:40

如何5分钟构建终极M3U8视频下载器:Go语言多线程下载完整指南

如何5分钟构建终极M3U8视频下载器:Go语言多线程下载完整指南 【免费下载链接】m3u8-downloader 一个M3U8 视频下载(M3U8 downloader)工具。跨平台: 提供windows、linux、mac三大平台可执行文件,方便直接使用。 项目地址: https://gitcode.com/gh_mirrors/m3u8d/m…

作者头像 李华
网站建设 2026/8/10 12:35:02

Jenkins多分支流水线配置与优化实战

1. Jenkins多分支流水线配置实战指南 在持续集成/持续交付(CI/CD)实践中,多分支流水线已经成为现代软件开发的标准配置。作为从业多年的DevOps工程师,我发现很多团队在初次配置Jenkins多分支流水线时都会遇到相似的困惑:分支管理混乱、构建效…

作者头像 李华
网站建设 2026/8/10 12:33:10

Python心理学实验自动化:aepsych-client贝叶斯优化实战

1. 初识aepsych-client:当心理学实验遇上Python 作为一名长期在心理学实验自动化领域摸爬滚打的开发者,第一次接触aepsych-client包时,那种相见恨晚的感觉至今记忆犹新。这个由Facebook Research团队开源的Python工具包,专为自适应…

作者头像 李华
网站建设 2026/8/10 12:32:12

【C++初阶】速过C++语法基础

文章目录(一)命名空间 namespace(1)namespace的价值(2)namespace的定义①namespace的形式:②namespace的本质-C中的域相关(3)namespace的使用访问namespace内的内容 ::PS…

作者头像 李华