用Python进行AI数据分析进阶教程66:
神经网络的定义网络结构
关键词:输入层、隐藏层、输出层、PyTorch、全连接层
摘要:本文主要介绍了如何使用 PyTorch 定义神经网络的结构,包括输入层、隐藏层和输出层的功能与实现方法。输入层的神经元数量需与数据特征匹配,隐藏层通过激活函数进行非线性变换以提升模型表达能力,输出层则根据任务类型(如分类或回归)选择合适的激活函数,例如 Softmax 用于多分类问题。文章还展示了如何构建一个完整的神经网络类,封装各层及前向传播逻辑,并对关键代码语句进行了详细解读,帮助读者理解神经网络的基本构成和工作流程。
👉 欢迎订阅🔗
《用Python进行AI数据分析进阶教程》专栏
《AI大模型应用实践进阶教程》专栏
《Python编程知识集锦》专栏
《字节跳动旗下AI制作抖音视频》专栏
《智能辅助驾驶》专栏
《工具软件及IT技术集锦》专栏
一、整体概述
在 Python 中,通常使用深度学习框架(如PyTorch或TensorFlow)来定义和训练神经网络。下面会以PyTorch为例,详细讲解神经网络各层结构的定义、关键点、注意点,给出示例代码并解读重点语句。
二、输入层
1、关键点
输入层是神经网络接收原始数据的地方,其神经元数量应与输入数据的特征数量一致。比如,处理手写数字识别问题,每个图像是 28x28 像素,将其展平为一维向量后,输入层就需要有 28 * 28 = 784 个神经元。
2、注意点
- 要保证输入数据的维度和输入层神经元数量匹配,否则会引发维度不匹配的错误。
- 对于不同类型的数据(如文本、图像、音频),需要进行合适的预处理,以使其能作为输入层的有效输入。
3、示例代码
Python脚本
# 导入必要的库
import torch
import torch.nn as nn
def create_sample_data(batch_size=1, height=28, width=28):
"""
创建示例输入数据
Args:
batch_size (int): 批次大小
height (int): 图像高度
width (int): 图像宽度
Returns:
torch.Tensor: 展平后的输入数据张量,形状为(batch_size, height*width)
"""
input_size = height * width
# 生成随机输入数据,模拟展平后的图像数据
input_data = torch.randn(batch_size, input_size)
return input_data, input_size
def main():
"""主函数"""
try:
# 设置随机种子以确保结果可重现(可选)
torch.manual_seed(42)
# 定义输入数据的维度
BATCH_SIZE = 1
IMAGE_HEIGHT = 28
IMAGE_WIDTH = 28
# 创建输入数据
input_data, input_size = create_sample_data(BATCH_SIZE,
IMAGE_HEIGHT,
IMAGE_WIDTH)
# 打印相关信息
print(f"输入数据形状: {input_data.shape}")
print(f"输入数据特征数量: {input_size}")
print("输入数据样本:")
print(input_data)
# 可选:打印一些统计信息
print(f"\n数据统计信息:")
print(f"均值: {input_data.mean().item():.4f}")
print(f"标准差: {input_data.std().item():.4f}")
print(f"最小值: {input_data.min().item():.4f}")
print(f"最大值: {input_data.max().item():.4f}")
except Exception as e:
print(f"发生错误: {e}")
return None
return input_data
# 如果直接运行此脚本,则执行main函数
if __name__ == "__main__":
data = main()
三、隐藏层
1、关键点
- 隐藏层位于输入层和输出层之间,可以有一层或多层。每一层隐藏层通过对输入数据进行非线性变换,学习数据中的复杂模式。
- 隐藏层的层数和每层的神经元数量是超参数,需要根据具体问题进行调整。增加隐藏层数量和神经元数量可以提高模型的表达能力,但也可能导致过拟合。
2、注意点
- 激活函数的选择很重要,它能为网络引入非线性,常用的激活函数有 ReLU、Sigmoid、Tanh 等。
- 每层隐藏层的输入和输出维度要匹配,确保数据能在网络中顺利流动。
3、示例代码
Python脚本
import torch
import torch.nn as nn
# 定义输入层和隐藏层的神经元数量
# 这些值都是超参数,需要根据具体问题进行调整
input_size = 784 # 例如:MNIST图像的像素数 (28*28)
hidden_size = 128 # 隐藏层神经元数量
# 创建一个全连接层作为隐藏层
# nn.Linear是PyTorch中用于创建全连接层的类
# input_size是输入层的神经元数量,也就是输入数据的特征数量
# hidden_size是隐藏层的神经元数量
# 该层会对输入数据进行线性变换,将输入数据从input_size维映射到hidden_size维
hidden_layer = nn.Linear(input_size, hidden_size)
# 应用激活函数,这里使用ReLU
# ReLU(Rectified Linear Unit)是一种常用的激活函数,其公式为 f(x) = max(0, x)
# 它可以为神经网络引入非线性,增强模型的表达能力
activation = nn.ReLU()
# 创建示例输入数据
# 假设我们有一个批次大小为1的样本,每个样本有input_size个特征
input_data = torch.randn(1, input_size) # 生成随机输入数据用于演示
# 前向传播
# 首先将输入数据input_data传入隐藏层hidden_layer进行线性变换
# 然后将线性变换的结果传入激活函数activation进行非线性变换
# 最终得到隐藏层的输出hidden_output
hidden_output = activation(hidden_layer(input_data))
# 打印隐藏层的输出
print("隐藏层输出形状:", hidden_output.shape)
print("隐藏层输出:", hidden_output)
# 输出结果说明:
# 输出一个形状为(1, hidden_size)的张量,
# 其中每个元素都是经过ReLU激活函数处理后的值
# 由于ReLU的特性,输出值要么是0,要么是正数
# 示例输出(实际值会因随机性而不同):
# 隐藏层输出形状: torch.Size([1, 128])
# 隐藏层输出:
# tensor([[0.0000, 0.0000, 0.1234, ..., 0.5678, 0.0000, 0.0000]],
# grad_fn=<ReluBackward0>)
四、输出层
1、关键点
- 输出层的神经元数量取决于具体的任务。例如,在二分类问题中,输出层通常有 1 个神经元;在多分类问题中,输出层的神经元数量等于类别数。
2、注意点
- 对于分类问题,输出层通常需要搭配合适的激活函数,如 Sigmoid 用于二分类,Softmax 用于多分类。
- 对于回归问题,输出层一般不需要激活函数,直接输出连续值。
3、示例代码(多分类问题)
Python脚本
import torch
import torch.nn as nn
# 假设是10分类问题
# 定义输出层的神经元数量,由于是10分类问题,所以输出层要有10个神经元对应10个类别
output_size = 10
# 创建输出层
# 使用nn.Linear类创建一个全连接层作为输出层
# 该层接收隐藏层的输出,将隐藏层的hidden_size个神经元连接到输出层的output_size个神经元
# 会对隐藏层的输出进行线性变换,得到每个类别的得分
output_layer = nn.Linear(hidden_size, output_size)
# 方法1:显式使用Softmax(适用于需要概率输出的场景)
# Softmax函数用于将线性输出转换为概率分布,使得所有输出值之和为1
# dim=1表示在第1维(即类别维度)上进行Softmax操作,确保每行的元素之和为1
softmax = nn.Softmax(dim=1)
# 前向传播得到最终输出
# 先将隐藏层的输出hidden_output传入输出层output_layer进行线性变换
# 然后将线性变换的结果传入Softmax激活函数,得到每个类别的概率值
output_prob = softmax(output_layer(hidden_output))
print("概率输出:", output_prob)
# 方法2:推荐的优化方式 - 直接返回线性输出(训练时)或使用LogSoftmax(数值稳定性更好)
# 在实际训练中,通常直接返回线性输出给损失函数(如CrossEntropyLoss)
# 因为CrossEntropyLoss内部已经包含了LogSoftmax操作
raw_output = output_layer(hidden_output)
print("原始线性输出:", raw_output)
# 如果需要概率输出,也可以这样写(更简洁)
output_prob_direct = torch.softmax(raw_output, dim=1)
print("直接使用torch.softmax:", output_prob_direct)
# 验证概率和为1
print("概率之和:", torch.sum(output_prob_direct, dim=1))
# 如果用于训练,推荐使用LogSoftmax + NLLLoss 或直接使用CrossEntropyLoss
log_softmax = nn.LogSoftmax(dim=1)
log_probs = log_softmax(output_layer(hidden_output))
print("对数概率输出:", log_probs)
五、完整的神经网络类定义
将上述各层组合起来,定义一个完整的神经网络类。
Python脚本
# 导入PyTorch核心库
import torch
import torch.nn as nn
# 定义一个简单的神经网络类
class SimpleNeuralNetwork(nn.Module):
def __init__(self, input_size: int, hidden_size: int, output_size: int):
"""
初始化神经网络结构。
参数:
input_size (int): 输入特征维度(如28*28=784)
hidden_size (int): 隐藏层神经元数量
output_size (int): 输出类别数(如10类)
"""
super().__init__() # 简化写法,适用于Python 3+
# 全连接层 + 激活函数
self.fc1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(hidden_size, output_size)
# 注意:Softmax通常不在模型中显式使用,尤其当使用CrossEntropyLoss时
def forward(self, x):
"""
前向传播过程。
参数:
x (Tensor): 输入张量,形状为 (batch_size, input_size)
返回:
Tensor: 输出张量,形状为 (batch_size, output_size)
"""
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
# 不加 softmax,交由损失函数处理(如 CrossEntropyLoss)
return out
# 设置参数
input_size = 28 * 28 # MNIST 图像大小
hidden_size = 128 # 隐藏层大小
output_size = 10 # 分类数(0~9)
# 创建网络实例
net = SimpleNeuralNetwork(input_size, hidden_size, output_size)
# 创建一个模拟输入(batch_size=1)
input_data = torch.randn(1, input_size)
# 前向传播
output = net(input_data)
# 打印输出结果(logits)
print("模型输出(logits):", output)
# 如果你想查看概率分布(仅用于推理/可视化),可以手动加 softmax:
probabilities = torch.softmax(output, dim=1)
print("Softmax 概率分布:", probabilities)
说明与建议:
- 如果你后续使用 nn.CrossEntropyLoss(),那么模型输出不应该包含 Softmax。
- 如果你只是做推理或者可视化,可以手动调用 torch.softmax()。
- 这样做的好处是避免数值不稳定(比如 log(0)),因为 CrossEntropyLoss 内部已经高效地处理了这些。
重点语句解读
- class SimpleNeuralNetwork(nn.Module):定义了一个名为SimpleNeuralNetwork的神经网络类,继承自nn.Module,这是PyTorch中所有神经网络模块的基类。
- super(SimpleNeuralNetwork, self).__init__():调用父类nn.Module的构造函数,确保正确初始化。
- self.fc1 = nn.Linear(input_size, hidden_size):创建一个全连接层,将输入层的input_size个神经元连接到隐藏层的hidden_size个神经元。
- self.relu = nn.ReLU():定义 ReLU 激活函数,为网络引入非线性。
- self.fc2 = nn.Linear(hidden_size, output_size):创建另一个全连接层,将隐藏层的hidden_size个神经元连接到输出层的output_size个神经元。
- self.softmax = nn.Softmax(dim=1):定义 Softmax 激活函数,用于多分类问题,dim=1表示在第 1 维(通常是类别维度)上进行 Softmax 操作。
- def forward(self, x):定义前向传播函数,描述数据在网络中的流动过程。
- out = self.fc1(x):将输入数据x通过第一个全连接层。
- out = self.relu(out):对第一个全连接层的输出应用 ReLU 激活函数。
- out = self.fc2(out):将经过激活函数处理后的数据通过第二个全连接层。
- out = self.softmax(out):对第二个全连接层的输出应用 Softmax 激活函数,得到最终的概率分布。
——The END——
🔗 欢迎订阅专栏
| 序号 | 专栏名称 | 说明 |
|---|---|---|
| 1 | 用Python进行AI数据分析进阶教程 | 《用Python进行AI数据分析进阶教程》专栏 |
| 2 | AI大模型应用实践进阶教程 | 《AI大模型应用实践进阶教程》专栏 |
| 3 | Python编程知识集锦 | 《Python编程知识集锦》专栏 |
| 4 | 字节跳动旗下AI制作抖音视频 | 《字节跳动旗下AI制作抖音视频》专栏 |
| 5 | 智能辅助驾驶 | 《智能辅助驾驶》专栏 |
| 6 | 工具软件及IT技术集锦 | 《工具软件及IT技术集锦》专栏 |
👉 关注我 @理工男大辉郎 获取实时更新
欢迎关注、收藏或转发。
敬请关注 我的
微信搜索公众号:cnFuJH
优快云博客:理工男大辉郎
抖音号:31580422589

被折叠的 条评论
为什么被折叠?



