Pytorch深度学习教程_5_编写第一个神经网络

发布于:2025-02-21 ⋅ 阅读:(16) ⋅ 点赞:(0)

欢迎来到《pytorch深度学习教程》系列的第五篇!在前面的四篇中,我们已经介绍了Python、numpy及pytorch的基本使用,并在上一个教程中介绍了梯度。今天,我们将探索神经网络,对于神经网络进行概述并进行简单的实践学习

欢迎订阅专栏:

深度学习保姆教程_tRNA做科研的博客-CSDN博客 

神经网络是受人类大脑启发的计算模型,旨在识别数据中的模式。它们是深度学习的核心,推动了各个领域的突破。


目录

1.生物学启示

(1)大脑作为模型

(2)深度学习中的生物学原理

2.生物启发式AI的未来

(1)应用生物学启示:从理论到实践

3.人工神经元

(1)人工神经元的结构

(2)神经元的计算

(3)数学表达式总结 

(4)常见的激活函数:

(5)神经元在神经网络中的作用

(6)常见神经网络 

4.建立第一个神经网络:前馈神经网络

(1)前馈神经网络的结构

(2)前馈神经网络的工作原理

(3)训练前馈神经网络

(4)你的第一个神经网络训练

训练过程

5.结语


1.生物学启示

几个世纪以来,自然界一直是科学家和工程师宝贵的灵感来源。人工智能领域,特别是深度学习,也不例外。通过研究生物系统,研究人员开发了模仿大脑处理信息方式的创新算法和架构。

(1)大脑作为模型

人脑是一个复杂的、相互连接的神经元网络。这种复杂结构启发了人工神经网络的发展。

  • 神经元:大脑的基本构建块,负责处理和传输信息。
  • 突触:神经元之间的连接,促进通信。
  • 神经网络:受大脑结构启发,人工神经网络由相互连接的节点(神经元)组成,用于处理信息。

(2)深度学习中的生物学原理

  • 学习:大脑通过经验学习,调整突触连接。深度学习模型通过反向传播从数据中学习。
  • 层次性:大脑以层次化的方式处理信息。深度神经网络也采用层次化的表示方法。
  • 特征提取:大脑从感官输入中提取特征。卷积神经网络在图像特征提取方面表现出色。
  • 适应性:大脑适应新信息和环境。深度学习模型可以针对特定任务进行微调

2.生物启发式AI的未来

神经科学和人工智能的交叉领域具有巨大的潜力。通过继续探索大脑的机制,我们可以开发出更强大和更智能的AI系统。

(1)应用生物学启示:从理论到实践

了解神经网络的生物学基础是重要的,但其真正的力量在于实际应用。让我们探讨如何利用这些概念来构建现实世界的系统。

卷积神经网络(CNNs):视觉皮层的对应物

  • 图像识别:训练一个CNN将图像分类为不同的类别(例如,猫与狗)。
  • 目标检测:检测并定位图像中的对象。
  • 图像分割:图像的像素级分类。

循环神经网络(RNNs):处理顺序数据

  • 自然语言处理:构建用于文本分类、情感分析和语言翻译的模型。
  • 时间序列分析:基于过去的数据预测未来的值。
  • 语音识别:将音频信号转换为文本。

长短期记忆(LSTM)网络:捕捉长期依赖关系

  • 自然语言处理:处理复杂的语言模式和长期依赖关系。
  • 时间序列预测:基于长期模式预测未来的值。
  • 机器翻译:将一种语言的文本翻译成另一种语言。

 

3.人工神经元

人工神经元是神经网络的基本计算单元。受其生物对应物的启发,这些数学函数处理输入数据,应用变换并产生输出

(1)人工神经元的结构

一个人工神经元由几个组件组成:

  • 输入:输入神经元的数据。
  • 权重:分配给每个输入的数值,表示该输入的重要性。
  • 偏置:加到输入加权和上的常数值。
  • 激活函数:应用于神经元输出的非线性函数。

(2)神经元的计算

神经元的输出分两步计算:

  • 加权和:将每个输入乘以其对应的权重,对结果求和,并加上偏置。
  • 激活:将激活函数应用于加权和的结果。

我们给一个通俗的解释:

