学人工智能一次竞赛都不打?闹呢?
各位人工智能愛好者,大家好!
由TinyMind發(fā)起的?#第一屆漢字書法識(shí)別挑戰(zhàn)賽#?正在火熱進(jìn)行中,比賽才開始2周,已有數(shù)只黑馬沖進(jìn)榜單。目前TOP23全部為90分以上了,可謂競(jìng)爭(zhēng)激烈,高手如林。不是比賽太簡(jiǎn)單,是大佬們太厲害了啊!
No.1微胖君(microfat_htu)目前以99.01高分領(lǐng)銜榜首,還未報(bào)名的同學(xué)歡迎點(diǎn)擊"原文鏈接"參賽,向這些同學(xué)發(fā)起挑戰(zhàn)~~
4.24 榜單
本次比賽主要是以學(xué)習(xí)交流為目的,吸引了不少萌新們報(bào)名參賽~雖是入門級(jí)別的賽題,對(duì)于沒動(dòng)手實(shí)戰(zhàn)過的同學(xué),還是有些不知所措。為此TinyMind特邀戰(zhàn)場(chǎng)中奮勇拼搏的三名前鋒,為大家整理了一些經(jīng)驗(yàn)心得,用不同的解題思路,以啟發(fā)新手們?nèi)绾伍_動(dòng),參與到本次書法識(shí)別比賽中。
以下為參賽ID:真的學(xué)不會(huì) 的經(jīng)驗(yàn)分享
漢字書法識(shí)別入門
前段時(shí)間參加了一次TinyMind舉辦的漢字書法識(shí)別挑戰(zhàn)賽,說是挑戰(zhàn)賽其實(shí)就是一場(chǎng)練習(xí)賽。為一些剛剛?cè)腴T的同學(xué)和沒有比賽經(jīng)驗(yàn)的同學(xué)提供了一個(gè)探索圖像識(shí)別領(lǐng)域的平臺(tái)。我目前是暫列榜首(沒想到轉(zhuǎn)眼就被超越了-。-),所以把自己的思路和想法稍微做一個(gè)分享,給有需要的人提供一個(gè)base line。
先來看數(shù)據(jù)集~~
100個(gè)漢字的訓(xùn)練集
10000張書法圖片的測(cè)試集
上面的訓(xùn)練集總共有100個(gè)漢字,每一個(gè)漢字都有400張不同字體的圖片,數(shù)據(jù)量上來看算是一個(gè)比較小的數(shù)據(jù)集。
等等,看到的確定是漢字嗎,第一眼望過去我是真的emmmmm.....甲骨文,篆體各種字體都冒出來了。先喝口水冷靜一下,仔細(xì)看一看發(fā)現(xiàn)圖片都是gray的。想了一想突然覺得這個(gè)和mnist并沒有太大的區(qū)別只是字體更加復(fù)雜一些,可能要用稍微深一點(diǎn)的網(wǎng)絡(luò)來訓(xùn)練。
圖片看完了,那么開始擼代碼了。分析終究是分析,還是實(shí)踐才能說明一切。
數(shù)據(jù)集劃分
競(jìng)賽中只給了train和test,所以需要自己手動(dòng)劃分一個(gè)val來做模型訓(xùn)練的驗(yàn)證測(cè)試。在這里簡(jiǎn)單說明一下經(jīng)常用的兩種劃分?jǐn)?shù)據(jù)集的方法。
本地劃分
內(nèi)存劃分
本地劃分:圖片是按照文件夾分類的,所以只需要從每個(gè)文件夾中按ratio抽取部分圖片到val中即可,當(dāng)然不要忘記了shuffle。
內(nèi)存劃分:把所有圖片和標(biāo)簽讀進(jìn)內(nèi)存中,存為list或者array然后shuffle后按長(zhǎng)度劃分。前提是把數(shù)據(jù)讀進(jìn)去內(nèi)存不會(huì)爆炸掉。內(nèi)存劃分只適合小型數(shù)據(jù)集,不然會(huì)Boom!!!
注:劃分?jǐn)?shù)據(jù)集的時(shí)候一定要打亂數(shù)據(jù),shuffle很重要!!!
1def move_ratio(data_list, original_str, replace_str):
2 ? ?for x in data_list:
3 ? ? ? ?fromImage = Image.open(x)
4 ? ? ? ?x = x.replace(original_str, replace_str)
5 ? ? ? ?fromImage.save(x)
注:這里只給出部分代碼,文章最下面github有完整鏈接。
1for d in $(ls datadir); do ? ? ? ? ? ? ? ? ? ? ? ?
2 ? ?for f in $(ls datadir/$d | shuf | head -n 100 ); do
3 ? ? ? ?mkdir -p valid_dir/$d/
4 ? ? ? ?mv datadir/$d/$f valid_dir/$d/;
5 ? ?done;
6done
注:這里引用dwSun的linux shell腳本,如果想用簡(jiǎn)單腳本實(shí)現(xiàn)也可以采用他的代碼~
模型建立與數(shù)據(jù)預(yù)處理
對(duì)于CNN網(wǎng)絡(luò)來說,大的數(shù)據(jù)集對(duì)應(yīng)大的訓(xùn)練樣本,如果小的數(shù)據(jù)集想要用深層次的網(wǎng)絡(luò)來訓(xùn)練的話,那么必不可少的一步就是數(shù)據(jù)增強(qiáng)。
數(shù)據(jù)增強(qiáng)的大部分方法,所有深度學(xué)習(xí)框架都已經(jīng)封裝好了。這里我采用的是keras自帶的數(shù)據(jù)增強(qiáng)方法。
1from keras.preprocessing.image import ImageDataGenerator
2datagen = ImageDataGenerator(
3 ? ?# horizontal_flip=True,
4 ? ?width_shift_range=0.15,
5 ? ?height_shift_range=0.15,
6 ? ?rescale=1 / 255
7)
由于漢字是具有筆畫順序的,所以做了翻轉(zhuǎn)以后訓(xùn)練的效果不是很好。這里就做了一個(gè)寬度和高度的偏移,由于給的數(shù)據(jù)集圖片長(zhǎng)寬不是固定的而且字體的內(nèi)容也是有長(zhǎng)有短。所以用這兩種增強(qiáng)方式可以提高模型的準(zhǔn)確率,結(jié)果測(cè)試這兩種方式還是有效的。
數(shù)據(jù)處理完了,那么下面就是我們可愛的CNN網(wǎng)絡(luò)模型了
cnn一把梭
嗯,就是干。
1# bn + prelu
2def bn_prelu(x):
3 ? ?x = BatchNormalization()(x)
4 ? ?x = PReLU()(x)
5 ? ?return x
6# build baseline model
7def build_model(out_dims, input_shape=(128, 128, 1)):
8 ? ?inputs_dim = Input(input_shape)
9 ? ?x = Conv2D(32, (3, 3), strides=(2, 2), padding='valid')(inputs_dim)
10 ? ?x = bn_prelu(x)
11 ? ?x = Conv2D(32, (3, 3), strides=(1, 1), padding='valid')(x)
12 ? ?x = bn_prelu(x)
13 ? ?x = MaxPool2D(pool_size=(2, 2))(x)
14 ? ?x = Conv2D(64, (3, 3), strides=(1, 1), padding='valid')(x)
15 ? ?x = bn_prelu(x)
16 ? ?x = Conv2D(64, (3, 3), strides=(1, 1), padding='valid')(x)
17 ? ?x = bn_prelu(x)
18 ? ?x = MaxPool2D(pool_size=(2, 2))(x)
19 ? ?x = Conv2D(128, (3, 3), strides=(1, 1), padding='valid')(x)
20 ? ?x = bn_prelu(x)
21 ? ?x = MaxPool2D(pool_size=(2, 2))(x)
22 ? ?x = Conv2D(128, (3, 3), strides=(1, 1), padding='valid')(x)
23 ? ?x = bn_prelu(x)
24 ? ?x = AveragePooling2D(pool_size=(2, 2))(x)
25 ? ?x_flat = Flatten()(x)
26 ? ?fc1 = Dense(512)(x_flat)
27 ? ?fc1 = bn_prelu(fc1)
28 ? ?dp_1 = Dropout(0.3)(fc1)
29 ? ?fc2 = Dense(out_dims)(dp_1)
30 ? ?fc2 = Activation('softmax')(fc2)
31 ? ?model = Model(inputs=inputs_dim, outputs=fc2)
32 ? ?return model
這里用了6個(gè)簡(jiǎn)單的卷積層,和PRelu+bn層。
下面是一個(gè)比較大的模型ResNet50,模型是已經(jīng)merge在了keras的applications中,可以直接用。不過需要調(diào)整分類層。
1def resnet50_100(feat_dims, out_dims):
2 ? ?# resnett50 only have a input_shape=(128, 128, 3), if use resnet we must change
3 ? ?# shape at least shape=(197, 197, 1)
4 ? ?resnet_base_model = ResNet50(include_top=False, weights=None, input_shape=(128, 128, 1))
5 ? ?# get output of original resnet50
6 ? ?x = resnet_base_model.get_layer('avg_pool').output
7 ? ?x = Flatten()(x)
8 ? ?fc = Dense(feat_dims)(x)
9 ? ?x = bn_prelu(fc)
10 ? ?x = Dropout(0.5)(x)
11 ? ?x = Dense(out_dims)(x)
12 ? ?x = Activation("softmax")(x)
13 ? ?# buid myself model
14 ? ?input_shape = resnet_base_model.input
15 ? ?output_shape = x
16 ? ?resnet50_100_model = Model(inputs=input_shape, outputs=output_shape)
17 ? ?return resnet50_100_model
好了,煉丹爐有了接下來就是你懂的。
訓(xùn)練模型
訓(xùn)練模型和調(diào)參真的是一個(gè)技術(shù)活,這里我跑了共40個(gè)epoch。思路只有一個(gè)那就是先把train的數(shù)據(jù)跑到loss下降并且先過擬合再說。只要過擬合了后面的一切都好調(diào)整了,如果訓(xùn)練數(shù)據(jù)都不能到過擬合或者99以上那么要仔細(xì)想想數(shù)據(jù)量夠不夠和模型的選擇了。
loss
acc
可以很清楚的看出來,訓(xùn)練數(shù)據(jù)集已經(jīng)過擬合了。我用的優(yōu)化器是sgd,學(xué)習(xí)率設(shè)置的是lr=0.01。val_acc可以跑到了0.94左右,這是一個(gè)比較正常的訓(xùn)練水平。還可以進(jìn)一步的提高。
提高方法
數(shù)據(jù)增強(qiáng):采取其他的數(shù)據(jù)增強(qiáng)方法進(jìn)一步擴(kuò)大訓(xùn)練數(shù)據(jù),這里可以采用GAN來生成近似于真實(shí)圖片的數(shù)據(jù)。
衰減學(xué)習(xí)率:當(dāng)?shù)竭_(dá)一定epoch的時(shí)候,loss不再下降了這個(gè)時(shí)候可以通過減小學(xué)習(xí)率的方法進(jìn)一步訓(xùn)練。
模型融合:模型融合的方法在大部分?jǐn)?shù)據(jù)集上都會(huì)有所提高,這個(gè)是最常用的一種競(jìng)賽方式。
以上就是我自己做的流程和思路,提交結(jié)果和評(píng)測(cè)的代碼寫在我的github上面了,有興趣參加比賽練手的同學(xué)可以參考一下。
github地址:https://github.com/FlyEgle/chinese_font_recognition/
好多小伙伴是從開發(fā)或者是其他工程上轉(zhuǎn)到AI的,所以下面我給有需要的同學(xué)列舉出一些必要的基礎(chǔ)知識(shí)點(diǎn).
基礎(chǔ)知識(shí)
數(shù)學(xué):線性代數(shù)和概率論是必須要會(huì)的,而且基本的概念和計(jì)算都要懂。可以把高數(shù),線性代數(shù)和概率論看一遍,這里推薦李航的統(tǒng)計(jì)學(xué)習(xí)方法。
圖像處理:如果是做圖像方面的小伙伴,那么需要把岡薩雷斯的圖像處理那本巨作看一遍,需要懂基本的圖像概念和基本方法。
機(jī)器學(xué)習(xí):周志華的西瓜書
深度學(xué)習(xí):
如果能把這幾本書完全吃透那也很厲害了,當(dāng)然學(xué)習(xí)知識(shí)點(diǎn)的途徑還有很多。
知乎
微信公眾號(hào)
Google
TinyMind
加油!!
以下為參賽ID:Link 的經(jīng)驗(yàn)分享
深度學(xué)習(xí)入門指南:從零開始TinyMind漢字書法識(shí)別
環(huán)境搭建
數(shù)據(jù)導(dǎo)入
啟動(dòng)網(wǎng)絡(luò)
環(huán)境搭建:
對(duì)入門來說,最容易的還是在windows下進(jìn)行開發(fā)。而且現(xiàn)在各種深度學(xué)習(xí)架構(gòu)大都支持windows,因此如果只是入門深度學(xué)習(xí),最好還是從windows開始。不過因?yàn)間ithub上提交的代碼全都運(yùn)行在linux環(huán)境下,因此希望大家最終能轉(zhuǎn)向linux下,話不多說,現(xiàn)在開始。
我們選用的深度學(xué)習(xí)架構(gòu)是pytorch, 相比于tensorflow,pytorch更加簡(jiǎn)單易用,而且符合python的編程習(xí)慣,官網(wǎng)的支持也足夠完善。
環(huán)境搭建步驟
安裝Anaconda, 裝python3.6版本的,至于為啥用python3這都2018年了,就別用上古版本了
安裝pycharm,將pycharm的解釋器改為anaconda安裝目錄下的python。當(dāng)然用別的IDE也可以,但是我習(xí)慣用pycahrm了,如果大家用別的IDE這步另當(dāng)別論
安裝深度學(xué)習(xí)架構(gòu)pytorch, 到了最重要的步驟了,如果沒有英偉達(dá)顯卡,或者顯卡不支持請(qǐng)忽略1-3步
安裝英偉達(dá)顯卡驅(qū)動(dòng)
安裝CUDA
安裝Cuddn
安裝pytorch gpu版 (沒有顯卡的裝cpu版)具體方法參見知乎這篇文章 https://zhuanlan.zhihu.com/p/26871672 選擇自己對(duì)應(yīng)的版本、系統(tǒng)、cuda版本,按照命令直接裝就可以
數(shù)據(jù)導(dǎo)入
數(shù)據(jù)下載在TinyMind的比賽網(wǎng)站 http://www.tinymind.cn/competitions/41 下載解壓后是兩部分,分別是train和test1,其中train是訓(xùn)練集,test1是用來提交評(píng)分的測(cè)試集 為了導(dǎo)入圖片數(shù)據(jù),需要調(diào)用opencv,沒裝opencv的話就先裝opencv
1conda install -c https://conda.binstar.org/menpo opencv
1import os
2import numpy as np
3import torch
4import torch.utils.data as data
5import cv2
6from PIL import Image
7from tqdm import tqdm
8trainpath = 'E:\\Code\\TMD1st\\train\\' #這是我的儲(chǔ)存路徑,windows下的路徑是需要用\\隔開的,linux是反斜杠/
9testpath = 'E:\\Code\\TMD1st\\test1\\'
10words = os.listdir(trainpath) ? # 按時(shí)間排序 從早到晚
11category_number = len(words) # 一共有多少個(gè)字
12img_size = (256, 256) #將圖片大小統(tǒng)一設(shè)定為這個(gè)值
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(): ? ?#將所有數(shù)據(jù)轉(zhuǎn)存,以后就不用每次都從原始數(shù)據(jù)讀取了
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) #將數(shù)據(jù)和標(biāo)簽分別存為data和label
38 ? ?np.save('label.npy', labels)
將轉(zhuǎn)存完的結(jié)果讀出來看一下
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個(gè)圖像的label按照one-hot編碼存的,這么干其實(shí)浪費(fèi)空間,但是反正也沒幾兆,就懶得改了,index那一行就是專為將ong-hot轉(zhuǎn)label
這才將數(shù)據(jù)轉(zhuǎn)存,為了訓(xùn)練時(shí)給pytorch使用,最方便的方法是使用pytorch做好的loader工具,為此需要實(shí)現(xiàn)自己的data.Dataset。只需繼承data.Dataset,并且重寫__getitem__和__len__兩個(gè)方法就可以。
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為label
6 ? ? ? ?np.random.seed(123)
7 ? ? ? ?np.random.shuffle(index)
8 ? ? ? ?if eval: ? ?#如果eval為真,就取10%作為驗(yàn)證集,設(shè)定隨機(jī)數(shù)種子是為了每次取出來的都是固定的10%,以免將驗(yàn)證集用于訓(xùn)練
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就可以自動(dòng)劃分batch。
啟動(dòng)網(wǎng)絡(luò)
無論網(wǎng)絡(luò)結(jié)構(gòu)如何,用網(wǎng)絡(luò)進(jìn)行訓(xùn)練的整個(gè)過程是相同的
1import torch
2import torch.optim as optim
3from torch.autograd import Variable
4import torch.nn as nn
5import data
6import torch.nn.functional as F
7n_epoch, batch_size = 25, 8 # 設(shè)置遍歷次數(shù)及每個(gè)batch的大小
8trainset = data.TrainSet(eval=False) #實(shí)例化上面定義的數(shù)據(jù)集對(duì)象
9trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True) #用trainset實(shí)例化loader
10evalset = data.TrainSet(eval=True) ?#驗(yàn)證集
11evalloader = torch.utils.data.DataLoader(evalset, batch_size=batch_size, shuffle=True)
12net = Net() # 實(shí)例化模型
13if torch.cuda.is_available(): ? # 將模型移到GPU上
14 ? ?net.cuda()
15criterion = nn.CrossEntropyLoss() ? #損失函數(shù)使用交叉熵
16optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=1e-1, weight_decay=1e-4) #優(yōu)化器使用SGD 學(xué)習(xí)率1e-3
17def train(epoch):
18 ? ?net.train() # 經(jīng)模型切換到訓(xùn)練模式
19 ? ?correct = 0
20 ? ?sum = 0
21 ? ?for batch_index, (datas, labels) in enumerate(trainloader, 0): ?#從loader裝載數(shù)據(jù)
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(): ? #數(shù)據(jù)轉(zhuǎn)移到GPU
27 ? ? ? ? ? ?datas = datas.cuda()
28 ? ? ? ? ? ?labels = labels.cuda()
29 ? ? ? ?optimizer.zero_grad() ? # 每次前項(xiàng)計(jì)算之前,將優(yōu)化器梯度清零
30 ? ? ? ?outputs = net(datas) ? ?# 前項(xiàng)計(jì)算
31 ? ? ? ?loss = criterion(outputs, labels) # 根據(jù)結(jié)果和label計(jì)算損失函數(shù)
32 ? ? ? ?loss.backward() # 做反向傳播
33 ? ? ? ?optimizer.step() # 用優(yōu)化器進(jìn)行一次更新
34 ? ? ? ?pred_choice = outputs.data.max(1)[1] ? ?# 前向輸出計(jì)算最大的一個(gè)作為最可能的輸出
35 ? ? ? ?correct += pred_choice.eq(labels.data).cpu().sum() # 統(tǒng)計(jì)正確個(gè)數(shù)
36 ? ? ? ?sum += len(labels) ?# 總數(shù)
37 ? ? ? ?# 輸出每次計(jì)算的信息
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): ? ?# 用驗(yàn)證集做類似過程,只是不計(jì)算梯度、不更新參數(shù)
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)
如此,我們就完成了從原始數(shù)據(jù)制作dataset送入loader并且啟動(dòng)網(wǎng)絡(luò)的所有代碼。 等等,我們忘記了最重要的部分,我們沒有定義網(wǎng)絡(luò)的結(jié)構(gòu)。 Net這里,這是一個(gè)繼承自nn.Moudule的類,只要在這個(gè)類中定義網(wǎng)絡(luò)的前向計(jì)算即可,反向計(jì)算會(huì)由pytorch自動(dòng)實(shí)現(xiàn)。
為了簡(jiǎn)單起見,我們只舉一個(gè)簡(jiǎn)單的例子,這個(gè)網(wǎng)絡(luò)是隨便寫的,完全沒有任何合理性的考慮,但至少能開始訓(xùn)練了。
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 是連續(xù)操作的寫法
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) ? ? ? ? ? ? ? ? ? ? ?# 連續(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
這樣,代碼就完整了,運(yùn)行開始以后我么你就恩能夠看到訓(xùn)練正確率從0慢慢的向上爬。當(dāng)然,這個(gè)網(wǎng)絡(luò)是隨意寫的,性能肯定極其的差,但至少舉了一個(gè)栗子。
我們都知道,深度學(xué)習(xí)也叫煉丹。所以接下來的活便是研究拜讀各個(gè)大牛級(jí)煉丹師的的煉丹秘籍(論文),學(xué)習(xí)人家先進(jìn)的煉丹手法(trick),把我們的栗子給煉成金丹。
五年煉丹,三年悟道,煉丹一道,非大毅力大智慧者不可成。吾等當(dāng)晝夜苦修,方有機(jī)緣窺得一絲丹道真諦,與諸君共勉。
源代碼
鏈接地址:https://github.com/Link2Link/TinyMind-start-with-0
以下為參賽ID:microfat_htu 的經(jīng)驗(yàn)分享
前一段時(shí)間在用遷移學(xué)習(xí)實(shí)現(xiàn)圖像分類Github,正好趕上這次書法識(shí)別比賽,就想嘗試用遷移學(xué)習(xí)的方法實(shí)現(xiàn)書法圖像分類。本來沒有抱太大希望,因?yàn)楦鶕?jù)遷移學(xué)習(xí)理論,訓(xùn)練源域模型的數(shù)據(jù)應(yīng)與訓(xùn)練目標(biāo)域的數(shù)據(jù)有相似的特征分布,然而,ILSVRC數(shù)據(jù)集中并沒有漢字符號(hào)類別,所以,期望的最好結(jié)果是能夠收斂。但,事實(shí)出乎意料,不僅收斂,而且得到99.01%的測(cè)試準(zhǔn)確率(看來我是低估深度模型的特征提取能力了)。
總結(jié)
以上是生活随笔為你收集整理的学人工智能一次竞赛都不打?闹呢?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (MATLAB/C/Python)快速中
- 下一篇: 单片机微型计算机原理及接口技术陈,单片机