24.8.11学习笔记

import torch
from torch import nn
from net import MyAlexNet
import numpy as np
from torch.optim import lr_scheduler
import os

from torchvision import transforms
from torchvision.datasets import ImageFolder
from torch.utils.data import DataLoader

import matplotlib.pyplot as plt

# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 定义训练数据的根目录路径
ROOT_TRAIN = r'C:/Users/kk/PycharmProjects/pythonProject2/dataset/train/catdog1/data/train'
# 定义测试数据的根目录路径
ROOT_TEST = r'C:/Users/kk/PycharmProjects/pythonProject2/dataset/train/catdog1/data/val'

# 将图像的像素值归一化到【-1, 1】之间
normalize = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])

# 定义训练数据的转换操作
train_transform = transforms.Compose([
    transforms.Resize((224, 224)),  # 将图像大小调整为 224x224
    transforms.RandomVerticalFlip(),  # 随机垂直翻转图像,增加数据多样性
    transforms.ToTensor(),  # 将图像转换为张量
    normalize  # 应用像素值归一化
])

# 定义验证数据的转换操作
val_transform = transforms.Compose([
    transforms.Resize((224, 224)),  # 将图像大小调整为 224x224
    transforms.ToTensor(),  # 将图像转换为张量
    normalize  # 应用像素值归一化
])

# 使用指定的根目录和转换操作创建训练数据集对象
train_dataset = ImageFolder(ROOT_TRAIN, transform=train_transform)
# 使用指定的根目录和转换操作创建验证数据集对象
val_dataset = ImageFolder(ROOT_TEST, transform=val_transform)

# 为训练数据集创建数据加载器,批量大小为 32,打乱数据顺序
train_dataloader = DataLoader(train_dataset, batch_size=32, shuffle=True)
# 为验证数据集创建数据加载器,批量大小为 32,打乱数据顺序
val_dataloader = DataLoader(val_dataset, batch_size=32, shuffle=True)

# 自动选择计算设备,如果有 CUDA 可用则使用 CUDA,否则使用 CPU
device = 'cuda' if torch.cuda.is_available() else 'cpu'

# 创建自定义的 MyAlexNet 模型,并将其移动到指定设备
model = MyAlexNet().to(device)

# 定义交叉熵损失函数
loss_fn = nn.CrossEntropyLoss()

# 使用随机梯度下降优化器来优化模型的参数,学习率为 0.01,动量为 0.9
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# 学习率每隔 10 轮变为原来的 0.5
lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5)

# 定义训练函数
def train(dataloader, model, loss_fn, optimizer):
    # 初始化损失、准确率累加器和样本数量
    loss, current, n = 0.0, 0.0, 0
    # 遍历数据加载器中的批次
    for batch, (x, y) in enumerate(dataloader):
        # 将图像和标签移动到指定设备
        image, y = x.to(device), y.to(device)
        # 模型进行前向传播得到输出
        output = model(image)
        # 计算当前批次的损失
        cur_loss = loss_fn(output, y)
        # 获取输出中的最大值索引作为预测结果
        _, pred = torch.max(output, axis=1)
        # 计算当前批次的准确率
        cur_acc = torch.sum(y == pred) / output.shape[0]

        # 反向传播前梯度清零
        optimizer.zero_grad()
        # 计算梯度
        cur_loss.backward()
        # 更新模型参数
        optimizer.step()
        # 累加损失和准确率
        loss += cur_loss.item()
        current += cur_acc.item()
        n = n + 1

    # 计算平均损失和准确率
    train_loss = loss / n
    train_acc = current / n
    # 打印训练损失和准确率
    print('train_loss' + str(train_loss))
    print('train_acc' + str(train_acc))
    # 返回训练损失和准确率
    return train_loss, train_acc

# 定义验证函数
def val(dataloader, model, loss_fn):
    # 将模型切换到评估模式
    model.eval()
    # 初始化损失、准确率累加器和样本数量
    loss, current, n = 0.0, 0.0, 0
    # 在不计算梯度的情况下进行计算
    with torch.no_grad():
        # 遍历数据加载器中的批次
        for batch, (x, y) in enumerate(dataloader):
            # 将图像和标签移动到指定设备
            image, y = x.to(device), y.to(device)
            # 模型进行前向传播得到输出
            output = model(image)
            # 计算当前批次的损失
            cur_loss = loss_fn(output, y)
            # 获取输出中的最大值索引作为预测结果
            _, pred = torch.max(output, axis=1)
            # 计算当前批次的准确率
            cur_acc = torch.sum(y == pred) / output.shape[0]
            # 累加损失和准确率
            loss += cur_loss.item()
            current += cur_acc.item()
            n = n + 1

    # 计算平均损失和准确率
    val_loss = loss / n
    val_acc = current / n
    # 打印验证损失和准确率
    print('val_loss' + str(val_loss))
    print('val_acc' + str(val_acc))
    # 返回验证损失和准确率
    return val_loss, val_acc

