在当今的科技领域,人工智能(AI)大模型正以前所未有的速度改变着我们的生活。从智能语音助手到自动驾驶汽车,从医疗诊断到金融风险评估,这些大模型展现出了强大的能力。而神经网络作为 AI 大模型的核心组成部分,是实现这些复杂功能的关键技术。
神经网络的灵感来源于人类大脑的神经元结构和工作方式。它通过模拟神经元之间的连接和信号传递,构建了一个能够自动学习和适应数据的计算模型。在过去的几十年里,随着计算能力的提升和数据量的爆炸式增长,神经网络技术取得了巨大的突破,从早期简单的感知机模型发展到如今的深度神经网络,如卷积神经网络(CNN)、循环神经网络(RNN)及其变体长短期记忆网络(LSTM)和门控循环单元(GRU),以及 Transformer 架构等。
本文将深入探讨 AI 大模型神经网络的原理,从最基础的神经元模型开始,逐步介绍神经网络的构建、训练和优化过程。我们将通过详细的源码分析,帮助读者理解每一个步骤的实现细节。无论是对于初学者想要了解神经网络的基本概念,还是对于有一定经验的开发者希望深入掌握其原理,本文都将提供有价值的参考。
人类大脑是一个极其复杂而神奇的器官,由大约 860 亿个神经元组成。这些神经元通过突触相互连接,形成了一个庞大而复杂的网络。当一个神经元接收到来自其他神经元的信号时,它会对这些信号进行整合,并根据一定的规则决定是否产生一个输出信号,这个过程被称为神经元的激活。
生物神经元的工作方式为人工神经网络的设计提供了重要的灵感。在人工神经网络中,我们模拟生物神经元的结构和功能,构建了人工神经元模型。
人工神经元是神经网络的基本计算单元,它接收多个输入信号,对这些信号进行加权求和,并通过一个激活函数产生输出。下面是一个简单的 Python 代码示例,展示了如何实现一个基本的人工神经元:
python
import numpy as np
# 定义激活函数,这里使用 sigmoid 函数
def sigmoid(x):
"""
sigmoid 激活函数,将输入值映射到 (0, 1) 区间
:param x: 输入值
:return: 经过 sigmoid 函数处理后的输出值
"""
return 1 / (1 + np.exp(-x))
# 定义人工神经元类
class Neuron:
def __init__(self, num_inputs):
"""
初始化神经元,随机初始化权重和偏置
:param num_inputs: 输入信号的数量
"""
# 随机初始化权重,范围在 -1 到 1 之间
self.weights = np.random.uniform(-1, 1, num_inputs)
# 随机初始化偏置,范围在 -1 到 1 之间
self.bias = np.random.uniform(-1, 1)
def forward(self, inputs):
"""
前向传播过程,计算神经元的输出
:param inputs: 输入信号的数组
:return: 神经元的输出值
"""
# 计算加权和,即输入信号与权重的点积加上偏置
weighted_sum = np.dot(inputs, self.weights) + self.bias
# 通过激活函数处理加权和,得到神经元的输出
output = sigmoid(weighted_sum)
return output
# 创建一个具有 3 个输入的神经元
neuron = Neuron(3)
# 定义输入信号
inputs = np.array([0.5, 0.3, 0.2])
# 计算神经元的输出
output = neuron.forward(inputs)
print("神经元的输出:", output)
激活函数在神经网络中起着至关重要的作用。它引入了非线性因素,使得神经网络能够学习到复杂的函数映射关系。如果没有激活函数,无论神经网络有多少层,其整体功能都等价于一个线性函数,无法处理复杂的非线性问题。
常见的激活函数有 sigmoid 函数、ReLU 函数、tanh 函数等。下面我们分别介绍这些激活函数的实现和特点:
python
import numpy as np
import matplotlib.pyplot as plt
# sigmoid 函数
def sigmoid(x):
"""
sigmoid 激活函数,将输入值映射到 (0, 1) 区间
:param x: 输入值
:return: 经过 sigmoid 函数处理后的输出值
"""
return 1 / (1 + np.exp(-x))
# ReLU 函数
def relu(x):
"""
ReLU 激活函数,将负数输入值置为 0,正数输入值保持不变
:param x: 输入值
:return: 经过 ReLU 函数处理后的输出值
"""
return np.maximum(0, x)
# tanh 函数
def tanh(x):
"""
tanh 激活函数,将输入值映射到 (-1, 1) 区间
:param x: 输入值
:return: 经过 tanh 函数处理后的输出值
"""
return np.tanh(x)
# 生成输入值
x = np.linspace(-10, 10, 100)
# 计算不同激活函数的输出
y_sigmoid = sigmoid(x)
y_relu = relu(x)
y_tanh = tanh(x)
# 绘制激活函数图像
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.plot(x, y_sigmoid)
plt.title('Sigmoid 函数')
plt.xlabel('输入')
plt.ylabel('输出')
plt.subplot(1, 3, 2)
plt.plot(x, y_relu)
plt.title('ReLU 函数')
plt.xlabel('输入')
plt.ylabel('输出')
plt.subplot(1, 3, 3)
plt.plot(x, y_tanh)
plt.title('tanh 函数')
plt.xlabel('输入')
plt.ylabel('输出')
plt.tight_layout()
plt.show()
从上述代码可以看出,不同的激活函数具有不同的特点和适用场景。sigmoid 函数将输入值映射到 (0, 1) 区间,常用于二分类问题的输出层;ReLU 函数在正数区间保持线性增长,在负数区间输出为 0,具有计算简单、收敛速度快等优点,广泛应用于隐藏层;tanh 函数将输入值映射到 (-1, 1) 区间,其输出关于原点对称,在某些情况下比 sigmoid 函数表现更好。
单层感知机是最简单的神经网络结构,它由一个或多个神经元组成,每个神经元接收多个输入信号,并产生一个输出信号。单层感知机可以用于解决简单的线性可分问题,如二分类问题。
下面是一个简单的单层感知机的 Python 实现:
python
import numpy as np
# 定义激活函数,这里使用阶跃函数
def step_function(x):
"""
阶跃函数,当输入值大于 0 时输出 1,否则输出 0
:param x: 输入值
:return: 经过阶跃函数处理后的输出值
"""
return np.where(x > 0, 1, 0)
# 定义单层感知机类
class Perceptron:
def __init__(self, num_inputs):
"""
初始化单层感知机,随机初始化权重和偏置
:param num_inputs: 输入信号的数量
"""
# 随机初始化权重,范围在 -1 到 1 之间
self.weights = np.random.uniform(-1, 1, num_inputs)
# 随机初始化偏置,范围在 -1 到 1 之间
self.bias = np.random.uniform(-1, 1)
def forward(self, inputs):
"""
前向传播过程,计算单层感知机的输出
:param inputs: 输入信号的数组
:return: 单层感知机的输出值
"""
# 计算加权和,即输入信号与权重的点积加上偏置
weighted_sum = np.dot(inputs, self.weights) + self.bias
# 通过激活函数处理加权和,得到单层感知机的输出
output = step_function(weighted_sum)
return output
# 创建一个具有 2 个输入的单层感知机
perceptron = Perceptron(2)
# 定义输入信号
inputs = np.array([0.5, 0.3])
# 计算单层感知机的输出
output = perceptron.forward(inputs)
print("单层感知机的输出:", output)
多层感知机是在单层感知机的基础上发展而来的,它由输入层、一个或多个隐藏层和输出层组成。隐藏层的存在使得多层感知机能够学习到更复杂的函数映射关系,从而解决非线性可分问题。
下面是一个简单的多层感知机的 Python 实现:
python
import numpy as np
# 定义激活函数,这里使用 sigmoid 函数
def sigmoid(x):
"""
sigmoid 激活函数,将输入值映射到 (0, 1) 区间
:param x: 输入值
:return: 经过 sigmoid 函数处理后的输出值
"""
return 1 / (1 + np.exp(-x))
# 定义多层感知机类
class MLP:
def __init__(self, input_size, hidden_size, output_size):
"""
初始化多层感知机,随机初始化各层的权重和偏置
:param input_size: 输入层的神经元数量
:param hidden_size: 隐藏层的神经元数量
:param output_size: 输出层的神经元数量
"""
# 随机初始化输入层到隐藏层的权重,形状为 (input_size, hidden_size)
self.weights_input_hidden = np.random.randn(input_size, hidden_size)
# 随机初始化隐藏层的偏置,形状为 (1, hidden_size)
self.bias_hidden = np.zeros((1, hidden_size))
# 随机初始化隐藏层到输出层的权重,形状为 (hidden_size, output_size)
self.weights_hidden_output = np.random.randn(hidden_size, output_size)
# 随机初始化输出层的偏置,形状为 (1, output_size)
self.bias_output = np.zeros((1, output_size))
def forward(self, inputs):
"""
前向传播过程,计算多层感知机的输出
:param inputs: 输入信号的数组,形状为 (1, input_size)
:return: 多层感知机的输出值,形状为 (1, output_size)
"""
# 计算隐藏层的输入,即输入信号与输入层到隐藏层的权重的点积加上隐藏层的偏置
hidden_input = np.dot(inputs, self.weights_input_hidden) + self.bias_hidden
# 通过激活函数处理隐藏层的输入,得到隐藏层的输出
hidden_output = sigmoid(hidden_input)
# 计算输出层的输入,即隐藏层的输出与隐藏层到输出层的权重的点积加上输出层的偏置
output_input = np.dot(hidden_output, self.weights_hidden_output) + self.bias_output
# 通过激活函数处理输出层的输入,得到多层感知机的输出
output = sigmoid(output_input)
return output
# 创建一个具有 2 个输入、3 个隐藏神经元和 1 个输出的多层感知机
mlp = MLP(2, 3, 1)
# 定义输入信号
inputs = np.array([[0.5, 0.3]])
# 计算多层感知机的输出
output = mlp.forward(inputs)
print("多层感知机的输出:", output)
深度神经网络是指具有多个隐藏层的神经网络。随着隐藏层数量的增加,深度神经网络能够学习到更复杂的特征和模式,从而在图像识别、语音识别、自然语言处理等领域取得了巨大的成功。
深度神经网络的训练通常采用反向传播算法,我们将在后面的章节中详细介绍。下面是一个简单的深度神经网络的 Python 实现,使用 PyTorch 框架:
python
import torch
import torch.nn as nn
# 定义深度神经网络类,继承自 nn.Module
class DeepNeuralNetwork(nn.Module):
def __init__(self, input_size, hidden_sizes, output_size):
"""
初始化深度神经网络,定义各层的线性变换
:param input_size: 输入层的神经元数量
:param hidden_sizes: 隐藏层的神经元数量列表
:param output_size: 输出层的神经元数量
"""
super(DeepNeuralNetwork, self).__init__()
# 存储各层的线性变换
self.layers = nn.ModuleList()
# 输入层到第一个隐藏层的线性变换
self.layers.append(nn.Linear(input_size, hidden_sizes[0]))
# 中间隐藏层的线性变换
for i in range(len(hidden_sizes) - 1):
self.layers.append(nn.Linear(hidden_sizes[i], hidden_sizes[i + 1]))
# 最后一个隐藏层到输出层的线性变换
self.layers.append(nn.Linear(hidden_sizes[-1], output_size))
# 定义激活函数,这里使用 ReLU 函数
self.activation = nn.ReLU()
def forward(self, x):
"""
前向传播过程,计算深度神经网络的输出
:param x: 输入信号的张量,形状为 (batch_size, input_size)
:return: 深度神经网络的输出值,形状为 (batch_size, output_size)
"""
# 依次通过各层的线性变换和激活函数
for layer in self.layers[:-1]:
x = self.activation(layer(x))
# 最后一层不使用激活函数
x = self.layers[-1](x)
return x
# 创建一个具有 2 个输入、2 个隐藏层(分别有 3 个和 4 个神经元)和 1 个输出的深度神经网络
input_size = 2
hidden_sizes = [3, 4]
output_size = 1
dnn = DeepNeuralNetwork(input_size, hidden_sizes, output_size)
# 定义输入信号
inputs = torch.randn(1, input_size)
# 计算深度神经网络的输出
output = dnn(inputs)
print("深度神经网络的输出:", output)
损失函数用于衡量神经网络的输出与真实标签之间的差异。在训练过程中,我们的目标是通过调整神经网络的参数,使得损失函数的值最小化。常见的损失函数有均方误差损失(MSE)、交叉熵损失等。
下面是一个使用均方误差损失和交叉熵损失的 Python 示例:
python
import torch
import torch.nn as nn
# 定义均方误差损失函数
mse_loss = nn.MSELoss()
# 定义预测值和真实值
predictions = torch.tensor([[0.8, 0.2], [0.3, 0.7]], dtype=torch.float32)
targets = torch.tensor([[1.0, 0.0], [0.0, 1.0]], dtype=torch.float32)
# 计算均方误差损失
mse = mse_loss(predictions, targets)
print("均方误差损失:", mse.item())
# 定义交叉熵损失函数
cross_entropy_loss = nn.CrossEntropyLoss()
# 注意:交叉熵损失函数的输入要求预测值为未经过 softmax 处理的 logits,真实值为类别索引
logits = torch.tensor([[2.0, 1.0], [0.5, 3.0]], dtype=torch.float32)
labels = torch.tensor([0, 1], dtype=torch.long)
# 计算交叉熵损失
cross_entropy = cross_entropy_loss(logits, labels)
print("交叉熵损失:", cross_entropy.item())
优化算法用于更新神经网络的参数,使得损失函数的值不断减小。常见的优化算法有随机梯度下降(SGD)、Adagrad、Adadelta、Adam 等。
下面是一个使用随机梯度下降算法训练简单神经网络的 Python 示例:
python
import torch
import torch.nn as nn
import torch.optim as optim
# 定义简单的神经网络类,继承自 nn.Module
class SimpleNetwork(nn.Module):
def __init__(self, input_size, output_size):
"""
初始化简单的神经网络,定义线性变换层
:param input_size: 输入层的神经元数量
:param output_size: 输出层的神经元数量
"""
super(SimpleNetwork, self).__init__()
# 定义线性变换层
self.linear = nn.Linear(input_size, output_size)
def forward(self, x):
"""
前向传播过程,计算神经网络的输出
:param x: 输入信号的张量,形状为 (batch_size, input_size)
:return: 神经网络的输出值,形状为 (batch_size, output_size)
"""
return self.linear(x)
# 定义输入层和输出层的神经元数量
input_size = 2
output_size = 1
# 创建神经网络实例
model = SimpleNetwork(input_size, output_size)
# 定义损失函数,这里使用均方误差损失
criterion = nn.MSELoss()
# 定义优化算法,这里使用随机梯度下降算法,学习率为 0.01
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 定义训练数据
inputs = torch.tensor([[0.5, 0.3], [0.2, 0.8]], dtype=torch.float32)
targets = torch.tensor([[0.7], [0.4]], dtype=torch.float32)
# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
# 前向传播
outputs = model(inputs)
# 计算损失
loss = criterion(outputs, targets)
# 反向传播
optimizer.zero_grad()
loss.backward()
# 更新参数
optimizer.step()
# 打印训练信息
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
反向传播算法是训练神经网络的核心算法,它通过链式法则计算损失函数对神经网络中每个参数的梯度,并根据梯度更新参数。下面我们详细介绍反向传播算法的原理和实现。
我们通过一个简单的两层神经网络示例来理解反向传播的过程。假设我们有一个简单的两层神经网络,输入层有若干个神经元,隐藏层有若干个神经元,输出层有若干个神经元。
python
import numpy as np
# 定义 sigmoid 函数及其导数
def sigmoid(x):
"""
sigmoid 激活函数,将输入值映射到 (0, 1) 区间
:param x: 输入值
:return: 经过 sigmoid 函数处理后的输出值
"""
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x):
"""
sigmoid 函数的导数
:param x: 输入值
:return: sigmoid 函数在 x 处的导数值
"""
return sigmoid(x) * (1 - sigmoid(x))
# 定义神经网络类
class NeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
"""
初始化神经网络,随机初始化各层的权重和偏置
:param input_size: 输入层的神经元数量
:param hidden_size: 隐藏层的神经元数量
:param output_size: 输出层的神经元数量
"""
# 随机初始化输入层到隐藏层的权重,形状为 (input_size, hidden_size)
self.weights_input_hidden = np.random.randn(input_size, hidden_size)
# 随机初始化隐藏层的偏置,形状为 (1, hidden_size)
self.bias_hidden = np.zeros((1, hidden_size))
# 随机初始化隐藏层到输出层的权重,形状为 (hidden_size, output_size)
self.weights_hidden_output = np.random.randn(hidden_size, output_size)
# 随机初始化输出层的偏置,形状为 (1, output_size)
self.bias_output = np.zeros((1, output_size))
def forward(self, inputs):
"""
前向传播过程,计算神经网络的输出
:param inputs: 输入信号的数组,形状为 (1, input_size)
:return: 神经网络的输出值,形状为 (1, output_size)
"""
# 计算隐藏层的输入,即输入信号与输入层到隐藏层的权重的点积加上隐藏层的偏置
self.hidden_input = np.dot(inputs, self.weights_input_hidden) + self.bias_hidden
# 通过激活函数处理隐藏层的输入,得到隐藏层的输出
self.hidden_output = sigmoid(self.hidden_input)
# 计算输出层的输入,即隐藏层的输出与隐藏层到输出层的权重的点积加上输出层的偏置
self.output_input = np.dot(self.hidden_output, self.weights_hidden_output) + self.bias_output
# 通过激活函数处理输出层的输入,得到神经网络的输出
self.output = sigmoid(self.output_input)
return self.output
def backward(self, inputs, targets, learning_rate):
"""
反向传播过程,更新神经网络的参数
:param inputs: 输入信号的数组,形状为 (1, input_size)
:param targets: 真实标签的数组,形状为 (1, output_size)
:param learning_rate: 学习率
"""
# 计算输出层的误差
output_error = self.output - targets
# 这里的误差传播需要用到 sigmoid 函数的导数,因为输出是经过 sigmoid 激活的
output_delta = output_error * sigmoid_derivative(self.output_input)
# 计算隐藏层的误差,它与输出层的误差和隐藏层到输出层的权重有关
hidden_error = np.dot(output_delta, self.weights_hidden_output.T)
# 同样,隐藏层的误差传播也需要用到 sigmoid 函数的导数
hidden_delta = hidden_error * sigmoid_derivative(self.hidden_input)
# 计算隐藏层到输出层权重的梯度
d_weights_hidden_output = np.dot(self.hidden_output.T, output_delta)
# 计算输出层偏置的梯度
d_bias_output = np.sum(output_delta, axis=0, keepdims=True)
# 计算输入层到隐藏层权重的梯度
d_weights_input_hidden = np.dot(inputs.T, hidden_delta)
# 计算隐藏层偏置的梯度
d_bias_hidden = np.sum(hidden_delta, axis=0, keepdims=True)
# 更新隐藏层到输出层的权重
self.weights_hidden_output -= learning_rate * d_weights_hidden_output
# 更新输出层的偏置
self.bias_output -= learning_rate * d_bias_output
# 更新输入层到隐藏层的权重
self.weights_input_hidden -= learning_rate * d_weights_input_hidden
# 更新隐藏层的偏置
self.bias_hidden -= learning_rate * d_bias_hidden
# 创建一个具有 2 个输入、3 个隐藏神经元和 1 个输出的神经网络
nn = NeuralNetwork(2, 3, 1)
# 定义训练数据
inputs = np.array([[0.5, 0.3]])
targets = np.array([[0.7]])
# 定义学习率和训练轮数
learning_rate = 0.1
num_epochs = 1000
# 训练神经网络
for epoch in range(num_epochs):
# 前向传播
output = nn.forward(inputs)
# 反向传播
nn.backward(inputs, targets, learning_rate)
# 打印训练信息
if (epoch + 1) % 100 == 0:
loss = np.mean((output - targets) ** 2)
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss:.4f}')
卷积层是卷积神经网络的核心层,它通过卷积操作提取输入数据的特征。卷积操作是指将一个卷积核(也称为滤波器)在输入数据上滑动,计算卷积核与输入数据的对应元素的乘积之和,得到一个特征图。
下面是一个简单的卷积操作的 Python 实现:
python
import numpy as np
def convolve(input_data, kernel):
"""
实现简单的卷积操作
:param input_data: 输入数据的二维数组
:param kernel: 卷积核的二维数组
:return: 卷积后的特征图
"""
input_height, input_width = input_data.shape
kernel_height, kernel_width = kernel.shape
output_height = input_height - kernel_height + 1
output_width = input_width - kernel_width + 1
output = np.zeros((output_height, output_width))
for i in range(output_height):
for j in range(output_width):
# 提取输入数据的局部区域
patch = input_data[i:i + kernel_height, j:j + kernel_width]
# 计算卷积核与局部区域的对应元素的乘积之和
output[i, j] = np.sum(patch * kernel)
return output
# 定义输入数据和卷积核
input_data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
kernel = np.array([[1, 0], [0, 1]])
# 进行卷积操作
output = convolve(input_data, kernel)
print("卷积后的特征图:")
print(output)
池化层用于减少特征图的尺寸,同时保留重要的特征信息。常见的池化操作有最大池化和平均池化。
下面是一个简单的最大池化操作的 Python 实现:
python
import numpy as np
def max_pooling(input_data, pool_size):
"""
实现简单的最大池化操作
:param input_data: 输入数据的二维数组
:param pool_size: 池化窗口的大小
:return: 池化后的特征图
"""
input_height, input_width = input_data.shape
output_height = input_height // pool_size
output_width = input_width // pool_size
output = np.zeros((output_height, output_width))
for i in range(output_height):
for j in range(output_width):
# 提取输入数据的局部区域
patch = input_data[i * pool_size:(i + 1) * pool_size, j * pool_size:(j + 1) * pool_size]
# 计算局部区域的最大值
output[i, j] = np.max(patch)
return output
# 定义输入数据和池化窗口大小
input_data = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
pool_size = 2
# 进行最大池化操作
output = max_pooling(input_data, pool_size)
print("最大池化后的特征图:")
print(output)
全连接层用于将卷积层和池化层提取的特征映射到最终的输出类别。在全连接层中,每个神经元与上一层的所有神经元都有连接。
下面是一个使用 PyTorch 实现简单卷积神经网络的示例:
python
import torch
import torch.nn as nn
import torch.optim as optim
# 定义卷积神经网络类,继承自 nn.Module
class SimpleCNN(nn.Module):
def __init__(self):
"""
初始化卷积神经网络,定义卷积层、池化层和全连接层
"""
super(SimpleCNN, self).__init__()
# 定义第一个卷积层,输入通道数为 1,输出通道数为 16,卷积核大小为 3
self.conv1 = nn.Conv2d(1, 16, kernel_size=3)
# 定义最大池化层,池化窗口大小为 2
self.pool = nn.MaxPool2d(2)
# 定义第二个卷积层,输入通道数为 16,输出通道数为 32,卷积核大小为 3
self.conv2 = nn.Conv2d(16, 32, kernel_size=3)
# 定义全连接层,输入特征数根据卷积和池化操作的结果计算得到
self.fc1 = nn.Linear(32 * 5 * 5, 128)
# 定义第二个全连接层,输出类别数为 10
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
"""
前向传播过程,计算卷积神经网络的输出
:param x: 输入图像的张量,形状为 (batch_size, 1, 28, 28)
:return: 卷积神经网络的输出值,形状为 (batch_size, 10)
"""
# 通过第一个卷积层和激活函数
x = torch.relu(self.conv1(x))
# 通过最大池化层
x = self.pool(x)
# 通过第二个卷积层和激活函数
x = torch.relu(self.conv2(x))
# 通过最大池化层
x = self.pool(x)
# 展平特征图
x = x.view(-1, 32 * 5 * 5)
# 通过第一个全连接层和激活函数
x = torch.relu(self.fc1(x))
# 通过第二个全连接层
x = self.fc2(x)
return x
# 创建卷积神经网络实例
model = SimpleCNN()
# 定义损失函数,这里使用交叉熵损失
criterion = nn.CrossEntropyLoss()
# 定义优化算法,这里使用随机梯度下降算法,学习率为 0.001
optimizer = optim.SGD(model.parameters(), lr=0.001)
# 定义训练数据,这里简单模拟
inputs = torch.randn(1, 1, 28, 28)
labels = torch.tensor([1], dtype=torch.long)
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
# 前向传播
outputs = model(inputs)
# 计算损失
loss = criterion(outputs, labels)
# 反向传播
optimizer.zero_grad()
loss.backward()
# 更新参数
optimizer.step()
# 打印训练信息
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
循环神经网络(RNN)是一种专门用于处理序列数据的神经网络。它通过引入循环结构,使得网络能够记住之前的输入信息,并在处理当前输入时考虑这些历史信息。
下面是一个简单的基本 RNN 的 Python 实现:
python
import numpy as np
# 定义激活函数,这里使用 tanh 函数
def tanh(x):
"""
tanh 激活函数,将输入值映射到 (-1, 1) 区间
:param x: 输入值
:return: 经过 tanh 函数处理后的输出值
"""
return np.tanh(x)
# 定义基本 RNN 类
class BasicRNN:
def __init__(self, input_size, hidden_size):
"""
初始化基本 RNN,随机初始化权重和偏置
:param input_size: 输入的特征数量
:param hidden_size: 隐藏状态的维度
"""
# 随机初始化输入到隐藏状态的权重
self.W_xh = np.random.randn(input_size, hidden_size)
# 随机初始化隐藏状态到隐藏状态的权重
self.W_hh = np.random.randn(hidden_size, hidden_size)
# 随机初始化隐藏状态的偏置
self.b_h = np.zeros((1, hidden_size))
def forward(self, inputs):
"""
前向传播过程,计算 RNN 的输出
:param inputs: 输入序列,形状为 (序列长度, 输入特征数量)
:return: 隐藏状态序列,形状为 (序列长度, 隐藏状态维度)
"""
sequence_length = inputs.shape[0]
hidden_states = []
# 初始化隐藏状态为全零
h_t = np.zeros((1, self.W_hh.shape[0]))
for t in range(sequence_length):
# 获取当前时刻的输入
x_t = inputs[t:t + 1]
# 计算当前时刻的隐藏状态
h_t = tanh(np.dot(x_t, self.W_xh) + np.dot(h_t, self.W_hh) + self.b_h)
# 将当前时刻的隐藏状态添加到隐藏状态序列中
hidden_states.append(h_t)
# 将隐藏状态序列转换为 numpy 数组
hidden_states = np.vstack(hidden_states)
return hidden_states
# 创建一个具有 3 个输入特征和 2 个隐藏状态维度的基本 RNN
rnn = BasicRNN(3, 2)
# 定义输入序列
inputs = np.random.randn(5, 3)
# 计算 RNN 的输出
hidden_states = rnn.forward(inputs)
print("RNN 的隐藏状态序列:")
print(hidden_states)
RNN 在处理长序列数据时会遇到梯度消失问题。在反向传播过程中,梯度会随着时间步的增加而逐渐变小,导致网络无法学习到长距离的依赖关系。
长短期记忆网络(LSTM)是为了解决传统 RNN 的梯度消失问题而提出的。LSTM 通过引入门控机制,能够有效地控制信息的流动,从而更好地处理长序列数据。
LSTM 单元包含三个门:输入门(input gate)、遗忘门(forget gate)和输出门(output gate),以及一个细胞状态(cell state)。下面是对这些组件的详细解释:
python
import numpy as np
# 定义 sigmoid 函数
def sigmoid(x):
"""
sigmoid 激活函数,将输入值映射到 (0, 1) 区间
:param x: 输入值
:return: 经过 sigmoid 函数处理后的输出值
"""
return 1 / (1 + np.exp(-x))
# 定义 tanh 函数
def tanh(x):
"""
tanh 激活函数,将输入值映射到 (-1, 1) 区间
:param x: 输入值
:return: 经过 tanh 函数处理后的输出值
"""
return np.tanh(x)
# 定义 LSTM 类
class LSTM:
def __init__(self, input_size, hidden_size):
"""
初始化 LSTM,随机初始化权重和偏置
:param input_size: 输入的特征数量
:param hidden_size: 隐藏状态的维度
"""
# 输入到遗忘门的权重
self.W_fx = np.random.randn(input_size, hidden_size)
# 隐藏状态到遗忘门的权重
self.W_fh = np.random.randn(hidden_size, hidden_size)
# 遗忘门的偏置
self.b_f = np.zeros((1, hidden_size))
# 输入到输入门的权重
self.W_ix = np.random.randn(input_size, hidden_size)
# 隐藏状态到输入门的权重
self.W_ih = np.random.randn(hidden_size, hidden_size)
# 输入门的偏置
self.b_i = np.zeros((1, hidden_size))
# 输入到细胞状态候选值的权重
self.W_cx = np.random.randn(input_size, hidden_size)
# 隐藏状态到细胞状态候选值的权重
self.W_ch = np.random.randn(hidden_size, hidden_size)
# 细胞状态候选值的偏置
self.b_c = np.zeros((1, hidden_size))
# 输入到输出门的权重
self.W_ox = np.random.randn(input_size, hidden_size)
# 隐藏状态到输出门的权重
self.W_oh = np.random.randn(hidden_size, hidden_size)
# 输出门的偏置
self.b_o = np.zeros((1, hidden_size))
def forward(self, inputs):
"""
前向传播过程,计算 LSTM 的输出
:param inputs: 输入序列,形状为 (序列长度, 输入特征数量)
:return: 隐藏状态序列,形状为 (序列长度, 隐藏状态维度)
"""
sequence_length = inputs.shape[0]
hidden_states = []
# 初始化隐藏状态为全零
h_t = np.zeros((1, self.W_fh.shape[0]))
# 初始化细胞状态为全零
c_t = np.zeros((1, self.W_fh.shape[0]))
for t in range(sequence_length):
# 获取当前时刻的输入
x_t = inputs[t:t + 1]
# 计算遗忘门的输出
f_t = sigmoid(np.dot(x_t, self.W_fx) + np.dot(h_t, self.W_fh) + self.b_f)
# 计算输入门的输出
i_t = sigmoid(np.dot(x_t, self.W_ix) + np.dot(h_t, self.W_ih) + self.b_i)
# 计算细胞状态候选值
c_tilde_t = tanh(np.dot(x_t, self.W_cx) + np.dot(h_t, self.W_ch) + self.b_c)
# 更新细胞状态
c_t = f_t * c_t + i_t * c_tilde_t
# 计算输出门的输出
o_t = sigmoid(np.dot(x_t, self.W_ox) + np.dot(h_t, self.W_oh) + self.b_o)
# 更新隐藏状态
h_t = o_t * tanh(c_t)
# 将当前时刻的隐藏状态添加到隐藏状态序列中
hidden_states.append(h_t)
# 将隐藏状态序列转换为 numpy 数组
hidden_states = np.vstack(hidden_states)
return hidden_states
# 创建一个具有 3 个输入特征和 2 个隐藏状态维度的 LSTM
lstm = LSTM(3, 2)
# 定义输入序列
inputs = np.random.randn(5, 3)
# 计算 LSTM 的输出
hidden_states = lstm.forward(inputs)
print("LSTM 的隐藏状态序列:")
print(hidden_states)
门控循环单元(GRU)是另一种改进的循环神经网络结构,它简化了 LSTM 的结构,减少了参数数量,同时仍然能够有效地处理长序列数据。
GRU 包含两个门:重置门(reset gate)和更新门(update gate)。重置门决定了上一时刻的隐藏状态 (h_{t - 1}) 中有多少信息需要被重置,更新门决定了当前时刻的隐藏状态 (h_t) 是由上一时刻的隐藏状态 (h_{t - 1}) 和当前输入 (x_t) 组合而成的比例。
python
import numpy as np
# 定义 sigmoid 函数
def sigmoid(x):
"""
sigmoid 激活函数,将输入值映射到 (0, 1) 区间
:param x: 输入值
:return: 经过 sigmoid 函数处理后的输出值
"""
return 1 / (1 + np.exp(-x))
# 定义 tanh 函数
def tanh(x):
"""
tanh 激活函数,将输入值映射到 (-1, 1) 区间
:param x: 输入值
:return: 经过 tanh 函数处理后的输出值
"""
return np.tanh(x)
# 定义 GRU 类
class GRU:
def __init__(self, input_size, hidden_size):
"""
初始化 GRU,随机初始化权重和偏置
:param input_size: 输入的特征数量
:param hidden_size: 隐藏状态的维度
"""
# 输入到重置门的权重
self.W_rx = np.random.randn(input_size, hidden_size)
# 隐藏状态到重置门的权重
self.W_rh = np.random.randn(hidden_size, hidden_size)
# 重置门的偏置
self.b_r = np.zeros((1, hidden_size))
# 输入到更新门的权重
self.W_ux = np.random.randn(input_size, hidden_size)
# 隐藏状态到更新门的权重
self.W_uh = np.random.randn(hidden_size, hidden_size)
# 更新门的偏置
self.b_u = np.zeros((1, hidden_size))
# 输入到候选隐藏状态的权重
self.W_hx = np.random.randn(input_size, hidden_size)
# 隐藏状态到候选隐藏状态的权重
self.W_hh = np.random.randn(hidden_size, hidden_size)
# 候选隐藏状态的偏置
self.b_h = np.zeros((1, hidden_size))
def forward(self, inputs):
"""
前向传播过程,计算 GRU 的输出
:param inputs: 输入序列,形状为 (序列长度, 输入特征数量)
:return: 隐藏状态序列,形状为 (序列长度, 隐藏状态维度)
"""
sequence_length = inputs.shape[0]
hidden_states = []
# 初始化隐藏状态为全零
h_t = np.zeros((1, self.W_rh.shape[0]))
for t in range(sequence_length):
# 获取当前时刻的输入
x_t = inputs[t:t + 1]
# 计算重置门的输出
r_t = sigmoid(np.dot(x_t, self.W_rx) + np.dot(h_t, self.W_rh) + self.b_r)
# 计算更新门的输出
u_t = sigmoid(np.dot(x_t, self.W_ux) + np.dot(h_t, self.W_uh) + self.b_u)
# 计算候选隐藏状态
h_tilde_t = tanh(np.dot(x_t, self.W_hx) + np.dot(r_t * h_t, self.W_hh) + self.b_h)
# 更新隐藏状态
h_t = (1 - u_t) * h_t + u_t * h_tilde_t
# 将当前时刻的隐藏状态添加到隐藏状态序列中
hidden_states.append(h_t)
# 将隐藏状态序列转换为 numpy 数组
hidden_states = np.vstack(hidden_states)
return hidden_states
# 创建一个具有 3 个输入特征和 2 个隐藏状态维度的 GRU
gru = GRU(3, 2)
# 定义输入序列
inputs = np.random.randn(5, 3)
# 计算 GRU 的输出
hidden_states = gru.forward(inputs)
print("GRU 的隐藏状态序列:")
print(hidden_states)
自注意力机制是 Transformer 架构的核心组件之一,它允许模型在处理序列中的每个元素时,能够关注到序列中的其他元素,从而捕捉到序列中的长距离依赖关系。
自注意力机制的核心思想是通过计算输入序列中每个元素与其他元素之间的相关性,为每个元素分配一个权重,然后根据这些权重对输入序列进行加权求和,得到每个元素的表示。
具体来说,自注意力机制通过三个线性变换将输入序列转换为查询(query)、键(key)和值(value)三个矩阵,然后计算查询和键之间的相似度,得到注意力分数,再通过 softmax 函数将注意力分数转换为注意力权重,最后根据注意力权重对值矩阵进行加权求和,得到输出。
python
import numpy as np
def softmax(x):
"""
softmax 函数,将输入值转换为概率分布
:param x: 输入值
:return: 经过 softmax 函数处理后的输出值
"""
exp_x = np.exp(x - np.max(x, axis=-1, keepdims=True))
return exp_x / np.sum(exp_x, axis=-1, keepdims=True)
def self_attention(inputs, d_k):
"""
实现自注意力机制
:param inputs: 输入序列,形状为 (序列长度, 输入特征数量)
:param d_k: 查询和键的维度
:return: 自注意力机制的输出,形状为 (序列长度, 输入特征数量)
"""
sequence_length = inputs.shape[0]
input_size = inputs.shape[1]
# 初始化查询、键和值的权重矩阵
W_q = np.random.randn(input_size, d_k)
W_k = np.random.randn(input_size, d_k)
W_v = np.random.randn(input_size, input_size)
# 计算查询、键和值矩阵
Q = np.dot(inputs, W_q)
K = np.dot(inputs, W_k)
V = np.dot(inputs, W_v)
# 计算注意力分数
attention_scores = np.dot(Q, K.T) / np.sqrt(d_k)
# 计算注意力权重
attention_weights = softmax(attention_scores)
# 计算自注意力机制的输出
output = np.dot(attention_weights, V)
return output
# 定义输入序列
inputs = np.random.randn(5, 10)
# 定义查询和键的维度
d_k = 5
# 计算自注意力机制的输出
output = self_attention(inputs, d_k)
print("自注意力机制的输出:")
print(output)
多头注意力机制是自注意力机制的扩展,它通过并行地运行多个自注意力头,每个头关注输入序列的不同方面,然后将这些头的输出拼接起来,再通过一个线性变换得到最终的输出。
多头注意力机制的优点是能够捕捉到输入序列的多种不同的依赖关系,提高模型的表达能力。
python
import numpy as np
def softmax(x):
"""
softmax 函数,将输入值转换为概率分布
:param x: 输入值
:return: 经过 softmax 函数处理后的输出值
"""
exp_x = np.exp(x - np.max(x, axis=-1, keepdims=True))
return exp_x / np.sum(exp_x, axis=-1, keepdims=True)
def single_head_attention(inputs, d_k):
"""
实现单个自注意力头
:param inputs: 输入序列,形状为 (序列长度, 输入特征数量)
:param d_k: 查询和键的维度
:return: 单个自注意力头的输出,形状为 (序列长度, 输入特征数量)
"""
sequence_length = inputs.shape[0]
input_size = inputs.shape[1]
# 初始化查询、键和值的权重矩阵
W_q = np.random.randn(input_size, d_k)
W_k = np.random.randn(input_size, d_k)
W_v = np.random.randn(input_size, input_size)
# 计算查询、键和值矩阵
Q = np.dot(inputs, W_q)
K = np.dot(inputs, W_k)
V = np.dot(inputs, W_v)
# 计算注意力分数
attention_scores = np.dot(Q, K.T) / np.sqrt(d_k)
# 计算注意力权重
attention_weights = softmax(attention_scores)
# 计算单个自注意力头的输出
output = np.dot(attention_weights, V)
return output
def multi_head_attention(inputs, num_heads, d_k):
"""
实现多头注意力机制
:param inputs: 输入序列,形状为 (序列长度, 输入特征数量)
:param num_heads: 注意力头的数量
:param d_k: 查询和键的维度
:return: 多头注意力机制的输出,形状为 (序列长度, 输入特征数量)
"""
head_outputs = []
for _ in range(num_heads):
# 计算单个自注意力头的输出
head_output = single_head_attention(inputs, d_k)
head_outputs.append(head_output)
# 拼接所有头的输出
concatenated_output = np.concatenate(head_outputs, axis=-1)
# 初始化输出的权重矩阵
input_size = inputs.shape[1]
W_o = np.random.randn(input_size * num_heads, input_size)
# 计算多头注意力机制的最终输出
output = np.dot(concatenated_output, W_o)
return output
# 定义输入序列
inputs = np.random.randn(5, 10)
# 定义注意力头的数量
num_heads = 3
# 定义查询和键的维度
d_k = 5
# 计算多头注意力机制的输出
output = multi_head_attention(inputs, num_heads, d_k)
print("多头注意力机制的输出:")
print(output)
Transformer 架构由编码器(encoder)和解码器(decoder)组成,编码器用于对输入序列进行编码,解码器用于根据编码器的输出生成输出序列。
编码器和解码器都由多个相同的层堆叠而成,每个层包含多头注意力机制和前馈神经网络。此外,Transformer 还引入了位置编码(positional encoding)来处理序列的顺序信息。
下面是一个简化的 Transformer 架构的实现:
python
import numpy as np
def softmax(x):
"""
softmax 函数,将输入值转换为概率分布
:param x: 输入值
:return: 经过 softmax 函数处理后的输出值
"""
exp_x = np.exp(x - np.max(x, axis=-1, keepdims=True))
return exp_x / np.sum(exp_x, axis=-1, keepdims=True)
def single_head_attention(inputs, d_k):
"""
实现单个自注意力头
:param inputs: 输入序列,形状为 (序列长度, 输入特征数量)
:param d_k: 查询和键的维度
:return: 单个自注意力头的输出,形状为 (序列长度, 输入特征数量)
"""
sequence_length = inputs.shape[0]
input_size = inputs.shape[1]
# 初始化查询、键和值的权重矩阵
W_q = np.random.randn(input_size, d_k)
W_k = np.random.randn(input_size, d_k)
W_v = np.random.randn(input_size, input_size)
# 计算查询、键和值矩阵
Q = np.dot(inputs, W_q)
K = np.dot(inputs, W_k)
V = np.dot(inputs, W_v)
# 计算注意力分数
attention_scores = np.dot(Q, K.T) / np.sqrt(d_k)
# 计算注意力权重
attention_weights = softmax(attention_scores)
# 计算单个自注意力头的输出
output = np.dot(attention_weights, V)
return output
def multi_head_attention(inputs, num_heads, d_k):
"""
实现多头注意力机制
:param inputs: 输入序列,形状为 (序列长度, 输入特征数量)
:param num_heads: 注意力头的数量
:param d_k: 查询和键的维度
:return: 多头注意力机制的输出,形状为 (序列长度, 输入特征数量)
"""
head_outputs = []
for _ in range(num_heads):
# 计算单个自注意力头的输出
head_output = single_head_attention(inputs, d_k)
head_outputs.append(head_output)
# 拼接所有头的输出
concatenated_output = np.concatenate(head_outputs, axis=-1)
# 初始化输出的权重矩阵
input_size = inputs.shape[1]
W_o = np.random.randn(input_size * num_heads, input_size)
# 计算多头注意力机制的最终输出
output = np.dot(concatenated_output, W_o)
return output
def feed_forward(inputs, d_ff):
"""
实现前馈神经网络
:param inputs: 输入序列,形状为 (序列长度, 输入特征数量)
:param d_ff: 前馈神经网络的隐藏层维度
:return: 前馈神经网络的输出,形状为 (序列长度, 输入特征数量)
"""
input_size = inputs.shape[1]
# 初始化第一个线性变换的权重矩阵和偏置
W_1 = np.random.randn(input_size, d_ff)
b_1 = np.zeros((1, d_ff))
# 初始化第二个线性变换的权重矩阵和偏置
W_2 = np.random.randn(d_ff, input_size)
b_2 = np.zeros((1, input_size))
# 第一个线性变换
hidden = np.dot(inputs, W_1) + b_1
# ReLU 激活函数
hidden = np.maximum(0, hidden)
# 第二个线性变换
output = np.dot(hidden, W_2) + b_2
return output
def encoder_layer(inputs, num_heads, d_k, d_ff):
"""
实现编码器层
:param inputs: 输入序列,形状为 (序列长度, 输入特征数量)
:param num_heads: 注意力头的数量
:param d_k: 查询和键的维度
:param d_ff: 前馈神经网络的隐藏层维度
:return: 编码器层的输出,形状为 (序列长度, 输入特征数量)
"""
# 多头注意力机制
attention_output = multi_head_attention(inputs, num_heads, d_k)
# 残差连接和层归一化
attention_output = inputs + attention_output
attention_output = layer_normalization(attention_output)
# 前馈神经网络
ff_output = feed_forward(attention_output, d_ff)
# 残差连接和层归一化
output = attention_output + ff_output
output = layer_normalization(output)
return output
def layer_normalization(x, epsilon=1e-6):
"""
实现层归一化
:param x: 输入序列
:param epsilon: 防止除零的小常数
:return: 层归一化后的输出
"""
mean = np.mean(x, axis=-1, keepdims=True)
variance = np.var(x, axis=-1, keepdims=True)
return (x - mean) / np.sqrt(variance + epsilon)
def positional_encoding(sequence_length, input_size):
"""
实现位置编码
:param sequence_length: 序列长度
:param input_size: 输入特征数量
:return: 位置编码矩阵,形状为 (序列长度, 输入特征数量)
"""
position = np.arange(sequence_length)[:, np.newaxis]
div_term = np.exp(np.arange(0, input_size, 2) * (-np.log(10000.0) / input_size))
pe = np.zeros((sequence_length, input_size))
pe[:, 0::2] = np.sin(position * div_term)
pe[:, 1::2] = np.cos(position * div_term)
return pe
def encoder(inputs, num_layers, num_heads, d_k, d_ff):
"""
实现编码器
:param inputs: 输入序列,形状为 (序列长度, 输入特征数量)
:param num_layers: 编码器层的数量
:param num_heads: 注意力头的数量
:param d_k: 查询和键的维度
:param d_ff: 前馈神经网络的隐藏层维度
:return: 编码器的输出,形状为 (序列长度, 输入特征数量)
"""
sequence_length = inputs.shape[0]
input_size = inputs.shape[1]
# 添加位置编码
pe = positional_encoding(sequence_length, input_size)
inputs = inputs + pe
# 堆叠多个编码器层
output = inputs
for _ in range(num_layers):
output = encoder_layer(output, num_heads, d_k, d_ff)
return output
# 定义输入序列
inputs = np.random.randn(5, 10)
# 定义编码器层的数量
num_layers = 2
# 定义注意力头的数量
num_heads = 3
# 定义查询和键的维度
d_k = 5
# 定义前馈神经网络的隐藏层维度
d_ff = 20
# 计算编码器的输出
encoder_output = encoder(inputs, num_layers, num_heads, d_k, d_ff)
print("编码器的输出:")
print(encoder_output)
批量归一化是一种用于加速神经网络训练的技术,它通过对每个批次的输入数据进行归一化处理,使得输入数据的均值为 0,方差为 1,从而减少了内部协变量偏移(Internal Covariate Shift)的问题,加快了模型的收敛速度。
具体来说,批量归一化在每个层的输入之前,对输入数据进行归一化处理,然后通过可学习的缩放因子 (\gamma) 和偏移因子 (\beta) 对归一化后的数据进行缩放和偏移,以保证模型的表达能力。
python
import numpy as np
class BatchNormalization:
def __init__(self, input_size, momentum=0.9, epsilon=1e-5):
"""
初始化批量归一化层
:param input_size: 输入特征的数量
:param momentum: 动量,用于计算移动平均和移动方差
:param epsilon: 防止除零的小常数
"""
self.input_size = input_size
self.momentum = momentum
self.epsilon = epsilon
# 初始化缩放因子
self.gamma = np.ones((1, input_size))
# 初始化偏移因子
self.beta = np.zeros((1, input_size))
# 初始化移动平均
self.running_mean = np.zeros((1, input_size))
# 初始化移动方差
self.running_var = np.zeros((1, input_size))
def forward(self, inputs, training=True):
"""
前向传播过程,计算批量归一化的输出
:param inputs: 输入数据,形状为 (批量大小, 输入特征数量)
:param training: 是否为训练模式
:return: 批量归一化的输出,形状为 (批量大小, 输入特征数量)
"""
if training:
# 计算当前批次的均值
batch_mean = np.mean(inputs, axis=0, keepdims=True)
# 计算当前批次的方差
batch_var = np.var(inputs, axis=0, keepdims=True)
# 更新移动平均
self.running_mean = self.momentum * self.running_mean + (1 - self.momentum) * batch_mean
# 更新移动方差
self.running_var = self.momentum * self.running_var + (1 - self.momentum) * batch_var
# 归一化处理
normalized = (inputs - batch_mean) / np.sqrt(batch_var + self.epsilon)
else:
# 使用移动平均和移动方差进行归一化处理
normalized = (inputs - self.running_mean) / np.sqrt(self.running_var + self.epsilon)
# 缩放和偏移
output = self.gamma * normalized + self.beta
return output
# 创建批量归一化层
bn = BatchNormalization(10)
# 定义输入数据
inputs = np.random.randn(32, 10)
# 计算批量归一化的输出
output = bn.forward(inputs, training=True)
print("批量归一化的输出:")
print(output)
L1 和 L2 正则化是常用的正则化方法,用于防止模型过拟合。L1 正则化通过在损失函数中添加权重的绝对值之和,使得模型的权重更加稀疏;L2 正则化通过在损失函数中添加权重的平方和,使得模型的权重更加平滑。
下面是一个使用 L2 正则化的简单示例:
python
import torch
import torch.nn as nn
import torch.optim as optim
# 定义简单的神经网络类,继承自 nn.Module
class SimpleNetwork(nn.Module):
def __init__(self, input_size, output_size):
"""
初始化简单的神经网络,定义线性变换层
:param input_size: 输入层的神经元数量
:param output_size: 输出层的神经元数量
"""
super(SimpleNetwork, self).__init__()
# 定义线性变换层
self.linear = nn.Linear(input_size, output_size)
def forward(self, x):
"""
前向传播过程,计算神经网络的输出
:param x: 输入信号的张量,形状为 (batch_size, input_size)
:return: 神经网络的输出值,形状为 (batch_size, output_size)
"""
return self.linear(x)
# 定义输入层和输出层的神经元数量
input_size = 2
output_size = 1
# 创建神经网络实例
model = SimpleNetwork(input_size, output_size)
# 定义损失函数,这里使用均方误差损失
criterion = nn.MSELoss()
# 定义优化算法,这里使用随机梯度下降算法,添加 L2 正则化,权重衰减系数为 0.001
optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay=0.001)
# 定义训练数据
inputs = torch.randn(1, input_size)
targets = torch.tensor([[0.7]], dtype=torch.float32)
# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
# 前向传播
outputs = model(inputs)
# 计算损失
loss = criterion(outputs, targets)
# 反向传播
optimizer.zero_grad()
loss.backward()
# 更新参数
optimizer.step()
# 打印训练信息
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
Dropout 是一种随机丢弃神经元的正则化方法,它在训练过程中随机地将一部分神经元的输出置为 0,从而减少神经元之间的依赖关系,防止模型过拟合。
下面是一个使用 Dropout 的简单示例:
python
import torch
import torch.nn as nn
import torch.optim as optim
# 定义包含 Dropout 的神经网络类,继承自 nn.Module
class DropoutNetwork(nn.Module):
def __init__(self, input_size, hidden_size, output_size, dropout_rate):
"""
初始化包含 Dropout 的神经网络,定义线性变换层和 Dropout 层
:param input_size: 输入层的神经元数量
:param hidden_size: 隐藏层的神经元数量
:param output_size: 输出层的神经元数量
:param dropout_rate: Dropout 的丢弃率
"""
super(DropoutNetwork, self).__init__()
# 定义第一个线性变换层
self.linear1 = nn.Linear(input_size, hidden_size)
# 定义 Dropout 层
self.dropout = nn.Dropout(dropout_rate)
# 定义第二个线性变换层
self.linear2 = nn.Linear(hidden_size, output_size)
def forward(self, x):
"""
前向传播过程,计算神经网络的输出
:param x: 输入信号的张量,形状为 (batch_size, input_size)
:return: 神经网络的输出值,形状为 (batch_size, output_size)
"""
x = torch.relu(self.linear1(x))
x = self.dropout(x)
x = self.linear2(x)
return x
# 定义输入层、隐藏层和输出层的神经元数量
input_size = 2
hidden_size = 3
output_size = 1
# 定义 Dropout 的丢弃率
dropout_rate = 0.2
# 创建神经网络实例
model = DropoutNetwork(input_size, hidden_size, output_size, dropout_rate)
# 定义损失函数,这里使用均方误差损失
criterion = nn.MSELoss()
# 定义优化算法,这里使用随机梯度下降算法
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 定义训练数据
inputs = torch.randn(1, input_size)
targets = torch.tensor([[0.7]], dtype=torch.float32)
# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
# 前向传播
outputs = model(inputs)
# 计算损失
loss = criterion(outputs, targets)
# 反向传播
optimizer.zero_grad()
loss.backward()
# 更新参数
optimizer.step()
# 打印训练信息
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
学习率衰减是一种常用的学习率调整策略,它在训练过程中逐渐减小学习率,使得模型在训练初期能够快速收敛,在训练后期能够更加稳定地收敛到最优解。
下面是一个使用学习率衰减的简单示例:
python
import torch
import torch.nn as nn
import torch.optim as optim
# 定义简单的神经网络类,继承自 nn.Module
class SimpleNetwork(nn.Module):
def __init__(self, input_size, output_size):
"""
初始化简单的神经网络,定义线性变换层
:param input_size: 输入层的神经元数量
:param output_size: 输出层的神经元数量
"""
super(SimpleNetwork, self).__init__()
# 定义线性变换层
self.linear = nn.Linear(input_size, output_size)
def forward(self, x):
"""
前向传播过程,计算神经网络的输出
:param x: 输入信号的张量,形状为 (batch_size, input_size)
:return: 神经网络的输出值,形状为 (batch_size, output_size)
"""
return self.linear(x)
# 定义输入层和输出层的神经元数量
input_size = 2
output_size = 1
# 创建神经网络实例
model = SimpleNetwork(input_size, output_size)
#
python
# 定义损失函数,这里使用均方误差损失
criterion = nn.MSELoss()
# 定义初始学习率
initial_lr = 0.1
# 定义优化算法,这里使用随机梯度下降算法
optimizer = optim.SGD(model.parameters(), lr=initial_lr)
# 定义学习率衰减策略,这里使用指数衰减,gamma为衰减因子
scheduler = optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.9)
# 定义训练数据
inputs = torch.randn(1, input_size)
targets = torch.tensor([[0.7]], dtype=torch.float32)
# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
# 前向传播
outputs = model(inputs)
# 计算损失
loss = criterion(outputs, targets)
# 反向传播
optimizer.zero_grad()
loss.backward()
# 更新参数
optimizer.step()
# 调整学习率
scheduler.step()
# 打印训练信息,包括当前学习率
current_lr = optimizer.param_groups[0]['lr']
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}, Learning Rate: {current_lr}')
在这段代码中,我们通过optim.lr_scheduler.ExponentialLR
实现了指数衰减的学习率调整策略。随着训练轮次epoch
的增加,学习率会按照gamma
指定的衰减因子逐渐变小。这有助于模型在训练初期以较大的步长快速接近最优解,而在训练后期以较小的步长进行微调,避免错过最优解。
除了学习率衰减这种预先设定调整规则的方法外,还有自适应学习率算法,如 Adagrad、Adadelta、RMSProp 和 Adam 等。这些算法能够根据模型在训练过程中的表现,动态地调整每个参数的学习率。
以 Adam 算法为例,它结合了 Adagrad 和 RMSProp 的优点,不仅能够自适应地调整学习率,还能有效地处理稀疏梯度问题。以下是使用 Adam 优化器的示例:
python
import torch
import torch.nn as nn
import torch.optim as optim
# 定义简单的神经网络类,继承自nn.Module
class SimpleNetwork(nn.Module):
def __init__(self, input_size, output_size):
"""
初始化简单的神经网络,定义线性变换层
:param input_size: 输入层的神经元数量
:param output_size: 输出层的神经元数量
"""
super(SimpleNetwork, self).__init__()
# 定义线性变换层
self.linear = nn.Linear(input_size, output_size)
def forward(self, x):
"""
前向传播过程,计算神经网络的输出
:param x: 输入信号的张量,形状为(batch_size, input_size)
:return: 神经网络的输出值,形状为(batch_size, output_size)
"""
return self.linear(x)
# 定义输入层和输出层的神经元数量
input_size = 2
output_size = 1
# 创建神经网络实例
model = SimpleNetwork(input_size, output_size)
# 定义损失函数,这里使用均方误差损失
criterion = nn.MSELoss()
# 定义优化算法,这里使用Adam算法
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 定义训练数据
inputs = torch.randn(1, input_size)
targets = torch.tensor([[0.7]], dtype=torch.float32)
# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
# 前向传播
outputs = model(inputs)
# 计算损失
loss = criterion(outputs, targets)
# 反向传播
optimizer.zero_grad()
loss.backward()
# 更新参数
optimizer.step()
# 打印训练信息
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
在上述代码中,我们使用optim.Adam
初始化优化器,它会自动根据模型参数的梯度情况动态调整每个参数的学习率。这种自适应调整使得模型在不同参数维度上能够以合适的步长进行更新,提高了训练的效率和稳定性。
图像识别是神经网络应用最为广泛的领域之一,而卷积神经网络(CNN)在图像分类任务中表现卓越。以经典的 MNIST 手写数字识别任务为例,以下是使用 PyTorch 实现的基于 CNN 的图像分类代码:
python
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
# 定义数据预处理
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
# 加载MNIST训练数据集
train_dataset = datasets.MNIST(root='./data', train=True,
download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
# 加载MNIST测试数据集
test_dataset = datasets.MNIST(root='./data', train=False,
download=True, transform=transform)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
# 定义CNN模型
class MNISTCNN(nn.Module):
def __init__(self):
super(MNISTCNN, self).__init__()
# 第一个卷积层,输入通道1,输出通道16,卷积核大小3
self.conv1 = nn.Conv2d(1, 16, kernel_size=3)
# 第一个最大池化层,池化核大小2
self.pool1 = nn.MaxPool2d(2)
# 第二个卷积层,输入通道16,输出通道32,卷积核大小3
self.conv2 = nn.Conv2d(16, 32, kernel_size=3)
# 第二个最大池化层,池化核大小2
self.pool2 = nn.MaxPool2d(2)
# 全连接层,将卷积和池化后的特征映射到128维
self.fc1 = nn.Linear(32 * 5 * 5, 128)
# 输出层,输出10个类别(对应0-9数字)
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = torch.relu(self.conv1(x))
x = self.pool1(x)
x = torch.relu(self.conv2(x))
x = self.pool2(x)
# 将特征图展平
x = x.view(-1, 32 * 5 * 5)
x = torch.relu(self.fc1(x))
x = self.fc2(x)
return x
# 创建模型实例
model = MNISTCNN()
# 定义损失函数,这里使用交叉熵损失
criterion = nn.CrossEntropyLoss()
# 定义优化算法,这里使用随机梯度下降算法
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
model.train()
for images, labels in train_loader:
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 测试模型
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy of the network on the 10000 test images: {100 * correct / total}%')
在这段代码中,我们首先对 MNIST 数据集进行预处理,将图像转换为张量并进行归一化。然后构建了一个简单的 CNN 模型,包含卷积层、池化层和全连接层。在训练过程中,使用交叉熵损失函数和随机梯度下降优化器对模型进行训练。最后在测试集上评估模型的准确率,通过这种方式,CNN 能够有效地学习到手写数字的特征模式,实现高精度的分类。
目标检测是图像识别中的另一重要任务,旨在识别图像中不同目标的类别和位置。以基于 Faster R - CNN 的目标检测为例,以下是简化的原理性代码结构(实际实现更为复杂,涉及更多组件):
python
import torch
import torch.nn as nn
import torchvision.models as models
# 假设我们有一个预训练的CNN模型,这里以ResNet50为例
base_model = models.resnet50(pretrained=True)
num_ftrs = base_model.fc.in_features
base_model.fc = nn.Identity()
# 定义区域提议网络(RPN)
class RegionProposalNetwork(nn.Module):
def __init__(self, in_channels):
super(RegionProposalNetwork, self).__init__()
# 这里简单定义一个卷积层来生成提议区域,实际会更复杂
self.conv = nn.Conv2d(in_channels, 512, kernel_size=3, padding=1)
# 分类分支,判断提议区域是否包含目标
self.cls = nn.Conv2d(512, 2 * 9, kernel_size=1)
# 回归分支,预测提议区域的位置偏移
self.reg = nn.Conv2d(512, 4 * 9, kernel_size=1)
def forward(self, x):
x = torch.relu(self.conv(x))
cls_scores = self.cls(x)
bbox_preds = self.reg(x)
return cls_scores, bbox_preds
# 定义感兴趣区域池化(RoI Pooling)
class RoIPooling(nn.Module):
def __init__(self, output_size):
super(RoIPooling, self).__init__()
self.output_size = output_size
def forward(self, features, rois):
# 这里简化实现,实际需要根据RoI的坐标从特征图中提取对应区域并进行池化
pooled_features = []
for roi in rois:
x1, y1, x2, y2 = roi
roi_features = features[:, :, y1:y2, x1:x2]
pooled_roi = nn.functional.adaptive_max_pool2d(roi_features, self.output_size)
pooled_features.append(pooled_roi)
return torch.cat(pooled_features, dim=0)
# 定义Fast R - CNN头部
class FastRCNNHead(nn.Module):
def __init__(self, in_channels, num_classes):
super(FastRCNNHead, self).__init__()
self.fc1 = nn.Linear(in_channels * 7 * 7, 1024)
self.fc2 = nn.Linear(1024, 1024)
self.cls_score = nn.Linear(1024, num_classes)
self.bbox_pred = nn.Linear(1024, num_classes * 4)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
cls_score = self.cls_score(x)
bbox_pred = self.bbox_pred(x)
return cls_score, bbox_pred
# 构建Faster R - CNN模型
class FasterRCNN(nn.Module):
def __init__(self, num_classes):
super(FasterRCNN, self).__init__()
self.base_model = base_model
self.rpn = RegionProposalNetwork(2048)
self.roi_pooling = RoIPooling((7, 7))
self.fast_rcnn_head = FastRCNNHead(2048, num_classes)
def forward(self, images, gt_boxes=None):
features = self.base_model(images)
cls_scores, bbox_preds = self.rpn(features)
# 这里简化处理,实际需要根据分类和回归结果生成提议区域(RoIs)
rois = generate_rois(cls_scores, bbox_preds)
pooled_features = self.roi_pooling(features, rois)
pooled_features = pooled_features.view(pooled_features.size(0), -1)
cls_scores, bbox_preds = self.fast_rcnn_head(pooled_features)
return cls_scores, bbox_preds
# 假设的生成提议区域函数
def generate_rois(cls_scores, bbox_preds):
# 这里是一个简化的示例,实际实现需要根据分类分数和回归偏移计算RoIs
rois = []
# 简单假设根据分类分数选择得分较高的区域作为RoIs
scores = cls_scores.view(-1)
top_indices = torch.topk(scores, 10)[1]
for index in top_indices:
x1 = index % 10
y1 = index // 10
x2 = x1 + 5
y2 = y1 + 5
rois.append([x1, y1, x2, y2])
return rois
# 创建Faster R - CNN模型实例,假设类别数为80
num_classes = 80
model = FasterRCNN(num_classes)
Faster R - CNN 通过区域提议网络(RPN)生成可能包含目标的提议区域,然后利用感兴趣区域池化(RoI Pooling)从特征图中提取这些区域的特征,最后通过 Fast R - CNN 头部对这些特征进行分类和位置回归,从而实现对图像中多个目标的检测。
在自然语言处理中,文本分类是一项基础任务。以基于循环神经网络(RNN)的 IMDB 影评情感分类为例,以下是使用 PyTorch 实现的代码:
python
import torch
import torch.nn as nn
import torch.optim as optim
from torchtext.legacy import data, datasets
# 定义文本字段
TEXT = data.Field(tokenize='spacy', lower=True)
# 定义标签字段
LABEL = data.LabelField(dtype=torch.float)
# 加载IMDB数据集
train_data, test_data = datasets.IMDB.splits(TEXT, LABEL)
# 构建词汇表
TEXT.build_vocab(train_data, max_size=25000)
LABEL.build_vocab(train_data)
# 创建数据迭代器
train_iterator, test_iterator = data.BucketIterator.splits(
(train_data, test_data),
batch_size=64,
device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
)
# 定义基于RNN的文本分类模型
class RNNTextClassifier(nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super(RNNTextClassifier, self).__init__()
# 嵌入层,将单词索引转换为向量表示
self.embedding = nn.Embedding(input_dim, 100)
# RNN层
self.rnn = nn.RNN(100, hidden_dim)
# 全连接层,将RNN输出映射到输出类别
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, text):
embedded = self.embedding(text)
output, hidden = self.rnn(embedded)
# 这里取最后一个时间步的隐藏状态作为文本表示
return self.fc(hidden.squeeze(0))
# 获取词汇表大小和输出类别数
input_dim = len(TEXT.vocab)
output_dim = len(LABEL.vocab)
# 定义隐藏层维度
hidden_dim = 128
# 创建模型实例
model = RNNTextClassifier(input_dim, hidden_dim, output_dim)
# 定义损失函数,这里使用二元交叉熵损失
criterion = nn.BCEWithLogitsLoss()
# 定义优化算法,这里使用Adam算法
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练模型
num_epochs = 10
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
for epoch in range(num_epochs):
model.train()
for batch in train_iterator:
optimizer.zero_grad()
text = batch.text.to(device)
label = batch.label.to(device)
predictions = model(text).squeeze(1)
loss = criterion(predictions, label)
loss.backward()
optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}
在机器翻译任务中,Transformer 架构展现出了强大的性能。以下通过一个简化的基于 Transformer 的机器翻译示例来进行分析,这里假设使用的是英语到法语的翻译任务,借助torchtext
库来处理数据。
python
import torch
import torch.nn as nn
import torch.optim as optim
from torchtext.legacy import data, datasets
import math
# 定义源语言(英语)和目标语言(法语)的文本字段
SRC = data.Field(tokenize='spacy', tokenizer_language='en_core_web_sm', lower=True)
TRG = data.Field(tokenize='spacy', tokenizer_language='fr_core_news_sm', lower=True)
# 加载WMT14英语-法语数据集的训练集、验证集和测试集
train_data, valid_data, test_data = datasets.Multi30k.splits(
exts=('.en', '.fr'), fields=(SRC, TRG)
)
# 构建源语言和目标语言的词汇表,设置最大词汇量为25000
SRC.build_vocab(train_data, max_size=25000)
TRG.build_vocab(train_data, max_size=25000)
# 创建数据迭代器,设置批量大小为64,并根据设备情况选择CPU或GPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits(
(train_data, valid_data, test_data),
batch_size = 64,
device = device
)
# 位置编码类,为输入序列添加位置信息
class PositionalEncoding(nn.Module):
def __init__(self, d_model, max_len = 5000):
super(PositionalEncoding, self).__init__()
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype = torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0).transpose(0, 1)
self.register_buffer('pe', pe)
def forward(self, x):
return x + self.pe[:x.size(0), :]
# 定义Transformer的编码器层
class EncoderLayer(nn.Module):
def __init__(self, d_model, num_heads, d_ff, dropout = 0.1):
super(EncoderLayer, self).__init__()
self.self_attn = nn.MultiheadAttention(d_model, num_heads)
self.ffn = nn.Sequential(
nn.Linear(d_model, d_ff),
nn.ReLU(),
nn.Linear(d_ff, d_model)
)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, src, src_mask):
attn_output, _ = self.self_attn(src, src, src, attn_mask = src_mask)
src = self.norm1(src + self.dropout(attn_output))
ffn_output = self.ffn(src)
return self.norm2(src + self.dropout(ffn_output))
# 定义Transformer的编码器
class Encoder(nn.Module):
def __init__(self, input_dim, d_model, num_layers, num_heads, d_ff, dropout):
super(Encoder, self).__init__()
self.embedding = nn.Embedding(input_dim, d_model)
self.pos_encoding = PositionalEncoding(d_model)
self.layers = nn.ModuleList([EncoderLayer(d_model, num_heads, d_ff, dropout) for _ in range(num_layers)])
self.dropout = nn.Dropout(dropout)
self.scale = math.sqrt(d_model)
def forward(self, src, src_mask):
src = self.embedding(src) * self.scale
src = self.pos_encoding(src)
src = self.dropout(src)
for layer in self.layers:
src = layer(src, src_mask)
return src
# 定义Transformer的解码器层
class DecoderLayer(nn.Module):
def __init__(self, d_model, num_heads, d_ff, dropout = 0.1):
super(DecoderLayer, self).__init__()
self.self_attn = nn.MultiheadAttention(d_model, num_heads)
self.enc_attn = nn.MultiheadAttention(d_model, num_heads)
self.ffn = nn.Sequential(
nn.Linear(d_model, d_ff),
nn.ReLU(),
nn.Linear(d_ff, d_model)
)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.norm3 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, trg, enc_output, trg_mask, src_trg_mask):
attn_output, _ = self.self_attn(trg, trg, trg, attn_mask = trg_mask)
trg = self.norm1(trg + self.dropout(attn_output))
attn_output, _ = self.enc_attn(trg, enc_output, enc_output, attn_mask = src_trg_mask)
trg = self.norm2(trg + self.dropout(attn_output))
ffn_output = self.ffn(trg)
return self.norm3(trg + self.dropout(ffn_output))
# 定义Transformer的解码器
class Decoder(nn.Module):
def __init__(self, output_dim, d_model, num_layers, num_heads, d_ff, dropout):
super(Decoder, self).__init__()
self.embedding = nn.Embedding(output_dim, d_model)
self.pos_encoding = PositionalEncoding(d_model)
self.layers = nn.ModuleList([DecoderLayer(d_model, num_heads, d_ff, dropout) for _ in range(num_layers)])
self.fc_out = nn.Linear(d_model, output_dim)
self.dropout = nn.Dropout(dropout)
self.scale = math.sqrt(d_model)
def forward(self, trg, enc_output, trg_mask, src_trg_mask):
trg = self.embedding(trg) * self.scale
trg = self.pos_encoding(trg)
trg = self.dropout(trg)
for layer in self.layers:
trg = layer(trg, enc_output, trg_mask, src_trg_mask)
return self.fc_out(trg)
# 定义完整的Transformer模型
class Transformer(nn.Module):
def __init__(self, input_dim, output_dim, d_model, num_layers, num_heads, d_ff, dropout):
super(Transformer, self).__init__()
self.encoder = Encoder(input_dim, d_model, num_layers, num_heads, d_ff, dropout)
self.decoder = Decoder(output_dim, d_model, num_layers, num_heads, d_ff, dropout)
self.src_pad_idx = SRC.vocab.stoi[SRC.pad_token]
self.trg_pad_idx = TRG.vocab.stoi[TRG.pad_token]
def make_src_mask(self, src):
src_mask = (src != self.src_pad_idx).unsqueeze(1).unsqueeze(2)
return src_mask
def make_trg_mask(self, trg):
trg_pad_mask = (trg != self.trg_pad_idx).unsqueeze(1).unsqueeze(2)
trg_len = trg.shape[0]
trg_sub_mask = torch.tril(torch.ones((trg_len, trg_len), device = trg.device)).bool()
trg_mask = trg_pad_mask & trg_sub_mask
return trg_mask
def forward(self, src, trg):
src_mask = self.make_src_mask(src)
trg_mask = self.make_trg_mask(trg)
enc_output = self.encoder(src, src_mask)
output = self.decoder(trg, enc_output, trg_mask, src_mask)
return output
# 设置模型参数
input_dim = len(SRC.vocab)
output_dim = len(TRG.vocab)
d_model = 512
num_layers = 6
num_heads = 8
d_ff = 2048
dropout = 0.1
# 创建Transformer模型实例
model = Transformer(input_dim, output_dim, d_model, num_layers, num_heads, d_ff, dropout).to(device)
# 定义损失函数,这里使用交叉熵损失,并忽略填充标记的损失
criterion = nn.CrossEntropyLoss(ignore_index = TRG.vocab.stoi[TRG.pad_token])
# 定义优化算法,这里使用Adam算法,并根据论文设置特定的学习率策略
optimizer = optim.Adam(model.parameters(), lr = 0, betas = (0.9, 0.98), eps = 1e - 9)
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda = lambda step: (d_model ** -0.5) * min((step + 1) ** -0.5, (step + 1) * (10000 ** -1.5)))
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
model.train()
epoch_loss = 0
for i, batch in enumerate(train_iterator):
src = batch.src.to(device)
trg = batch.trg.to(device)
optimizer.zero_grad()
output = model(src, trg[:, :-1])
output_dim = output.shape[-1]
output = output.contiguous().view(-1, output_dim)
trg = trg[:, 1:].contiguous().view(-1)
loss = criterion(output, trg)
loss.backward()
optimizer.step()
scheduler.step()
epoch_loss += loss.item()
print(f'Epoch: {epoch + 1}, Loss: {epoch_loss / len(train_iterator)}')
在上述代码中,首先定义了源语言和目标语言的文本字段,并加载了 WMT14 英语 - 法语数据集。接着构建了 Transformer 模型的各个组件,包括位置编码、编码器层、编码器、解码器层、解码器以及完整的 Transformer 模型。在模型训练部分,定义了损失函数和优化算法,并按照特定的学习率策略进行训练。Transformer 模型通过自注意力机制有效地捕捉输入序列中不同位置之间的依赖关系,从而在机器翻译任务中能够准确地将源语言句子翻译成目标语言句子。
语音识别是将人类语音转换为文本的技术。基于循环神经网络(RNN)及其变体长短时记忆网络(LSTM)在语音识别领域有广泛应用。以下是一个简化的基于 RNN - LSTM 的语音识别模型实现示例,这里使用torchaudio
库来处理音频数据。
python
import torch
import torch.nn as nn
import torch.optim as optim
import torchaudio
from torch.utils.data import Dataset, DataLoader
import numpy as np
# 定义音频数据集类
class SpeechDataset(Dataset):
def __init__(self, audio_files, labels, transform = None):
self.audio_files = audio_files
self.labels = labels
self.transform = transform
def __len__(self):
return len(self.audio_files)
def __getitem__(self, idx):
audio, sr = torchaudio.load(self.audio_files[idx])
label = self.labels[idx]
if self.transform:
audio = self.transform(audio)
return audio, label
# 定义音频数据预处理转换
class AudioPreprocessing:
def __init__(self, n_mels = 128, n_fft = 2048, hop_length = 512):
self.n_mels = n_mels
self.n_fft = n_fft
self.hop_length = hop_length
def __call__(self, audio):
mel_spectrogram = torchaudio.transforms.MelSpectrogram(
sample_rate = 16000,
n_mels = self.n_mels,
n_fft = self.n_fft,
hop_length = self.hop_length
)(audio)
log_mel_spectrogram = torchaudio.transforms.AmplitudeToDB()(mel_spectrogram)
return log_mel_spectrogram
# 定义基于RNN - LSTM的语音识别模型
class RNNLSTMModel(nn.Module):
def __init__(self, input_dim, hidden_dim, num_layers, output_dim):
super(RNNLSTMModel, self).__init__()
self.lstm = nn.LSTM(input_dim, hidden_dim, num_layers, batch_first = True)
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
out, _ = self.lstm(x)
out = self.fc(out[:, -1, :])
return out
# 假设我们有音频文件路径列表和对应的标签列表
audio_files = ['audio1.wav', 'audio2.wav', ...]
labels = [0, 1, ...]
# 创建音频数据集实例,并应用预处理转换
preprocess = AudioPreprocessing()
dataset = SpeechDataset(audio_files, labels, transform = preprocess)
# 创建数据迭代器,设置批量大小为32
dataloader = DataLoader(dataset, batch_size = 32, shuffle = True)
# 设置模型参数
input_dim = 128
hidden_dim = 256
num_layers = 2
output_dim = 10 # 假设是10个类别的语音识别任务
# 创建RNN - LSTM模型实例
model = RNNLSTMModel(input_dim, hidden_dim, num_layers, output_dim).to(device)
# 定义损失函数,这里使用交叉熵损失
criterion = nn.CrossEntropyLoss()
# 定义优化算法,这里使用Adam算法
optimizer = optim.Adam(model.parameters(), lr = 0.001)
# 训练模型
num_epochs = 10
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
for epoch in range(num_epochs):
model.train()
for i, (audio, label) in enumerate(dataloader):
audio = audio.to(device)
label = label.to(device)
optimizer.zero_grad()
output = model(audio)
loss = criterion(output, label)
loss.backward()
optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
在这个示例中,首先定义了一个音频数据集类SpeechDataset
,用于加载音频文件和对应的标签,并可以应用数据预处理。音频数据预处理通过AudioPreprocessing
类实现,将音频转换为对数梅尔频谱图。接着构建了基于 RNN - LSTM 的语音识别模型,该模型通过 LSTM 层学习音频序列中的时间依赖关系,最后通过全连接层输出分类结果。在训练过程中,使用交叉熵损失函数和 Adam 优化器对模型进行训练,以实现将音频准确分类到不同类别的语音识别任务。
在医疗领域,神经网络可用于疾病诊断辅助。例如,通过对医学影像(如 X 光、CT、MRI 等)进行分析,卷积神经网络能够识别影像中的异常特征,辅助医生检测疾病,如肺癌、乳腺癌等。在心电图(ECG)分析中,循环神经网络可以处理 ECG 信号的时间序列数据,识别出心律失常等异常情况。
在金融领域,神经网络可用于风险预测。例如,通过分析历史金融数据,包括股票价格、利率、汇率等,使用递归神经网络或 Transformer 架构可以预测金融市场的波动,帮助投资者进行风险评估和投资决策。同时,在信用风险评估中,多层感知机可以综合考虑客户的信用记录、收入情况等多维度数据,评估客户的信用风险等级。
在工业领域,神经网络可用于设备故障预测。通过传感器收集设备运行过程中的各种数据,如温度、振动、压力等,利用深度学习模型(如自编码器结合循环神经网络)可以学习设备正常运行时的数据模式。当设备出现异常时,模型能够根据数据的变化预测可能出现的故障,提前进行维护,减少设备停机时间,提高生产效率。
神经网络作为人工智能领域的核心技术,经过多年的发展,已经取得了令人瞩目的成就。从最初简单的神经元模型,逐步发展为包含多种复杂结构的深度神经网络,其在不同领域的应用也日益广泛和深入。
我们从神经元模型开始,了解了人工神经元如何模拟生物神经元的工作方式,通过加权求和与激活函数产生输出。单层感知机作为最简单的神经网络