- import torch.nn as nn
- class Net(nn.Module):
- """
- 定义一个简单点的神经网络,卷积,池化,激活,全连接 嗯.....够简单了!
- 输入的话就64*64的图片吧,通道数为3,卷积核为2,padding为1吧,这样的话就是
- : (3, 64, 64)
- 卷积核为2,padding为1,输出通道数为64,这样的话就是
- : (64, 64, 64)
- 池化核为2,输出通道数为64,这样的话就是
- : (64, 32, 32)
- 全连接层的话就32*32*64=65536个神经元,输出10个类别的概率
- """
- def __init__(self):
- super(Net, self).__init__()
- self.conv1 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=2, padding=1)
- self.pool = nn.MaxPool2d(kernel_size=2)
- self.relu = nn.ReLU()
- self.fc = nn.Linear(in_features=64*32*32, out_features=10)
- self.dropout = nn.Dropout(0.5) # 随机失活,防止过拟合
- # 接下来的话就是定义前向传播了!
- def forward(self, x):
- x = self.conv1(x)
- x = self.pool(x)
- x = self.relu(x)
- x = x.view(-1, 64*32*32) # 这里的-1就是让Pytorch自动计算这个维度的值
- x = self.fc(x)
- x = self.dropout(x)
- return x
- """
- 这里就是定义了前向传播,这里就是将输入的图片进行卷积,然后进行池化,然后进行激活,然后进行全连接,然后返回结果
- """
- # 实例化模型,看看效果吧
- net = Net()
- print(net)
- import torch
- # 创建一个简单的64*64的图片张量
- array = torch.rand(64, 3, 64, 64)
- # 创建目标标签(假设是10分类问题)
- target = torch.randint(0, 10, (64,))
- # 超参数定义
- echo = 100
- lr = 0.001
- optimizer = torch.optim.SGD(net.parameters(), lr=lr) # 优化器
- """
- 简单的训练过程实现
- :
- """
- for i in range(echo):
- # 设置模型为训练模式
- net.train()
- output = net(array)
- # 定义损失函数
- criterion = nn.CrossEntropyLoss() # 损失函数
- loss = criterion(output, target) # 计算损失
- optimizer.zero_grad() # 梯度清零
- loss.backward() # 反向传播
- optimizer.step() # 更新参数
- # 反向传播
- print(f"第{i+1}轮训练,损失值: {loss.item():.4f}")
- print("反向传播完成,梯度已计算")
- # 保存模型
- torch.save(net.state_dict(), 'model.pth')
- # 测试
- net.eval()
- # 加载模型
- model = Net()
- model.load_state_dict(torch.load('model.pth'))
- model.eval()
- # 测试数据
- test_array = torch.rand(1, 3, 64, 64)
- with torch.no_grad():
- output = model(test_array)
- print(output)
- print(f"当前模型预测的类别是: {torch.argmax(output, dim=1).item()}")
- # import torchvision.transforms as transforms
- # import torchvision.datasets as datasets
- # train_dataset = datasets.ImageFolder(root='./data/train', transform=transforms.ToTensor())
- # train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
- # test_dataset = datasets.ImageFolder(root='./data/test', transform=transforms.ToTensor())
- # test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False)
- # print(len(train_dataset))
- # print(len(test_dataset))
- # print(train_dataset.class_to_idx)
- # import matplotlib.pyplot as plt
- # plt.imshow(train_dataset[0][0].numpy().transpose(1, 2, 0))
- # plt.title(train_dataset.classes[train_dataset[0][1]])
- # plt.show()
复制代码 核心组件详解
1. 卷积层 (nn.Conv2d)
- 作用: 提取图像特征
- 参数:
- in_channels=3: 输入通道数(RGB)
- out_channels=64: 输出特征图数量
- kernel_size=2: 卷积核大小
- padding=1: 边缘填充,保持尺寸
2. 池化层 (nn.MaxPool2d)
- 作用: 降维、防止过拟合
- 参数: kernel_size=2: 2×2最大池化
3. 激活函数 (nn.ReLU)
4. 全连接层 (nn.Linear)
- 作用: 分类决策
- 参数:
- in_features=65536: 展平后的特征数量
- out_features=10: 输出类别数
训练流程
基本设置
- # 模型实例化
- net = Net()
- # 优化器
- optimizer = torch.optim.SGD(net.parameters(), lr=0.001)
- # 损失函数
- criterion = nn.CrossEntropyLoss()
复制代码 训练循环
- for epoch in range(100):
- # 前向传播
- output = net(input_tensor)
-
- # 计算损失
- loss = criterion(output, target)
-
- # 反向传播三部曲
- optimizer.zero_grad() # 梯度清零
- loss.backward() # 反向传播
- optimizer.step() # 参数更新
-
- print(f"第{epoch+1}轮训练,损失值: {loss.item():.4f}")
复制代码 关键要点
1. 反向传播原理
- 梯度清零: 防止梯度累积
- loss.backward(): 自动计算所有参数的梯度
- optimizer.step(): 根据梯度更新参数
2. 尺寸匹配规则
- 卷积输出尺寸: (输入尺寸 + 2×padding - kernel_size) / stride + 1
- 池化输出尺寸: 输入尺寸 / kernel_size
- 全连接层输入必须展平为一维
3. 常见问题解决
- RuntimeError: grad can be implicitly created only for scalar outputs
- 原因: backward()只能对标量求导
- 解决: 使用损失函数(loss)而不是原始输出
快速构建模板
基础模板
- import torch
- import torch.nn as nn
- class SimpleCNN(nn.Module):
- def __init__(self, input_channels, num_classes):
- super(SimpleCNN, self).__init__()
- self.conv1 = nn.Conv2d(input_channels, 64, 3, padding=1)
- self.pool = nn.MaxPool2d(2)
- self.relu = nn.ReLU()
- self.fc = nn.Linear(64*32*32, num_classes) # 根据实际尺寸调整
-
- def forward(self, x):
- x = self.conv1(x)
- x = self.pool(x)
- x = self.relu(x)
- x = x.view(x.size(0), -1) # 自动展平
- x = self.fc(x)
- return x
- # 使用示例
- model = SimpleCNN(3, 10)
- optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
- criterion = nn.CrossEntropyLoss()
复制代码 数据加载模板
- from torchvision import datasets, transforms
- # 数据预处理
- transform = transforms.Compose([
- transforms.Resize((64, 64)),
- transforms.ToTensor(),
- ])
- # 数据集加载
- train_dataset = datasets.ImageFolder('./data/train', transform=transform)
- train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
复制代码 进阶功能
1. 模型保存与加载
- # 保存模型
- torch.save(model.state_dict(), 'model.pth')
- # 加载模型
- model = SimpleCNN(3, 10)
- model.load_state_dict(torch.load('model.pth'))
复制代码 2. 训练验证分离
- def train(model, dataloader, criterion, optimizer):
- model.train()
- for batch_idx, (data, target) in enumerate(dataloader):
- optimizer.zero_grad()
- output = model(data)
- loss = criterion(output, target)
- loss.backward()
- optimizer.step()
- def validate(model, dataloader, criterion):
- model.eval()
- total_loss = 0
- with torch.no_grad():
- for data, target in dataloader:
- output = model(data)
- total_loss += criterion(output, target).item()
- return total_loss / len(dataloader)
复制代码 实用技巧
- 学习率调整: 使用torch.optim.lr_scheduler
- 早停机制: 监控验证集损失
- 数据增强: 使用torchvision.transforms
- GPU加速: 使用.to('cuda')迁移到GPU
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |