Activation Functions in Neural Networks

激活函数在神经网络中引入非线性,使其成为通用函数近似器。Sigmoid和Tanh存在梯度消失问题,而ReLU解决了这一问题但可能导致死神经元。Leaky ReLU和Maxout是ReLU的改进版,Maxout虽无ReLU的缺点,但参数数量增加。结论是隐藏层可使用ReLU,注意学习率和死单元比例,避免使用sigmoid。

This article is inspired by 这里 and 这里.

- 激活函数的主要意义是为NN加入非线性的元素。在神经学上模仿的是一个神经元是否有效。

A Neural Network without Activation function would simply be a Linear regression Model. Neural-Networks are considered Universal Function ApproximatorsIt means that they can compute and learn any function at all. Almost any process we can think of can be represented as a functional computation in Neural Networks.

- 激活函数must be 'differentiable' for gradient descent.

- 一些常见的Function

  1.  Sigmo
<think>我们正在讨论的是在Matlab中实现自适应激活函数,参考论文《Adaptive activation functions accelerate convergence in deep and physics-informed neural networks》。自适应激活函数的核心思想是引入一个可训练的参数(通常记为a)来调整激活函数的形状,从而加速神经网络的收敛。在论文中,作者主要提出了两种形式:一种是缩放型(如a*sigmoid(x)),另一种是参数型(如sigmoid(a*x))。其中,参数型在论文中表现出更好的效果。 在Matlab中实现自适应激活函数,我们需要自定义激活函数层。从Matlab R2019a开始,Deep Learning Toolbox支持自定义层,我们可以通过创建`nnet.layer.Layer`类的子类来实现。 步骤: 1. 创建一个自定义层类,继承自`nnet.layer.Layer`(对于激活函数层,也可以继承`nnet.layer.Formattable`,但这里简单起见,我们直接继承`Layer`)。 2. 在构造函数中设置层的属性,包括可学习参数(如果有的话)。 3. 实现`predict`方法(前向传播)和`backward`方法(反向传播,可选,如果未实现则自动使用数值微分,但为了提高效率建议实现)。 注意:在自适应激活函数中,我们有一个可训练参数`a`。根据论文,我们可以为每个神经元(即每个通道)设置一个独立的`a`,也可以为整个层设置一个共享的`a`。这里我们采用整个层共享一个`a`(简单起见)。 下面我们以实现一个参数型的自适应Sigmoid激活函数为例(即sigmoid(a*x))。我们将其命名为`AdaptiveSigmoidLayer`。 步骤详解: 1. 定义类:`classdef AdaptiveSigmoidLayer < nnet.layer.Layer` 2. 在属性块中定义可学习参数(使用`LearnableParameter`对象)。注意:我们只需要一个参数`a`。 3. 在构造函数中初始化参数。根据论文,通常将`a`初始化为1(即开始时不改变激活函数形状),并设置其学习率等。 4. 实现`predict`方法:输入数据通过激活函数并输出。 5. 实现`backward`方法:计算损失函数关于输入的梯度和关于参数`a`的梯度。 注意:在Matlab中,自定义层需要满足一定的规范。同时,由于激活函数是逐元素的,我们不需要考虑空间维度。 以下是代码框架: ```matlab classdef AdaptiveSigmoidLayer < nnet.layer.Layer % 属性块 properties (Learnable) % 可训练参数 a end methods function layer = AdaptiveSigmoidLayer(name) % 构造函数,输入参数为层名称(可选) if nargin == 1 layer.Name = name; end % 设置层描述 layer.Description = "Adaptive Sigmoid activation with parameter a"; % 初始化可训练参数a,初始值为1(标量) layer.a = 1; end function Z = predict(layer, X) % 前向传播: 输出 = sigmoid(a * X) Z = 1 ./ (1 + exp(-layer.a * X)); end function [dLdX, dLdA] = backward(layer, X, Z, dLdZ, memory) % 反向传播 % 输入: % X: 输入数据 % Z: 前向传播的输出(即predict的输出) % dLdZ: 损失对Z的梯度(即下一层传回来的梯度) % memory: 前向传播中存储的中间值(这里我们没有使用) % 输出: % dLdX: 损失对X的梯度 % dLdA: 损失对参数a的梯度 % 计算sigmoid函数的导数:dZ/dX = a * sigmoid(a*X) * (1-sigmoid(a*X)) % 注意:Z = sigmoid(a*X),所以我们有: dZdX = layer.a * Z .* (1 - Z); % 损失对X的梯度:dL/dX = dL/dZ * dZ/dX dLdX = dLdZ .* dZdX; % 计算损失对参数a的梯度:dL/da = dL/dZ * dZ/da % dZ/da = X * (sigmoid(a*X) * (1-sigmoid(a*X))) % = X * (Z .* (1-Z)) [因为Z=sigmoid(a*X)] dZda = X .* Z .* (1 - Z); dLda = dLdZ .* dZda; % 由于a是一个标量(整个层共享),我们需要将dLda在所有元素上求和(或者平均?论文中没有明确,但通常求和) dLdA = sum(dLda, 'all'); % 对所有的元素求和 end end end ``` 注意: 1. 上面的反向传播推导: 前向传播:$Z = \sigma(a X)$,其中$\sigma$是sigmoid函数。 则: $\frac{\partial Z}{\partial X} = a \cdot \sigma'(a X) = a \cdot \sigma(a X)(1-\sigma(a X)) = a \cdot Z \cdot (1-Z)$ $\frac{\partial Z}{\partial a} = \sigma'(a X) \cdot X = Z(1-Z) \cdot X$ 2. 在反向传播函数中,我们计算了dLdX和dLdA。由于参数a是一个标量,我们需要将每个输入位置上的梯度dLda加起来,得到整个batch上对a的总梯度(因为a是被所有输入共享的)。 3. 在训练过程中,Matlab的自动微分机制会使用这些梯度来更新参数a。 4. 上述层可以像其他层一样被添加到网络层数组中。例如: layers = [ imageInputLayer([28 28 1]) fullyConnectedLayer(20) adaptiveSigmoidLayer % 我们的自定义层 fullyConnectedLayer(10) softmaxLayer classificationLayer ]; 但是,请注意:论文中使用了自适应激活函数在物理信息神经网络(PINN)中,通常用于求解偏微分方程。因此,在构建PINN时,我们需要将该层用于隐藏层。 另外,论文中还提到了一种自适应激活函数的形式:$a \cdot \tanh(x)$(即缩放型)和$\tanh(a \cdot x)$(参数型)。我们可以类似地实现自适应Tanh层。 此外,论文中强调了可训练参数a的重要性,并且通过实验表明,自适应激活函数可以显著加速收敛。 注意事项: 1. 在实现中,我们假设a是一个标量。但论文中提到了为每个神经元(即每个通道)设置独立的a。这可以通过将a初始化为一个向量(长度等于该层的神经元个数)来实现。在这种情况下,我们需要在反向传播时按照通道维度进行求和(或适当广播)。 2. 初始值:论文中尝试了不同的初始化,比如a=1,5,10等,但最终都是通过训练得到的。 如果你需要实现每个神经元独立的参数a,则需要修改: - 在构造函数中,根据输入通道数(例如,上一层的神经元个数)来确定a的大小,并初始化为一个向量(每个元素为1)。 - 在predict和backward中,需要将a进行适当的扩展(例如,使用reshape和隐式扩展)以匹配输入数据的维度(通常输入X的维度为[height, width, channels, batch])。但在全连接层后,数据通常是二维矩阵:[batch, channels](对于序列或向量)或四维(对于图像)。为了简单,我们假设在全连接层后使用,所以输入X是二维矩阵:[batch, features]。 假设我们实现一个每个特征(即每个神经元)独立参数a的自适应Sigmoid层(用于全连接层之后): - 假设输入X的维度为[batch, numFeatures]。 - a的形状应为[1, numFeatures](即每个特征一个a)。 修改后的代码框架如下: ```matlab classdef AdaptiveSigmoidPerFeatureLayer < nnet.layer.Layer properties (Learnable) a % 参数,大小为[1, numFeatures] end methods function layer = AdaptiveSigmoidPerFeatureLayer(numFeatures, name) if nargin < 2 name = ''; end layer.Name = name; layer.Description = "Adaptive Sigmoid with per-feature parameter a"; % 初始化a为1的行向量,长度为特征数 layer.a = ones(1, numFeatures); end function Z = predict(layer, X) % 输入X: [batch, features] % 参数a: [1, features] % 我们需要将a扩展成与X相同的形状(通过隐式扩展) Z = 1 ./ (1 + exp(-layer.a .* X)); % 注意:使用 .* 逐元素乘,并且a会自动扩展(每一行重复batch次) end function [dLdX, dLdA] = backward(layer, X, Z, dLdZ, ~) % 输入: % X: [batch, features] % Z: [batch, features] % dLdZ: [batch, features] % 输出: % dLdX: [batch, features] % dLdA: [1, features] 每个特征对应的梯度(需要对batch求和) % 计算dZdX: [batch, features] dZdX = layer.a .* Z .* (1 - Z); % dLdX = dLdZ * dZdX (逐元素乘) dLdX = dLdZ .* dZdX; % 计算dZda: [batch, features] = X .* Z .* (1-Z) dZda = X .* Z .* (1 - Z); % dLda = dLdZ .* dZda, 然后对batch维度求和(得到每个特征的总梯度) dLdA = sum(dLdZ .* dZda, 1); % 按第一维(batch)求和,得到[1, features] end end end ``` 这样,每个特征(即每个神经元)都有一个独立的a,并且梯度更新也是独立的。 在构建网络时,你需要指定特征数(即上一层的神经元个数): layers = [ fullyConnectedLayer(20) AdaptiveSigmoidPerFeatureLayer(20) ... ]; 注意:全连接层的输出大小(20)就是下一层自适应激活函数层的特征数。 最后,在训练过程中,我们可以通过设置合适的训练选项(如使用Adam优化器)来训练网络,包括参数a。 关于论文的更多细节,请参考原始论文[^1]。 相关问题: 1. 在物理信息神经网络(PINN)中如何使用自适应激活函数? 2. 除了Sigmoid和Tanh,自适应激活函数还能用于其他激活函数吗? 3. 自适应激活函数在普通深度学习任务(如图像分类)中的效果如何? [^1]: Jagtap, Ameya D., Kenji Kawaguchi, and George Em Karniadakis. "Adaptive activation functions accelerate convergence in deep and physics-informed neural networks." Journal of Computational Physics 404 (2020): 109136. </think>### 在Matlab中实现自适应激活函数的方法(基于论文《Adaptive activation functions accelerate convergence in deep and physics-informed neural networks》) #### 核心原理 自适应激活函数的核心是通过引入**可训练参数** $a$ 动态调整激活函数的非线性特征: $$ \sigma(a \cdot x) \quad \text{或} \quad a \cdot \sigma(x) $$ 其中 $\sigma$ 是基础激活函数(如Sigmoid、Tanh),参数 $a$ 在训练过程中自动优化,增强网络表达能力[^1]。 --- #### Matlab实现步骤(含代码) ##### 1. 自定义激活函数层 ```matlab classdef AdaptiveSigmoidLayer < nnet.layer.Layer properties (Learnable) a % 可训练缩放参数 end methods function layer = AdaptiveSigmoidLayer(name) layer.Name = name; layer.a = 1; % 初始化参数a=1 end function Z = predict(layer, X) % 自适应Sigmoid: σ(a*x) Z = 1 ./ (1 + exp(-layer.a * X)); end function [dLdX, dLdA] = backward(layer, X, Z, dLdZ, ~) % 反向传播梯度计算 dZdX = layer.a * Z .* (1 - Z); % ∂Z/∂X dLdX = dLdZ .* dZdX; % ∂L/∂X dZda = X .* Z .* (1 - Z); % ∂Z/∂a dLdA = sum(dLdZ .* dZda, 'all'); % ∂L/∂a (全局梯度) end end end ``` ##### 2. 构建包含自适应激活函数的网络 ```matlab layers = [ imageInputLayer([28 28 1]) fullyConnectedLayer(64) AdaptiveSigmoidLayer('adapt_sigm1') % 自定义层 fullyConnectedLayer(32) AdaptiveSigmoidLayer('adapt_sigm2') % 自定义层 fullyConnectedLayer(10) softmaxLayer classificationLayer]; ``` ##### 3. 训练配置关键参数(参考论文建议) ```matlab options = trainingOptions('adam', ... 'InitialLearnRate', 0.001, ... 'LearnRateSchedule', 'piecewise', ... 'LearnRateDropFactor', 0.5, ... 'L2Regularization', 1e-4, ... % 防止a过度增大 'MaxEpochs', 100); ``` ##### 4. 监控参数 $a$ 的演化 ```matlab net = trainNetwork(data, layers, options); a1 = net.Layers(2).a; % 提取第一层自适应参数 a2 = net.Layers(4).a; % 提取第二层自适应参数 fprintf('最终参数值: a1=%.3f, a2=%.3f', a1, a2); ``` --- #### 关键实现细节 1. **参数初始化** - 初始值 $a=1$ 等效于标准Sigmoid - 可尝试 $a>1$ 的初始化增强初始非线性(论文推荐 $a=5$ 或 $10$)[^1] 2. **梯度计算推导** 前向传播:$Z = \sigma(a X)$ 反向传播: $$ \begin{cases} \frac{\partial L}{\partial X} = \frac{\partial L}{\partial Z} \cdot a \sigma'(aX) \\ \frac{\partial L}{\partial a} = \sum \frac{\partial L}{\partial Z} \cdot X \sigma'(aX) \end{cases} $$ 3. **正则化约束** 在损失函数中增加 $L_2$ 正则项 $\lambda a^2$ 防止 $a$ 无界增长: ```matlab % 在backward函数中添加正则化梯度 dLdA_reg = dLdA + 2 * lambda * layer.a; ``` --- #### 物理信息神经网络(PINN)应用 在PINN中求解微分方程时,将自适应激活函数插入ResNet块: ```matlab % 物理损失函数示例 function loss = physicsLoss(net, x) u = predict(net, x); % 神经网络预测解 du = dlgradient(sum(u), x); % 自动微分求导 d2u = dlgradient(sum(du), x); % 二阶导 residual = d2u + sin(x); % 微分方程残差 loss = mean(residual.^2); % 物理约束损失 end ``` **优势**:自适应激活函数显著提升PINN收敛速度,尤其在求解高振荡解时[^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值