吴恩达深度学习课程第四章第一周编程作业(pytorch实现)

该博客分享了作者如何使用PyTorch复现TensorFlow课程中的卷积神经网络模型,用于手写数字识别,包括数据预处理、模型构建(含卷积层、池化层及全连接层)、主控函数的实现,并展示了训练和测试过程及结果。
摘要由CSDN通过智能技术生成


声明

  本博客只是记录一下本人在深度学习过程中的学习笔记和编程经验,大部分代码是参考了【中文】【吴恩达课后编程作业】Course 4 - 卷积神经网络 - 第一周作业这篇博客,对其代码实现了复现,但是原博客中代码使用的是tensorflow,而我在学习生活中主要用到的是pytorch,所以此次作业我使用pytorch框架来完成。代码或文字表述中还存在一些问题,请见谅,之前的博客也是主要参考这个大佬。下文中的完整代码已经上传到百度网盘中,提取码:iw7j。
  所以开始作业前,请大家安装好pytorch的环境,我代码是在服务器上利用gpu加速运行的,但是cpu版本的pytorch也能运行,只是速度会比较慢。

一、问题描述

  【中文】【吴恩达课后编程作业】Course 4 - 卷积神经网络 - 第一周作业 里面讲述了用numpy实现padding和pooling的操作,我并未将这部分代码进行复现,本文的重点在于用pytorch复现原文中的tensorflow代码。
  此次作业需要处理的任务在之前的任务中出现过:完成一个多分类器,识别图像中手势代表的数字:
在这里插入图片描述
  与之前的作业不同的是,需要在神经网络中加入卷积层和池化层,神经网络的大致结构为:

CONV2D→RELU→MAXPOOL→CONV2D→RELU→MAXPOOL→FULLCONNECTED

二、模型搭建

1.封装dataloader

  pytorch提供的Dataloader和Dataset包可以很好的帮助我们加载数据,划分batch:

class Digit_data(Dataset):
    def __init__(self, data_path):
        super(Digit_data, self).__init__()
        dataset = h5py.File(data_path, "r")
        if data_path == "datasets/train_signs.h5":
            dataset_set_x_orig = np.array(dataset["train_set_x"][:])  # your train set features
            dataset_set_y_orig = np.array(dataset["train_set_y"][:])  # your train set labels
        else:
            dataset_set_x_orig = np.array(dataset["test_set_x"][:])  # your train set features
            dataset_set_y_orig = np.array(dataset["test_set_y"][:])  # your train set labels

        dataset_set_x_orig = dataset_set_x_orig.astype("float32") / 255
        dataset_set_y_orig = dataset_set_y_orig.astype("float32")

        self.x_data = torch.from_numpy(dataset_set_x_orig)
        self.y_data = torch.from_numpy(dataset_set_y_orig)

        self.len = self.y_data.size()[0]

    def __getitem__(self, index):
        return self.x_data[index], self.y_data[index]

    def __len__(self):
        return self.len

  因为训练集数据文件和测试集数据文件的数据结构不太一致,需要通过文件路径判断是训练集还是测试集,然后抽取数据集和标签集。

2.模型封装

import torch
class CNN_digit(torch.nn.Module):
    def __init__(self):
        super(CNN_digit, self).__init__()
        self.conv2d1 = torch.nn.Conv2d(in_channels=3, out_channels=8, stride=1, padding=1, kernel_size=4)
        self.relu1 = torch.nn.ReLU()
        self.maxpool1 = torch.nn.MaxPool2d(kernel_size=8, stride=8, padding=1)

        self.conv2d2 = torch.nn.Conv2d(in_channels=8, out_channels=16, stride=1, padding=0, kernel_size=2)
        self.relu2 = torch.nn.ReLU()
        self.maxpool2 = torch.nn.MaxPool2d(kernel_size=4, stride=4)

        self.fc = torch.nn.Linear(16, 6)
        self.softmax = torch.nn.Softmax(dim=1)

    def forward(self, x):
        conv2d1 = self.conv2d1(x)
        relu1 = self.relu1(conv2d1)
        maxpool1 = self.maxpool1(relu1)

        conv2d2 = self.conv2d2(maxpool1)
        relu2 = self.relu2(conv2d2)
        maxpool2 = self.maxpool2(relu2)

        batch_size = maxpool2.size()[0]
        maxpool2 = maxpool2.view(batch_size, -1)

        fc = self.fc(maxpool2)

        return fc

    def test(self, x):
        y_pred = self.forward(x)
        y_predict = self.softmax(y_pred)
        return y_predict

  将整个神经网络结构封装成类 CNN_digit ,包含两个卷积层和一个全连接层,卷积层的操作包括:卷积,非线性激活和最大池化。
  前向传播函数 forward 中,依次计算各层的输出,需要注意的是第二层卷积层的输出送到全连接层之前需要进行维度变化,将单个样本转换成一维向量。另外,前向传播时不需要经过softmax层,因为损失函数包含softmax的功能。
  test 函数的作用是进行预测,因此再调用forward后,需要再经过softmax层的处理。

