pytorch实现神经元、激活函数(Sigmoid函数和ReLU函数)

实验代码 

import torch
import matplotlib.pyplot as plt
# Logistic函数
def logistic(z):
    return 1.0 / (1.0 + torch.exp(-z))
# ReLU
def relu(z):
    return torch.maximum(z, torch.tensor(0.))
# 2个特征数为5的样本
X = torch.rand(2, 5)
# 含有5个参数的权重向量
w = torch.rand(5, 1)
# 偏置项
b = torch.rand(1, 1)
# 使用'torch.matmul'实现矩阵相乘
z = torch.matmul(X, w) + b
print("input X:", X)
print("weight w:", w, "\nbias b:", b)
print("output z:", z)
# Tanh函数
def tanh(z):
    return (torch.exp(z) - torch.exp(-z)) / (torch.exp(z) + torch.exp(-z))
# 带泄露的ReLU
def leaky_relu(z, negative_slope=0.1):
    a1 = (z > 0).float() * z
    a2 = (z <= 0).float() * (negative_slope * z)
    return a1 + a2

# 在[-10,10]的范围内生成10000个输入值,用于绘制函数曲线
z = torch.linspace(-10, 10, 10000)
plt.figure()
plt.plot(z.tolist(), logistic(z).tolist(), color='#8E004D', label="Logistic Function")
plt.plot(z.tolist(), tanh(z).tolist(), color='#E20079', linestyle ='--', label="Tanh Function")
ax = plt.gca() # 获取轴,默认有4个
# 隐藏两个轴,通过把颜色设置成none
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
# 调整坐标轴位置
ax.spines['left'].set_position(('data',0))
ax.spines['bottom'].set_position(('data',0))
plt.legend(loc='lower right', fontsize='large')
plt.savefig('fw-logistic-tanh.pdf')
plt.show()


plt.figure()
plt.plot(z.tolist(), relu(z).tolist(), color="#8E004D", label="ReLU Function")
plt.plot(z.tolist(), leaky_relu(z).tolist(), color="#E20079", linestyle="--", label="LeakyReLU Function")
ax = plt.gca()
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['left'].set_position(('data', 0))
ax.spines['bottom'].set_position(('data', 0))
plt.legend(loc='upper left', fontsize='large')
plt.savefig('fw-relu-leakyrelu.pdf')
plt.show()

运行结果 

Sigmoid函数和ReLU函数的区别 

Sigmoid函数:

输出范围:(0,1)

特点:函数在 x=0x=0 处输出为 0.5,接近于 −∞ 时输出接近于 0,接近于 +∞ 时输出接近于 1。

ReLU 函数:

输出范围:[0,+∞)[0,+∞)

特点:如果输入 xx 小于 0,输出为 0;如果输入 xx 大于 0,输出为 xx 的值。

ReLU(x)=max⁡(0,x)

2. 输出范围

Sigmoid: 输出被限制在 (0,1)(0,1) 的范围内,因此适合于处理概率值或二分类问题。

ReLU: 输出范围是从 0 到正无穷,能提供更大的响应值,适合用于深层网络。

3. 导数特性

Sigmoid:

导数可以用 Sigmoid 函数本身来表示:S′(x)=S(x)⋅(1−S(x))

当输入的绝对值很大时,导数的值会接近于 0,导致梯度消失(vanishing gradient)。

ReLU:

