赞
踩
定义和基本概念
卷积神经网络(CNN)是一种专门用于处理具有网格结构数据(如图像)的深度学习模型。它们在图像识别和计算机视觉领域表现尤为突出。与传统的全连接神经网络不同,CNN利用局部连接和共享权重的方式,能够有效减少参数数量,提高计算效率。
CNN在图像处理中的优势
输入层
处理输入数据,比如一张图片,通常用三维数组表示(宽度,高度,颜色通道数)。
卷积层
通过应用不同的滤波器来提取特征。滤波器滑过输入图像,生成特征映射。
池化层
进行降采样,减少数据维度,提高计算效率,同时保留重要特征。
全连接层
将卷积层和池化层提取的特征展开成一维向量,并通过多个全连接层进行分类。
输出层
根据具体任务(如分类、回归)输出最终结果。
实例:
假设有一个3x3的输入图像和一个2x2的滤波器:
输入图像:
1 2 3
4 5 6
7 8 9
滤波器:
1 0
0 -1
卷积操作是将滤波器应用于图像的每个局部区域,计算它们的点积和:
1*1 + 2*0 + 4*0 + 5*(-1) = 1 - 5 = -4
2*1 + 3*0 + 5*0 + 6*(-1) = 2 - 6 = -4
4*1 + 5*0 + 7*0 + 8*(-1) = 4 - 8 = -4
5*1 + 6*0 + 8*0 + 9*(-1) = 5 - 9 = -4
最终得到的特征映射:
-4 -4
-4 -4
实例:
ReLU(Rectified Linear Unit):f(x) = max(0, x)
假设输入为[-1, 2, -3, 4],经过ReLU后:
ReLU([-1, 2, -3, 4]) = [0, 2, 0, 4]
实例:
Max Pooling:
输入:
1 2
3 4
最大池化结果:
4
Average Pooling:
输入:
1 2
3 4
平均池化结果:
(1+2+3+4)/4 = 2.5
实例:
假设有两个类别,实际标签为[1, 0](表示第一类),预测概率为[0.8, 0.2]。
交叉熵损失计算:
Loss = - (1 * log(0.8) + 0 * log(0.2)) = - log(0.8) = 0.223
安装和配置PyTorch
pip install torch torchvision
构建简单的CNN模型
import torch.nn as nn import torch.nn.functional as F class SimpleCNN(nn.Module): def __init__(self): super(SimpleCNN, self).__init__() self.conv1 = nn.Conv2d(3, 16, 3, 1) # 3个输入通道,16个输出通道,3x3的卷积核,步长1 self.conv2 = nn.Conv2d(16, 32, 3, 1) self.fc1 = nn.Linear(32 * 6 * 6, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = F.relu(self.conv1(x)) x = F.max_pool2d(x, 2, 2) x = F.relu(self.conv2(x)) x = F.max_pool2d(x, 2, 2) x = x.view(-1, 32 * 6 * 6) x = F.relu(self.fc1(x)) x = self.fc2(x) return F.log_softmax(x, dim=1)
数据预处理
import torchvision.transforms as transforms
from torchvision.datasets import CIFAR10
from torch.utils.data import DataLoader
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
trainset = CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = DataLoader(trainset, batch_size=32, shuffle=True)
训练和评估模型
import torch.optim as optim model = SimpleCNN() criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9) for epoch in range(10): # 训练10个epoch running_loss = 0.0 for i, data in enumerate(trainloader, 0): inputs, labels = data optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() if i % 100 == 99: # 每100个批次打印一次 print(f'Epoch {epoch + 1}, Batch {i + 1}, Loss: {running_loss / 100:.3f}') running_loss = 0.0 print('Finished Training')
LeNet
由Yann LeCun提出,适用于手写数字识别。
AlexNet
由Alex Krizhevsky提出,首次在ImageNet竞赛中大放异彩。
VGGNet
由Oxford大学Visual Geometry Group提出,使用多个小卷积核代替大卷积核。
GoogLeNet/Inception
由Google提出,使用Inception模块提高模型性能。
ResNet
由Microsoft提出,引入残差连接解决深层网络训练困难问题。
DenseNet
由Cornell大学提出,通过密集连接提高梯度流动。
使用预训练模型
from torchvision import models
resnet = models.resnet18(pretrained=True)
微调(Fine-Tuning)
for param in resnet.parameters():
param.requires_grad = False
resnet.fc = nn.Linear(resnet.fc.in_features, 10)
学习率调度
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)
正则化方法
self.dropout = nn.Dropout(0.5) # 在网络中使用dropout防止过拟合
批量归一化
self.bn1 = nn.BatchNorm2d(16) # 在卷积层后添加批量归一化层
数据增强
transform = transforms.Compose([
transforms.RandomHorizontalFlip(),
transforms.RandomCrop(32, padding=4),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
混合精度训练
from torch.cuda.amp import GradScaler, autocast
scaler = GradScaler()
for epoch in range(10):
for inputs, labels in trainloader:
optimizer.zero_grad()
with autocast():
outputs = model(inputs)
loss = criterion(outputs, labels)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
数据集规模 | 数据集大小 | 推荐的卷积层数量 | 推荐的卷积核数(每层) | 推荐的全连接层数量 | 推荐的全连接神经元数(每层) | 说明 |
---|---|---|---|---|---|---|
小型数据集 | 1,000 - 10,000 | 2 - 3 | 32 - 64 | 1 - 2 | 128 - 256 | 例如MNIST等简单任务,可以用少量卷积层和全连接层。 |
中型数据集 | 10,000 - 100,000 | 3 - 5 | 64 - 128 | 2 - 3 | 256 - 512 | 例如CIFAR-10等任务,需要更多的卷积层来提取特征。 |
大型数据集 | 100,000 - 1,000,000 | 5 - 10 | 128 - 256 | 2 - 4 | 512 - 1024 | 例如CIFAR-100、ImageNet子集等任务,复杂特征需要更多的卷积层。 |
超大型数据集 | 1,000,000+ | 10+ | 256+ | 3 - 5 | 1024+ | 例如完整的ImageNet数据集或更大规模的任务,深度网络(如ResNet)通常是必要的。 |
import torch.nn as nn import torch.nn.functional as F class SmallCNN(nn.Module): def __init__(self): super(SmallCNN, self).__init__() self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, padding=1) self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1) self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0) self.fc1 = nn.Linear(64 * 7 * 7, 128) # 假设输入图像大小为28x28 self.fc2 = nn.Linear(128, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = x.view(-1, 64 * 7 * 7) x = F.relu(self.fc1(x)) x = self.fc2(x) return x
在这个示例中:
conv1
和 conv2
)fc1
和 fc2
)import torch.nn as nn import torch.nn.functional as F class MediumCNN(nn.Module): def __init__(self): super(MediumCNN, self).__init__() self.conv1 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, padding=1) self.conv2 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=1) self.conv3 = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, padding=1) self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0) self.fc1 = nn.Linear(256 * 4 * 4, 512) # 假设输入图像大小为32x32 self.fc2 = nn.Linear(512, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = self.pool(F.relu(self.conv3(x))) x = x.view(-1, 256 * 4 * 4) x = F.relu(self.fc1(x)) x = self.fc2(x) return x
在这个示例中:
conv1
, conv2
和 conv3
)fc1
和 fc2
)import torch.nn as nn import torch.nn.functional as F class LargeCNN(nn.Module): def __init__(self): super(LargeCNN, self).__init__() self.conv1 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, padding=1) self.conv2 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=1) self.conv3 = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, padding=1) self.conv4 = nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, padding=1) self.conv5 = nn.Conv2d(in_channels=512, out_channels=1024, kernel_size=3, padding=1) self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0) self.fc1 = nn.Linear(1024 * 1 * 1, 1024) # 假设输入图像大小为32x32 self.fc2 = nn.Linear(1024, 512) self.fc3 = nn.Linear(512, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = self.pool(F.relu(self.conv3(x))) x = self.pool(F.relu(self.conv4(x))) x = self.pool(F.relu(self.conv5(x))) x = x.view(-1, 1024 * 1 * 1) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x
在这个示例中:
conv1
, conv2
, conv3
, conv4
和 conv5
)fc1
, fc2
和 fc3
)对抗生成网络(GANs)
生成与判别网络相互竞争,提高生成图像质量。
目标检测(Object Detection)
检测图像中的多个对象并定位它们的边界框。
语义分割(Semantic Segmentation)
将图像中的每个像
素分类到特定类别。
项目介绍
MNIST数据集是一个经典的手写数字识别数据集,包含60,000个训练样本和10,000个测试样本。每个样本是28x28的灰度图像,表示从0到9的数字。
步骤
详细过程
import torch
import torchvision
import torchvision.transforms as transforms
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True)
testset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=False)
import torch.nn as nn import torch.nn.functional as F class SimpleCNN(nn.Module): def __init__(self): super(SimpleCNN, self).__init__() self.conv1 = nn.Conv2d(1, 32, 3, 1) self.conv2 = nn.Conv2d(32, 64, 3, 1) self.fc1 = nn.Linear(12 * 12 * 64, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = F.relu(self.conv1(x)) x = F.max_pool2d(self.conv2(x), 2) x = torch.flatten(x, 1) x = F.relu(self.fc1(x)) x = self.fc2(x) return F.log_softmax(x, dim=1)
import torch.optim as optim model = SimpleCNN() criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) for epoch in range(5): # 训练5个epoch model.train() running_loss = 0.0 for inputs, labels in trainloader: 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(trainloader):.3f}')
model.eval()
correct = 0
total = 0
with torch.no_grad():
for inputs, labels in testloader:
outputs = model(inputs)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy: {100 * correct / total:.2f}%')
项目介绍
CIFAR-10数据集包含60,000张32x32的彩色图像,分为10个类别。每个类别有6,000张图像。
步骤
详细过程
transform = transforms.Compose([
transforms.RandomHorizontalFlip(),
transforms.RandomCrop(32, padding=4),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True)
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=False)
class CIFAR10CNN(nn.Module): def __init__(self): super(ImprovedImageClassifier, self).__init__() self.conv1 = nn.Conv2d(3, 32, 3, stride=1, padding=1) self.bn1 = nn.BatchNorm2d(32) self.conv2 = nn.Conv2d(32, 64, 3, stride=1, padding=1) self.bn2 = nn.BatchNorm2d(64) self.pool = nn.MaxPool2d(2, 2) self.conv3 = nn.Conv2d(64, 128, 3, stride=1, padding=1) self.bn3 = nn.BatchNorm2d(128) self.dropout = nn.Dropout(0.1) # 加入Dropout层 self.fc1 = nn.Linear(128 * 4 * 4, 256) self.fc2 = nn.Linear(256, 128) self.out = nn.Linear(128, 10) def forward(self, x): x = self.pool(torch.relu(self.bn1(self.conv1(x)))) x = self.pool(torch.relu(self.bn2(self.conv2(x)))) x = self.pool(torch.relu(self.bn3(self.conv3(x)))) x = x.view(-1, 128 * 4 * 4) x = torch.relu(self.fc1(x)) x = self.dropout(x) x = torch.relu(self.fc2(x)) x = self.out(x) return x
model = CIFAR10CNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
for epoch in range(10): # 训练10个epoch
model.train()
running_loss = 0.0
for inputs, labels in trainloader:
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(trainloader):.3f}')
# 构建数据加载器 dataloader = DataLoader(valid_dataset, batch_size=BATCH_SIZE, shuffle=True) model.eval() # 计算精度和其他评估指标 y_true = [] y_pred = [] with torch.no_grad(): for x, y in dataloader: x = x.to(device) y = y.to(device) output = model(x) y_pred.extend(torch.argmax(output, dim=-1).cpu().numpy()) y_true.extend(y.cpu().numpy()) # 混淆矩阵和分类报告 conf_mat = confusion_matrix(y_true, y_pred) class_report = classification_report(y_true, y_pred, target_names=train_dataset.classes) # 打印分类报告 print("Classification Report:\n", class_report) # 绘制混淆矩阵 plt.figure(figsize=(10, 8)) sns.heatmap(conf_mat, annot=True, fmt='d', cmap='Blues', xticklabels=train_dataset.classes, yticklabels=train_dataset.classes) plt.xlabel('Predicted') plt.ylabel('True') plt.title('Confusion Matrix') plt.show()
项目介绍
ImageNet数据集包含超过100万张带标签的高分辨率图像,分为1000个类别。它是深度学习和计算机视觉领域的标准数据集。
步骤
详细过程
from torchvision import models
model = models.resnet18(pretrained=True)
# 冻结除最后一层外的所有层
for param in model.parameters():
param.requires_grad = False
# 替换最后一层
model.fc = nn.Linear(model.fc.in_features, 1000)
# 仅训练最后一层
optimizer = optim.Adam(model.fc.parameters(), lr=0.001)
for epoch in range(5): # 训练5个epoch
model.train()
running_loss = 0.0
for inputs, labels in trainloader:
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(trainloader):.3f}')
model.eval()
correct = 0
total = 0
with torch.no_grad():
for inputs, labels in testloader:
outputs = model(inputs)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy: {100 * correct / total:.2f}%')
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。