当前位置: 首页 > news >正文

Python可视化五大激活函数及其导数:从Sigmoid到Softmax的深度解析

1. 从“画”开始:为什么我们要亲手绘制激活函数?

如果你刚开始接触深度学习或者神经网络,可能会在无数的教程和论文里看到Sigmoid、ReLU这些名字。它们通常被称作“激活函数”,是神经网络里决定神经元是否“兴奋”的关键组件。很多初学者,包括当年的我,一开始都是直接调用torch.nn.ReLU()或者tf.nn.sigmoid,把函数当成一个黑盒来用。公式虽然也看,但总觉得隔着一层纱,理解不够透彻。

直到有一次,我在调试一个模型时,发现梯度消失得特别快,训练几乎停滞。排查了半天,最后定位到是某一层错误地选用了Sigmoid函数。那一刻我才真正意识到,仅仅知道函数的名字和调用方式是远远不够的。你必须“看见”它——看见它的形状,看见它的导数(梯度)变化,看见它在不同输入区间下的行为。而“看见”最直观的方式,就是亲手把它画出来。

用Python画图,远不止是得到一个漂亮的曲线。这个过程强迫你去理解函数的定义域、值域、数学表达式,以及最重要的——它的特性如何影响了神经网络的训练。比如,Sigmoid的输出为什么会被压缩在0到1之间?ReLU的“死区”到底在哪里?Softmax为什么能把一堆数字变成概率分布?这些问题,在动手编码绘图的过程中,答案会变得异常清晰。

所以,这个系列的第一篇,我们不谈复杂的网络结构,也不做项目实战,就做一件最基础但至关重要的事:用Python的Matplotlib库,把Sigmoid、ReLU、Softmax、Tanh、Leaky ReLU这几个最核心的激活函数,以及它们对应的导数函数,清晰地绘制出来。我会带你一步步搭建绘图环境,编写每一个函数,并详细解释图像背后的每一个关键点。当你完成时,这些函数对你而言将不再是抽象的符号,而是有形状、有性格的“工具”,你能清楚地知道在什么场景下该请谁“出场”。

2. 绘图基石:搭建你的Python可视化环境

工欲善其事,必先利其器。在开始画函数之前,我们需要一个稳定、顺手的环境。对于科学计算和可视化,我强烈推荐使用Anaconda来管理Python环境,它集成了几乎所有我们需要的科学计算库,并且能很好地处理包依赖问题,避免“装了这个,那个又报错”的窘境。

2.1 环境安装与核心库介绍

首先,如果你还没有安装Python,可以去Python官网下载最新版本,但我更建议直接安装Anaconda。安装过程很简单,一路下一步即可。安装完成后,你会拥有一个独立的、干净的Python环境。

我们这次绘图的核心武器是两个库:NumPyMatplotlib

  • NumPy:它是Python科学计算的基石。我们画函数图,本质上是在坐标轴上描点。我们需要生成一系列在X轴上的点(比如从-10到10),然后根据函数公式计算出每个点对应的Y值。NumPy的np.linspacenp.array操作能极其高效地完成这项任务。
  • Matplotlib:这是Python绘图领域的事实标准,功能强大且灵活。我们将主要使用它的pyplot模块,这个模块提供了一套类似MATLAB的绘图接口,非常容易上手。

在Anaconda环境中,这两个库通常已经预装好了。你可以打开终端(Windows叫Anaconda Prompt,Mac/Linux叫Terminal),输入以下命令来确认和安装:

# 检查是否已安装 conda list numpy matplotlib # 如果未安装,使用conda安装(推荐,能自动处理依赖) conda install numpy matplotlib # 或者使用pip安装 pip install numpy matplotlib

安装无误后,我们就可以在代码中导入它们了。标准的导入惯例是:

import numpy as np import matplotlib.pyplot as plt

这里as npas plt是别名,是社区约定俗成的写法,能让代码更简洁。

2.2 构建统一的绘图画布与坐标轴

一个好的对比图,应该让观众一眼就能看出差异。如果我们把五个函数曲线杂乱地画在一起,会显得非常混乱。因此,我习惯为每个函数及其导数创建独立的子图(Subplot),并将它们排列在一个大画布上。

