PyTorch 基本图像分类器

  • 入门深度学习,手里刚刚有点算力,就想训练一下自己的数据。

  • 从最基本的工作开始做起:

  • 本文采用了最朴素的卷积+全链接的形式训练一个三类分类器,并进行可视化

  • 直接分享出代码

"""
# 分类任务
# 导入自己的数据 进行训练和测试

0 胶带
1 芦荟胶
2 魔方
"""

import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt
import os
import collections  # 序列化列表

os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

"""
整体结构:
1.加载数据
2.定义网络结构
3.训练网络参数
4.用测试集测试
"""

# 对类别进行对应编号
class_list = [
    "tape",
    'makeup',
    'cude',
    'background']


# 有序化
class_list = {x:class_list[x] for  x in range(4)}

print('class_list: ', class_list)

print(type(class_list))

""" 
数据变换
"""
transform = transforms.Compose([
    transforms.Resize((28, 28)),
    transforms.ToTensor()])

"""
加载数据
"""
batch_size_train = 20
batch_size_test = 20

data_root = os.path.abspath("../../../00.Dataset/my_data")  # get data root path

print(data_root)

# 对于单纯的分类任务,使用ImageFolder简化数据加载
mnist_data_train = torchvision.datasets.ImageFolder(data_root, transform=transform)

train_loader = torch.utils.data.DataLoader(mnist_data_train,
                                           batch_size_train, shuffle=True, num_workers=4)

mnist_data_test = torchvision.datasets.ImageFolder(data_root, transform=transform)

test_loader = torch.utils.data.DataLoader(mnist_data_test,
                                          batch_size_test, shuffle=True, num_workers=4)



# 搭建网络
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # 重定义函数
        self.conv1 = nn.Conv2d(3, 7, 5, 1)  # kernel_1 in-1  out-6  kernel_size=5x5  ->24x24
        self.bn1 = nn.BatchNorm2d(7)  # 输入通道数
        self.conv2 = nn.Conv2d(7, 20, 5, 1)
        self.pool = nn.MaxPool2d(2, 2)  # max pooling
        self.liner1 = nn.Linear(4 * 4 * 20, 20)  # 需要计算才能知道
        self.liner2 = nn.Linear(20, 4)  # in_features, out_features, bias=True

    # 自动被调用
    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))  # Conv -> Relu -> Pool  -> 12x12 @ 6 CHs
        self.bn1(x)
        x = self.pool(F.relu(self.conv2(x)))  # -> 8x8 @6 ->  4x4 @ 20 CHs
        # print("x_sizer: ", x.shape)

        x = x.view(-1, 4 * 4 * 20)
        x = F.relu(self.liner1(x))
        x = self.liner2(x)

        # return x.log_softmax(x, dim=1)
        return x


net = Net().cuda()

"""
损失函数
优化器
"""

import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

"""
训练集训练
"""


def train():
    for epoch in range(500):  # 遍历两次
        running_loss = 0
        for i, data in enumerate(train_loader):  # 遍历一遍全部的数据集
            inputs, labels = data  # batch_size个样本
            optimizer.zero_grad()

            # 前向传播
            output = net(inputs.cuda())

            # print("out : ", output)
            # print("labels : ", labels)

            loss = criterion(output, labels.cuda())
            # 反向传播
            loss.backward()
            optimizer.step()  # 更新变量

            running_loss += loss.item()
            if (i % 20 == 0):
                print("epoch:{} , i:{} , running_loss:{}".format(epoch, i, running_loss))
                running_loss = 0

    print("Finished Training!")


# train()
#
# # 仅保存模型参数  注意 训练完保存一次,再次运行务必注释掉该句
# print("Saving model paremeters...")
# torch.save(net.state_dict(), "../model/params_mydata.pkl")

# 加载模型参数
net.load_state_dict(torch.load("../model/params_mydata.pkl"))

# 保存整个模型
# torch.save(net, "../data/MNIST/model.pkl")
# 加载模型
# net = torch.load("../data/MNIST/model.pkl")

# Test
"""
img
predicted
img_size   
"""


def imshow(img, nrow, predicted, img_size=28):
    # img = img / 2 + 0.5  # unnormalize  显示用
    npimg = img.numpy()
    # print("npimg shape: ", npimg.shape)
    npimg_trans = np.transpose(npimg, (1, 2, 0))  # 调换了位置
    # print("npimg_trans shape: ", npimg_trans.shape) #
    for i in range(len(predicted) // nrow):  # 行
        for j in range(nrow):  # 列
            # plt.text(5 + (img_size+3) * j, 5 + (img_size+3) * i, "pred:" + str(predicted[i * nrow + j].item()), color="r") #
            plt.text(5 + (img_size+3) * j, 5 + (img_size+3) * i, class_list[predicted[i * nrow + j].item()], color="r") #

    plt.imshow(npimg_trans)
    plt.show()


# 拿出一个batch来测试

test_data1 = iter(test_loader)
images, labels = test_data1.next()  # 取出其中的一个batch  里面有4个样本
images2, labels2 = test_data1.next()  # 取出其中的一个batch  里面有4个样本

outputs = net(images.cuda())
_, predicted = torch.max(outputs, 1)

# 预测
print('Predicted: ', ' '.join('%3s' % int(predicted[j]) for j in range(batch_size_test)))
# 实际
print("Grounf truth: ", labels)


nrow = 5
imshow(torchvision.utils.make_grid(images, nrow=nrow), nrow, predicted)

# 测试 全部样本上的整体准确度
correct = 0
total = 0

class_correct = list(0. for i in range(batch_size_test))
class_total = list(0 for j in range(batch_size_test))

with torch.no_grad():  # Dont need backward
    for data in test_loader:
        images, labels = data
        outputs = net(images.cuda())
        _, predicted = torch.max(outputs, dim=1)  # 每行的最大值  可以推出,列是对不同变量,行内是各类的概率
        total += labels.size(0)
        correct += (predicted == labels.cuda()).sum().item()

        c = (predicted == labels.cuda()).squeeze()

        for i in range(batch_size_test):  # 每个 batch 内的样本个数
            label = labels[i]
            class_total[label] += 1
            class_correct[label] += c[i].item()

print("Total samples: %4d Accuracy: %3f %%" % (total, 100 * correct / total))
print("Accuracy on each class:")
# 在我们这,标签的索引就是类别 ! Take it easy
for i in range(10):
    print("Accuracy each class:%2d  %3f" % (i, class_correct[i] / class_total[i]))

  • 结果展示
  • 分别对应: 0 胶带; 1 芦荟胶 ; 2 魔方 ; 3 背景
Total samples:  400 Accuracy: 100.000000 %
Accuracy on each class:
Accuracy each class: 0  1.000000
Accuracy each class: 1  1.000000
Accuracy each class: 2  1.000000
Accuracy each class: 3  1.000000

在这里插入图片描述

  • epoch小的时候,准确率还是很低的,但我迭代上几百次也没关系阿hehe。epoch是第一生产力!

  • 分类任务就做到这,接下来再进行下一步的工作

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值