Python pytorch的一个简单封装(最简调参,自适应Size)

什么是Pytorch

PyTorch是一个开源的Python机器学习库,基于Torch,用于自然语言处理等应用程序。
2017年1月,由Facebook人工智能研究院(FAIR)基于Torch推出了PyTorch。它是一个基于Python的可续计算包,提供两个高级功能:
1、具有强大的GPU加速的张量计算(如NumPy)。
2、包含自动求导系统的深度神经网络。

TorchTools

功能及其简介

这是一个基于Pytorch的框架
在神经网络中,最难的就是对于张量Size的掌控,而这个框架可以对Tensor的Size进行自适应调整,让工作重点从对Size的调整转到对网络主干的理解

构成

Size类,包括channel,width,height三个属性,可以储存图片和向量的信息

Layer类,储存层级的单位,包括了in_size和out_size两个数据

Options类,储存所有的层级信息和其他信息

Block类,代替nn.Module,有自动前馈的功能

Utils类,包括了Train和Draw两个函数,可以实现低代码调参训练

实例代码

CNN网络

class CNN(Block):
    def __init__(self, options):
        super(CNN, self).__init__(options)

        self.UseConv2d(8) \
            .UseReLU() \
            .UseBatchNorm2d() \
            .UseMaxPool2d()

        self.UseConv2d(16) \
            .UseReLU() \
            .UseBatchNorm2d() \
            .UseMaxPool2d()

        self.UseConv2d(32) \
            .UseReLU() \
            .UseBatchNorm2d() \
            .UseMaxPool2d()

        self.UseView(0)

        self.UseLinear(1000) \
            .UseLinear(100) \
            .UseLinear(10)

训练代码

data_tf = Compose([ToTensor(), Normalize([0.5], [0.5])])
data_path = 'C:\\0_data\\MNIST_DATA_PyTorch'  # minist数据集的下载路径
# 获取数据集
train_data = mnist.MNIST(data_path, train=True, transform=data_tf, download=False)
test_data = mnist.MNIST(data_path, train=False, transform=data_tf, download=False)
train_loader = data.DataLoader(train_data, batch_size=128, shuffle=True)
test_loader = data.DataLoader(test_data, batch_size=128, shuffle=True)

model, loss, accuracy = Utils.Train(model_name=CNN,
                                    options=Options(1, 28, 28, 'cuda'),
                                    train_loader=train_loader,
                                    test_loader=test_loader,
                                    accuracy_calculate=lambda x, y: (max(x, 1)[1].numpy() == y.numpy()).mean(),
                                    epoch_cout=10,
                                    loss_func_name=nn.CrossEntropyLoss,
                                    optimizer_name=optim.Adam,
                                    learn_rate=0.001)
Utils.Draw('LOSS', Loss=loss, Accuracy=accuracy)
save(model, 'model/cnn')

结构展示
在这里插入图片描述

可使用对象

数据

一维向量,二维图片

网络结构

名称介绍对象
Conv2d2维卷积层图片
MaxPool2d2维最大池化图片
AvgPool2d2维平均池化图片
BatchNorm2d()2为标准化图片
Linear全连接层向量
ReLUReLU激活函数*
SigmoidSigmoid激活函数*
View对数据进行拉伸只支持图片和向量的转换

Utils代码

from matplotlib import pyplot as plt
from torch import nn
from torch.autograd import Variable
import numpy as np


class Size:
    def __init__(self, channel, width, height):
        self.channel = channel
        self.width = width
        self.height = height

    def __str__(self):
        return f'channel:{self.channel}\twidth:{self.width}\theight:{self.height}'


class Layer:
    def __init__(self, typename, **kwargs):
        self.name = typename
        self.args = kwargs

    @property
    def in_size(self) -> Size:
        return self.args['in_size']

    @property
    def out_size(self) -> Size:
        return self.args['out_size']