导数为:ReLU′(x)={0if x<01if x≥0,对于正输入,ReLU 可以提供恒定的梯度。

4. 计算效率

Sigmoid: 由于涉及指数运算,计算较慢。

ReLU: 计算非常简单,仅需取最大值,速度快。

5. 梯度消失问题

Sigmoid: 在反向传播中,输入值为极大或极小时,Sigmoid 函数的导数接近于 0,导致梯度消失。

ReLU: 不会出现梯度消失的问题,但可能会有“死亡 ReLU”现象,即某些神经元在训练过程中可能一直输出 0,从而无法更新。

6. 

Sigmoid:常用于输出层,特别是在二分类问题中,能够输出概率值。

ReLU:常用于隐藏层,适合于深度学习网络,能够更好地处理非线性问题。

<think>好的,我现在需要帮助用户解决关于同时使用ReLUsigmoid激活函数时如何选择权重初始化方法的问题。首先,我得回顾一下之前提供的回答,确保信息的一致性。 用户的问题是在同一个神经网络中同时使用ReLUSigmoid激活函数,这时候应该如何选择初始化方法。之前的回答中,我分别介绍了ReLU对应的Kaiming初始化Sigmoid对应的Xavier初始化,但现在需要处理两者共存的情况。 首先,我需要确认这两种激活函数在神经网络中的位置。通常,ReLU常用于隐藏层,而Sigmoid可能用于输出层,比如二分类问题。这种情况下,不同层可能需要不同的初始化方法。例如,隐藏层使用ReLU,用Kaiming初始化;输出层用Sigmoid,用Xavier初始化。 但用户的问题可能更复杂,比如网络中有交替使用的情况,或者某些隐藏层用ReLU,另一些用Sigmoid。这时候需要分析不同层对初始化的需求。ReLU需要补偿方差减半,而Sigmoid需要避免梯度消失,保持输入输出方差平衡。如果两种激活函数在同一个网络中混合使用,可能需要分层处理初始化。 接下来,我需要参考用户提供的引用内容。引用[4]提到在构建多层网络时,不同激活函数配合不同的初始化方法会影响激活值的分布。例如,使用He初始化(Kaiming)配合ReLU,而Xavier配合Sigmoid,这可能更有效。因此,如果网络的不同层使用不同激活函数,对应层应该使用适合该激活函数的初始化方法。 此外,用户之前的回答中已经提到错误使用初始化的后果,比如ReLU用Xavier会导致梯度消失,Sigmoid用Kaiming会导致过早饱。因此,混合使用时必须避免这种情况,需要为每个层选择合适的初始化。 另外,用户可能需要考虑网络整体的稳定性。例如,隐藏层用ReLUKaiming,而输出层用SigmoidXavier,这样各层各自优化,确保信号传播的正确性。同时,可以结合批量归一化(Batch Normalization)来进一步稳定训练,减少对初始化的依赖。 还要考虑实际框架中的实现方式,比如在PyTorch或TensorFlow中如何分层设置初始化。例如,在定义每一层时,手动指定对应的初始化方法,或者在构建网络时自动根据激活函数选择。 最后,需要验证这种分层初始化的有效性,比如通过实验观察各层的激活值分布是否合理,是否避免了梯度消失或爆炸的问题。可能还需要调整学习率,因为不同的初始化方法可能对学习率敏感,尤其是当混合使用时。</think>--- ### **同时使用ReLUSigmoid时的权重初始化策略** 在神经网络中同时使用ReLUSigmoid激活函数时(例如,隐藏层用ReLU,输出层用Sigmoid),需根据**各层的激活函数特性**选择对应的初始化方法,确保信号传播的稳定性训练效率。以下是具体策略: --- #### **一、分层初始化:按激活函数类型匹配** 1. **隐藏层(ReLU)**: - **推荐方法**:**Kaiming/He初始化**(正态或均匀分布) - **原因**:ReLU的负半轴归零特性会导致前向传播中**方差减半**,Kaiming初始化通过调整权重方差($\sigma_w = \sqrt{2/n_{in}}$)补偿这一损失,保持输入输出方差一致[^1][^4]。 - **错误后果**:若使用Xavier初始化,深层网络可能因方差衰减出现**梯度消失**。 2. **输出层(Sigmoid)**: - **推荐方法**:**Xavier/Glorot初始化**(正态或均匀分布) - **原因**:Sigmoid的饱非零中心化输出需要平衡输入输出方差($\sigma_w = \sqrt{2/(n_{in} + n_{out})}$),避免梯度过早趋近于零[^2][^3]。 - **错误后果**:若使用Kaiming初始化,输入值易进入Sigmoid的**饱区**(如绝对值过大),导致梯度消失训练停滞。 --- #### **二、代码实现示例(PyTorch)** ```python import torch.nn as nn class MixedActivationNet(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim): super().__init__() # 隐藏层:ReLU + Kaiming初始化 self.fc1 = nn.Linear(input_dim, hidden_dim) nn.init.kaiming_normal_(self.fc1.weight, mode='fan_in', nonlinearity='relu') # 输出层:Sigmoid + Xavier初始化 self.fc2 = nn.Linear(hidden_dim, output_dim) nn.init.xavier_normal_(self.fc2.weight, gain=1.0) # gain=1适配Sigmoid def forward(self, x): x = torch.relu(self.fc1(x)) x = torch.sigmoid(self.fc2(x)) return x ``` --- #### **三、混合使用的注意事项** 1. **批量归一化(BatchNorm)的辅助作用**: - 在隐藏层后添加`BatchNorm`层,可进一步稳定输入分布,减少对初始化的敏感度[^4]。 - 例如: ```python self.bn = nn.BatchNorm1d(hidden_dim) # 添加在ReLU之后 ``` 2. **学习率调整**: - ReLUSigmoid的梯度范围差异较大(ReLU梯度为0或1,Sigmoid梯度最大0.25),建议为输出层设置**更低的学习率**,防止Sigmoid层参数更新过快。 3. **梯度检查**: - 训练初期监控各层梯度幅值,确保ReLU层梯度未消失(如梯度幅值接近0),Sigmoid层未饱(如输入绝对值远大于5)。 --- #### **四、实验验证** 通过可视化激活值分布验证初始化效果(引用[4]的方法): - **ReLU层**:激活值应集中在正区间,避免大量神经元死亡(全零输出)。 - **Sigmoid层**:输入值应分布在$[-3, 3]$区间内,避免进入饱区(如$|x|>5$时梯度接近0)。 --- #### **五、扩展问题** 1. 如何为Transformer模型中混合使用的GELUSigmoid设计初始化策略? 2. 残差网络(ResNet)中跳跃连接如何影响初始化方法的选择? 3. 自注意力机制中的权重初始化是否需要特殊处理? --- ### **总结** | 层类型 | 激活函数 | 初始化方法 | 目标 | |----------|----------|------------------|--------------------| | 隐藏层 | ReLU | Kaiming/He初始化 | 补偿方差衰减 | | 输出层 | Sigmoid | Xavier/Glorot初始化 | 平衡梯度,避免饱 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值