各位人工智能爱好者,大家好!

由TinyMind发起的#第一届汉字书法识别挑战赛#正在火热进行中,比赛才开始3周,已有数只黑马冲进榜单。目前TOP54全部为90分以上!可谓竞争激烈,高手如林。不是比赛太简单,是大佬们太厉害了啊!

查看榜单

本次比赛主要是以学习交流为目的,吸引了不少萌新们报名参赛~虽是入门级别的赛题,对于没动手实战过的同学,还是有些不知所措。为此TinyMind特邀战场中奋勇拼搏的参赛队员“Link”,为大家整理了参赛经验心得,以启发新手们如何开动,参与到本次书法识别比赛中。

以下为参赛ID:Link 的经验分享

深度学习入门指南:从零开始TinyMind汉字书法识别

- 环境搭建

- 数据导入

- 启动网络

环境搭建

对入门来说,最容易的还是在windows下进行开发。而且现在各种深度学习架构大都支持windows,因此如果只是入门深度学习,最好还是从windows开始。不过因为github上提交的代码全都运行在linux环境下,因此希望大家最终能转向linux下,话不多说,现在开始。

我们选用的深度学习架构是pytorch, 相比于tensorflow,pytorch更加简单易用,而且符合python的编程习惯,官网的支持也足够完善。

环境搭建步骤

1、安装Anaconda, 装python3.6版本的,至于为啥用python3这都2018年了,就别用上古版本了

2、安装pycharm,将pycharm的解释器改为anaconda安装目录下的python。当然用别的IDE也可以,但是我习惯用pycahrm了,如果大家用别的IDE这步另当别论

3、 安装深度学习架构pytorch, 到了最重要的步骤了,如果没有英伟达显卡,或者显卡不支持请忽略1-3步

  • 安装英伟达显卡驱动

    • 安装CUDA
    • 安装Cuddn
    • 安装pytorch gpu版 (没有显卡的装cpu版)具体方法参见知乎这篇文章
      https://zhuanlan.zhihu.com/p/26871672 选择自己对应的版本、系统、cuda版本,按照命令直接装就可以

数据导入

数据下载在TinyMind的比赛网站 http://www.tinymind.cn/competitions/41 下载解压后是两部分,分别是train和test1,其中train是训练集,test1是用来提交评分的测试集 为了导入图片数据,需要调用opencv,没装opencv的话就先装opencv

 conda install -c https://conda.binstar.org/menpo opencv
 1import os2import numpy as np3import torch4import torch.utils.data as data5import cv26from PIL import Image7from tqdm import tqdm8trainpath = 'E:\\Code\\TMD1st\\train\\' #这是我的储存路径,windows下的路径是需要用\\隔开的,linux是反斜杠/9testpath = 'E:\\Code\\TMD1st\\test1\\'
10words = os.listdir(trainpath)   # 按时间排序 从早到晚
11category_number = len(words) # 一共有多少个字
12img_size = (256, 256) #将图片大小统一设定为这个值
13def loadOneWord(order):
14    path = trainpath + words[order] + '\\'
15    files = os.listdir(path)
16    datas = []
17    for file in files:
18        file = path + file
19        img = np.asarray(Image.open(file))
20        img = cv2.resize(img, img_size)
21        datas.append(img)
22    datas = np.array(datas)
23    labels = np.zeros([len(datas), len(words)], dtype=np.uint8)
24    labels[:, order] = 1
25    return datas, labels
26def transData():    #将所有数据转存,以后就不用每次都从原始数据读取了
27    num = len(words)
28    datas = np.array([], dtype=np.uint8)
29    datas.shape = -1, 256, 256
30    labels = np.array([], dtype=np.uint8)
31    labels.shape = -1, 100
32    for k in range(num):
33        data, label = loadOneWord(k)
34        datas = np.append(datas, data, axis=0)
35        labels = np.append(labels, label, axis=0)
36        print('loading', k)
37    np.save('data.npy', datas) #将数据和标签分别存为data和label
38    np.save('label.npy', labels)

将转存完的结果读出来看一下

1if __name__ == '__main__':
2    datas = np.load('data.npy')
3    labels = np.load('label.npy')
4    index = np.arange(0, len(datas), 1, dtype=np.int)
5    print(datas.shape, labels.shape)

(40000, 256, 256) (40000, 100)

我是将40000个图像的label按照one-hot编码存的,这么干其实浪费空间,但是反正也没几兆,就懒得改了,index那一行就是专为将ong-hot转label