class Options:
    def __init__(self, channel, width, height, device='cpu'):
        self.__options = {}
        self.__layers = [Layer('Input',
                               out_size=Size(channel, width, height),
                               in_size=Size(channel, width, height))]
        self.__device = device

    def Device(self, model=None):
        if model is not None:
            model = model.to(self.__device)
            return model
        else:
            return self.__device

    @property
    def Layers(self):
        return self.__layers

    def __getitem__(self, item):
        if item not in self.__options.keys():
            raise Exception('Unknown Key')
        return self.__options[item]

    def __setitem__(self, key, value):
        self.__options[key] = value
        self.__dict__[key] = value

    def __len__(self):
        return len(self.__layers)

    def AddProperty(self, **kwargs):
        for item in kwargs.keys():
            self.__options[item] = kwargs[item]
            self.__dict__[item] = kwargs[item]

    def AddLayer(self, typename, **kwargs):
        data = Layer(typename, **kwargs)
        self.__layers.append(data)

    def GetIndexLayer(self, index) -> Layer:
        return self.__layers[index]

    def GetLastLayerSize(self) -> Size:
        return self.GetIndexLayer(-1).out_size


class Block(nn.Module):
    def __init__(self, options: Options = None):
        super(Block, self).__init__()

        self.options = options if options is not None else Options()
        self.layer = nn.Sequential()
        self._start = len(self.options)
        self._count = 0

    def SetDevice(self):
        self.options.Device(self)

    def GetOptions(self):
        return self.options

    def UseConv2d(self, out_channels, kernel_size=3, padding=0, stride=1):
        in_size = self.options.GetLastLayerSize()
        self.layer.append(nn.Conv2d(in_channels=in_size.channel,
                                    out_channels=out_channels,
                                    kernel_size=kernel_size,
                                    padding=padding,
                                    stride=stride))
        self.options.AddLayer('Conv2d',
                              in_channels=in_size.channel,
                              out_channels=out_channels,
                              kernel_size=kernel_size,
                              padding=padding,
                              stride=stride,
                              in_size=in_size,
                              out_size=Size(out_channels,
                                            int((in_size.width + 2 * padding - kernel_size) / stride + 1),
                                            int((in_size.height + 2 * padding - kernel_size) / stride + 1)))
        self._count += 1
        return self

    def UseMaxPool2d(self, kernel_size=2, padding=0, stride=1):
        self.layer.append(nn.MaxPool2d(kernel_size=kernel_size, padding=padding, stride=stride))
        in_size = self.options.GetLastLayerSize()
        self.options.AddLayer('MaxPool2d',
                              kernel_size=kernel_size,
                              padding=padding,
                              stride=stride,
                              in_size=in_size,
                              out_size=Size(in_size.channel,
                                            int((in_size.width + 2 * padding - kernel_size) / stride + 1),
                                            int((in_size.height + 2 * padding - kernel_size) / stride + 1)))
        self._count += 1
        return self

    def UseAvgPool2d(self, kernel_size=2, padding=0, stride=1):
        self.layer.append(nn.AvgPool2d(kernel_size=kernel_size, padding=padding, stride=stride))
        in_size = self.options.GetLastLayerSize()
        self.options.AddLayer('AvgPool2d',
                              kernel_size=kernel_size,
                              padding=padding,
                              stride=stride,
                              in_size=in_size,
                              out_size=Size(in_size.channel,
                                            int((in_size.width + 2 * padding - kernel_size) / stride + 1),
                                            int((in_size.height + 2 * padding - kernel_size) / stride + 1)))
        self._count += 1
        return self

    def UseLinear(self, out_features):
        in_size = self.options.GetLastLayerSize()
        in_features = in_size.width
        if in_size.channel != 0:  # 如果是0通道,代表是线性的
            raise Exception('in_features is None')

        self.layer.append(nn.Linear(in_features=in_features, out_features=out_features))

        self.options.AddLayer('Linear',
                              in_features=in_features,
                              out_features=out_features,
                              in_size=in_size,
                              out_size=Size(0, out_features, 0))
        self._count += 1
        return self

    def UseBatchNorm2d(self, channel=None):
        in_size = self.options.GetLastLayerSize()
        if in_size.channel == 0:
            raise Exception('This Layer Could Not Be 0')

        channel = in_size.channel

        self.layer.append(nn.BatchNorm2d(channel))

        self.options.AddLayer('BatchNorm2d',
                              channel=channel,
                              in_size=in_size,
                              out_size=in_size)
        self._count += 1
        return self

    def UseView(self, channel, width=0, height=0):
        # 只支持图像或者向量
        in_size = self.options.GetLastLayerSize()
        if channel == 0:
            width = in_size.channel * in_size.width * in_size.height
        self.options.AddLayer('View',
                              channel=channel,
                              width=width,
                              height=height,
                              in_size=in_size,
                              out_size=Size(channel, width, height))
        self._count += 1
        return self

    def UseReLU(self):
        in_size = self.options.GetLastLayerSize()
        self.layer.append(nn.ReLU())
        self.options.AddLayer('ReLU',
                              in_size=in_size,
                              out_size=in_size)
        self._count += 1
        return self

    def UseSigmoid(self):
        in_size = self.options.GetLastLayerSize()
        self.layer.append(nn.Sigmoid())
        self.options.AddLayer('Sigmoid',
                              in_size=in_size,
                              out_size=in_size)
        self._count += 1
        return self

    def forward(self, data):
        cnt = 0
        for index in range(self._count):
            layer = self.options.Layers[self._start + index]
            if layer.name == 'View':
                if layer.args['channel'] == 0:
                    # 转换为向量
                    data = data.view(data.size(0), -1)
                else:
                    data = data.view(data.size(0), layer.args['width'], layer.args['height'])
            elif layer.name == 'Input':
                data = data.to(self.options.Device)
                continue
            else:
                data = self.layer[cnt](data)
                cnt += 1
        return data


