2026年了,你还只知道ReLU?一文搞懂神经网络的核心“大脑”

张开发
2026/5/17 20:27:08 15 分钟阅读
2026年了,你还只知道ReLU?一文搞懂神经网络的核心“大脑”
学会选对激活函数你的AI模型准确率至少提升10%你有没有想过——手机怎么认出你的脸自动驾驶怎么分清行人和路标ChatGPT怎么懂你问啥这些神奇的能力都离不开一个叫“神经网络”的东西。而神经网络里最核心、最基础的那个小单元叫做激活函数。它就像是神经元的“开关”决定了信号能不能往下传。最近AI圈又有大新闻中科院团队搞出了CATS Net让AI能像人一样自己提炼概念、互相交流日本科学家更狠直接用活体大鼠的脑细胞搭了一个神经网络让活细胞学会了生成各种波形。但不管技术怎么变激活函数始终是那个让AI“活”起来的关键零件。今天我就带你从零开始把神经网络和激活函数彻底搞明白。我会用最通俗的话、最形象的比喻再加上能直接跑的代码让你看完就能自己动手写一个识别手写数字的神经网络。文章有点长但保证你读得下去。一、先看看真正的神经元长啥样——AI的“灵感之源”咱们先别急着敲代码来看看人脑是怎么工作的。你的大脑里有大约860亿个神经元。每个神经元就像一个微小的“传令兵”树突像很多根小触手负责接收别的神经元传来的信号。细胞体把收到的所有信号加起来“算个总账”。如果总和超过某个“门槛”这个神经元就会“兴奋”。轴突像一根长长的电线把“兴奋”的信号传出去。突触信号传到终点时会释放一些化学物质去刺激下一个神经元。这个过程叫“全或无”——要么不激活要么激活后信号强度是一样的。就像扣扳机要么不扣一扣子弹就射出去了。科学家们一拍大腿这玩意儿能在电脑里模拟吗于是就有了人工神经元。一个人工神经元干三件事加权求和把多个输入分别乘上不同的“重要性系数”权重然后加起来。权重越大这个输入就越重要。加偏置偏置就像“门槛调节器”。偏置越大神经元越容易被激活。激活函数把上面算出来的总和转成一个输出。激活函数决定了这个神经元“兴奋”到什么程度。把很多这样的人工神经元连起来就成了多层神经网络。最左边是输入层喂原始数据最右边是输出层吐结果中间都叫隐藏层。相邻层之间通常每个神经元都连到下一层的所有神经元——这叫全连接每条线上都有一个权重。信息从输入层开始一层一层往右传直到输出层。这个过程叫前向传播。好了背景知识结束。下面咱们看看最早的那个“祖宗级”模型。二、感知机神经网络的“老古董”1957年一个叫Frank Rosenblatt的人提出了感知机。它就是神经网络的鼻祖。感知机干的事很简单接收一堆0或1的信号输出一个0或1。你可以把它想象成一个“投票机器”每个投票者输入手里有一票但票的“份量”不同——这就是权重。权重越大这个人说了越算。还有一个偏置相当于“起跑线”偏置越大越容易通过。公式长这样两个输入的情况y{0(bw1x1w2x2≤0)1(bw1x1w2x20)y{01(bw1x1w2x2≤0)(bw1x1w2x20)举个例子你想做一个“与门”AND——只有两个输入都是1输出才是1。你可以设 w10.5,w20.5,b−0.7w10.5,w20.5,b−0.7。算一下输入(1,1)0.50.5-0.70.3 0 → 输出1 ✅输入(1,0)0.50-0.7-0.2 ≤0 → 输出0 ✅输入(0,1)同理0 → 输出0 ✅输入(0,0)-0.7 ≤0 → 输出0 ✅完美感知机学会了“与门”。但它有个致命伤只能解决线性可分的问题。什么叫线性可分就是你能在平面上画一条直线把两类点分开。比如“与门”可以但“异或门”XOR就不行——你画不出一条直线把(0,1)和(1,0)放一边(0,0)和(1,1)放另一边。这个缺陷让神经网络差点“凉”了十几年。后来人们发现只要加上多层和非线性激活函数就能解决XOR问题。而激活函数就是拯救神经网络的关键。三、为什么激活函数必须是“非线性的”——叠直线还是直线想象一下你手里只有直尺线性变换无论你拿多少把直尺叠在一起画出来的还是直线。一个全是线性层的神经网络本质上和一个单层线性模型没有区别——它学不了XOR认不出手写数字就是个“高级线性回归”。激活函数必须是非线性函数因为它给网络带来了“弯弯绕绕”的能力。有了非线性网络才能拟合曲线、识别复杂图案。下面我们就一个个来看最常用的激活函数。我会用最直白的话告诉你它长什么样、好在哪、烂在哪、什么时候用。四、阶跃函数最原始的“开关”这就是感知机里用的那个f(x){0,x01,x≥0f(x){0,1,x0x≥0图像就是x0时在0高度x0时突然跳到1像楼梯台阶。问题它的导数几乎处处是0除了0点不可导。如果你用梯度下降法训练多层网络梯度乘上0就没了前面的层永远学不到东西。这就是“梯度消失”的极端例子。代码def step_function(x): return 1 if x 0 else 0 # 支持数组 import numpy as np def step_array(x): return np.array(x 0, dtypeint)结论只在教科书里出现实际不用。五、Sigmoid曾经的大明星如今过气了Sigmoid函数长这样f(x)11e−xf(x)1e−x1你可以在脑子里画一下x很大时e⁻ˣ≈0所以f(x)≈1x很小时e⁻ˣ巨大f(x)≈0x0时f(0)0.5。整个形状像个平滑的S。优点平滑、可导能用梯度下降。输出在0~1之间可以当概率用。比如二分类输出0.8就是“80%概率是正类”。缺点一堆梯度消失当x6或x-6时导数几乎为0。深层网络里梯度一层层乘传到前面就没了。网络根本学不动。输出全为正不是零中心。这会导致梯度更新时走“之”字形收敛慢。计算慢里面有指数运算比简单的比较慢得多。代码def sigmoid(x): return 1 / (1 np.exp(-x))建议二分类的输出层可以用。隐藏层千万别用除非你的网络只有一两层。六、Tanh零中心的“S形”Tanh是Sigmoid的升级版f(x)1−e−2x1e−2xf(x)1e−2x1−e−2x输出范围(-1,1)并且过原点(0,0)。优点输出均值是0零中心比Sigmoid好。因为下一层收到的数据有正有负梯度更新更稳。缺点照样有梯度消失问题。深层网络还是不行。代码def tanh(x): return np.tanh(x)建议浅层网络2-3层可以考虑或者用在RNN/LSTM里。深层网络别用。七、ReLU当今隐藏层的“绝对王者”ReLU的全称是Rectified Linear Unit修正线性单元。它是目前最最最常用的激活函数。公式简单得令人发指f(x)max⁡(0,x){0,x≤0x,x0f(x)max(0,x){0,x,x≤0x0图像负数全部“咔嚓”砍成0正数原样输出。优点计算极快就一个比较和取最大值没有指数。GPU上比Sigmoid快5-10倍。正区间无梯度消失x0时梯度恒为1信号可以无损传到深层。稀疏激活负数变0相当于关掉了一部分神经元。这不仅省计算还有点像正则化能防过拟合。缺点神经元死亡如果一个神经元的所有输入都是负数它输出永远为0梯度也是0再也活不过来。如果很多神经元都死了网络能力大打折扣。代码def relu(x): return np.maximum(0, x)建议隐藏层无脑上ReLU。99%的情况它都很好用。如果你发现训练时损失一直降不下去或者ReLU输出中0的比例超过30%再考虑换下面的Leaky ReLU。八、Leaky ReLU给负数留条“缝”为了解决“神经元死亡”Leaky ReLU给负数区域开了一个小口子f(x){αx,x≤0x,x0f(x){αx,x,x≤0x0α通常取0.01或0.001是一个很小的正数。图像正数不变负数是一条很缓的直线不是0。优点负数也有梯度虽然小神经元有机会“复活”。代码def leaky_relu(x, alpha0.01): return np.where(x 0, x, alpha * x)变种PReLUα不是固定的而是可训练的参数。网络自己学。RReLUα在训练时随机从某个范围里抽测试时取平均。有点正则化效果。建议ReLU出现死亡问题时换它。九、Softmax把分数变成概率的“魔术师”Softmax不是用在隐藏层的它专门用在多分类问题的输出层。公式假设有n个类别ykexk∑i1nexiyk∑i1nexiexk它干了什么对每个原始分数取指数 exkexk。指数函数增长极快大的变得巨大小的变得极小。再除以所有指数的和。这样所有输出都在0~1之间而且加起来等于1。结果就是一个漂亮的概率分布。比如三个类别的原始分数是[1, 5, 10]经过Softmax后变成大约[0.0001, 0.0067, 0.9892]。最大的那个几乎接近1。注意数值稳定性如果x很大eˣ会溢出。所以实现时要先减去最大值。代码def softmax(x): # x可以是1维或2维批量 x x - np.max(x, axis-1, keepdimsTrue) exp_x np.exp(x) return exp_x / np.sum(exp_x, axis-1, keepdimsTrue)建议多分类输出层必须用Softmax。二分类可以用Sigmoid效果等价但更快。十、其他几个“配角”激活函数了解一下以后读论文不懵。1. Identity恒等函数f(x)xf(x)x什么都不做。只用于回归问题的输出层比如预测房价。千万别放隐藏层因为它是线性的。2. ELU负数部分是指数曲线输出接近零中心。比ReLU平滑但计算稍慢。3. Swish也叫SiLUf(x)x⋅sigmoid(x)f(x)x⋅sigmoid(x)Google提出在非常深的网络100层或Transformer中有时比ReLU好。计算量稍大。4. GELUBERT、GPT等大模型用的就是它。可以理解为ReLU的平滑、随机版。做自然语言处理时常用。十一、怎么选激活函数——一张表搞定隐藏层中间层情况推荐别用默认不知道用啥ReLUSigmoid / TanhReLU导致大量神经元死亡Leaky ReLU或 PReLU—非常深的网络100层Swish 或 GELU—循环神经网络RNN/LSTMTanh Sigmoid门控—输出层任务激活函数二分类Sigmoid多分类Softmax回归预测任意实数Identity无激活回归输出有边界如[0,1]Sigmoid 或 Tanh 再缩放十二、手把手写代码一个三层神经网络超详细注释咱们别光说不练。下面用Python NumPy实现一个三层神经网络的前向传播。不训练只演示数据怎么一层层流过去。假设网络结构输入层2个节点比如二维数据点第1隐藏层3个节点第2隐藏层2个节点输出层2个节点二分类或回归隐藏层用Sigmoid仅演示实际请用ReLU输出层用恒等函数。第一步理解权重矩阵的形状铁律如果前一层有 mm 个神经元后一层有 nn 个神经元那么权重矩阵的形状就是 (m,n)(m,n)。每一行的权重连接前一层的一个神经元到后一层的所有神经元。输入层(2) → 隐藏层1(3)W1形状(2,3)隐藏层1(3) → 隐藏层2(2)W2形状(3,2)隐藏层2(2) → 输出层(2)W3形状(2,2)偏置向量的长度等于后一层神经元数。第二步完整代码每一行都有注释import numpy as np # 激活函数 def sigmoid(x): S形曲线把输入压缩到0~1之间 return 1 / (1 np.exp(-x)) def identity(x): 恒等函数原样输出 return x def init_network(): 初始化参数这里用了固定值实际训练时会是随机或学到的 network {} # 第1层输入 - 隐藏层1 network[W1] np.array([[0.1, 0.3, 0.5], # 第1个输入到3个隐藏节点的权重 [0.2, 0.4, 0.6]]) # 第2个输入到3个隐藏节点的权重 network[b1] np.array([0.1, 0.2, 0.3]) # 3个偏置 # 第2层隐藏层1 - 隐藏层2 network[W2] np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]]) network[b2] np.array([0.1, 0.2]) # 第3层隐藏层2 - 输出层 network[W3] np.array([[0.1, 0.3], [0.2, 0.4]]) network[b3] np.array([0.1, 0.2]) return network def forward(network, x): 前向传播从输入x计算输出y x: 形状 (2,) 的向量比如 [1.0, 0.5] W1, W2, W3 network[W1], network[W2], network[W3] b1, b2, b3 network[b1], network[b2], network[b3] # 第1层 a1 np.dot(x, W1) b1 # (2,) dot (2,3) (3,) z1 sigmoid(a1) # 激活 # 第2层 a2 np.dot(z1, W2) b2 # (3,) dot (3,2) (2,) z2 sigmoid(a2) # 输出层 a3 np.dot(z2, W3) b3 # (2,) dot (2,2) (2,) y identity(a3) # 输出层一般不用激活或Softmax return y # 测试 network init_network() x np.array([1.0, 0.5]) y forward(network, x) print(输出:, y) # 例如 [0.316, 0.696]运行一下你会得到两个数。虽然这个结果没啥实际意义因为没训练但你看到了完整的计算流程。十三、终极实战手写数字识别MNIST含批处理现在咱们来真的——识别手写数字。用的是Kaggle的Digit Recognizer数据集和MNIST一样。每张图是28×28像素共784个灰度值0~255。我们搭一个三层网络输入层784个节点隐藏层150个节点隐藏层2100个节点输出层10个节点对应数字0~9用Softmax激活注意这里的参数是从一个已经训练好的文件nn_sample里加载的。我们只做推理前向传播。如果你想自己训练需要反向传播和梯度下降篇幅有限这里不展开。第一步加载数据数据集下载https://pan.baidu.com/s/1xg4UnBRx2h0ysmhmAttn8g?pwd6tzwimport numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import MinMaxScaler def get_data(): # 读取CSV data pd.read_csv(./data/train.csv) X data.drop(label, axis1).values # (42000, 784) y data[label].values # (42000,) # 分出测试集30% _, x_test, _, y_test train_test_split(X, y, test_size0.3, random_state42) # 归一化把0~255映射到0~1让数值范围友好 scaler MinMaxScaler() # 注意实际应该用训练集的scaler来转换测试集这里为了简化只用了测试集 x_test scaler.fit_transform(x_test) return x_test, y_test第二步加载训练好的模型参数模型下载https://pan.baidu.com/s/1Nf0ECKRt2yN5YWqdW6AKDQ?pwd4i77import joblib def init_network(): # 假设模型保存在这个文件 network joblib.load(./data/nn_sample) return network第三步预测函数支持批量def sigmoid(x): return 1 / (1 np.exp(-x)) def softmax(x): # 批量版x形状 (N, 10) x x - np.max(x, axis1, keepdimsTrue) # 防溢出 exp_x np.exp(x) return exp_x / np.sum(exp_x, axis1, keepdimsTrue) def predict(network, x): W1, W2, W3 network[W1], network[W2], network[W3] b1, b2, b3 network[b1], network[b2], network[b3] a1 np.dot(x, W1) b1 # (N,784) dot (784,50) (N,50) z1 sigmoid(a1) a2 np.dot(z1, W2) b2 # (N,50) dot (50,100) (N,100) z2 sigmoid(a2) a3 np.dot(z2, W3) b3 # (N,100) dot (100,10) (N,10) y softmax(a3) return y第四步计算准确率分批处理防止内存爆def evaluate(x_test, y_test, network, batch_size100): accuracy_cnt 0 n len(x_test) for i in range(0, n, batch_size): x_batch x_test[i:ibatch_size] y_batch y_test[i:ibatch_size] y_prob predict(network, x_batch) # 概率 p np.argmax(y_prob, axis1) # 预测的类别 accuracy_cnt np.sum(p y_batch) return accuracy_cnt / n # 主程序 if __name__ __main__: x_test, y_test get_data() network init_network() acc evaluate(x_test, y_test, network) print(f准确率: {acc:.4f}) # 训练好的模型通常能到97%以上代码解读np.dot(x, W1) 里x可以是二维矩阵多个样本NumPy会自动做批量矩阵乘法非常高效。Softmax里减去最大值是为了防止exp(1000)这种溢出。np.argmax(y_prob, axis1) 返回每行最大值的列索引就是预测的数字。如果你没有预训练模型可以用随机权重跑一下——准确率大概10%瞎猜。这说明训练有多重要。十四、总结一张表记住所有激活函数名字公式输出范围优点缺点什么时候用阶跃0/1阈值{0,1}简单不可导不用Sigmoid1/(1e⁻ˣ)(0,1)平滑可当概率梯度消失非零中心二分类输出层Tanh(eˣ-e⁻ˣ)/(eˣe⁻ˣ)(-1,1)零中心仍有梯度消失浅层网络RNNReLUmax(0,x)[0,∞)快无正区间梯度消失神经元死亡隐藏层默认首选Leaky ReLUmax(αx, x)(-∞,∞)解决死亡多一个参数ReLU死亡时换它Softmaxeˣ/Σeˣ(0,1), 和为1输出概率分布计算稍重多分类输出层Identityx(-∞,∞)简单线性回归输出层最后送你三句话隐藏层无脑上ReLU。遇到神经元死亡就换Leaky ReLU。输出层分类用Softmax回归用Identity二分类也可用Sigmoid。千万别在隐藏层用Sigmoid和Tanh——2026年了该升级了。神经网络能“思考”全靠激活函数带来的非线性。搞懂这些基础你就能更自信地设计自己的模型。如果这篇文章帮到了你点个赞、收个藏评论区随便问我会一一回复。

更多文章