这才将数据转存,为了训练时给pytorch使用,最方便的方法是使用pytorch做好的loader工具,为此需要实现自己的data.Dataset。只需继承data.Dataset,并且重写getitemlen两个方法就可以。

 1class TrainSet(data.Dataset):2    def __init__(self, eval=False):3        datas = np.load('data.npy') #装载4        labels = np.load('label.npy')5        index = np.arange(0, len(datas), 1, dtype=np.int) #换one-hot为label6        np.random.seed(123)7        np.random.shuffle(index)8        if eval:    #如果eval为真,就取10%作为验证集,设定随机数种子是为了每次取出来的都是固定的10%,以免将验证集用于训练9            index = index[:int(len(datas) * 0.1)]
10        else:
11            index = index[int(len(datas) * 0.1):]
12        self.data = datas[index]
13        self.label = labels[index]
14        np.random.seed()
15    def __getitem__(self, index):
16        return torch.from_numpy(self.data[index]), \
17               torch.from_numpy(self.label[index])
18    def __len__(self):
19        return len(self.data)

完成dataset后只要使用torch.utils.data.DataLoader就可以自动划分batch。

启动网络

无论网络结构如何,用网络进行训练的整个过程是相同的

 1import torch2import torch.optim as optim3from torch.autograd import Variable4import torch.nn as nn5import data6import torch.nn.functional as F7n_epoch, batch_size = 25, 8 # 设置遍历次数及每个batch的大小8trainset = data.TrainSet(eval=False) #实例化上面定义的数据集对象9trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True) #用trainset实例化loader
10evalset = data.TrainSet(eval=True)  #验证集
11evalloader = torch.utils.data.DataLoader(evalset, batch_size=batch_size, shuffle=True)
12net = Net() # 实例化模型
13if torch.cuda.is_available():   # 将模型移到GPU上
14    net.cuda()
15criterion = nn.CrossEntropyLoss()   #损失函数使用交叉熵
16optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=1e-1, weight_decay=1e-4) #优化器使用SGD 学习率1e-3
17def train(epoch):
18    net.train() # 经模型切换到训练模式
19    correct = 0
20    sum = 0
21    for batch_index, (datas, labels) in enumerate(trainloader, 0):  #从loader装载数据
22        labels = labels.max(1)[1]
23        datas = Variable(datas).float()
24        datas = datas.view(-1, 1, 256, 256)
25        labels = Variable(labels).long()
26        if torch.cuda.is_available():   #数据转移到GPU
27            datas = datas.cuda()
28            labels = labels.cuda()
29        optimizer.zero_grad()   # 每次前项计算之前,将优化器梯度清零
30        outputs = net(datas)    # 前项计算
31        loss = criterion(outputs, labels) # 根据结果和label计算损失函数
32        loss.backward() # 做反向传播
33        optimizer.step() # 用优化器进行一次更新
34        pred_choice = outputs.data.max(1)[1]    # 前向输出计算最大的一个作为最可能的输出
35        correct += pred_choice.eq(labels.data).cpu().sum() # 统计正确个数
36        sum += len(labels)  # 总数
37        # 输出每次计算的信息
38        print('batch_index: [%d/%d]' % (batch_index, len(trainloader)),
39              'Train epoch: [%d]' % (epoch),
40              # 'acc:%.4f p:%.4f r:%.4f F1:%.4f' % (acc, p, r, F1),
41              'correct/sum:%d/%d, %.4f' % (correct, sum, correct / sum))
42def eval(epoch):    # 用验证集做类似过程,只是不计算梯度、不更新参数
43    net.eval()
44    correct = 0
45    sum = 0
46    for batch_index, (datas, labels) in enumerate(evalloader, 0):
47        labels = labels.max(1)[1]
48        datas = Variable(datas).cuda().float()
49        datas = datas.view(-1, 1, 256, 256)
50        labels = Variable(labels).cuda().long()
51        # optimizer.zero_grad()
52        outputs = net(datas)
53        # loss = criterion(outputs, labels)
54        # loss.backward()
55        # optimizer.step()
56        pred_choice = outputs.data.max(1)[1]
57        correct += pred_choice.eq(labels.data).cpu().sum()
58        sum += len(labels)
59        print('batch_index: [%d/%d]' % (batch_index, len(evalloader)),
60              'Eval epoch: [%d]' % (epoch),
61              # 'acc:%.4f p:%.4f r:%.4f F1:%.4f' % (acc, p, r, F1),
62              'correct/sum:%d/%d, %.4f' % (correct, sum, correct / sum))
63if __name__ == '__main__':
64    for epoch in range(n_epoch):
65        train(epoch)
66        eval(epoch)

