接下来,我们在神经网络方面继续展开
神经网络
- 多层感知机(MLP)
- 解决问题:多层感知机是一种基本的前馈神经网络,可用于解决分类和回归问题。它通过多个神经元层的非线性变换,能够学习复杂的非线性关系,对数据进行分类或预测连续值。例如,在手写数字识别中,它可以从数字图像的像素数据中学习到特征模式,从而判断该数字是 0 - 9 中的哪一个;在房价预测中,根据房屋的面积、房间数量等特征预测房价。
- 案例:以手写数字识别为例,MLP 可以学习数字图像中的特征模式,从而准确判断图像中的数字是 0 - 9 中的哪一个。
- 框架/库:在 Python 中, scikit - learn 库中的 MLPClassifier (用于分类)和 MLPRegressor (用于回归)类可以方便地实现 MLP。 Keras 库也能轻松搭建 MLP 模型。
使用 Keras 实现手写数字识别的代码示例:
from keras.models import Sequential
from keras.layers import Dense
from keras.datasets import mnist
from keras.utils import to_categorical
import numpy as np
# 加载手写数字数据集,mnist 数据集包含大量手写数字的图像及其对应的标签
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# 将图像数据展平为一维数组,因为 MLP 输入要求是一维向量。这里每张图像原本是 28x28 的二维矩阵,展平后变为 784 维向量
train_images = train_images.reshape((-1, 28 * 28))
test_images = test_images.reshape((-1, 28 * 28))
# 将数据归一化到 [0, 1] 区间,有助于模型更快收敛和更好地学习。因为神经网络对小范围数值更敏感
train_images = train_images.astype('float32') / 255
test_images = test_images.astype('float32') / 255
# 将标签进行独热编码,将数字标签转换为向量形式,便于神经网络处理。例如数字 3 编码为 [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
# 构建 MLP 模型
model = Sequential()
# 添加第一个全连接层,512 个神经元,使用 ReLU 激活函数引入非线性。输入形状为 (28 * 28,),即展平后的图像向量维度
model.add(Dense(512, activation='relu', input_shape=(28 * 28,)))
# 添加输出层,10 个神经元对应 10 个数字类别,使用 softmax 激活函数输出每个类别的概率分布
model.add(Dense(10, activation='softmax'))
# 编译模型,指定损失函数、优化器和评估指标
model.compile(optimizer='adam',
# 多分类问题常用的交叉熵损失函数
loss='categorical_crossentropy',
metrics=['accuracy'])
# 训练模型,训练 5 个 epoch,每个 batch 包含 64 个样本
model.fit(train_images, train_labels, epochs=5, batch_size=64)
# 评估模型在测试集上的性能
test_loss, test_acc = model.evaluate(test_images, test_labels)
print('Test accuracy:', test_acc)
- 卷积神经网络(CNN)
- 解决问题:主要用于处理具有网格结构的数据,如图像、音频等。通过卷积层、池化层和全连接层的组合,自动提取数据的局部特征,有效减少参数数量,提高模型的泛化能力,在图像分类、目标检测、语义分割等计算机视觉任务中表现卓越。例如在图像分类中,它能从图像的像素中提取诸如边缘、纹理等局部特征,从而判断图像所属类别;在目标检测中,不仅能识别目标物体,还能定位其在图像中的位置。- 案例:图像分类,例如识别猫和狗的图片。CNN 能够学习到猫和狗在图像中的不同特征,如脸部特征、身体轮廓等,从而准确分类。- 框架/库: Keras 、 TensorFlow 和 PyTorch 都提供了强大的工具来构建 CNN 模型。 使用 Keras 实现猫和狗图像分类的简单代码示例(假设已有猫和狗的图像数据集,并已进行预处理):
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
import numpy as np
# 假设 X_train, y_train 为训练数据,X_test, y_test 为测试数据
# 数据形状假设为 (样本数, 图像高度, 图像宽度, 通道数)
# 这里简单生成一些模拟数据
X_train = np.random.random((100, 100, 100, 3))
y_train = np.random.randint(0, 2, (100,))
X_test = np.random.random((20, 100, 100, 3))
y_test = np.random.randint(0, 2, (20,))
model = Sequential()
# 添加第一个卷积层,32 个卷积核,大小为 (3, 3),激活函数为 ReLU,输入形状为 (100, 100, 3)
model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(100, 100, 3)))
# 添加最大池化层,池化窗口大小为 (2, 2),用于减少数据维度,同时保留主要特征
model.add(MaxPooling2D((2, 2)))
# 再次添加卷积层,64 个卷积核,大小 (3, 3),进一步提取特征
model.add(Conv2D(64, (3, 3), activation='relu'))
# 再次添加最大池化层
model.add(MaxPooling2D((2, 2)))
# 将卷积层输出展平为一维向量,以便连接全连接层
model.add(Flatten())
# 添加全连接层,64 个神经元,使用 ReLU 激活函数
model.add(Dense(64, activation='relu'))
# 输出层,1 个神经元,用于二分类(猫或狗),使用 sigmoid 激活函数输出概率
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='adam',
# 二分类问题常用的二元交叉熵损失函数
loss='binary_crossentropy',
metrics=['accuracy'])
model.fit(X_train, y_train, epochs=10, batch_size=32)
test_loss, test_acc = model.evaluate(X_test, y_test)
print('Test accuracy:', test_acc)
- 循环神经网络(RNN)
- 解决问题:适用于处理序列数据,如时间序列数据或自然语言。RNN 具有记忆能力,能够处理前后关联的信息,捕捉序列中的长期依赖关系,但传统 RNN 在处理长序列时存在梯度消失或梯度爆炸问题。梯度消失指在反向传播过程中,梯度随着时间步的增加而指数级减小,导致较早时间步的梯度变得极小,使得模型难以学习到长距离的依赖关系;梯度爆炸则相反,梯度随着时间步增加而指数级增大,导致模型参数更新过大,无法收敛。例如在语音识别中,它可以根据语音信号的时间序列特征识别出对应的文字;在股票价格预测中,分析历史价格序列预测未来价格。
- 案例:在自然语言处理中,用于词性标注。给定一个句子,RNN 可以根据每个单词在句子中的位置以及之前单词的信息,预测该单词的词性。
- 框架/库: Keras 、 TensorFlow 和 PyTorch 都支持 RNN 的实现。
使用 Keras 进行简单时间序列预测的代码示例(这里以预测正弦函数时间序列为例):
import numpy as np
from keras.models import Sequential
from keras.layers import SimpleRNN, Dense
import matplotlib.pyplot as plt
# 生成正弦函数时间序列数据
time_steps = 100
data = np.sin(np.linspace(0, 10 * np.pi, time_steps))
X = []
y = []
# 构建训练数据,每个样本包含 10 个时间步的数据,标签为第 11 个时间步的数据
for i in range(len(data) - 10):
X.append(data[i:i + 10])
y.append(data[i + 10])
X = np.array(X).reshape(-1, 10, 1)
y = np.array(y)
model = Sequential()
# 添加简单 RNN 层,32 个神经元,输入形状为 (10, 1),即每个样本有 10 个时间步,每个时间步 1 个特征
model.add(SimpleRNN(32, input_shape=(10, 1)))
# 添加全连接输出层,1 个神经元,用于预测下一个时间步的值
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
model.fit(X, y, epochs=50, batch_size=32)
# 预测未来 10 个时间步
future_prediction = []
current_sequence = data[-10:].reshape(1, 10, 1)
for _ in range(10):
next_value = model.predict(current_sequence)
future_prediction.append(next_value[0, 0])
# 更新当前序列,将预测值添加到序列末尾,并去掉第一个值
current_sequence = np.roll(current_sequence, -1, axis = 1)
current_sequence[0, -1, 0] = next_value
plt.plot(range(len(data)), data, label='Original')
plt.plot(range(len(data), len(data) + len(future_prediction)), future_prediction, label='Prediction')
plt.legend()
plt.show()
- 长短时记忆网络(LSTM)
- 解决问题:专门为解决 RNN 中的长期依赖问题而设计。LSTM 通过引入门控机制(输入门、遗忘门和输出门),能够更好地控制信息的流动和记忆,有效处理长序列数据,在自然语言处理、语音识别等领域广泛应用。输入门决定哪些新信息要被添加到记忆单元;遗忘门决定哪些旧信息要从记忆单元中丢弃;输出门决定记忆单元中的哪些信息要被输出用于当前的预测。例如在机器翻译中,处理长句子时能准确捕捉句子中的语义信息并进行翻译。
- 案例:机器翻译。LSTM 可以处理源语言句子中的长距离依赖关系,将其准确翻译成目标语言。
- 框架/库: Keras 、 TensorFlow 和 PyTorch 都提供了 LSTM 的实现。
使用 Keras 实现简单文本情感分析的代码示例(假设已有预处理好的文本数据和标签):
from keras.models import Sequential
from keras.layers import Embedding, LSTM, Dense
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
import numpy as np
# 假设 texts 为文本数据,labels 为情感标签(0 为负面,1 为正面)
texts = ["This is a great product", "I hate this service", "The movie was awesome"]
labels = np.array([1, 0, 1])
# 创建 Tokenizer 对象,将文本转换为数字序列,num_words 设置只考虑出现频率最高的 1000 个单词
tokenizer = Tokenizer(num_words = 1000)
tokenizer.fit_on_texts(texts)
X = tokenizer.texts_to_sequences(texts)
# 将所有序列填充到相同长度,maxlen 设置为 100
X = pad_sequences(X, maxlen = 100)
model = Sequential()
# 添加嵌入层,将单词索引转换为低维向量表示,1000 为词汇表大小,128 为嵌入维度
model.add(Embedding(1000, 128))
# 添加 LSTM 层,128 个神经元
model.add(LSTM(128))
# 添加全连接输出层,1 个神经元,用于二分类,使用 sigmoid 激活函数输出概率
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='adam',
# 二分类问题常用的二元交叉熵损失函数
loss='binary_crossentropy',
metrics=['accuracy'])
model.fit(X, labels, epochs=10, batch_size=32)
- Transformer 架构
- 解决问题:主要用于自然语言处理任务,通过自注意力机制,有效捕捉序列中的长距离依赖关系,同时并行计算能力强,训练效率高,打破了传统 RNN 顺序处理的限制。自注意力机制允许模型在处理序列中的每个位置时,同时关注序列中的其他所有位置,从而更好地捕捉全局信息。例如在文本生成中,能根据前文生成连贯的后续文本;在机器翻译中,对源语言句子的每个单词都能综合考虑全局信息进行翻译。- 案例:文本生成,如自动写新闻报道。Transformer 可以根据给定的主题和一些初始信息,生成连贯、有逻辑的新闻文本。- 框架/库: Hugging Face 的 Transformers 库提供了丰富的基于 Transformer 架构的预训练模型和工具,方便进行各种自然语言处理任务。 TensorFlow 和 PyTorch 也可用于搭建自定义的 Transformer 模型。 使用 Hugging Face 的 Transformers 库进行文本生成的简单代码示例:
from transformers import pipeline
# 使用 GPT - 2 模型进行文本生成,pipeline 函数构建一个文本生成的管道,
# 'text - generation' 表示任务类型为文本生成,model='gpt2'指定使用 GPT - 2 预训练模型
generator = pipeline('text - generation', model='gpt2')
# 生成文本,从 "Once upon a time" 开始生成,设置最大长度为 50 个词元,生成 1 条文本序列
generated_text = generator("Once upon a time", max_length = 50, num_return_sequences = 1)
print(generated_text[0]['generated_text'])
- Vision Transformer(ViT)
- 解决问题:将 Transformer 架构应用于计算机视觉领域,打破了卷积神经网络在图像领域的长期主导地位。传统的 CNN 在处理图像时,通过卷积核在图像上滑动来提取局部特征。而 ViT 通过将图像分割成多个小块,并将这些小块视为序列中的元素,利用自注意力机制处理图像,在图像分类等任务中展现出与传统 CNN 相当甚至更优的性能。它可以捕捉图像中不同区域之间的长距离依赖关系,对图像的全局信息有更好的把握,例如在处理具有复杂场景和多个物体的图像时,能更准确地分类。- 案例:花卉分类。ViT 可以学习不同花卉图像的整体特征模式,对花卉图像进行准确分类。比如,准确区分玫瑰、郁金香、百合等不同花卉的图片。- 框架/库: PyTorch 中有多个开源实现,如 timm (PyTorch Image Models)库提供了方便的 ViT 模型调用和训练工具。 以下是使用 timm 库在自定义花卉图像数据集上进行分类的简单代码框架(假设已完成数据预处理):
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import transforms, datasets
import timm
# 定义数据变换,将图像调整为 224x224 大小,转换为张量,并进行标准化
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
# 加载自定义花卉数据集,train_dataset 为训练集,test_dataset 为测试集
train_dataset = datasets.ImageFolder('path_to_train_data', transform = transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size = 32, shuffle = True)
test_dataset = datasets.ImageFolder('path_to_test_data', transform = transform)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size = 32, shuffle = False)
# 创建 ViT 模型,'vit_base_patch16_224' 是一种预定义的 ViT 模型架构,
# num_classes 根据花卉类别数量设置
model = timm.create_model('vit_base_patch16_224', num_classes = len(train_dataset.classes))
# 定义交叉熵损失函数,常用于多分类问题
criterion = nn.CrossEntropyLoss()
# 使用 Adam 优化器,设置学习率为 0.001
optimizer = optim.Adam(model.parameters(), lr = 0.001)
# 训练模型
for epoch in range(10):
model.train()
for images, labels in train_loader:
optimizer.zero_grad()
outputs = model(images)
# 计算模型输出与真实标签之间的损失
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
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'Epoch {epoch + 1}, Accuracy: {correct / total}')
- 生成对抗网络(GAN)
- 解决问题:旨在通过生成器和判别器的对抗训练,让生成器学习到真实数据的分布,从而生成与真实数据相似的数据。生成器尝试生成逼真的数据样本,判别器则努力区分生成的数据和真实数据。两者相互博弈,共同提升,最终生成器能够生成高质量的模拟数据。它在图像生成、数据增强、图像修复等领域有广泛应用。例如在图像生成中,能够生成逼真的人脸图像、风景图像等;在数据增强中,可以扩充训练数据集,提升模型的泛化能力。- 案例:生成动漫角色图像。给定一些动漫角色的特征描述,GAN 可以生成对应的动漫角色图片,为动漫创作提供灵感和素材。- 框架/库: PyTorch 和 TensorFlow 都有实现 GAN 的丰富资源。下面是使用 PyTorch 实现简单 GAN 生成手写数字图像的代码示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torchvision.utils import save_image
import os
# 数据预处理,将图像转换为张量并归一化到 [-1, 1]
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
# 加载 MNIST 数据集
mnist_dataset = datasets.MNIST(root='./data', train=True,
download=True, transform=transform)
dataloader = torch.utils.data.DataLoader(mnist_dataset, batch_size=64, shuffle=True)
# 生成器模型,将随机噪声向量映射为图像
class Generator(nn.Module):
def __init__(self):
super(Generator, self).__init__()
self.model = nn.Sequential(
nn.Linear(100, 128),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(128, 256),
nn.BatchNorm1d(256),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(256, 512),
nn.BatchNorm1d(512),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(512, 784),
nn.Tanh()
)
def forward(self, x):
return self.model(x)
# 判别器模型,判断输入图像是真实的还是生成的
class Discriminator(nn.Module):
def __init__(self):
super(Discriminator, self).__init__()
self.model = nn.Sequential(
nn.Linear(784, 512),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(512, 256),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(256, 1),
nn.Sigmoid()
)
def forward(self, x):
return self.model(x)
# 创建生成器和判别器实例
generator = Generator()
discriminator = Discriminator()
# 定义损失函数,这里使用二元交叉熵损失
criterion = nn.BCELoss()
# 定义生成器和判别器的优化器,使用 Adam 优化器
optimizer_G = optim.Adam(generator.parameters(), lr=0.0002, betas=(0.5, 0.999))
optimizer_D = optim.Adam(discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999))
# 训练循环
for epoch in range(50):
for i, (images, _) in enumerate(dataloader):
images = images.view(-1, 784)
# 训练判别器
optimizer_D.zero_grad()
real_labels = torch.ones(images.size(0), 1)
fake_labels = torch.zeros(images.size(0), 1)
real_outputs = discriminator(images)
real_loss = criterion(real_outputs, real_labels)
noise = torch.randn(images.size(0), 100)
fake_images = generator(noise)
fake_outputs = discriminator(fake_images.detach())
fake_loss = criterion(fake_outputs, fake_labels)
d_loss = real_loss + fake_loss
d_loss.backward()
optimizer_D.step()
# 训练生成器
optimizer_G.zero_grad()
fake_outputs = discriminator(fake_images)
g_loss = criterion(fake_outputs, real_labels)
g_loss.backward()
optimizer_G.step()
if (i + 1) % 100 == 0:
print(f'Epoch [{epoch + 1}/50], Step [{i + 1}/{len(dataloader)}], '
f'd_loss: {d_loss.item():.4f}, g_loss: {g_loss.item():.4f}')
# 保存生成的图像
with torch.no_grad():
noise = torch.randn(64, 100)
fake_images = generator(noise)
save_image(fake_images.view(-1, 1, 28, 28),
os.path.join('images', f'epoch_{epoch + 1}.png'), nrow=8, normalize=True)
- 自编码器(Autoencoder)
- 解决问题:自编码器作为一种无监督学习的神经网络架构,主要目标是学习一种数据的高效表示形式。它由编码器和解码器两大部分构成。编码器负责将输入数据压缩映射到一个低维的特征空间,提取数据中的关键特征,就像是从一堆复杂信息中提炼出精华;解码器则把这个低维表示重构回原始数据的近似形式。通过最小化原始输入与重构输出之间的差异(通常使用均方误差等损失函数)来训练模型。自编码器在多个领域都有重要应用,例如数据降维,能把高维数据转换为低维,减少数据存储和处理的复杂度,同时尽量保留关键信息;在图像领域,可用于图像去噪,去除图像中混入的噪声,恢复清晰的图像;还能用于异常检测,通过判断重构误差是否异常来识别数据中的异常点。- 案例:以人脸识别系统中的数据预处理为例。在一个大型的人脸识别数据库中,图像数据维度很高。使用自编码器可以将这些高维的人脸图像数据压缩成低维的特征向量。这样在进行人脸识别匹配时,计算量大幅减少,同时保留了人脸的关键特征,不影响识别准确率。例如,当新的人脸图像输入系统时,先经过自编码器的编码器得到其低维特征表示,然后与数据库中已有的人脸特征向量进行比对,从而判断是否为同一人。- 框架/库:在Python的深度学习框架中, Keras 、 PyTorch 和 TensorFlow 都提供了便捷的方式来构建自编码器。下面以 PyTorch 为例展示一个简单的自编码器代码示例,用于对MNIST手写数字图像进行特征提取和重构。
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
# 数据预处理,将图像转换为张量并归一化到 [0, 1]
transform = transforms.Compose([
transforms.ToTensor()
])
# 加载MNIST数据集
train_dataset = datasets.MNIST(root='./data', train=True,
download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataset = datasets.MNIST(root='./data', train=False,
download=True, transform=transform)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False)
# 定义自编码器模型
class Autoencoder(nn.Module):
def __init__(self):
super(Autoencoder, self).__init__()
# 编码器部分
self.encoder = nn.Sequential(
nn.Linear(28 * 28, 128),
nn.ReLU(True),
nn.Linear(128, 64),
nn.ReLU(True),
nn.Linear(64, 32)
)
# 解码器部分
self.decoder = nn.Sequential(
nn.Linear(32, 64),
nn.ReLU(True),
nn.Linear(64, 128),
nn.ReLU(True),
nn.Linear(128, 28 * 28),
nn.Tanh()
)
def forward(self, x):
x = self.encoder(x)
x = self.decoder(x)
return x
# 创建自编码器实例
model = Autoencoder()
# 定义均方误差损失函数
criterion = nn.MSELoss()
# 使用Adam优化器,学习率设置为0.001
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练自编码器
num_epochs = 10
for epoch in range(num_epochs):
model.train()
running_loss = 0.0
for i, data in enumerate(train_loader, 0):
inputs, _ = data
inputs = inputs.view(-1, 28 * 28)
optimizer.zero_grad()
# 前向传播
outputs = model(inputs)
loss = criterion(outputs, inputs)
# 反向传播和优化
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f'Epoch {epoch + 1}, Loss: {running_loss / len(train_loader)}')
# 在测试集上进行测试
model.eval()
with torch.no_grad():
for i, data in enumerate(test_loader, 0):
inputs, _ = data
inputs = inputs.view(-1, 28 * 28)
outputs = model(inputs)
# 绘制原始图像和重构图像
if i == 0:
n = 10
plt.figure(figsize=(20, 4))
for j in range(n):
# 显示原始图像
ax = plt.subplot(2, n, j + 1)
plt.imshow(inputs[j].view(28, 28).numpy(), cmap='gray')
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
# 显示重构图像
ax = plt.subplot(2, n, j + 1 + n)
plt.imshow(outputs[j].view(28, 28).numpy(), cmap='gray')
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
- 胶囊网络(Capsule Network)
- 解决问题:传统的卷积神经网络在处理物体的姿态、大小、方向等变化时存在一定局限。胶囊网络旨在通过引入“胶囊”的概念来更好地解决这些问题。胶囊是一组神经元,其输出向量的长度表示实体存在的概率,向量的方向表示实体的属性(如姿态等)。胶囊之间通过动态路由算法进行信息传递,使得模型能够更有效地捕捉数据中的空间层次结构和实体关系。在图像识别中,胶囊网络可以更准确地识别不同姿态和大小的物体,提高对复杂场景图像的理解能力;在视频分析中,对于运动物体的跟踪和识别也能取得较好效果。- 案例:在自动驾驶场景中的交通标志识别。交通标志可能会因为拍摄角度、距离远近等因素呈现出不同的姿态和大小。胶囊网络能够更好地处理这些变化,准确识别出各种交通标志,比如在不同光照和角度下的限速标志、转弯标志等,为自动驾驶系统提供可靠的环境信息。- 框架/库:虽然没有像 Keras 、 PyTorch 和 TensorFlow 那样通用广泛,但也有一些开源项目尝试在这些框架基础上实现胶囊网络。以下是一个基于 PyTorch 搭建简单胶囊网络用于MNIST数字分类的示例代码框架(实际应用中可能需要更多的优化和调整)。
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
import numpy as np
# 数据预处理,将图像转换为张量并归一化到 [0, 1]
transform = transforms.Compose([
transforms.ToTensor()
])
# 加载MNIST数据集
train_dataset = datasets.MNIST(root='./data', train=True,
download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataset = datasets.MNIST(root='./data', train=False,
download=True, transform=transform)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False)
# 定义胶囊层
class CapsuleLayer(nn.Module):
def __init__(self, in_capsules, in_channels, out_capsules, out_channels, kernel_size=None, stride=None,
num_routing=3):
super(CapsuleLayer, self).__init__()
self.in_capsules = in_capsules
self.in_channels = in_channels
self.out_capsules = out_capsules
self.out_channels = out_channels
self.num_routing = num_routing
if kernel_size:
self.conv = nn.Conv2d(in_channels, out_channels * out_capsules, kernel_size=kernel_size, stride=stride)
else:
self.fc = nn.Linear(in_capsules * in_channels, out_capsules * out_channels)
def squash(self, tensor, dim=-1):
squared_norm = (tensor ** 2).sum(dim=dim, keepdim=True)
scale = squared_norm / (1 + squared_norm)
return scale * tensor / torch.sqrt(squared_norm)
def forward(self, x):
if hasattr(self, 'conv'):
x = self.conv(x)
batch_size = x.size(0)
x = x.view(batch_size, self.out_capsules, self.out_channels, -1)
else:
batch_size = x.size(0)
x = self.fc(x)
x = x.view(batch_size, self.out_capsules, self.out_channels)
u_hat = x
b_ij = torch.zeros((batch_size, self.in_capsules, self.out_capsules, 1)).to(x.device)
for _ in range(self.num_routing - 1):
c_ij = torch.softmax(b_ij, dim=1)
s_j = (c_ij * u_hat).sum(dim=1, keepdim=True)
v_j = self.squash(s_j)
u_vj = (u_hat * v_j).sum(dim=2, keepdim=True)
b_ij = b_ij + u_vj
c_ij = torch.softmax(b_ij, dim=1)
s_j = (c_ij * u_hat).sum(dim=1, keepdim=True)
v_j = self.squash(s_j)
return v_j.view(batch_size, -1)
# 定义胶囊网络模型
class CapsuleNet(nn.Module):
def __init__(self):
super(CapsuleNet, self).__init__()
self.conv1 = nn.Conv2d(1, 256, kernel_size=9, stride=1)
self.primary_capsules = CapsuleLayer(1, 256, 8, 32, kernel_size=9, stride=2)
self.digit_capsules = CapsuleLayer(32 * 6 * 6, 8, 10, 16)
def forward(self, x):
x = nn.functional.relu(self.conv1(x), inplace=True)
x = self.primary_capsules(x)
x = self.digit_capsules(x)
return torch.sqrt((x ** 2).sum(dim=2))
# 创建胶囊网络实例
model = CapsuleNet()
# 定义交叉熵损失函数
criterion = nn.CrossEntropyLoss()
# 使用Adam优化器,学习率设置为0.001
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练胶囊网络
num_epochs = 10
for epoch in range(num_epochs):
model.train()
running_loss = 0.0
for i, data in enumerate(train_loader, 0):
inputs, labels = data
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f'Epoch {epoch + 1}, Loss: {running_loss / len(train_loader)}')
# 在测试集上评估模型
model.eval()
correct = 0
total = 0
with torch.no_grad():
for data in test_loader:
images, labels = data
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}%')
小结
从上面你也可以看见,TensorFlow 和 PyTorch 能够实现众多神经网络。
TensorFlow 采用静态计算图,在计算开始前构建完整计算图。这一特性使其在分布式训练与优化方面优势显著,如同搭建一座大型建筑,先绘制精确蓝图,而后有条不紊地施工。在 Google 的云服务中,TensorFlow 借助静态计算图可高效将计算资源分配到多服务器或 GPU 上。静态图构建完成后,能进行自动并行化计算、内存优化等操作,为搭建复杂神经网络筑牢根基。例如在训练大规模图像识别神经网络时,可利用静态计算图的优化机制,快速处理海量图像数据。
PyTorch 使用动态计算图,在运行时构建计算过程。这种方式就像即兴创作,更加直观灵活。研究人员编写神经网络代码如同编写常规 Python 代码,便于调试与快速迭代模型。在探索新神经网络架构时,依据实验结果随时调整网络结构,无需重新构建整个静态图。比如在研究新型循环神经网络结构时,能实时修改网络连接与参数,动态计算图实时跟踪计算过程,助力理解模型运行机制。
在实际使用中,若侧重生产环境,追求大规模分布式训练的高效性与稳定性,像开发工业级的图像识别系统、语音识别服务等,TensorFlow 是不错选择。开发者先定义好计算图中的各个节点与操作,例如构建卷积神经网络时,明确卷积层、池化层等操作及其连接关系,再配置好优化器、损失函数等参数进行模型训练。
若聚焦于研究探索,渴望快速尝试新想法、新架构,如高校或科研机构进行前沿神经网络研究,PyTorch 更为契合。以构建生成对抗网络(GAN)为例,开发者可按逻辑顺序逐步定义生成器与判别器,在训练过程中轻松调整网络结构与参数,通过即时反馈优化模型。
当然框架和库是对理论的封装,要想实现更复杂的模型,了解和学习底层理论必不可少。