import numpy as np
import matplotlib.pyplot as plt

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# 示例神经元
inputs = [1, 2, 3]
weights = [0.2, 0.3, 0.4]
bias = 0.1

# 计算加权和
weighted_sum = np.dot(inputs, weights) + bias

# 应用激活函数
output = sigmoid(weighted_sum)

# 绘制 Sigmoid 函数
x = np.linspace(-10, 10, 100)
y = sigmoid(x)

plt.figure(figsize=(8, 4))
plt.plot(x, y, label='Sigmoid Function')
plt.scatter([weighted_sum], [output], color='red', label=f'Output ({output:.2f})')
plt.axvline(x=weighted_sum, color='gray', linestyle='--', label=f'Weighted Sum ({weighted_sum:.2f})')
plt.xlabel('x')
plt.ylabel('Sigmoid(x)')
plt.title('Sigmoid')
plt.legend()
plt.grid(True)
plt.show()

然后我们详细看看发生了什么,这是什么:

-1输入与权重

  • 输入:inputs = [1, 2, 3] 表示神经元接收到三个输入值。
  • 权重:weights = [0.2, 0.3, 0.4] 表示每个输入对应的权重。

 -2计算加权和

  • 点积运算:np.dot(inputs, weights) 计算输入向量与权重向量的点积,即 1×0.2+2×0.3+3×0.41×0.2+2×0.3+3×0.4。具体计算:1×0.2=0.2, 2×0.3=0.6, 3×0.4=1.2
  • 点积结果:0.2+0.6+1.2=2.0
  • 加上偏置:bias = 0.1,所以加权和为 2.0+0.1=2.1。

 -3应用激活函数

 

(3)数学表达式总结 

整个神经元的计算过程可以用以下数学表达式表示: 

 

(4)常见的激活函数:

  • Sigmoid:输出介于0和1之间的值。
  • ReLU(修正线性单元):输出输入与0的最大值。
  • Tanh:输出介于-1和1之间的值。
  • Softmax:用于分类任务,输出每个类别的概率。

(5)神经元在神经网络中的作用

神经元在神经网络中按层组织:

  • 输入层:接收输入数据。
  • 隐藏层:通过多层神经元处理信息。
  • 输出层:产生最终输出。

注意事项

  • 梯度消失问题:可能出现在深层网络中,使训练变得困难。
  • 过拟合:模型可能变得过于复杂,在新数据上的表现不佳。
  • 计算成本:训练大型神经网络可能需要大量的计算资源。

(6)常见神经网络 

1.前馈神经网络

在前馈神经网络中,信息单向流动,从输入层流向输出层,没有循环或周期。

  • 全连接层:一层中的每个神经元都连接到下一层中的每个神经元。
  • 激活函数:应用于每个神经元的输出以引入非线性。

2.深度神经网络

深度神经网络具有多个隐藏层,允许它们学习复杂的模式。

  • 深度:隐藏层的数量。
  • 宽度:每层中神经元的数量。

3.循环神经网络(RNNs)

RNNs在相同层的神经元之间引入连接,形成周期。这使得它们能够处理序列数据。

  • 梯度消失问题:RNNs在处理长期依赖时可能会遇到困难。
  • LSTM和GRU:解决梯度消失问题的RNN变体。

4.卷积神经网络(CNNs)

CNNs专为处理网格状数据(如图像)而设计。

  • 卷积层:应用滤波器以从输入数据中提取特征。
  • 池化层:降低维度同时保留重要信息。

挑战和注意事项

  • 过拟合:神经网络容易过拟合,需要正则化技术
  • 超参数调整:找到最佳超参数对于性能至关重要。

4.建立第一个神经网络:前馈神经网络

前馈神经网络(FNNs)是最简单的人工神经网络类型。信息单向流动,从输入到输出,不形成循环。它们是理解更复杂架构的基础。

(1)前馈神经网络的结构

一个典型的FNN由以下部分组成:

  • 输入层:从外部世界接收数据。
  • 隐藏层:通过多层神经元处理信息。
  • 输出层:产生最终结果。

一层中的神经元与下一层中的每个神经元相连,形成全连接网络。

(2)前馈神经网络的工作原理

  • 输入:数据被输入到输入层。
  • 传播:信息通过隐藏层传递,每个神经元应用其激活函数
  • 输出:最终层产生输出,可以是分类、回归或其他所需的结果。