如此,我们就完成了从原始数据制作dataset送入loader并且启动网络的所有代码。 等等,我们忘记了最重要的部分,我们没有定义网络的结构。 Net这里,这是一个继承自nn.Moudule的类,只要在这个类中定义网络的前向计算即可,反向计算会由pytorch自动实现。

为了简单起见,我们只举一个简单的例子,这个网络是随便写的,完全没有任何合理性的考虑,但至少能开始训练了。

 1class net(nn.Module):2    def __init__(self):3        super(net, self).__init__()4        self.pool = nn.MaxPool2d(2)5        self.drop = nn.Dropout(p=0.5)6        self.conv1 = nn.Conv2d(1, 32, 7, stride=2, padding=3)7        self.norm1 = nn.BatchNorm2d(32)8        self.conv2 = nn.Conv2d(32, 32, 3, stride=1, padding=1)9        self.norm2 = nn.BatchNorm2d(32)
10        self.conv3 = nn.Conv2d(32, 64, 3, stride=1, padding=1)
11        self.norm3 = nn.BatchNorm2d(64)
12        # Sequential 是连续操作的写法
13        self.convs = nn.Sequential(nn.Conv2d(64, 128, 3, stride=1, padding=1),
14                                   nn.BatchNorm2d(128),
15                                   nn.ReLU(),
16                                   nn.Conv2d(128, 128, 3, stride=1, padding=1),
17                                   nn.BatchNorm2d(128),
18                                   nn.ReLU(),
19                                   )
20        self.out_layers = nn.Sequential(nn.Linear(128 * 8 * 8, 1024),
21                                        nn.BatchNorm1d(1024),
22                                        nn.ReLU(),
23                                        nn.Linear(1024, 256),
24                                        nn.BatchNorm1d(256),
25                                        nn.ReLU(),
26                                        nn.Linear(256, 100),
27                                        nn.BatchNorm1d(100),
28                                        nn.ReLU(),
29                                        )
30    def forward(self, x):
31        x = F.relu(self.norm1(self.conv1(x)))   # 卷积 BN ReLU
32        x = self.pool(x)                        # 池化
33        x = F.relu(self.norm2(self.conv2(x)))  # 卷积 BN ReLU
34        x = F.relu(self.norm3(self.conv3(x)))  # 卷积 BN ReLU
35        x = self.pool(x)
36        x = self.convs(x)                      # 连续操作,里面是 conv -> BN -> ReLU -> conv -> BN -> ReLU
37        x = self.pool(x)
38        x = x.view(-1, 128 * 8 * 8)             # 将图像拉直为向量
39        x = self.drop(x)
40        x = self.out_layers(x)
41        return x

这样,代码就完整了,运行开始以后我么你就恩能够看到训练正确率从0慢慢的向上爬。当然,这个网络是随意写的,性能肯定极其的差,但至少举了一个栗子。

我们都知道,深度学习也叫炼丹。所以接下来的活便是研究拜读各个大牛级炼丹师的的炼丹秘籍(论文),学习人家先进的炼丹手法(trick),把我们的栗子给炼成金丹。

五年炼丹,三年悟道,炼丹一道,非大毅力大智慧者不可成。吾等当昼夜苦修,方有机缘窥得一丝丹道真谛,与诸君共勉。

源代码

链接地址:https://github.com/Link2Link/TinyMind-start-with-0

欢迎对汉字书法识别感兴趣的同学踊跃参赛!竞赛地址:https://www.tinymind.cn/competitions/41

文章转自 #汉字书法识别挑战赛#经验分享 专栏