# 定义绘制损失曲线的函数
def matplot_loss(train_loss, val_loss):
    plt.plot(train_loss, label='train_loss')  # 绘制训练集损失曲线
    plt.plot(val_loss, label='val_loss')  # 绘制验证集损失曲线
    plt.legend(loc='best')  # 显示图例,位置为最佳
    plt.ylabel('loss')  # 设置 y 轴标签为'loss'
    plt.xlabel('epoch')  # 设置 x 轴标签为'epoch'
    plt.title("训练集和验证集loss值对比图")  # 设置标题
    plt.show()  # 显示图像

# 定义绘制准确率曲线的函数
def matplot_acc(train_acc, val_acc):
    plt.plot(train_acc, label='train_acc')  # 绘制训练集准确率曲线
    plt.plot(val_acc, label='val_acc')  # 绘制验证集准确率曲线
    plt.legend(loc='best')  # 显示图例,位置为最佳
    plt.ylabel('acc')  # 设置 y 轴标签为'acc'
    plt.xlabel('epoch')  # 设置 x 轴标签为'epoch'
    plt.title("训练集和验证集acc值对比图")  # 设置标题
    plt.show()  # 显示图像

# 初始化用于存储训练和验证过程中的损失和准确率的列表
loss_train = []
acc_train = []
loss_val = []
acc_val = []

# 定义训练轮数
epoch = 20
min_acc = 0

# 进行训练
for t in range(epoch):
    lr_scheduler.step()  # 调整学习率
    print(f"epoch{t + 1}\n-----------")  # 打印当前轮数
    # 进行训练并获取训练损失和准确率
    train_loss, train_acc = train(train_dataloader, model, loss_fn, optimizer)
    # 进行验证并获取验证损失和准确率
    val_loss, val_acc = val(val_dataloader, model, loss_fn)

    # 将损失和准确率添加到相应的列表中
    loss_train.append(train_loss)
    acc_train.append(train_acc)
    loss_val.append(val_loss)
    acc_val.append(val_acc)

    # 如果当前验证准确率高于之前的最高准确率,保存模型权重
    if val_acc > min_acc:
        folder = 'save_model'
        if not os.path.exists(folder):
            os.mkdir('save_model')
        min_acc = val_acc
        print(f"save best model, 第{t + 1}轮")
        torch.save(model.state_dict(), 'save_model/best_model.pth')
    # 如果是最后一轮,保存模型权重
    if t == epoch - 1:
        torch.save(model.state_dict(), 'save_model/last_model.pth')

# 绘制损失曲线
matplot_loss(loss_train, loss_val)
# 绘制准确率曲线
matplot_acc(acc_train, acc_val)
print('Done!')  # 打印训练完成的提示
import torch
from torch import nn
import torch.nn.functional as F