这里会用到Matplotlib的plt.subplots函数。它一次性创建画布(Figure)和一组坐标轴(Axes)对象,非常方便。我们来规划一下布局:我们有5个激活函数,每个函数我们既要画它的曲线,也要画它的导数曲线。所以总共需要10个子图。我们可以把它们排列成5行2列。

# 创建一个画布和10个子图(5行,2列),画布尺寸设置为宽15英寸,高20英寸,以保证每个子图有足够的空间 fig, axes = plt.subplots(5, 2, figsize=(15, 20)) # fig是画布对象,axes是一个5行2列的二维数组,存储了每个子图的坐标轴对象 # 例如,axes[0, 0] 就是第一行第一列的子图(Sigmoid函数图),axes[0, 1] 就是第一行第二列的子图(Sigmoid导数图)

接下来,我们需要为所有函数生成统一的X轴输入数据。为了能清晰展示函数在正负区间的行为,我们选择一个对称且范围足够的区间,比如从-10到10。

# 生成从-10到10,共1000个等间距的点。点数越多,曲线越平滑。 x = np.linspace(-10, 10, 1000)

准备工作就绪,现在我们可以开始逐个“绘制”这些函数了。记住,我们的目标不是简单地画出线,而是要理解这条线为什么长这样。

3. 经典元老:Sigmoid函数的平滑与困境

Sigmoid函数可以说是神经网络激活函数的“开国元老”,在早期感知机模型中广泛应用。它的数学表达式是:

[ \sigma(x) = \frac{1}{1 + e^{-x}} ]

3.1 Sigmoid函数的实现与绘图

用NumPy实现它非常简单,因为NumPy提供了指数计算np.exp

def sigmoid(x): """计算Sigmoid函数值""" return 1 / (1 + np.exp(-x)) # 计算y值 y_sigmoid = sigmoid(x)

现在,我们在第一个子图(axes[0, 0])上绘制它。

ax = axes[0, 0] # 获取第一行第一列的坐标轴 ax.plot(x, y_sigmoid, label='Sigmoid', color='blue', linewidth=2) ax.set_title('Sigmoid Activation Function') ax.set_xlabel('Input (x)') ax.set_ylabel('Output σ(x)') ax.grid(True, linestyle='--', alpha=0.6) # 添加网格线,方便观察 ax.legend() ax.set_ylim(-0.1, 1.1) # 将Y轴范围固定在-0.1到1.1,因为Sigmoid输出在(0,1)

运行这段代码,你会看到一条漂亮的S型曲线。它有几个关键特性:

  1. 输出范围在(0, 1):无论输入多大或多小,输出都被压缩到0和1之间。这使得它可以被解释为一种“概率”(例如,二分类问题的输出)。
  2. 单调连续:函数处处可导,且是平滑的。
  3. 中心对称点:在x=0时,输出为0.5。

3.2 Sigmoid的导数:梯度消失问题的根源

一个函数的导数描述了其变化率。在神经网络的反向传播中,我们需要计算梯度,而梯度就是通过激活函数的导数来传递的。Sigmoid的导数有一个很有趣的性质:

[ \sigma'(x) = \sigma(x) \cdot (1 - \sigma(x)) ]

我们可以用两种方式计算并绘制它:一是直接用上面的导数公式,二是用数值方法(如中心差分法)来近似,后者在验证我们公式正确性时很有用。

# 方法一:使用导数公式 def sigmoid_derivative(x): s = sigmoid(x) return s * (1 - s) y_sigmoid_derivative = sigmoid_derivative(x) # 方法二:数值导数(用于验证) def numerical_derivative(f, x, h=1e-5): """计算函数f在点x处的数值导数(中心差分法,更精确)""" return (f(x + h) - f(x - h)) / (2 * h) y_sigmoid_derivative_num = numerical_derivative(sigmoid, x) # 绘制到第二个子图 (axes[0, 1]) ax = axes[0, 1] ax.plot(x, y_sigmoid_derivative, label='Derivative (Formula)', color='red', linewidth=2, linestyle='-') ax.plot(x, y_sigmoid_derivative_num, label='Derivative (Numerical)', color='green', linewidth=1, linestyle='--', alpha=0.7) ax.set_title('Derivative of Sigmoid') ax.set_xlabel('Input (x)') ax.set_ylabel('dσ/dx') ax.grid(True, linestyle='--', alpha=0.6) ax.legend() ax.set_ylim(-0.1, 0.3)

观察导数图,你会发现一个严重的问题:当输入x的绝对值很大时(无论是正还是负),Sigmoid的导数都趋近于0。在反向传播中,梯度是链式相乘的。如果某一层的梯度接近0,那么乘以这个梯度后,传递到更前面层的梯度会以指数级速度衰减,直至消失。这就是著名的“梯度消失”问题。这使得深层网络使用Sigmoid时变得极难训练。因此,在现代深度学习中,Sigmoid通常只用于输出层(做二分类概率),而隐藏层已很少使用。

实操心得:画导数图时,用数值导数(中心差分法)和解析导数公式一起画,用虚线稍微区分。这不仅能验证你写的导数公式是否正确,还能直观地向读者展示“导数”这个抽象概念,其实就是函数在某一点切线的斜率。当两条线完全重合时,说明你的公式推导和代码实现都是正确的。

4. 现代王者:ReLU家族及其变种

为了解决Sigmoid带来的梯度消失问题(在正区间其实也有,但更严重的是饱和区的梯度消失),ReLU(Rectified Linear Unit,修正线性单元)被提出,并迅速成为深度隐藏层的默认选择。

4.1 标准ReLU:简单粗暴的有效

ReLU的定义简单得令人惊讶:

[ \text{ReLU}(x) = \max(0, x) ]

它的意思是:如果输入x大于0,输出就是x本身;如果输入x小于等于0,输出就是0。用NumPy实现,我们可以利用其向量化操作的特性,一行代码搞定:

def relu(x): """计算ReLU函数值""" return np.maximum(0, x) y_relu = relu(x)

在子图axes[1, 0]上绘制:

ax = axes[1, 0] ax.plot(x, y_relu, label='ReLU', color='orange', linewidth=2) ax.set_title('ReLU Activation Function') ax.set_xlabel('Input (x)') ax.set_ylabel('Output ReLU(x)') ax.grid(True, linestyle='--', alpha=0.6) ax.legend() # ReLU输出范围是[0, +∞),我们设定一个合理的显示范围 ax.set_ylim(-1, 11)

图像是一条折线:在负半轴是平的(值为0),在正半轴是一条斜率为1的直线。它的优点非常突出:

  1. 计算极其高效:只需要比较和取最大值,没有指数、除法等复杂运算。
  2. 缓解梯度消失:在正区间,导数为常数1,梯度可以毫无衰减地传递下去,极大地促进了深层网络的训练。
  3. 带来稀疏性:负半轴输出为0,使得网络中的一部分神经元被“关闭”,这相当于一种隐式的稀疏化,可能让模型更易解释且具有更好的泛化能力。

4.2 ReLU的导数与“死区”问题

ReLU的导数也不复杂: [ \text{ReLU}'(x) = \begin{cases} 1 & \text{if } x > 0 \ 0 & \text{if } x \le 0 \end{cases} ] 注意,在x=0处,导数在数学上是不确定的(不可导)。但在实际实现中,通常约定俗成地将其设为0或1(PyTorch和TensorFlow中通常设为0)。

def relu_derivative(x): """计算ReLU的导数""" # 这里我们采用x>0时为1,否则为0的约定 return np.where(x > 0, 1.0, 0.0) y_relu_derivative = relu_derivative(x) # 绘制到 axes[1, 1] ax = axes[1, 1] ax.plot(x, y_relu_derivative, label='Derivative of ReLU', color='darkorange', linewidth=2, drawstyle='steps-post') # 使用阶梯图样式更直观 ax.set_title('Derivative of ReLU') ax.set_xlabel('Input (x)') ax.set_ylabel('dReLU/dx') ax.grid(True, linestyle='--', alpha=0.6) ax.legend() ax.set_ylim(-0.1, 1.5)

从导数图可以清晰地看到ReLU的**“死区”(Dying ReLU)问题**:一旦某个神经元的输入加权和落入了负半轴(x<=0),它的梯度就变成了0。在后续的训练中,这个梯度为0的神经元将无法再通过梯度下降法更新其权重,相当于“死亡”了,永远输出0。如果这种情况大面积发生,网络的有效容量会大幅下降。

4.3 Leaky ReLU:给负区间一点生机

为了解决“死区”问题,Leaky ReLU被提出。它对负区间不再一概置零,而是赋予一个很小的斜率(比如0.01)。

[ \text{LeakyReLU}(x) = \begin{cases} x & \text{if } x > 0 \ \alpha x & \text{if } x \le 0 \end{cases} ] 其中,(\alpha)是一个很小的正数,如0.01。

def leaky_relu(x, alpha=0.01): """计算Leaky ReLU函数值""" return np.where(x > 0, x, alpha * x) y_leaky_relu = leaky_relu(x, alpha=0.01)

在子图axes[2, 0]绘制。你会发现,它的图像在负半轴是一条斜率很小的斜线,不再与X轴重合。

ax = axes[2, 0] ax.plot(x, y_leaky_relu, label=f'Leaky ReLU (α={0.01})', color='purple', linewidth=2) ax.set_title('Leaky ReLU Activation Function') ax.set_xlabel('Input (x)') ax.set_ylabel('Output LeakyReLU(x)') ax.grid(True, linestyle='--', alpha=0.6) ax.legend() ax.set_ylim(-0.5, 11)

它的导数在负区间是一个很小的常数(\alpha),保证了梯度永远不会完全消失。

def leaky_relu_derivative(x, alpha=0.01): """计算Leaky ReLU的导数""" return np.where(x > 0, 1.0, alpha) y_leaky_relu_derivative = leaky_relu_derivative(x, alpha=0.01) # 绘制到 axes[2, 1] ax = axes[2, 1] ax.plot(x, y_leaky_relu_derivative, label=f'Derivative (α={0.01})', color='darkviolet', linewidth=2, drawstyle='steps-post') ax.set_title('Derivative of Leaky ReLU') ax.set_xlabel('Input (x)') ax.set_ylabel('dLeakyReLU/dx') ax.grid(True, linestyle='--', alpha=0.6) ax.legend() ax.set_ylim(-0.02, 1.5)

Leaky ReLU是ReLU一个简单有效的改进,在实践中(尤其是使用较深网络时)往往能获得比标准ReLU更稳定、更好的训练效果。参数(\alpha)通常作为超参数,也可以学习得到(这就是Parametric ReLU, PReLU)。

注意事项:在绘制Leaky ReLU时,因为负区间的值很小(-10*0.01 = -0.1),如果Y轴范围设置得和ReLU一样(如-1到11),负区间的那条线会几乎贴在X轴上,看不清楚。因此,我特意将Y轴下限设为-0.5,以便清晰展示负区间的微小斜率。这是绘图时的一个小技巧:根据数据范围动态调整坐标轴,以突出你想展示的关键特征。

5. 双曲正切:Tanh,一个中心化的Sigmoid

Tanh(双曲正切)函数可以看作是Sigmoid的“放大平移”版本。它的公式是:

[ \tanh(x) = \frac{e^{x} - e^{-x}}{e^{x} + e^{-x}} = 2 \cdot \sigma(2x) - 1 ]

从最后一个等式可以看出,它其实就是把Sigmoid函数的输入放大2倍,输出范围从(0,1)线性变换到了(-1,1)。

5.1 Tanh的实现与特性

NumPy直接提供了np.tanh函数,我们也可以自己实现来加深理解。

def tanh_custom(x): """自定义实现Tanh函数""" return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x)) # 使用NumPy内置函数,更高效稳定 y_tanh = np.tanh(x) # 或 y_tanh = tanh_custom(x)