【AI参赛经验】深度学习入门指南:从零开始TinyMind汉字书法识别——by:Link相关推荐

  1. 深度学习入门指南:从零开始TinyMind汉字书法识别

    深度学习入门指南:从零开始TinyMind汉字书法识别 这几天在刷这个新出的比赛,受举办方邀请谢了一篇文章,也转到CSDN来和大家分享下吧.话说TinyMind不是被CSDN收购了么,我这算不算把统一 ...

  2. 2023年的深度学习入门指南(1) - 从chatgpt入手

    2023年的深度学习入门指南(1) - 从chatgpt入手 2012年,加拿大多伦多大学的Hinton教授带领他的两个学生Alex和Ilya一起用AlexNet撞开了深度学习的大门,从此人类走入了深 ...

  3. 2023年的深度学习入门指南(6) - 在你的电脑上运行大模型

    2023年的深度学习入门指南(6) - 在你的电脑上运行大模型 上一篇我们介绍了大模型的基础,自注意力机制以及其实现Transformer模块.因为Transformer被PyTorch和Tensor ...

  4. 2023年的深度学习入门指南(10) - CUDA编程基础

    2023年的深度学习入门指南(10) - CUDA编程基础 上一篇我们走马观花地看了下SIMD和GPGPU的编程.不过线条太粗了,在开发大模型时遇到问题了肯定还会晕. 所以我们还是需要深入到CUDA中 ...

  5. 2023年的深度学习入门指南(14) - 不能只关注模型代码

    2023年的深度学习入门指南(14) - 不能只关注模型代码 最近,有一张大模型的发展树非常流行: 这个图是相当不错的,对于加深对于Transformer模型编码器.解码器作用的理解,模型的开源和闭源 ...

  6. 2023年的深度学习入门指南(5) - HuggingFace Transformers库

    2023年的深度学习入门指南(5) - HuggingFace Transformers库 这一节我们来学习下预训练模型的封装库,Hugging Face的Transformers库的使用.Huggi ...

  7. 2023年的深度学习入门指南(8) - 剪枝和量化

    2023年的深度学习入门指南(8) - 剪枝和量化 从这一节开始,我们要准备一些技术专项了.因为目前大模型技术还在快速更新迭代中,各种库和实现每天都在不停出现.因为变化快,所以难免会遇到一些问题.对于 ...

  8. 【AI竞赛】TinyMind汉字书法识别挑战赛开始报名啦!!

    书法是中国及深受中国文化影响过的国家和地区特有的一种文字美的艺术表现形式.书法艺术的背景是中国传统文化.书法植根于中国传统文化土壤,传统文化是书法赖以生存.发展的背景.我们今天能够看到的汉代以来的书法 ...

  9. 给初学者的深度学习入门指南

    从无人驾驶汽车到AlphaGo战胜人类,机器学习成为了当下最热门的技术.而机器学习中一种重要的方法就是深度学习. 作为一个有理想的程序员,若是不懂人工智能(AI)领域中深度学习(DL)这个超热的技术, ...

最新文章

  1. html语言区别大小写吗,用HTML语言制作静态网页基础问题1.标注是否区分大小写?2.下 爱问知识人...
  2. protobuf message定义_ProtoBuf 协议设计与开发
  3. 支撑计算机高速化的半导体技术
  4. 【剑指offer】面试题05:替换空格(java)
  5. 解决Axure发布分享预览的3个方法
  6. css基础知识汇总3
  7. 罗马数字和阿拉伯数字转换
  8. C语言求17以后的5个质数,C语言求质数的算法
  9. 数学建模:R语言的正态性检验
  10. PMS(PackageManagerService)原理简单介绍,启动过程源码简单解析
  11. springboot 当前无法使用此页面(无法打开页面)
  12. 【电信学】【2013】未知环境下移动机器人导航研究
  13. gbk编解码器无法解码的问题,有可能出题出在文件名上
  14. UltraRAM:在UltraScale+器件上集成嵌入式存储器
  15. 编制计算机程序解决问题的5个步骤,第四章第一节编制计算机程序解决问题
  16. sql 2005安装图解
  17. 豌豆淘讲分析会员制,企业为何要做会员营销?
  18. EMC-传导发射的共模和差模噪声的有效处理方案
  19. 《海上钢琴师》The Legend Of 1900
  20. Repellat qui perferendis praesentium dignissimos sit.

热门文章

  1. asp.net 控制页面css样式
  2. java连接数据库不使用框架_实体框架数据库连接不重新连接
  3. 《java第二次实验》
  4. 使用grep过滤make的输出内容
  5. 系统设计规范化攻克了什么问题
  6. IncDec Sequence(codevs 2098)
  7. 测试用例设计白皮书--正交实验设计方法
  8. css3实现3D立体翻转效果
  9. Xcode 5.0.1安装插件:规范注释生成器VVDocumenter + OSX 10.9.2
  10. 基于Matlab的多层BP神经网络在非线性函数拟合中的应用