# 定义一个继承自nn.Module的类MyAlexNet
class MyAlexNet(nn.Module):
    def __init__(self):
        # 调用父类nn.Module的构造函数
        super(MyAlexNet, self).__init__()
        # 定义第一个卷积层,输入通道数为3,输出通道数为48,卷积核大小为11x11,步长为4,填充为2
        self.c1 = nn.Conv2d(in_channels=3, out_channels=48, kernel_size=11, stride=4, padding=2)
        # 定义ReLU激活函数
        self.ReLU = nn.ReLU()
        # 定义第二个卷积层,输入通道数为48,输出通道数为128,卷积核大小为5x5,步长为1,填充为2
        self.c2 = nn.Conv2d(in_channels=48, out_channels=128, kernel_size=5, stride=1, padding=2)
        # 定义最大池化层,池化窗口大小为2x2
        self.s2 = nn.MaxPool2d(2)
        # 定义第三个卷积层,输入通道数为128,输出通道数为192,卷积核大小为3x3,步长为1,填充为1
        self.c3 = nn.Conv2d(in_channels=128, out_channels=192, kernel_size=3, stride=1, padding=1)
        # 定义最大池化层,池化窗口大小为2x2
        self.s3 = nn.MaxPool2d(2)
        # 定义第四个卷积层,输入通道数为192,输出通道数为192,卷积核大小为3x3,步长为1,填充为1
        self.c4 = nn.Conv2d(in_channels=192, out_channels=192, kernel_size=3, stride=1, padding=1)
        # 定义第五个卷积层,输入通道数为192,输出通道数为128,卷积核大小为3x3,步长为1,填充为1
        self.c5 = nn.Conv2d(in_channels=192, out_channels=128, kernel_size=3, stride=1, padding=1)
        # 定义最大池化层,池化窗口大小为3x3,步长为2
        self.s5 = nn.MaxPool2d(kernel_size=3, stride=2)
        # 定义Flatten层,用于将多维张量展平成一维张量
        self.flatten = nn.Flatten()
        # 定义第一个全连接层,输入维度为4608,输出维度为2048
        self.f6 = nn.Linear(4608, 2048)
        # 定义第二个全连接层,输入维度为2048,输出维度为2048
        self.f7 = nn.Linear(2048, 2048)
        # 定义第三个全连接层,输入维度为2048,输出维度为1000
        self.f8 = nn.Linear(2048, 1000)
        # 定义第四个全连接层,输入维度为1000,输出维度为2
        self.f9 = nn.Linear(1000, 2)

    def forward(self, x):
        # 通过第一个卷积层,然后应用ReLU激活函数
        x = self.ReLU(self.c1(x))
        # 通过第二个卷积层,然后应用ReLU激活函数
        x = self.ReLU(self.c2(x))
        # 通过最大池化层s2
        x = self.s2(x)
        # 通过第三个卷积层,然后应用ReLU激活函数
        x = self.ReLU(self.c3(x))
        # 通过最大池化层s3
        x = self.s3(x)
        # 通过第四个卷积层,然后应用ReLU激活函数
        x = self.ReLU(self.c4(x))
        # 通过第五个卷积层,然后应用ReLU激活函数
        x = self.ReLU(self.c5(x))
        # 通过最大池化层s5
        x = self.s5(x)
        # 将特征图展平成一维张量
        x = self.flatten(x)
        # 通过第一个全连接层f6,然后应用Dropout(概率为0.5)
        x = self.f6(x)
        x = F.dropout(x, p=0.5)
        # 通过第二个全连接层f7,然后应用Dropout(概率为0.5)
        x = self.f7(x)
        x = F.dropout(x, p=0.5)
        # 通过第三个全连接层f8,然后应用Dropout(概率为0.5)
        x = self.f8(x)
        x = F.dropout(x, p=0.5)
        # 通过第四个全连接层f9
        x = self.f9(x)
        # 返回最终输出
        return x

# 主函数入口
if __name__ == '__main__':
    # 创建一个随机输入张量,形状为(1, 3, 224, 224),其中1表示批次大小,3表示输入通道数,224x224是图像尺寸
    x = torch.rand([1, 3, 224, 224])
    # 实例化MyAlexNet模型
    model = MyAlexNet()
    # 将随机输入通过模型
    y = model(x)
    # 输出模型的输出y,这通常是不需要的,这里只是为了测试
    print(y)

TensorBoard 是 TensorFlow 提供的一个可视化工具,用于帮助理解、调试和优化深度学习模型的训练过程。

以下是 TensorBoard 的一些关键特点和用途:

  1. 监控训练指标:可以实时跟踪和展示训练过程中的各种指标,如损失值、准确率等。这使得能够直观地观察模型在训练过程中的性能变化。

    • 例如,可以清晰地看到随着训练轮数的增加,损失值是如何逐渐下降,准确率是如何逐步上升的。
  2. 可视化模型结构:帮助理解模型的架构,包括各层的类型、连接方式和参数数量。

    • 对于复杂的模型,这有助于确认模型的构建是否符合预期。
  3. 数据分布可视化:查看输入数据、权重等的分布情况,以便检测数据是否存在异常或不均衡。

  4. 图像和音频数据:如果模型处理图像或音频数据,可以直接在 TensorBoard 中展示这些数据。

  5. 嵌入向量可视化:对于生成嵌入向量的模型(如词嵌入),可以直观地观察向量的分布和关系。

  6. 直方图和分布图:展示参数(如权重、偏置)的直方图和分布变化,有助于分析模型的学习情况和是否存在梯度消失或爆炸等问题。

  7. 多运行比较:能够同时比较多个训练运行的结果,方便选择最优的超参数和模型结构。

使用 TensorBoard 通常需要在训练代码中添加适当的记录语句,将需要监控的数据写入特定的日志目录,然后通过命令行启动 TensorBoard 服务来查看可视化结果。

总的来说,TensorBoard 极大地增强了对深度学习模型训练过程的洞察力,有助于更高效地开发和优化模型。

明天开始 系统的听一下b站pytorch的教学,不管自己学过没,就当复习了

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值