zoukankan      html  css  js  c++  java
  • 字符识别--字符识别模型

    这一节主要开始构建一个字符识别模型,基于赛题理解,本章将构建一个定长多字符分类模型
    工欲善其事必先利其器,首先来了解下pytorch与TensorFlow。(本比赛主要用到pytorch框架用于解决这个问题)

    PyTorch基本结构

    pytorch主要分为以下几个模块来训练模型:

    • tensor:tensor为基本结构,可以直接创建,从list创建以及由numpy数组得到,torch还提供一套运算以及shape变换的方法
    • Variable:自动求导机制,利用Variable包括tensor后,便可以使用其求导的功能了,有点像装饰器
    • nn:nn模块是整个pytorch的核心,自己设计的NEt(),继承nn.Model后可以提取模型参数,进行前向forward()运算(自己设计的),以及后向运算(自动),nn提供基本网络结构单元,例如nn.Linear(),nn.Conv2d()等,还提供了基本损失函数nn.CrossEntropyLoss等
    • torch.optim:该模块提供自动求导更新参数等功能,用它来封装模型参数nn.parameter()后,loss求导后,可以用.step来更新整个参数。
    • torch.utils.data.DataSet:该模块提供加载数据初始化的方式,需要实现完善__getitem__()和__len__()的接口,便可以使用DataLoader多进程加载数据。
      参考:https://blog.csdn.net/qq_16949707/article/details/79067474

    Tensorflow 处理结构及基本应用

    处理结构

    Tensorflow的设计理念主要体现在两个方面

    1. 将图定义和图运算完全分开
    2. TensorFlow 中涉及的运算都要放在图中,而图的运行只发生在会话(session)中。开启会话后,就可以用数据去填充节点,进行运算;关闭会话后,就不能进行计算了。因此,会话提供了操作运行和 Tensor 求值的环境。
      Tensorflow 首先要定义神经网络的结构,然后再把数据放入结构种运算和training

    Alt Text

    因为TensorFlow是采用 数据流图(data flow graphs)来计算, 所以首先我们得创建一个数据流图,然后再将我们的数据(数据以 张量(tensor) 的形式存在)放到数据流图中计算。 图中的 节点(Nodes)一般用来表示施加的数学操作,但也可以表示数据输入(feed in)的起点/输出(push out)的终点,或者是读取/写入持久变量(persistent variable)的终点;线(edges)则表示在节点间相互联系的多维数据数组,即 张量(tensor),训练模型时,tensor 会不断的从数据流图中的一个节点 flow 到另一节点, 这就是 TensorFlow 名字的由来。一旦输入端的所有张量准备好,节点将被分配到各种计算设备完成异步并行地执行运算。

    基本应用

    • 使用图(graph)来计算任务
    • 在被称为会话(Session)的上下文(context)执行图
    • 使用tensor表示数据
    • 通过变量(Variable)维护状态
    • 使用feed和fetch可以为任意的操作(arbitrary operation)赋值或从其中获取数据
      参考:https://www.jianshu.com/p/2b06b5630852,TensorFlow入门教程

    CNN

    卷积神经网络(CNN)每一层由众多的卷积核组成,每个卷积核对输入的像素进行卷积操作,得到下一次的输入。随着网络层的增加卷积核会逐渐扩大感受野,并缩减图像的尺寸。

    输入图片经过卷积后所得特征图大小的计算公式
    输入图片大小:W x W
    Filter大小:F x F
    步长:S
    padding的像素数:P
    输出图片大小N x N ,计算公式:
    N = (W-F + 2P)/S + 1
    参考:https://blog.csdn.net/ieasyer/article/details/84970693

    CNN 是一种层次模型,输入的是原始的图像的像素数据。CNN通过卷积(converlution)、池化(pooling)、非线性激活函数(non-linear activation function)和全连接层(fully connected layer)构成。
    如下所示,是非常经典的字符识别模型--LeNet网络结构。它包括两个卷积层,两个池化层,两个全连接层。卷积核都为5 x 5,stride= 1,池化层使用最大池化。

    通过多次卷积和池化,CNN的最后一层将输入的图像像素映射为具体的输出。如在分类任务中会转换成不同类别的概率输出,然后计算真实标签与CNN模型的预测结果的差异,并通过反向传播更新每层的参数,并在更新完成后再次前向全波,如此反复直到训练完成。

    比较典型的网络结构

    LeNet--5(1998)

    AlexNet(2012)

    VGG-16(2014)

    Inception-v1(2014)

    ResNet-50(2015)

    PyTorch构建CNN模型

    在pytorch中构建CNN模型只需要定义好模型的参数和正向传播,pytorch会根据正向传播自动计算反向传播
    本模型包括两层卷积层,最后并联6个全连接层用于分类。
    导入模块

    import os,sys,glob,shutil,json
    
    import cv2
    from PIL import Image
    import numpy as np
    from tqdm import tqdm,tqdm_notebook
    
    import torch
    import torchvision.datasets as datasets
    from torchvision import transforms
    import torchvision.models as models
    import torch.nn as nn
    import torch.nn.functional as F
    import torch.optim as optim
    from torch.autograd import Variable
    from torch.utils.data.dataset import Dataset
    

    模型

    class SVHN_Model1(nn.Module):
        def __init__(self):
            super(SVHN_Model1,self).__init__()
            
            #CNN提取特征模块
            self.nn = nn.Sequential(nn.Conv2d(3,16,kernel_size=(3,3),stride=(2,2)),
                                   nn.ReLU(),
                                   nn.MaxPool2d(2),
                                   nn.Conv2d(16,32,kernel_size=(3,3),stride=(2,2)),
                                   nn.ReLU(),
                                   nn.MaxPool2d(2)
                                   )
            self.fc1 = nn.Linear(32*3*7,11)
            self.fc2 = nn.Linear(32*3*7,11)
            self.fc3 = nn.Linear(32*3*7,11)
            self.fc4 = nn.Linear(32*3*7,11)
            self.fc5 = nn.Linear(32*3*7,11)
            self.fc6 = nn.Linear(32*3*7,11)
        def forward(self,img):
            feat = self.nn(img)
            feat = feat.view(feat.shape[0],-1)
            c1 = self.fc1(feat)
            c2 = self.fc2(feat)        
            c3 = self.fc3(feat)        
            c4 = self.fc4(feat)        
            c5 = self.fc5(feat)        
            c6 = self.fc6(feat)        
            return c1,c2,c3,c4,c5,c6
    model = SVHN_Model1()
    

    对super()的理解:(参考:https://www.runoob.com/python/python-func-super.html)

    super()函数用于调用父类(超类)的一个方法,它用于解决多重继承的问题。
    python3.x和python2.x的一个区别就是:python3可以直接使用super().xxx 代替super(class,self).xxx
    举例:

    torch.nn.Sequential()(参考:https://pytorch-cn.readthedocs.io/zh/latest/package_references/torch-nn/#torchnn)

    torch.nn.Sequential(*args):是一个时序容器,Models会以传入的顺序被添加到容器中。
    举例:

    关于卷积后图像尺寸大小的计算,可参考前面的公式,以及举例链接:https://www.jianshu.com/p/45a26d278473

    模型的训练

    #损失函数
    criterion  = nn.CrossEntropyLoss()
    #优化器
    optimizer = optim.Adam(model.parameters(),0.005)
    loss_plot,c0_plot = [],[]
    
    #迭代10次
    for epoch in range(10):
        for input,target in train_loader:
            
            c0,c1,c2,c3,c4,c5 = model(data[0])
            loss = criterion(c0,data[1].long()[:,0])+
            criterion(c1,data[1].long()[:,1])+
            criterion(c2,data[1].long()[:,2])+
            criterion(c3,data[1].long()[:,3])+
            criterion(c4,data[1].long()[:,4])
    #         criterion(c5,data[1].long()[:,5])
        loss /=6
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        loss_plot.append(loss.item())
        c0_plot.append((c0.argmax(1) == data[1][:,1]).sum().item()*1.0/c0.shape[0])
        print(epoch)
    

    plot 画的的loss以及c0_plot不知道是训练次数少的缘故,似乎得到的结果有点不对劲

    也可以使用pytorch提供的模型(在ImageNet数据集上的预训练模型)

    class SVHN_Model2(nn.Module):
        def __init__(self):
            super(SVHN_Model2,self).__init__()
            
            model_conv = models.resnet18(pretrained=True)
            model_conv.avgpool = nn.AdaptiveAvgPool2d(1)
            model_conv = nn.Sequential(*list(model_conv.children())[:-1])
            self.cnn = model_conv
            
            self.fc1 = nn.Linear(512,11)
            self.fc2 = nn.Linear(512,11)
            self.fc3 = nn.Linear(512,11)        
            self.fc4 = nn.Linear(512,11)        
            self.fc5 = nn.Linear(512,11)  
        def forward(self,img):
            feat = self.cnn(img)
            feat = feat.view(feat.shape[0],-1)
            c1 = self.fc1(feat)
            c2 = self.fc2(feat)
            c3 = self.fc3(feat)
            c4 = self.fc4(feat)
            c5 = self.fc5(feat)
            return c1,c2,c3,c4,c5
    

    对children()的理解

    返回当前模型 子模块的迭代器

  • 相关阅读:
    Github上的英文解释
    快速搭建脚手架的方法
    vue生命周期简介和钩子函数
    vue2.0 路由模式mode="history"的作用
    浅谈vue $mount()
    vue——解决“You may use special comments to disable some warnings. Use // eslint-disable-next-line to ignore the next line. Use /* eslint-disable */ to ignore all warnings in a file. ”
    Vue组件中的父子传值
    URL中的hash(井号)
    大数据-高并发网络基础1
    大数据-6Linux-shell编程
  • 原文地址:https://www.cnblogs.com/whiteBear/p/12952446.html
Copyright © 2011-2022 走看看