在子图axes[3, 0]绘制:

ax = axes[3, 0] ax.plot(x, y_tanh, label='Tanh', color='brown', linewidth=2) ax.set_title('Tanh Activation Function') ax.set_xlabel('Input (x)') ax.set_ylabel('Output tanh(x)') ax.grid(True, linestyle='--', alpha=0.6) ax.legend() ax.set_ylim(-1.1, 1.1) # 输出范围是(-1, 1)

与Sigmoid对比,Tanh具有零中心化的特性,即其输出以0为中心。这在某些情况下是有益的,因为下一层神经元的输入是正负交替的,可能有助于缓解梯度更新时的“Z”字形震荡,加速收敛。因此,在循环神经网络(RNN)中,Tanh仍然被广泛使用。然而,它和Sigmoid一样,在两端也存在饱和区,导数会趋近于0,因此同样存在梯度消失的问题。

5.2 Tanh的导数

Tanh的导数公式为: [ \tanh'(x) = 1 - \tanh^2(x) ] 它的值域在(0, 1]之间,当x=0时,导数值最大,为1。

def tanh_derivative(x): """计算Tanh的导数""" return 1 - np.tanh(x) ** 2 y_tanh_derivative = tanh_derivative(x) # 绘制到 axes[3, 1] ax = axes[3, 1] ax.plot(x, y_tanh_derivative, label='Derivative of Tanh', color='saddlebrown', linewidth=2) ax.set_title('Derivative of Tanh') ax.set_xlabel('Input (x)') ax.set_ylabel('dtanh/dx') ax.grid(True, linestyle='--', alpha=0.6) ax.legend() ax.set_ylim(-0.1, 1.1)

观察导数图,其形状和Sigmoid的导数类似,都是一个“钟形”曲线,但最大值是1(在x=0处),且关于Y轴对称。这意味着Tanh在0附近有更强的梯度信号。

6. 概率转换器:Softmax函数的特殊性与可视化挑战

Softmax函数与前几个函数有本质区别。Sigmoid、ReLU、Tanh都是逐元素操作,每个神经元的输出只依赖于自己的输入。而Softmax是向量函数,它的输出是一个概率分布,每个元素的输出依赖于整个输入向量的所有值。

对于一个K维向量(\mathbf{z} = [z_1, z_2, ..., z_K]),Softmax的定义是: [ \text{Softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{K} e^{z_j}} ] 它的输出满足两个重要性质:1) 每个元素在(0,1)之间;2) 所有元素之和为1。这使得它非常适合作为多分类神经网络输出层的激活函数。