class Utils:
    @staticmethod
    def Train(model_name,
              options: Options,
              train_loader,
              test_loader,
              accuracy_calculate,
              epoch_cout,
              loss_func_name,
              optimizer_name,
              learn_rate):
        loss_func = loss_func_name()
        model = model_name(options)
        model.SetDevice()
        optimizer = optimizer_name(model.parameters(), lr=learn_rate)
        loss_value = []
        accuracy_value = []
        for epoch in range(epoch_cout):
            for index, (x, y) in enumerate(train_loader):
                batch_x = options.Device(Variable(x))
                batch_y = options.Device(Variable(y))

                out = model(batch_x)

                loss = loss_func(out, batch_y)

                optimizer.zero_grad()
                loss.backward()
                optimizer.step()

            loss = loss.cpu()
            loss_value.append(loss.data)

            accuracy = []
            accuracy.clear()

            for index, (x, y) in enumerate(test_loader):
                batch_x = options.Device(Variable(x))
                batch_y = Variable(y)

                out = model(batch_x).cpu()

                accuracy.append(accuracy_calculate(out, batch_y))

            accuracy_value.append(np.array(accuracy).mean())

        return model, loss_value, accuracy_value

    @staticmethod
    def Draw(name, **kwargs):
        plt.figure('LOSS')
        for key in kwargs.keys():
            plt.plot(kwargs[key], label=key)
        plt.legend()
        plt.show()


  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python PyTorch是一个用于深度学习的开源框架。验证码(CAPTCHA)是一种用来区分计算机和人类用户的图像验证码技术。在使用Python PyTorch实现验证码功能时,可以按照以下步骤进行: 1. 数据准备:收集和准备用于训练和测试的图像验证码数据集。可以包括数字、字母、符号等不同类型的验证码图像。 2. 数据预处理:对图像进行预处理,如调整图像大小、图像归一化等操作,以便于神经网络的训练和预测。 3. 网络设计:构建一个深度学习模型,可以使用PyTorch提供的各种层类型来设计网络结构。例如,可以使用卷积层、池化层、全连接层等。 4. 网络训练:使用准备好的数据集对深度学习网络进行训练。可以使用PyTorch提供的优化器和损失函数进行网络参数的优化,并通过反向传播算法更新权重以最小化损失。 5. 模型评估:使用测试数据集对训练好的验证码识别模型进行评估,计算模型的准确率、精确率、召回率等指标。 6. 验证码预测:使用训练好的模型对新的验证码图像进行预测。将验证码图像输入模型,输出预测结果,即模型对验证码的识别结果。 在实际应用中,可以将验证码功能嵌入到网站注册、登录等操作中,确保只有真正的人类用户才能进行相关操作。使用Python PyTorch可以快速搭建验证码识别的深度学习模型,并实现准确可靠的验证码识别功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纸墨青鸢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值