当你在社交媒体上看到一只傲娇的猫或一只憨态可掬的狗时,你会不会好奇:计算机是怎样识别这些萌宠的呢?在深度学习的世界里,主要有两大模型来完成这一任务:深度神经网络(DNN)和卷积神经网络(CNN)。但事实证明,面对图像数据,这两位选手的表现可大相径庭!
自己学习了几天后,我将通过生动的理论讲解和实战代码演示,让你看到 DNN 在处理图片时的各种“囧态”,以及 CNN 如何迎难而上,完美解决问题。
深度神经网络(DNN)的基本思路非常简单:
想象一下,你拿到一张可爱的猫咪照片,它的尺寸是 150x150 像素,每个像素有 3 个颜色通道。整个图片就有 150×150×3 = 67,500 个数据!DNN 要把这 67,500 个数据当成一长条“特征向量”,然后每个神经元都“盯”这整条数据看。这就好比让你记住一本小说中的每一个字,然后回答:“这本小说讲的是猫还是狗?”很明显,这种方法既累赘又不靠谱!
以一张猫咪图片来做形象化讲解:
总的来说,DNN 就像一个只会死记硬背的学生,面对复杂多变的图像信息,显得力不从心,内存消耗大,泛化能力弱。
与 DNN 大相径庭的是,卷积神经网络(CNN)专门为图像识别设计。它主要包含以下几个关键部分:
让我们具体看看 CNN 是如何应对前面 DNN 遇到的各种问题:
CNN 就像一个有经验的侦探,能通过局部细节中找出蛛丝马迹,然后组合成完整的“证据链”,最终精确判断图片中到底是猫还是狗!
在前面详细介绍了理论部分后,下面我们通过实际的 PyTorch 代码来对比 DNN 和 CNN 在猫狗分类任务中的表现。我们将依次介绍两种模型的实现、训练过程以及网络结构的可视化。
首先,我们需要加载猫狗分类数据集,并对图像进行预处理。假设数据集已经按目录结构分为训练集和测试集。
import torch
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
# 定义图像预处理:调整大小、转换为 Tensor、归一化
transform = transforms.Compose([
transforms.Resize((150, 150)), # 调整图像为 150x150
transforms.ToTensor(), # 转换为 Tensor
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])
# 加载数据集
train_data = datasets.ImageFolder(root='data/train', transform=transform)
test_data = datasets.ImageFolder(root='data/test', transform=transform)
train_loader = DataLoader(train_data, batch_size=32, shuffle=True)
test_loader = DataLoader(test_data, batch_size=32, shuffle=False)
import torch.nn as nn
import torch.optim as optim
class DNN(nn.Module):
def __init__(self):
super(DNN, self).__init__()
self.fc1 = nn.Linear(150*150*3, 512) # 第一层,全连接层
self.fc2 = nn.Linear(512, 512) # 第二层,全连接层
self.fc3 = nn.Linear(512, 1) # 输出层
def forward(self, x):
# 将输入图像展平成一维向量
x = x.view(-1, 150*150*3)
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = torch.sigmoid(self.fc3(x))
return x
model_dnn = DNN()
由于 DNN 需要处理所有像素之间的关系,因此参数数量非常庞大,不仅内存消耗高,而且训练过程也相对较慢。我就不尝试了,内存大的小伙伴可以试一下。
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
# 第一卷积层:输入通道 3,输出通道 32,使用 3x3 卷积核,边缘填充1
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
# 第二卷积层:输入 32,输出 64
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
# 池化层:2x2 最大池化
self.pool = nn.MaxPool2d(2, 2)
# 全连接层:假设经过两次池化后,图像尺寸变为 37x37(150/2/2 ≈ 37)
self.fc1 = nn.Linear(64 * 37 * 37, 512)
self.fc2 = nn.Linear(512, 1)
def forward(self, x):
x = self.pool(torch.relu(self.conv1(x))) # 卷积 + 激活 + 池化
x = self.pool(torch.relu(self.conv2(x))) # 卷积 + 激活 + 池化
x = x.view(-1, 64 * 37 * 37) # 展平
x = torch.relu(self.fc1(x))
x = torch.sigmoid(self.fc2(x))
return x
model_cnn = CNN()
相比 DNN,CNN 通过局部感知和权重共享,显著减少了参数数量和计算量,还能更好地捕捉图像中的空间结构信息。
我们为两个模型分别定义训练函数:
def train_model(model, train_loader, criterion, optimizer, epochs=5):
model.train()
for epoch in range(epochs):
running_loss = 0.0
correct = 0
total = 0
for inputs, labels in train_loader:
optimizer.zero_grad()
outputs = model(inputs)
labels = labels.unsqueeze(1).float() # 转换标签格式为浮点型
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
predicted = (outputs > 0.5).float()
correct += (predicted == labels).sum().item()
total += labels.size(0)
print(f"Epoch [{epoch+1}/{epochs}], Loss: {running_loss/len(train_loader):.4f}, Accuracy: {correct/total:.4f}")
# 定义损失函数和优化器(分别对两个模型)
criterion = nn.BCELoss()
optimizer_dnn = optim.Adam(model_dnn.parameters(), lr=0.001)
optimizer_cnn = optim.Adam(model_cnn.parameters(), lr=0.001)
训练 DNN 模型:
print("Training DNN Model:")
train_model(model_dnn, train_loader, criterion, optimizer_dnn, epochs=5)
训练 CNN 模型:
print("Training CNN Model:")
train_model(model_cnn, train_loader, criterion, optimizer_cnn, epochs=5)
如果你成功训练了两个模型,你会发现:
通过本文的详细讲解与代码演示,希望你能深刻理解 DNN 与 CNN 在处理图像(如猫狗分类)时的本质区别。对于计算机视觉任务,CNN 无疑是更聪明、更高效的选择。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。