6.1 Softmax的绘图:需要升维思考

由于Softmax的输入和输出都是向量,我们无法像之前那样简单地用y=f(x)在二维平面上画出一条线。为了可视化,我们需要固定一个视角。最常见的方法是:假设我们有一个3维的输入向量[x1, x2, x3],然后固定其中两个维度的值,观察第三个维度变化时,三个输出概率的变化

例如,我们令x2 = 1.0,x3 = 0.5,然后让x1在区间[-10, 10]上变化,观察三个输出p1, p2, p3

def softmax(z): """计算Softmax函数值,z可以是一个向量或一批向量""" # 减去最大值,防止指数运算溢出(数值稳定技巧) exp_z = np.exp(z - np.max(z, axis=-1, keepdims=True)) return exp_z / np.sum(exp_z, axis=-1, keepdims=True) # 生成x1的变化范围 x1_range = np.linspace(-10, 10, 1000) # 固定x2和x3 x2_fixed = 1.0 x3_fixed = 0.5 # 初始化存储三个概率值的数组 p1_list, p2_list, p3_list = [], [], [] for x1 in x1_range: # 构造输入向量 z = np.array([x1, x2_fixed, x3_fixed]) # 计算softmax probs = softmax(z) p1_list.append(probs[0]) p2_list.append(probs[1]) p3_list.append(probs[2]) p1_array = np.array(p1_list) p2_array = np.array(p2_list) p3_array = np.array(p3_list)

现在,我们在子图axes[4, 0]上绘制三条曲线,分别代表p1,p2,p3x1变化的情况。

