ELU函数的全称是:Exponential Linear Units (ELUs),即指数线性单位。
$ ELU(x) = \left \{ \begin{array}{ll} x,& if\;x>0 \\ \alpha*(e^x-1),& if\;x \leq 0 \end{array} \right.$
其中:$x$ 是输入值,$α$ 是一个超参数(默认为 1.0),控制负输入区域的饱和下限。
(1)缓解“死亡ReLU”问题
ReLU存在固有缺陷,当输入为负时,ReLU的输出恒为0,可能导致神经元“死亡”(无法更新梯度)。而ELU针对这个问题进行了改进,在负输入区域,ELU使用指数函数平滑地过渡到负值(下限为-$α$),使得梯度非零,有助于梯度传播和参数更新。
(2)输出均值接近零
ELU函数在负区域的值域为 (-$α$, $0$) ,而正区域保持线性。这种对称性使得输出的均值更接近零(类似Batch Normalization的效果),可能加速训练收敛。
(3)平滑性
ELU函数在$x=0$处可导(且导数连续),避免了ReLU在零点处的不可导问题(实际应用中通常忽略ReLU的零点不可导)。
在PyTorch中有专门的ELU函数,其语法形式如下所示:
torch.nn.ELU(alpha=1.0, inplace=False)

import torch
import torch.nn as nn
# 方式1:作为网络层使用
elu_layer = nn.ELU(alpha=1.0) # alpha 默认为1.0
input_tensor = torch.tensor([-1.0, 0.0, 2.0])
output = elu_layer(input_tensor) # 输出: [-0.6321, 0.0, 2.0]
# 方式2:函数式调用
output = torch.nn.functional.elu(input_tensor, alpha=1.0)
ELU函数有个重要的特性:输出均值接近零,下面我们来演示一下。
首先我们生成一些随机数据(比如符合正态分布的数据),然后通过ELU激活函数后观察其输出的均值是否接近零。由于ELU在负值区域使用指数函数,它能够将负值推向一个负的饱和值,从而使得输出的均值接近零。
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei"] # 用来正常显示中文标签
plt.rcParams["axes.unicode_minus"] = False # 用来正常显示负号
# 创建ELU激活函数
elu = nn.ELU(alpha=1.0) # alpha参数默认为1.0
# 生成不同分布的输入数据
torch.manual_seed(42) # 设置随机种子以确保可重复性
# 创建不同均值的正态分布数据
means = [-2.0, -1.0, 0.0, 1.0, 2.0]
std_dev = 1.0
num_samples = 10000
# 存储结果
results = []
plt.figure(figsize=(15, 10))
for i, mean in enumerate(means):
# 生成输入数据
input_data = torch.normal(mean=mean, std=std_dev, size=(num_samples,))
# 应用ELU激活函数
output_data = elu(input_data)
# 计算统计量
input_mean = input_data.mean().item()
input_std = input_data.std().item()
output_mean = output_data.mean().item()
output_std = output_data.std().item()
results.append({
"input_mean": input_mean,
"input_std": input_std,
"output_mean": output_mean,
"output_std": output_std
})
# 绘制输入和输出的分布
plt.subplot(2, 3, i + 1)
plt.hist(input_data.numpy(), bins=50, alpha=0.5, label=f"输入 (μ={input_mean:.2f})", color="blue")
plt.hist(output_data.numpy(), bins=50, alpha=0.5, label=f"ELU输出 (μ={output_mean:.2f})", color="red")
plt.title(f"输入均值 = {mean}")
plt.legend()
plt.xlabel("值")
plt.ylabel("频率")
plt.tight_layout()
plt.suptitle("ELU激活函数对不同均值输入的输出分布", fontsize=16, y=1.02)
plt.show()
# 打印统计结果
print("ELU激活函数的输出均值接近零的统计结果:")
print("=" * 60)
for i, (mean, result) in enumerate(zip(means, results)):
print(f"输入均值: {mean:.1f} -> 输出均值: {result["output_mean"]:.4f} "
f"(偏移: {abs(result["output_mean"]):.4f})")
这段代码展示了ELU激活函数如何使输出均值接近零的特性。代码中创建了均值为 $-2, -1, 0, 1, 2$ 的正态分布数据,然后对每种输入数据应用 ELU 激活函数,并计算输出的均值。最后的效果如下图所示:

为了让大家更明确地看懂ELU与ReLU的区别,我特意做了一个图示例子,如下所示:
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei"] # 用来正常显示中文标签
plt.rcParams["axes.unicode_minus"] = False # 用来正常显示负号
# 创建ELU激活函数
elu = nn.ELU(alpha=1.0) # alpha参数默认为1.0
# 生成不同分布的输入数据
torch.manual_seed(42) # 设置随机种子以确保可重复性
# 创建不同均值的正态分布数据
means = [-2.0, -1.0, 0.0, 1.0, 2.0]
std_dev = 1.0
num_samples = 10000
# 与ReLU进行对比
relu = nn.ReLU()
# 测试ELU和ReLU对负均值的处理
neg_mean_input = torch.normal(mean=-1.5, std=1.0, size=(num_samples,))
elu_output = elu(neg_mean_input)
relu_output = relu(neg_mean_input)
print("\nELU与ReLU对负均值输入的对比:")
print("=" * 50)
print(f"输入均值: {neg_mean_input.mean().item():.4f}")
print(f"ELU输出均值: {elu_output.mean().item():.4f}")
print(f"ReLU输出均值: {relu_output.mean().item():.4f}")
# 可视化对比
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.hist(neg_mean_input.numpy(), bins=50, alpha=0.5, label="输入", color="gray")
plt.hist(elu_output.numpy(), bins=50, alpha=0.5, label="ELU输出", color="red")
plt.title("ELU对负均值输入的处理")
plt.xlabel("值")
plt.ylabel("频率")
plt.legend()
plt.subplot(1, 2, 2)
plt.hist(neg_mean_input.numpy(), bins=50, alpha=0.5, label="输入", color="gray")
plt.hist(relu_output.numpy(), bins=50, alpha=0.5, label="ReLU输出", color="blue")
plt.title("ReLU对负均值输入的处理")
plt.xlabel("值")
plt.ylabel("频率")
plt.legend()
plt.tight_layout()
plt.show()
下图可以很明显的看出ELU对负均值输入的处理更加合理:

(1)希望避免“死亡ReLU”问题且对计算开销不敏感的任务。
(2)需要输出均值接近零的模型(如无需 Batch Normalization 的简化网络)。
计算成本:ELU 的指数计算($e^x$)比 ReLU 更耗时,可能影响训练/推理速度。
超参数选择:$α$ 通常保持默认值 1.0,但也可根据任务调整。ELU在不同alpha参数下的表现,如下图所示:

ELU 函数 是由 Djork-Arné Clevert、Thomas Unterthiner 和 Sepp Hochreiter 于 2015 年发表的论文中首次提出的。作者首先分析了当时最流行的激活函数 ReLU 的局限性。虽然 ReLU 成功解决了梯度消失问题并加速了训练,但它也存在所谓的“死亡 ReLU”问题(Dying ReLU Problem),即一旦神经元输出为负,其梯度将永远为0,该神经元在后续训练中可能再也无法被激活。为了克服 ReLU 的缺点,他们提出了 ELU 函数。对于正输入,其行为与 ReLU 完全一样,对于负输入,它不是一个简单的零或小的斜率(如 Leaky ReLU 或 PReLU),而是一个平滑的、渐近饱和的指数函数。平滑饱和的意义在于使得ELU的输出均值更接近零,这被认为可以加速学习,因为它让每一层的输入更接近以零为中心分布,类似于批归一化(Batch Normalization)的效果。
实验结果:论文在多个图像分类(如 CIFAR-10, CIFAR-100, ImageNet)和语音处理数据集上进行了实验,结果表明:(1)使用 ELU 函数的神经网络在分类准确率上通常优于或与使用 ReLU、LReLU 等激活函数的网络相当。(2)ELU 能够带来更快的收敛速度,有时甚至无需批归一化的辅助。