(3)训练前馈神经网络

  • 反向传播:一种基于预测输出与实际输出之间的误差来调整权重和偏置的算法。
  • 损失函数:衡量预测值与实际值之间的差异。
  • 优化器:更新网络的参数以最小化损失函数。

(4)你的第一个神经网络训练

我们用一个简单的二分类神经网络的例子进行学习:

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
import numpy as np

# 设置随机种子以确保结果可复现
torch.manual_seed(42)

# 生成一些简单的二维数据用于分类
def generate_data(num_samples=100):
    # 生成两个类别的数据,每个类别50个样本
    data = []
    labels = []
    for i in range(num_samples // 2):
        # 第一类:左下角
        data.append([np.random.rand() * 0.6 - 0.3, np.random.rand() * 0.6 - 0.3])
        labels.append(0)
        # 第二类:右上角
        data.append([np.random.rand() * 0.6 + 0.2, np.random.rand() * 0.6 + 0.2])
        labels.append(1)
    return torch.tensor(data, dtype=torch.float32), torch.tensor(labels, dtype=torch.long)

# 定义一个简单的前馈神经网络
class SimpleFFNN(nn.Module):
    def __init__(self):
        super(SimpleFFNN, self).__init__()
        # 输入层到隐藏层,输入特征为2,隐藏单元为10
        self.fc1 = nn.Linear(2, 10)
        # 隐藏层到输出层,输出类别为2
        self.fc2 = nn.Linear(10, 2)
    
    def forward(self, x):
        # 使用ReLU激活函数
        x = torch.relu(self.fc1(x))
        # 输出层不使用激活函数,因为后续会使用交叉熵损失函数
        x = self.fc2(x)
        return x

# 初始化模型、损失函数和优化器
model = SimpleFFNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)

# 生成数据
X, y = generate_data()

# 训练模型
num_epochs = 100
losses = []

for epoch in range(num_epochs):
    optimizer.zero_grad()  # 清零梯度
    outputs = model(X)      # 前向传播
    loss = criterion(outputs, y)  # 计算损失
    loss.backward()         # 反向传播
    optimizer.step()        # 更新参数
    
    losses.append(loss.item())
    if (epoch+1) % 10 == 0:
        print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

# 绘制损失曲线
plt.figure(figsize=(8, 4))
plt.plot(range(1, num_epochs + 1), losses, label='Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss Over Epochs')
plt.legend()
plt.show()

# 可视化分类结果
def plot_decision_boundary(model, X, y):
    # 创建网格
    h = 0.02
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))
    grid = torch.tensor(np.c_[xx.ravel(), yy.ravel()], dtype=torch.float32)
    with torch.no_grad():
        Z = model(grid)
        Z = torch.argmax(Z, dim=1).reshape(xx.shape)
    plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.Paired)
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired, edgecolors='k')

# 绘制决策边界
plt.figure(figsize=(8, 6))
plot_decision_boundary(model, X.numpy(), y.numpy())
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.title('Decision Boundary')
plt.show()

那么这个神经网络做了什么事情呢?我们来仔细剖析

网络结构

  1. 输入层:接收二维特征数据(每个样本有两个特征)。

  2. 隐藏层:包含10个神经元。使用ReLU激活函数,为网络引入非线性特性,使其能够学习更复杂的模式。

  3. 输出层:包含2个神经元,对应两个类别。不使用激活函数,因为后续使用了交叉熵损失函数,它内部已经包含了softmax操作。

训练过程

  1. 数据生成:生成了两类二维数据,每类50个样本,分别位于二维空间的左下角和右上角。

  2. 损失函数与优化器

    使用交叉熵损失函数(CrossEntropyLoss)来衡量预测值与真实标签之间的差异。使用随机梯度下降(SGD)优化器,学习率为0.1,用于更新网络参数以最小化损失。
  3. 训练步骤

    进行100个训练周期(epochs)。每个周期执行前向传播、计算损失、反向传播和参数更新。每10个周期打印一次当前的损失值,以便监控训练进度。

5.结语

我们对于神经网络的基本结构和神经元都有了基本的认识,也编写了我们第一个神经网络!这是一个非常值得纪念的里程碑