ax = axes[4, 0] ax.plot(x1_range, p1_array, label='p1 (x1变化)', color='teal', linewidth=2) ax.plot(x1_range, p2_array, label='p2 (x2固定=1.0)', color='skyblue', linewidth=2) ax.plot(x1_range, p3_array, label='p3 (x3固定=0.5)', color='lightcoral', linewidth=2) ax.set_title('Softmax Output (3-class, x2=1.0, x3=0.5)') ax.set_xlabel('Input x1') ax.set_ylabel('Probability') ax.grid(True, linestyle='--', alpha=0.6) ax.legend() ax.set_ylim(-0.05, 1.05)

从图中,你可以直观地看到Softmax的“竞争”特性:

  • x1远大于x2x3时(比如x1 > 5),p1接近1,p2p3接近0。
  • x1远小于其他值时,p1接近0。
  • 三条曲线的概率之和在任何一点都恒等于1。

6.2 Softmax的“导数”:Jacobian矩阵

Softmax的“导数”更为复杂,因为它的输出是一个向量,输入也是一个向量。它的导数是一个Jacobian矩阵,其中第i行第j列的元素是(\frac{\partial p_i}{\partial z_j})。这个矩阵不是对角阵,因为每个输出(p_i)都对所有输入(z_j)有依赖。

对于一个具体的输出(p_i),其关于输入(z_j)的偏导数为: [ \frac{\partial p_i}{\partial z_j} = p_i (\delta_{ij} - p_j) ] 其中(\delta_{ij})是克罗内克δ函数(当i=j时为1,否则为0)。

这意味着,Softmax的梯度计算涉及到整个输出向量。可视化这个完整的Jacobian矩阵很困难。通常,在反向传播的特定上下文中(比如计算交叉熵损失对logits的梯度),会有一个非常简洁的形式。但为了本教程的完整性,我们可以选择一个简单的标量输出来观察其梯度。例如,我们固定x2=1.0, x3=0.5,只考虑第一个类别的概率p1相对于其输入x1的变化率,即(\frac{\partial p_1}{\partial x_1} = p_1(1 - p_1))。注意,这不是完整的梯度,因为p1也随x2x3变化,但这里我们只变化x1

# 计算 p1 对 x1 的偏导数(在x2, x3固定的前提下) p1_derivative_wrt_x1 = p1_array * (1 - p1_array) # 绘制到 axes[4, 1] ax = axes[4, 1] ax.plot(x1_range, p1_derivative_wrt_x1, label='∂p1/∂x1 (approx.)', color='darkcyan', linewidth=2) ax.set_title('Partial Derivative of p1 w.r.t x1\n(x2, x3 fixed)') ax.set_xlabel('Input x1') ax.set_ylabel('∂p1/∂x1') ax.grid(True, linestyle='--', alpha=0.6) ax.legend() ax.set_ylim(-0.05, 0.3)

这个图看起来很像Sigmoid的导数图,也是一个钟形曲线。它告诉我们,当p1的概率接近0.5时(即x1x2x3的值相近,竞争激烈时),梯度最大;当p1接近0或1时(即某个类别概率绝对占优或绝对劣势时),梯度很小。这符合直觉:当模型对当前样本的预测非常确信或非常不确定时,梯度信号弱,参数更新幅度小;当模型“犹豫不决”时,梯度信号最强。

重要提示:Softmax的可视化是本章最难的部分,因为它本质上是高维函数。我们这里采用的方法是“切片”可视化,即固定其他维度,观察一个维度变化的影响。这是一种理解高维函数的常用技巧。在实际编程中,softmax函数及其梯度计算都是由深度学习框架(如PyTorch、TensorFlow)自动完成的,但理解其背后的数学和图像,对于调试模型、理解损失函数的行为至关重要。

7. 最终整合与图像美化

我们已经完成了所有函数和导数的计算与绘制。现在,我们需要调整一下整体布局,让这10个子图看起来更整洁、专业,然后显示最终图像。

# 调整子图之间的间距,防止标题和标签重叠 plt.tight_layout() # 显示图形 plt.show()

如果你是在Jupyter Notebook或类似交互式环境中运行,plt.show()会弹出一个窗口显示图像。如果你是在脚本中运行,你可能需要将图像保存到文件:

plt.savefig('activation_functions.png', dpi=300, bbox_inches='tight') # 保存为高清PNG plt.show()

