代码
import torch
# 1. 定义模型
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear1 = torch.nn.Linear(8, 6)
self.linear2 = torch.nn.Linear(6, 4)
self.linear3 = torch.nn.Linear(4, 1)
self.sigmoid = torch.nn.Sigmoid()
#可以替换为self.sigmoid = torch.nn.ReLU()
def forward(self, x):
x = self.sigmoid(self.linear1(x))
x = self.sigmoid(self.linear2(x))
x = self.sigmoid(self.linear3(x))
return x
# 2. 实例化模型
model = Model()
# 3. 准备数据
# 假设输入是一个随机生成的 N×8 的张量,标签是 N×1 的二分类数据
x_data = torch.randn(10, 8) # 10个样本,每个样本8个特征
y_data = torch.randint(0, 2, (10, 1)).float() # 二分类标签
# 4. 定义损失函数
criterion = torch.nn.BCELoss() # 二分类交叉熵损失函数
# 5. 定义优化器
optimizer = torch.optim.SGD(model.parameters(), lr=0.1) # 随机梯度下降优化器,学习率为0.1
# 6. 训练循环
num_epochs = 100 # 设置训练轮数
for epoch in range(num_epochs):
# 前向传播:计算预测值
y_pred = model(x_data)
# 计算损失
loss = criterion(y_pred, y_data)
# 反向传播:计算梯度
optimizer.zero_grad() # 清空梯度
loss.backward() # 计算梯度
# 更新权重
optimizer.step() # 使用梯度更新参数
# 打印损失(每10轮)
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
问题
1为什么网络的设计中使用多层结构,而不是直接从输入到输出的单层映射?
- 通过引入中间隐藏层(例如从输入8维到输出1维之间加入6维和4维隐藏层),模型可以逐步提取更加抽象和有用的特征。这些特征在分类或回归任务中往往能提高模型性能。
- 多层结构允许模型有能力更好地逼近复杂函数,从而更精确地映射输入到输出。
2.forward函数中不同变量怎样写,为什么写为同一变量?
- 将每次线性变换和激活函数的结果存回 x,可以使代码更简洁,不需要每一层都声明新的变量
- 将每一层的输出显式赋值到不同的变量
O1 = self.sigmoid(self.linear1(x))
O2 = self.sigmoid(self.linear2(O1))
output = self.sigmoid(self.linear3(O2))
3.特征提取是如何完成的?是否可以观察特征?
- 特征提取完全由网络中的权重和偏置参数决定,这些参数通过反向传播算法自动优化。因此,特征是机器通过训练数据“自己学到的”,没有明确的人工指定。
O1 = self.sigmoid(self.linear1(x))
print(O1) # 查看第一层提取的特征
O2 = self.sigmoid(self.linear2(O1))
print(O2) # 查看第二层提取的特征
4.使用 ReLU 替代 Sigmoid,性能有什么差异?
Sigmoid:
- 在输入值较大或较小时(正负饱和区间),函数的导数接近于 0,导致梯度消失,使得反向传播中的权重更新非常慢。
- 影响:训练深层网络时,学习速度减慢,难以捕捉复杂特征。
低层特征(简单特征):
在图像中:边缘、角点等局部特征。
在时间序列中:简单的上升趋势或周期性变化。
在文本中:单个词语或简单的句法结构。
高层特征(复杂特征):
通过多层网络,简单特征逐步组合成更高级的模式。
在图像中:完整的形状或对象。
在时间序列中:复杂的模式或行为。
在文本中:语义关系或句子意义。
ReLU:f(x)=max(0,x)