3.主控函数

  训练一个神经网络模型我个人习惯喜欢划分为以下步骤:

1.定义需要的参数:epoch,学习率。minibatch_size等。
2.用Dataloader加载训练数据。
3.初始化模型,初始化损失函数,定义优化器。
4.开始训练。

  定义需要的参数,用Dataloader加载训练数据:

# 定义一些需要使用到的参数
    num_epoch = 200
    learning_rate = 0.00095
    minibatch_size = 32
    costs = []

    # 加载训练数据
    train_data = Digit_data(train_data_path)
    train_data_loader = DataLoader(train_data, shuffle=True, batch_size=minibatch_size)

  初始化模型,定义损失函数,定义优化器:

 # 初始化模型,初始化损失函数,定义优化器
    m = CNN_digit()
    m.to(device)  # 使用GPU加速

    loss_fn = torch.nn.CrossEntropyLoss()  # 使用交叉熵损失

    optimizer = torch.optim.Adam(m.parameters(), lr=learning_rate)  # 使用Adam优化算法

  开始训练:

  for epoch in range(num_epoch):
        cost = 0
        for i, data in enumerate(train_data_loader):
            img_data, img_label = data
            img_data = img_data.permute(0, 3, 1, 2)  # 将维度从(32,64,64,3)转换为(32,3,64,64)
            img_data = img_data.to(device)
            img_label = img_label.to(device)

            optimizer.zero_grad()

            y_pred = m.forward(img_data)

            loss = loss_fn(y_pred, img_label.long())

            loss.backward()

            optimizer.step()

            cost = cost + loss.cpu().detach().numpy()
        costs.append(cost / (i + 1))
        if epoch % 5 == 0:
            print("epoch=" + str(epoch) + ":  " + "loss=" + str(cost / (i + 1)))

  在测试集和验证集上计算准确率:

 # 计算准确率
    test_data = Digit_data(test_data_path)
    test_data_loader = DataLoader(test_data, shuffle=True, batch_size=minibatch_size)

    acc_train = 0
    acc_test = 0
    correct_train = torch.zeros(1).squeeze().cuda()
    total_train = torch.zeros(1).squeeze().cuda()
    for i, data in enumerate(train_data_loader):
        img_data, img_label = data
        img_data = img_data.permute(0, 3, 1, 2)

        img_data = img_data.to(device)
        img_label = img_label.to(device)

        pred = m.test(img_data)

        prediciton = torch.argmax(pred, dim=1)

        correct_train += (prediciton == img_label).sum().float()
        total_train += len(img_label)

    acc_train = (correct_train / total_train).cpu().detach().data.numpy()

    print("训练集上准确率为:"+str(acc_train))

    correct_test = torch.zeros(1).squeeze().cuda()
    total_test = torch.zeros(1).squeeze().cuda()
    for j, data in enumerate(test_data_loader):
        img_data, img_label = data
        img_data = img_data.permute(0, 3, 1, 2)

        img_data = img_data.to(device)
        img_label = img_label.to(device)

        pred = m.test(img_data)

        prediciton = torch.argmax(pred, dim=1)

        correct_test += (prediciton == img_label).sum().float()
        total_test += len(img_label)

    acc_test = (correct_test / total_test).cpu().detach().data.numpy()
    print("测试集上准确率为:" + str(acc_test))

三、模型测试结果

在这里插入图片描述
在这里插入图片描述
  增加epoch至1500:
在这里插入图片描述
在这里插入图片描述

  我们知道padding的模式有两种 validsame ,但是pytorch仅支持步长为1时模式的选择(tensorflow支持),所以在代码中只是将padding的层数设置为1,没用使用 same 的填充方式。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值