运行完整的代码,你会得到一张包含10个子图的大图,清晰地展示了五大激活函数及其导数的全貌。通过这张图,你可以直观地比较:

  • Sigmoid/Tanh的平滑饱和与梯度消失。
  • ReLU的线性区域与“死区”。
  • Leaky ReLU如何尝试解决“死区”。
  • Softmax如何将竞争性输入转化为概率分布。

这张图本身就是一份极佳的参考资料。我建议你在学习深度学习时,经常回顾它,思考不同激活函数的特性如何影响你网络的前向传播和反向传播。当你下次为网络中的某一层选择激活函数时,脑海中能立刻浮现出这些曲线的形状,那么你的选择将会更加有理有据。

代码写到这里,一个完整的、可复现的激活函数可视化工具就完成了。但更重要的是,在这个过程中,我们不是被动地接受定义,而是主动地通过代码去探索、验证和理解每一个数学公式背后的几何意义。这才是“动手”学习的真谛。在下一篇文章中,我们可以基于这个基础,进一步探索如何将这些激活函数集成到一个简单的神经网络中,并可视化每一层的输出分布,那将是另一个有趣的故事。

http://www.jsqmd.com/news/1304599/

相关文章:

  • 零代码AI智能体实现招标文件高效解析与风险识别
  • 网口与串口深度解析:从硬件原理到实战调试的嵌入式通信指南
  • 三极管特性曲线深度解析:从原理到电路设计的实战指南
  • 写给 8 月的技术投资建议:AI 编译、推理优化与 Rust 生态的优先事项判断
  • 嵌入式系统开发入门:从核心架构到实战应用全解析
  • OpenAI首席科学家离职对AI开发者的影响与应对策略
  • 从困惑度到BLEU:深入理解NLP模型评估指标的核心原理与实战权衡
  • 5个神奇技巧:用Illustrator脚本让你的设计效率提升300%
  • VC++ 2013运行库深度解析:从DLL依赖到开源部署实践
  • 抖音内容下载终极指南:开源批量下载工具完全解析
  • 2026年度优选:徐州房地产纠纷律所服务团队业内推荐 - 装修教育财税推荐2026
  • 免费VR视频转换终极指南:3步让普通设备畅享沉浸式VR体验
  • FreeRTOS延时函数深度解析:从原理到实战避坑指南
  • GIS坐标系WKID详解:从核心概念到ArcGIS与SARscape实战应用
  • 【Bug已解决】[Feature Proposal] Add FunASR ASR Distributed Inference Examples 解决方案
  • 2026年8月东莞彩色标签纸类包装/彩盒纸类包装行业精选厂家_东莞市时岱包装制品有限公司 - 品牌宣传支持者
  • 【高阶·云原生】如何构建云原生 AI 可观测性体系:从 GPU 硬件指标到 Token 成本的八层全链路监控
  • 2026下半年北京液晶条形屏供货商推荐:高质价比单 - 装修教育财税推荐2026
  • 如何快速掌握macOS屏幕录制:QuickRecorder的完整入门指南
  • 计算机学习笔记 Java基础与底层原理详解③ 流程控制、大数值运算、数组与多维数组
  • 化工园区做AR安全巡检推荐哪家供应商
  • GPT-5.5技术前瞻:从架构创新到开发者应对策略
  • 2026年长沙自流平厂家推荐榜:环氧/防静电/导静电地坪源头施工品牌精选 - 优企名品
  • 2026短剧IP孵化哪家机构实力更强?深度评测 - 品牌排行榜
  • 从语言模型到行动智能:Mythos如何让AI从“会说”到“会做”
  • 2026年江苏常州升学规划综合评价榜单:强基计划/高考志愿/港澳本科/出国留学申请,高一选科与中外合办院校申请全案解析 - 优企名品
  • 西门子SCL批量处理模拟量信号:从数据分离到工程实践
  • 终极静音方案:TPFanControl2让你的ThinkPad风扇不再吵闹
  • 抖音批量下载完整指南:开源工具如何帮你轻松管理海量视频资源
  • CLI 工具的配置文件管理方案:多层级配置合并的工程实践