从零开始pytorch手写字母识别
因?yàn)檠幸坏娜斯ぶ悄艽笞鳂I(yè)-手寫(xiě)字母識(shí)別,在學(xué)習(xí)之余,綜合一些文章和代碼實(shí)現(xiàn)了本文,針對(duì)數(shù)據(jù)集Chars74K dataset。
數(shù)據(jù)集介紹:
(1)、數(shù)據(jù)集來(lái)源于Chars74K dataset,本項(xiàng)目選用數(shù)據(jù)集EnglishFnt中的一部分。Chars74K dataset網(wǎng)址鏈接 http://www.ee.surrey.ac.uk/CVSSP/demos/chars74k/;
(2)、A-Z共26種英文字母,每種字母對(duì)應(yīng)一個(gè)文件夾(Sample011對(duì)應(yīng)字母A, Sample012對(duì)應(yīng)字母B,…, Sample036對(duì)應(yīng)字母Z);
(3)、Sample011到Sample036每個(gè)文件夾下相同字母不同字體的圖片約1000張,PNG格式;
(4)、本項(xiàng)目數(shù)據(jù)集請(qǐng)從以下鏈接下載:
https://pan.baidu.com/s/1HEsbvusyYCni7MVGKUk4bA, 提取碼:dhix
要求:
1.每種字母當(dāng)成一類(lèi),利用卷積神經(jīng)元網(wǎng)絡(luò)構(gòu)建26類(lèi)分類(lèi)器;
2.每個(gè)類(lèi)別中隨機(jī)選擇80%作為訓(xùn)練數(shù)據(jù)集,剩余20%作為測(cè)試數(shù)據(jù)集。采用訓(xùn)練集進(jìn)行模型訓(xùn)練,采用測(cè)試集進(jìn)行模型測(cè)試,并給出測(cè)試集準(zhǔn)確率結(jié)果。
Bonus:
1、Bonus文件夾下為手寫(xiě)A-Z的字母圖片。請(qǐng)將之前訓(xùn)練好的分類(lèi)器遷移學(xué)習(xí)到Bonus數(shù)據(jù)集上,重新構(gòu)建分類(lèi)器,Bonus數(shù)據(jù)集中隨機(jī)選擇80%作為訓(xùn)練數(shù)據(jù)集,剩余20%作為測(cè)試數(shù)據(jù)集,并給出測(cè)試集準(zhǔn)確率結(jié)果。
2、將Bonus文件夾下的圖片當(dāng)作未標(biāo)注類(lèi)別的數(shù)據(jù),聯(lián)合之前的標(biāo)注圖片,采用半監(jiān)督學(xué)習(xí)的方法構(gòu)建分類(lèi)器。
其它。
前置知識(shí)體系
目前學(xué)習(xí)的稍微的前置知識(shí)
-
安裝虛擬環(huán)境
-
安裝pytorch
-
…等一系列前置工作
-
python 基礎(chǔ)語(yǔ)法
- 函數(shù)
- 類(lèi)
- pandas庫(kù)等
-
卷積神經(jīng)網(wǎng)絡(luò)基礎(chǔ) —可見(jiàn)機(jī)器學(xué)習(xí) -吳恩達(dá)-yyq
- 卷積
- 池化
- 全連接
-
pytorch 的基礎(chǔ)使用
-
關(guān)于pytorch 對(duì)于數(shù)據(jù)的預(yù)處理
-
關(guān)于pytroch cnn網(wǎng)絡(luò)的構(gòu)建
pytorch步驟
一、前言
在我們要用pytorch構(gòu)建自己的深度學(xué)習(xí)模型的時(shí)候,基本上都是下面這個(gè)流程步驟,寫(xiě)在這里讓一些新手童鞋學(xué)習(xí)的時(shí)候有一個(gè)大局感覺(jué),無(wú)論是從自己寫(xiě),還是閱讀他人代碼,按照這個(gè)步驟思想(默念4大步驟,
- 找數(shù)據(jù)定義、
- 找model定義、(找損失函數(shù)、優(yōu)化器定義),
- 主循環(huán)代碼邏輯,
- 直接去找對(duì)應(yīng)的代碼塊,會(huì)簡(jiǎn)單很多。
二、基本步驟思想
所有的深度學(xué)習(xí)模型過(guò)程都可以形式化如下圖:
分為四大步驟:
1、輸入處理模塊 (X 輸入數(shù)據(jù),變成網(wǎng)絡(luò)能夠處理的Tensor類(lèi)型)
- 進(jìn)行預(yù)處理 input - dataset - dataloader
2、模型構(gòu)建模塊 (主要負(fù)責(zé)從輸入的數(shù)據(jù),得到預(yù)測(cè)的y^, 這就是我們經(jīng)常說(shuō)的前向過(guò)程)
3、定義代價(jià)函數(shù)和優(yōu)化器模塊 (注意,前向過(guò)程只會(huì)得到模型預(yù)測(cè)的結(jié)果,并不會(huì)自動(dòng)求導(dǎo)和更新,是由這個(gè)模塊進(jìn)行處理)
4、構(gòu)建訓(xùn)練過(guò)程 (迭代訓(xùn)練過(guò)程,就是上圖表情包的訓(xùn)練迭代過(guò)程)
這幾個(gè)模塊分別與上圖的數(shù)字標(biāo)號(hào)1,2,3,4進(jìn)行一一對(duì)應(yīng)!
三、實(shí)例講解
知道了上面的宏觀思想之后,后面給出每個(gè)模塊稍微具體一點(diǎn)的解釋和具體一個(gè)例子,再幫助大家熟悉對(duì)應(yīng)的代碼!
1.數(shù)據(jù)處理
對(duì)于數(shù)據(jù)處理,最為簡(jiǎn)單的?式就是將數(shù)據(jù)組織成為?個(gè) 。但許多訓(xùn)練需要?到mini-batch,直 接組織成Tensor不便于我們操作。pytorch為我們提供了Dataset和Dataloader兩個(gè)類(lèi)來(lái)方便的構(gòu)建。
torch.utils.data.Dataset
繼承Dataset 類(lèi)需要override 以下?法:
torch.utils.data.DataLoader
torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False)DataLoader Batch。如果選擇shuffle = True,每?個(gè)epoch 后,mini-Batch batch_size 常?的使??法如下:
2. 模型構(gòu)建
所有的模型都需要繼承torch.nn.Module , 需要實(shí)現(xiàn)以下?法:
其中forward() ?法是前向傳播的過(guò)程。在實(shí)現(xiàn)模型時(shí),我們不需要考慮反向傳播。
3. 定義代價(jià)函數(shù)和優(yōu)化器
這部分根據(jù)??的需求去參照doc
4、構(gòu)建訓(xùn)練過(guò)程
pytorch的訓(xùn)練循環(huán)?致如下:
下面再用一個(gè)簡(jiǎn)單例子,來(lái)鞏固一下:
slides來(lái)自https://www.bilibili.com/video/BV1Y7411d7Ys?from=search&seid=3765076366663992699
slides來(lái)自https://www.bilibili.com/video/BV1Y7411d7Ys?from=search&seid=3765076366663992699
slides來(lái)自https://www.bilibili.com/video/BV1Y7411d7Ys?from=search&seid=3765076366663992699
slides來(lái)自https://www.bilibili.com/video/BV1Y7411d7Ys?from=search&seid=3765076366663992699
數(shù)據(jù)集預(yù)處理
文件處理
針對(duì)文件夾中都是圖片的數(shù)據(jù)集處理
例如 : data文件夾內(nèi)包含26個(gè)文件夾,分別包含a,b,c,d…各種相關(guān)圖片
利用這些圖片做出自己的數(shù)據(jù)集
-
./data/A/a_0.jpg
-
./data/A/a_1.jpg
-
./data/A/a_2.jpg
-
…
-
./data/B/b_0.jpg
-
./data/B/b_1.jpg
-
…
生成train.txt和test.txt 如下圖 地址與標(biāo)簽相對(duì)應(yīng)
!!!!!
自己踩得坑,自己解決,數(shù)據(jù)集預(yù)處理問(wèn)題,先獲取總的數(shù)據(jù),打亂,在獲取訓(xùn)練集和測(cè)試集
import os import random''' 處理文件夾中的圖片,并自動(dòng)分類(lèi)'''# 定義訓(xùn)練集和數(shù)據(jù)集比例 # 訓(xùn)練集 0.8 # 測(cè)試集 0.2 train_ratio = 0.8 test_ratio = 1 - train_ratio# 定義文件路徑 root_path = "./data" DataList = []# 定義訓(xùn)練列表 trainData_list = [] # 定義測(cè)試列表 testData_list = []# 為什么flag=-1 因?yàn)榈谝惠唂or循環(huán)獲取了root路徑下的文件夾,并沒(méi)有獲取文件 flag = -1 for root, dirs, files in os.walk(root_path):# 每輪掃描獲得路徑和文件列表# 獲取該輪文件的長(zhǎng)度# root 也會(huì)隨之改變length = files.__len__()for i in range(0, length):img_path = os.path.join(root, files[i]) + "\t" + str(flag) + "\n"DataList.append(img_path)flag = flag + 1; #打亂數(shù)據(jù)集 random.shuffle(DataList) length = len(DataList) print(length) print(DataList)for i in range(0, int(length * train_ratio)):trainData_list.append(DataList[i]) for i in range(int(length * train_ratio), length):testData_list.append(DataList[i])# 對(duì)列表打亂次序with open("./res/train.txt", "w", encoding="utf-8") as f:for data in trainData_list:f.write(data)with open("./res/test.txt", "w", encoding="utf-8") as f:for data in testData_list:f.write(data)主要使用的函數(shù) os.walk(rootdata)
舉例 :
讀取rootdata=./data
for root,dirs,files in os.walk(root_path):第一輪 :
- root = ./data
- dirs = [sample011…sample038 ]
- files = [] #因?yàn)閐ata目錄下沒(méi)有文件
第二輪 :
- root = ./data/Sample011
- dirs = [] #因?yàn)镾ample011里面沒(méi)有文件夾
- files = [ a.jpg…a100.jpg ]
第三輪
- root = ./data/Sample012
- dirs = [] #因?yàn)镾ample012里面沒(méi)有文件夾
- files = [ b.jpg…b100.jpg ]
…
DataSet
DataSet需要被繼承
- 實(shí)現(xiàn) __ init __(self)
- 構(gòu)造器 提前生成一些數(shù)據(jù)或者獲取一些數(shù)據(jù)
- 比如 imgPaths列表 [ [imagesPath,label],[imagesPath,label],[imagesPath,label]… ]
- train.txt文件路徑
- 構(gòu)造器 提前生成一些數(shù)據(jù)或者獲取一些數(shù)據(jù)
- 實(shí)現(xiàn) __ getitem __ (self, index)
- 獲取第index號(hào)的數(shù)據(jù)和標(biāo)簽
- 使用transforms 轉(zhuǎn)化為–tensor
- 實(shí)現(xiàn) __ len __(self)
- 獲取數(shù)據(jù)的長(zhǎng)度
其中用Dataset實(shí)現(xiàn)的類(lèi)可以直接看作列表使用
[ [ x , y ],[ x , y ] ,[ x , y ], [ x , y ] … ]
- 獲取 x y
- x,y = myDataset[0]
- x=myDataset[0] [0]
- y=myDataset[0] [1]
- 獲取長(zhǎng)度
- myDataset.__ len __
知識(shí)點(diǎn)
- self 相當(dāng)于java的this , self.data 為類(lèi)中的全局變量
- transformer.Compose 注意使用的順序
- PIL -> tensor ->…
DataLoader
#使用DataLoadertrain_dataloader = DataLoader(dataset=train_Dataset, num_workers=4, pin_memory=True, batch_size=batch_size,shuffle=True)test_dataloader = DataLoader(dataset=test_Dataset, num_workers=4, pin_memory=True, batch_size=batch_size,shuffle=True)# 使用Tensorboard --查看每步存放的圖片writer = SummaryWriter("logs")i=1#這里imgs.shape -> (10-照片個(gè)數(shù),3-通道數(shù),128-H,128-W)for data in train_dataloader:imgs,label=dataprint(imgs.shape)print(label)#這里是add_imges!!!!writer.add_images("test-dataloader",imgs,i)i+=iTensorBoard
–port 可以修改端口號(hào)
from torch.utils.tensorboard import SummaryWriter from PIL import Image import numpy as np writer = SummaryWriter("logs") imgepath=r"D:\機(jī)器學(xué)習(xí)\pytorch\數(shù)據(jù)預(yù)處理\dataset\不導(dǎo)電\不導(dǎo)電20180830131551對(duì)照樣本.jpg" img=Image.open(imgepath) img=np.array(img) #參數(shù) tag名稱(chēng) tensor ndarray writer.add_image("test",img,2,dataformats="HWC") # y = 2x for i in range(100):writer.add_scalar("y=2x",2*i, i)writer.close()常用的語(yǔ)句
- writer = SummaryWriter(“l(fā)ogs”)
- logs代表文件夾
- writer.add_image(“test”,img,2,dataformats=“HWC”)
- tag 名稱(chēng)
- img 圖片數(shù)據(jù) 需要是tensor narray 類(lèi)型
- dataformats 需要是 hwc
- H 高度 w寬度 c 通道
- writer.add_scalar(“y=2x”,2*i, i)
- 畫(huà)圖嘛
- tag
- y
- x
- writer.close()
控制行執(zhí)行指令
tensorboard --logdir=./study/logs --port=6000DONE!
搭建卷積神經(jīng)網(wǎng)絡(luò)
預(yù)訓(xùn)練模型地址
C:\Users\yyq\.cache\torch\hub\checkpoints可以手動(dòng)下載放到那里即可
參考搭建網(wǎng)絡(luò)-1
上圖少寫(xiě)了兩個(gè)全連接層
- 64@4×4 -Flatten-> 1024 -FC-> 64 -FC-> 10
所有的模型都需要繼承torch.nn.Module , 需要實(shí)現(xiàn)以下?法:
其中forward() ?法是前向傳播的過(guò)程。在實(shí)現(xiàn)模型時(shí),我們不需要考慮反向傳播。
這里使用到的Api
- Sequential
- Module
- nn.Conv2d
- nn.MaxPool2d
- nn.Linear
- SummaryWriter -from torch.utils.tensorboard import SummaryWriter
- 實(shí)現(xiàn) 3@ 32 * 32 分類(lèi)-10卷積神經(jīng)網(wǎng)絡(luò)
參考搭建網(wǎng)絡(luò) -2
此模型用于字母識(shí)別-26
參考地址:https://www.cnblogs.com/Liu-xing-wu/p/14770473.html
但是輸入的圖片尺寸不同,所以做了修改 輸入改為 128
網(wǎng)絡(luò)結(jié)構(gòu)
實(shí)現(xiàn)代碼
import torch from torch import nn from torch.nn import Sequential from torch.utils.tensorboard import SummaryWriterclass yyq_module(nn.Module):def __init__(self):super(yyq_module, self).__init__()self.module=Sequential(#3 * 128 * 128nn.Conv2d(in_channels=3, out_channels=16, kernel_size=5 , padding="same"),nn.BatchNorm2d(16),nn.ReLU(),nn.MaxPool2d(kernel_size=2),#16 * 64 * 64nn.Conv2d(in_channels=16, out_channels=32, kernel_size=5, padding="same"),nn.BatchNorm2d(32),nn.ReLU(),nn.MaxPool2d(kernel_size=2),#32 *32 *32nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding="same"),nn.BatchNorm2d(32),nn.ReLU(),nn.MaxPool2d(kernel_size=2),#32 * 16 * 16nn.Flatten(),# #隱藏層 兩個(gè)線性層 即全連接層nn.Linear(in_features=8192,out_features=400),nn.Dropout(p=0.5),nn.ReLU(),nn.Linear(in_features=400, out_features=80),nn.ReLU(),nn.Linear(80, 26))def forward(self,input):output = self.module(input)return output#測(cè)試一下網(wǎng)絡(luò) module=yyq_module() x=torch.zeros((64,3,128,128)) print(x.shape) y=module(x) print(module) print(y.shape)網(wǎng)絡(luò)模型的修改
- 修改方法一 : 最后加一層全連接
- 修改方法二 :直接在最后一層修改
模型的保存和加載
保存模型
import torch import torchvision from torch import nnvgg16 = torchvision.models.vgg16(pretrained=False) # 保存方式1,模型結(jié)構(gòu)+模型參數(shù) torch.save(vgg16, "vgg16_method1.pth")# 保存方式2,模型參數(shù)(官方推薦) torch.save(vgg16.state_dict(), "vgg16_method2.pth")# 陷阱 class Tudui(nn.Module):def __init__(self):super(Tudui, self).__init__()self.conv1 = nn.Conv2d(3, 64, kernel_size=3)def forward(self, x):x = self.conv1(x)return xtudui = Tudui() torch.save(tudui, "tudui_method1.pth")加載模型
import torch from model_save import * # 方式1-》保存方式1,加載模型 # 坑是需要導(dǎo)入定義的模型那個(gè)類(lèi) from model_save import * import torchvision from torch import nnmodel = torch.load("vgg16_method1.pth") # print(model)# 方式2,加載模型 vgg16 = torchvision.models.vgg16(pretrained=False) vgg16.load_state_dict(torch.load("vgg16_method2.pth")) # model = torch.load("vgg16_method2.pth") # print(vgg16)# 陷阱1 # class Tudui(nn.Module): # def __init__(self): # super(Tudui, self).__init__() # self.conv1 = nn.Conv2d(3, 64, kernel_size=3) # # def forward(self, x): # x = self.conv1(x) # return xmodel = torch.load('tudui_method1.pth') print(model)使用GPU
可以使用GPU的
- 網(wǎng)絡(luò)模型
- 損失函數(shù)
- 數(shù)據(jù)(輸入,標(biāo)注)
- .cuda()
- .to(device)
方法一
if torch.cuda.is_is_available():module = module.cuda()lossFun = lossFun.cuda()imgs = imgs.cuda()tagerts = tagerts.cuda() import torchvision from torch.utils.data import DataLoader from module import * from torch.utils.tensorboard import SummaryWriter import datetime import time start_time = time.time() # 導(dǎo)入數(shù)據(jù)集 train_dataset = torchvision.datasets.CIFAR10("../study/data", train=True, transform=torchvision.transforms.ToTensor(),download=True) test_dataset = torchvision.datasets.CIFAR10("../study/data", train=False, transform=torchvision.transforms.ToTensor(),download=True) # 數(shù)據(jù)集長(zhǎng)度 train_len=len(train_dataset) test_len=len(test_dataset)print("訓(xùn)練集數(shù)據(jù)集長(zhǎng)度{}".format(len(train_dataset))) print("測(cè)試集數(shù)據(jù)集長(zhǎng)度{}".format(len(test_dataset)))# 創(chuàng)建dataLoader train_dataloader=DataLoader(train_dataset,batch_size=64, shuffle=True) test_dataloader=DataLoader(test_dataset,batch_size=64, shuffle=True)# 引入模型 module=yyq_module() module = module.cuda()# 定義損失函數(shù) lossFun = torch.nn.CrossEntropyLoss() lossFun = lossFun.cuda() # 學(xué)習(xí)率 learning_rate=1e-2 # 定義優(yōu)化器 optim = torch.optim.SGD(module.parameters(), lr=learning_rate)# 訓(xùn)練輪數(shù) 每一輪是對(duì)整個(gè)數(shù)據(jù)集的一次遍歷 epoch = 10 # 圖像化 指定文件夾 ./yyq/logs writer = SummaryWriter("./logs") # 總的訓(xùn)練次數(shù) total_train_num = 0 total_test_num = 0 for i in range(0,epoch):# 定義訓(xùn)練次數(shù)total_train_step = 0total_test_step = 0# 訓(xùn)練for data in train_dataloader:imgs, tagerts = dataimgs = imgs.cuda()tagerts = tagerts.cuda()outputs = module(imgs)loss = lossFun(outputs,tagerts)# 優(yōu)化器優(yōu)化optim.zero_grad()loss.backward()optim.step()total_train_step = total_train_step+1total_train_num = total_train_num+1if total_train_step%100==0:print(str(time.time()-start_time)+"s")print("訓(xùn)練次數(shù):{}, Loss:{}".format(total_train_step, loss))writer.add_scalar("train_loss", loss, total_train_num)# 訓(xùn)練集的總損失total_test_loss = 0# 預(yù)測(cè)正確次數(shù)total_accuracy = 0# 測(cè)試# 不需要梯度 不要更新參數(shù)with torch.no_grad():for data in test_dataloader:imgs, targets = dataimgs = imgs.cuda()tagerts = tagerts.cuda()outputs = module(imgs)loss = lossFun(outputs, targets)# 總損失total_test_loss = total_test_loss+loss# 計(jì)算準(zhǔn)確率accuracy = (outputs.argmax(1) == targets).sum()total_accuracy = total_accuracy + accuracy# 總測(cè)試次數(shù)total_test_num=total_test_num+1writer.add_scalar("test_loss", loss, total_test_num)print("整體測(cè)試集上AvgLoss: {}".format(total_test_loss / len(test_dataloader)))print("整體測(cè)試集上的Accuracy: {}%".format(100*total_accuracy / test_len))writer.add_scalar("test_accuracy", 100*total_accuracy / test_len, i)writer.close() torch.save(module, "module_{}_{}.pth".format(epoch, 20211117))方法二
注意:
模型和損失函數(shù)可以直接to(device) 而不重新賦值,但是數(shù)據(jù)必須重新賦值
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print("device:"+device.type) # 引入模型 module=yyq_module() module.to(device)# 定義損失函數(shù) lossFun = torch.nn.CrossEntropyLoss() lossFun.to(device)# 訓(xùn)練for data in train_dataloader:imgs, tagerts = dataimgs = imgs.to(device)tagerts = tagerts.to(device) import torchvision from torch.utils.data import DataLoader from module import * from torch.utils.tensorboard import SummaryWriter import datetime import time start_time = time.time() device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print("device:"+device.type) # 導(dǎo)入數(shù)據(jù)集 train_dataset = torchvision.datasets.CIFAR10("../study/data", train=True, transform=torchvision.transforms.ToTensor(),download=True) test_dataset = torchvision.datasets.CIFAR10("../study/data", train=False, transform=torchvision.transforms.ToTensor(),download=True) # 數(shù)據(jù)集長(zhǎng)度 train_len=len(train_dataset) test_len=len(test_dataset)print("訓(xùn)練集數(shù)據(jù)集長(zhǎng)度{}".format(len(train_dataset))) print("測(cè)試集數(shù)據(jù)集長(zhǎng)度{}".format(len(test_dataset)))# 創(chuàng)建dataLoader train_dataloader=DataLoader(train_dataset,batch_size=64, shuffle=True) test_dataloader=DataLoader(test_dataset,batch_size=64, shuffle=True)# 引入模型 module=yyq_module() module.to(device)# 定義損失函數(shù) lossFun = torch.nn.CrossEntropyLoss() lossFun.to(device) # 學(xué)習(xí)率 learning_rate=1e-2 # 定義優(yōu)化器 optim = torch.optim.SGD(module.parameters(), lr=learning_rate)# 訓(xùn)練輪數(shù) 每一輪是對(duì)整個(gè)數(shù)據(jù)集的一次遍歷 epoch = 10 # 圖像化 指定文件夾 ./yyq/logs writer = SummaryWriter("./logs") # 總的訓(xùn)練次數(shù) total_train_num = 0 total_test_num = 0 for i in range(0,epoch):# 定義訓(xùn)練次數(shù)total_train_step = 0total_test_step = 0# 訓(xùn)練for data in train_dataloader:imgs, targets = dataimgs = imgs.to(device)targets = targets.to(device)outputs = module(imgs)loss = lossFun(outputs, targets)# 優(yōu)化器優(yōu)化optim.zero_grad()loss.backward()optim.step()total_train_step = total_train_step+1total_train_num = total_train_num+1if total_train_step%100==0:print(str(time.time()-start_time)+"s")print("訓(xùn)練次數(shù):{}, Loss:{}".format(total_train_step, loss))writer.add_scalar("train_loss", loss, total_train_num)# 訓(xùn)練集的總損失total_test_loss = 0# 預(yù)測(cè)正確次數(shù)total_accuracy = 0# 測(cè)試# 不需要梯度 不要更新參數(shù)with torch.no_grad():for data in test_dataloader:imgs, targets = dataimgs = imgs.to(device)targets = targets.to(device)outputs = module(imgs)loss = lossFun(outputs, targets)# 總損失total_test_loss = total_test_loss+loss# 計(jì)算準(zhǔn)確率accuracy = (outputs.argmax(1) == targets).sum()total_accuracy = total_accuracy + accuracy# 總測(cè)試次數(shù)total_test_num=total_test_num+1writer.add_scalar("test_loss", loss, total_test_num)print("整體測(cè)試集上AvgLoss: {}".format(total_test_loss / len(test_dataloader)))print("整體測(cè)試集上的Accuracy: {}%".format(100*total_accuracy / test_len))writer.add_scalar("test_accuracy", 100*total_accuracy / test_len, i)writer.close() torch.save(module, "module_{}_{}.pth".format(epoch, 20211117))各種網(wǎng)絡(luò)小問(wèn)題
注意原來(lái)模型的輸入Size
比如原來(lái)的圖像尺寸128 * 128
self.tf = transforms.Compose([#嘗試灰度化# transforms.Grayscale(num_output_channels=1), # 彩色圖像轉(zhuǎn)灰度圖像num_output_channels默認(rèn)1transforms.Resize((224,224)),transforms.ToTensor(),transforms.Normalize(mean=[0.5, 0.5, 0.5], # 取決于數(shù)據(jù)集std=[0.5, 0.5, 0.5])])圖片與模型通道數(shù)不同
比如:resnet默認(rèn)輸入尺寸為224X224,三維圖片,但是想輸入的數(shù)據(jù)集圖片尺寸是32X32,以為圖片
我們可以在處理尺寸大小時(shí)在預(yù)處理的地方將其resize為32X32,transforms.Resize(224)
然后在使用resnet之前用一次1X1網(wǎng)絡(luò)修改圖片通道,conv = nn.Conv2d(1, 3, kernel_size=1)即可傳入
在
resnet之前加一個(gè)
優(yōu)化器和loss函數(shù)-反向傳播
損失函數(shù)
這部分根據(jù)??的需求去參照doc
loss = nn.CrossEntropyLoss()for data in dataloader:imgs,target=dataoutput=module(imgs)result_loss=loss(output,target)result_loss.backward()#進(jìn)行反向傳播 算出每個(gè)參數(shù)的梯度 利用優(yōu)化器去調(diào)整參數(shù)print(result_loss)優(yōu)化器的使用
#創(chuàng)建優(yōu)化器 optimizer=SGD(module.parameters(), lr=0.01) for epoch in range(10):for data in dataloader:imgs,target=dataoutput=module(imgs)result_loss=loss(output, target)# 梯度值清零optimizer.zero_grad()# 計(jì)算出新的梯度值result_loss.backward()# 優(yōu)化參數(shù)optimizer.step()print("epoch:" + str(epoch))print(result_loss)添加優(yōu)化器損失函數(shù)后的完整訓(xùn)練網(wǎng)絡(luò)
#優(yōu)化器 import torch import torchvision from torch import nn from torch.nn import Sequential from torch.optim import SGD from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriterdataset = torchvision.datasets.CIFAR10("./data", train=False, transform=torchvision.transforms.ToTensor(),download=True) dataloader=DataLoader(dataset,batch_size=64, shuffle=True)class yyq_module(nn.Module):def __init__(self):super(yyq_module, self).__init__()self.module=Sequential(nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5 , padding="same"),nn.MaxPool2d(kernel_size=2),nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding="same"),nn.MaxPool2d(kernel_size=2),nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding="same"),nn.MaxPool2d(kernel_size=2),nn.Flatten(),#隱藏層 兩個(gè)線性層 即全連接層nn.Linear(in_features=1024,out_features=64),nn.Linear(in_features=64, out_features=10))def forward(self,input):output=self.module(input)return output module = yyq_module() loss = nn.CrossEntropyLoss() optimizer=SGD(module.parameters(), lr=0.01) for epoch in range(10):for data in dataloader:imgs,target=dataoutput=module(imgs)result_loss=loss(output, target)# 梯度值清零optimizer.zero_grad()# 計(jì)算出新的梯度值result_loss.backward()# 優(yōu)化參數(shù)optimizer.step()print("epoch:" + str(epoch))print(result_loss)實(shí)例 基于CIFAR10數(shù)據(jù)集的卷積神經(jīng)網(wǎng)絡(luò)
- 數(shù)據(jù)集 CIFAR10
模型代碼
import torch from torch import nn from torch.nn import Sequentialclass yyq_module(nn.Module):def __init__(self):super(yyq_module, self).__init__()self.module=Sequential(nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5 , padding="same"),nn.MaxPool2d(kernel_size=2),nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding="same"),nn.MaxPool2d(kernel_size=2),nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding="same"),nn.MaxPool2d(kernel_size=2),nn.Flatten(),#隱藏層 兩個(gè)線性層 即全連接層nn.Linear(in_features=1024,out_features=64),nn.Linear(in_features=64, out_features=10))def forward(self,input):output=self.module(input)return outputif __name__ == '__main__':# 測(cè)試網(wǎng)絡(luò)module=yyq_module()input=torch.zeros((64,3,32,32))output=module(input)print(output.shape)訓(xùn)練代碼-CPU
這里目前是使用cpu進(jìn)行訓(xùn)練…
- 更新使用GPU代碼在 搭建卷積神經(jīng)網(wǎng)絡(luò) -使用GPU章節(jié)中
module.train()使用與否看模型中是否有–>官方文檔
module.train() This has any effect only on certain modules. See documentations of particular modules for details of their behaviors in training/evaluation mode, if they are affected, e.g. Dropout, BatchNorm, etc.module.eval() This has any effect only on certain modules. See documentations of particular modules for details of their behaviors in training/evaluation mode, if they are affected, e.g. Dropout, BatchNorm, etc.測(cè)試模型
實(shí)例 手寫(xiě)字母識(shí)別
圖像文件處理
import os import random''' 處理文件夾中的圖片,并自動(dòng)分類(lèi)'''# 定義訓(xùn)練集和數(shù)據(jù)集比例 # 訓(xùn)練集 0.8 # 測(cè)試集 0.2 train_ratio = 0.8 test_ratio = 1 - train_ratio# 定義文件路徑 root_path = "./data"# 定義訓(xùn)練列表 trainData_list = [] # 定義測(cè)試列表 testData_list = []# 為什么flag=-1 因?yàn)榈谝惠唂or循環(huán)獲取了root路徑下的文件夾,并沒(méi)有獲取文件 flag = -1 for root, dirs, files in os.walk(root_path):print(flag)# 每輪掃描獲得路徑和文件列表# 獲取該輪文件的長(zhǎng)度# root 也會(huì)隨之改變length = files.__len__()for i in range(0, int(length * train_ratio)):# 拼接 root路徑和文件名 加上分隔符 和標(biāo)簽值img_path = os.path.join(root, files[i]) + "\t" + str(flag) + "\n"trainData_list.append(img_path)for i in range(int(length * train_ratio), length):img_path = os.path.join(root, files[i]) + "\t" + str(flag) + "\n"testData_list.append(img_path)flag = flag + 1; print(trainData_list)# 對(duì)列表打亂次序 random.shuffle(trainData_list)with open("./res/train.txt", "w", encoding="utf-8") as f:for data in trainData_list:f.write(data)with open("./res/test.txt", "w", encoding="utf-8") as f:for data in testData_list:f.write(data)DataSetAndDataLoader
import torch from torch.utils.data import Dataset from torch.utils.data import DataLoader import torchvision.transforms as transforms from torch.utils.tensorboard import SummaryWriter from PIL import Image import numpy as np# 數(shù)據(jù)歸一化與標(biāo)準(zhǔn)化 # 圖像標(biāo)準(zhǔn)化class Mydataset(Dataset):def getImgInfo(self):imginfo = []with open(self.textpath, "r", encoding="utf-8") as f:img_str = f.readlines()# map( func , list[]) 相當(dāng)于利用function對(duì)list中每個(gè)元素進(jìn)行操作 返回值為函數(shù)結(jié)果# 這里返回的是一個(gè)列表# 參考:https://blog.csdn.net/qq_29666899/article/details/88623026# list()# lambda# list( map(lambda x: x * x, [y for y in range(3)]) )imginfo = list(map(lambda x: x.strip().split("\t"), img_str))return imginfo# 構(gòu)造器self相當(dāng)于java-this# 其引用的為全局變量def __init__(self, textpath):# 文件路徑self.textpath = textpath# 獲取圖片list(-list[data,label]----)集合self.imgInfo = self.getImgInfo()# 定義transforms# 需要輸入 PIL img -> tensor -> ..self.tf = transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=[0.5, 0.5, 0.5], # 取決于數(shù)據(jù)集std=[0.5, 0.5, 0.5])])# 獲取第 index 的 數(shù)據(jù) 標(biāo)簽def __getitem__(self, index):img_path, label = self.imgInfo[index]img = Image.open(img_path)img = img.convert('RGB')data = self.tf(img)lable = int(label)return data, labledef __len__(self):return len(self.imgInfo)if __name__ == '__main__':# 一次傳多少個(gè)照片batch_size = 10train_Dataset = Mydataset("./res/train.txt")test_Dataset = Mydataset("./res/test.txt")print(len(train_Dataset))print(len(test_Dataset))訓(xùn)練
from dataLoader import Mydataset from torch.utils.data.dataloader import DataLoader import torchvision.models as models from torch.utils.tensorboard import SummaryWriter import torch import time import osos.environ["CUDA_VISIBLE_DEVICES"] = "0" start_time = time.time() # 設(shè)備 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print("device use {}".format(device))"""構(gòu)建自己的數(shù)據(jù)集 """ batchSize = 32 # dataset trainDataSet = Mydataset(textpath="./res/train.txt") testDataSet = Mydataset(textpath="./res/test.txt") train_len = len(trainDataSet) test_len = len(testDataSet) print("訓(xùn)練集大小{}".format(train_len)) print("測(cè)試集大小{}".format(test_len))# 導(dǎo)入dataLoader trainDataLoader = DataLoader(dataset=trainDataSet, batch_size=batchSize, shuffle=True) testDataLoader = DataLoader(dataset=testDataSet, batch_size=batchSize, shuffle=True)"""創(chuàng)建網(wǎng)絡(luò)-修改vgg16網(wǎng)絡(luò) """ vgg16 = models.vgg16(pretrained=True, progress=True) # vgg16 classifier多一層全連接 1000 - 26 vgg16.classifier.add_module("7", torch.nn.Linear(in_features=1000, out_features=26, bias=True)) # GPU vgg16.to(device) print("網(wǎng)絡(luò)結(jié)構(gòu)") print(vgg16)"""定義損失函數(shù) """ lossFun = torch.nn.CrossEntropyLoss() lossFun.to(device)"""定義優(yōu)化器 """ learning_rate = 1e-2 optim = torch.optim.SGD(params=vgg16.parameters(), lr=learning_rate)"""訓(xùn)練 """ # 訓(xùn)練輪數(shù) 每一輪是對(duì)整個(gè)數(shù)據(jù)集的一次遍歷 epoch = 10 # 圖像化 指定文件夾 ./logs writer = SummaryWriter("./logs") # 總的訓(xùn)練次數(shù) total_train_num = 0 total_test_num = 0 for i in range(0, epoch):print("開(kāi)始第{}輪-epoch".format(i+1))# 定義訓(xùn)練次數(shù)total_train_step = 0total_test_step = 0# 訓(xùn)練for data in trainDataLoader:imgs, tagerts = dataimgs = imgs.to(device)tagerts = tagerts.to(device)outputs = vgg16(imgs)loss = lossFun(outputs, tagerts)# 優(yōu)化器優(yōu)化optim.zero_grad()loss.backward()optim.step()total_train_step = total_train_step + 1total_train_num = total_train_num + 1if total_train_step % 100 == 0:print("訓(xùn)練次數(shù):{}/{}, Loss:{}".format(total_train_step*batchSize, train_len, loss))writer.add_scalar("train_loss", loss, total_train_num)# 訓(xùn)練集的總損失total_test_loss = 0# 預(yù)測(cè)正確次數(shù)total_accuracy = 0# 測(cè)試# 不需要梯度 不要更新參數(shù)with torch.no_grad():for data in testDataLoader:imgs, targets = dataimgs = imgs.to(device)targets = targets.to(device)outputs = vgg16(imgs)loss = lossFun(outputs, targets)# 總損失total_test_loss = total_test_loss + loss# 計(jì)算準(zhǔn)確率accuracy = (outputs.argmax(1) == targets).sum()total_accuracy = total_accuracy + accuracy# 總測(cè)試次數(shù)total_test_num = total_test_num + 1writer.add_scalar("test_loss", loss, total_test_num)print("整體測(cè)試集上AvgLoss: {}".format(total_test_loss / len(testDataLoader)))print("整體測(cè)試集上的Accuracy: {}%".format(100 * total_accuracy / test_len))writer.add_scalar("test_accuracy", 100 * total_accuracy / test_len, i+1)end_time = time.time()print("第{}輪-epoch-用時(shí){:.2f}".format(i+1, end_time-start_time))start_time = end_timetorch.save(vgg16.state_dict(), "vgg16_dict_module_{}.pth".format(i))writer.close()測(cè)試模型
import torch import torchvision.models as models from dataLoader import Mydataset from torch.utils.data.dataloader import DataLoader from module import yyq_module"""加載數(shù)據(jù) """testDataSet = Mydataset(textpath="./res/test.txt") testDataLoader = DataLoader(dataset=testDataSet, batch_size=16, pin_memory=True) test_len = len(testDataSet)"""加載網(wǎng)絡(luò) """yyq = yyq_module()# path = "yyq_dict_module_ep4_ac93.42.pth" path = "./模型/yyq_dict_module_ep42_ac99.32.pth"yyq.load_state_dict(torch.load(path),strict=False)yyq.cuda() print(yyq)"""開(kāi)始測(cè)試 """ sum_acc = 0.0yyq.eval() with torch.no_grad():for data in testDataLoader:imgs, targets = dataimgs = imgs.cuda()targets = targets.cuda()outputs = yyq(imgs)print(outputs.argmax(1))sum=(outputs.argmax(1) == targets).sum()sum_acc = sum_acc+sum print("準(zhǔn)確率:{:.4f}%".format(sum_acc/test_len*100)) import torch import torchvision.models as models from dataLoader import Mydataset from torch.utils.data.dataloader import DataLoader"""加載數(shù)據(jù) """testDataSet = Mydataset(textpath="./res/test.txt") testDataLoader = DataLoader(dataset=testDataSet, batch_size=16, pin_memory=True) test_len = len(testDataSet)"""加載網(wǎng)絡(luò) """vgg16 = models.vgg16(pretrained=False) vgg16.classifier.add_module("7", torch.nn.Linear(in_features=1000, out_features=26, bias=True)) vgg16.load_state_dict(torch.load("vgg16_dict_module_0.pth")) vgg16.cuda() print(vgg16)"""開(kāi)始測(cè)試 """ sum_acc = 0.0 vgg16.eval() with torch.no_grad():for data in testDataLoader:imgs, targets = dataimgs = imgs.cuda()targets = targets.cuda()outputs = vgg16(imgs)sum=(outputs.argmax(1) == targets).sum()sum_acc = sum_acc+sum print("準(zhǔn)確率:{:.2f}".format(sum_acc/test_len))Bonus-1
bonus-1任務(wù)
-
任務(wù)1 -測(cè)試原先模型在該數(shù)據(jù)集的準(zhǔn)確率
-
任務(wù)2 -遷移學(xué)習(xí)- 把之前訓(xùn)練好的模型 用在bonus數(shù)據(jù)集上,接著進(jìn)行訓(xùn)練,查看訓(xùn)練后模型在bonus測(cè)試集的準(zhǔn)確率
任務(wù)一
預(yù)處理
這里不用對(duì)數(shù)據(jù)集進(jìn)行劃分,只要輸出一個(gè)文本文件包含測(cè)試所需要的全部信息就行了。
import os import random''' 處理文件夾中的圖片,并自動(dòng)分類(lèi)''' # 定義文件路徑 root_path = "./data"# 定義測(cè)試列表 testData_list = []# 為什么flag=-1 因?yàn)榈谝惠唂or循環(huán)獲取了root路徑下的文件夾,并沒(méi)有獲取文件 flag = -1 for root, dirs, files in os.walk(root_path):print(flag)# 每輪掃描獲得路徑和文件列表# 獲取該輪文件的長(zhǎng)度# root 也會(huì)隨之改變length = files.__len__()for i in range(0, length):img_path = os.path.join(root, files[i]) + "\t" + str(flag) + "\n"testData_list.append(img_path)flag = flag + 1;# 對(duì)列表打亂次序with open("./res/test.txt", "w", encoding="utf-8") as f:for data in testData_list:f.write(data)DataSetAndDataLoader
這里需要對(duì)dataSet修改,修改圖片size
import torch from torch.utils.data import Dataset from torch.utils.data import DataLoader import torchvision.transforms as transforms from torch.utils.tensorboard import SummaryWriter from PIL import Image import numpy as np# 數(shù)據(jù)歸一化與標(biāo)準(zhǔn)化 # 圖像標(biāo)準(zhǔn)化class Mydataset(Dataset):def getImgInfo(self):imginfo = []with open(self.textpath, "r", encoding="utf-8") as f:img_str = f.readlines()# map( func , list[]) 相當(dāng)于利用function對(duì)list中每個(gè)元素進(jìn)行操作 返回值為函數(shù)結(jié)果# 這里返回的是一個(gè)列表# 參考:https://blog.csdn.net/qq_29666899/article/details/88623026# list()# lambda# list( map(lambda x: x * x, [y for y in range(3)]) )imginfo = list(map(lambda x: x.strip().split("\t"), img_str))return imginfo# 構(gòu)造器self相當(dāng)于java-this# 其引用的為全局變量def __init__(self, textpath):# 文件路徑self.textpath = textpath# 獲取圖片list(-list[data,label]----)集合self.imgInfo = self.getImgInfo()# 定義transforms# 需要輸入 PIL img -> tensor -> ..self.tf = transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=[0.5, 0.5, 0.5], # 取決于數(shù)據(jù)集std=[0.5, 0.5, 0.5])])# 獲取第 index 的 數(shù)據(jù) 標(biāo)簽def __getitem__(self, index):img_path, label = self.imgInfo[index]img = Image.open(img_path)img = img.convert('RGB')data = self.tf(img)lable = int(label)return data, labledef __len__(self):return len(self.imgInfo)if __name__ == '__main__':test_Dataset = Mydataset("./res/test.txt")print(len(test_Dataset))測(cè)試模型準(zhǔn)確率
找不到代碼了 簡(jiǎn)述:1 加載數(shù)據(jù)集2 加載模型3 跑模型,并統(tǒng)計(jì)正確率4 輸出正確率任務(wù)二
與上面源數(shù)據(jù)集c處理方式雷同不在贅述
Bonus-2
目標(biāo): 利用半監(jiān)督學(xué)習(xí),聯(lián)合源數(shù)據(jù)集和bonus數(shù)據(jù)集,訓(xùn)練一個(gè)新的模型
step 1:利用源數(shù)據(jù)集訓(xùn)練的模型,得到bonus數(shù)據(jù)集的標(biāo)簽
step 2: 聯(lián)合兩個(gè)數(shù)據(jù)集,重新訓(xùn)練模型
step-1 數(shù)據(jù)預(yù)處理
預(yù)處理,獲取所有圖片位置信息,但是假設(shè)label = -1
import os import random''' 處理文件夾中的圖片,這里假設(shè)標(biāo)簽都是-1 創(chuàng)建未標(biāo)記數(shù)據(jù)集'''# 定義文件路徑 root_path = "../data"# 定義測(cè)試列表 testData_list = []# 為什么flag=-1 因?yàn)槟壳安恢纋abel值 flag = -1 for root, dirs, files in os.walk(root_path):print(flag)# 每輪掃描獲得路徑和文件列表# 獲取該輪文件的長(zhǎng)度# root 也會(huì)隨之改變length = files.__len__()for i in range(0, length):img_path = os.path.join(root, files[i]) + "\t" + str(flag) + "\n"testData_list.append(img_path)# 對(duì)列表打亂次序with open("res/alldata.txt", "w", encoding="utf-8") as f:for data in testData_list:f.write(data)獲取數(shù)據(jù),利用源數(shù)據(jù)集訓(xùn)練的模型獲取bonus數(shù)據(jù)集的標(biāo)簽, 并按比例劃分為訓(xùn)練集和測(cè)試集
import torchvision.models as models import torch from torch.utils.data import DataLoader from dataSet import Mydataset from module import yyq_module import random device = torch.device("cuda" if torch.cuda.is_available() else "cpu") """通過(guò)半監(jiān)督學(xué)習(xí)獲取未標(biāo)記的數(shù)據(jù)input : bounsdataoutput : img_path - label """ train_ratio =0.8 test_ratio = 1 - train_ratio train_imgInfoList = [] test_imgInfoList = []dataList = [] """ step 1 : 讀取數(shù)據(jù) """ batch_size = 32 textpath = "./res/alldata.txt" allDataset = Mydataset(textpath=textpath) allDataLoader = DataLoader(dataset=allDataset, batch_size=batch_size , pin_memory=True) dataLength = len(allDataset) print("數(shù)據(jù)集長(zhǎng)度{}".format(dataLength))""" step 2 : 讀取模型 """ module_path = "../yyq_dict_module_ep47_ac99.39.pth" yyq = yyq_module() yyq.load_state_dict(torch.load(module_path)) yyq.to(device) print("模型結(jié)構(gòu)") print(yyq)""" step 3 : 讀取數(shù)據(jù),并且創(chuàng)建新文件 輸出文件的標(biāo)簽值 """ yyq.eval() with torch.no_grad():for data in allDataLoader:imgs , img_paths = dataimgs = imgs.to(device)outputs = yyq(imgs)targets = outputs.argmax(1)lenth = len(targets)for i in range(0,lenth):imgInfo = img_paths[i] + "\t" + str(targets[i].item()) + "\n"dataList.append(imgInfo) length = len(dataList) print("datalist長(zhǎng)度:{}".format(length)) random.shuffle(dataList) for i in range(0, int( length * train_ratio)):train_imgInfoList.append(dataList[i]) for i in range(int( length * train_ratio), length):test_imgInfoList.append(dataList[i])print(train_imgInfoList[0]) print(test_imgInfoList[0]) with open("DealRes/train.txt", "w", encoding="utf-8") as f:for data in train_imgInfoList:f.write(data) with open("DealRes/test.txt", "w", encoding="utf-8") as f:for data in test_imgInfoList:f.write(data)創(chuàng)建dataset,這里的dataset有所不同,他要獲取 源數(shù)據(jù)集的train.txt和bonus數(shù)據(jù)集的train.txt
對(duì)兩者進(jìn)行加和。
import torch from torch.utils.data import Dataset from torch.utils.data import DataLoader import torchvision.transforms as transforms from torch.utils.tensorboard import SummaryWriter from PIL import Image import numpy as np"""這里對(duì)數(shù)據(jù)處理:transforms.Resize((128,128)),transforms.ToTensor(), """class Mydataset(Dataset):def getImgInfo(self):imginfo = []with open(self.textpath, "r", encoding="utf-8") as f:img_str = f.readlines()# map( func , list[]) 相當(dāng)于利用function對(duì)list中每個(gè)元素進(jìn)行操作 返回值為函數(shù)結(jié)果# 這里返回的是一個(gè)列表# 參考:https://blog.csdn.net/qq_29666899/article/details/88623026# list()# lambda# list( map(lambda x: x * x, [y for y in range(3)]) )imginfo = list(map(lambda x: x.strip().split("\t"), img_str))return imginfo# 構(gòu)造器self相當(dāng)于java-this# 其引用的為全局變量def __init__(self, textpath):# 文件路徑self.textpath = textpath# 獲取圖片list(-list[data,label]----)集合self.imgInfo = self.getImgInfo()# 定義transforms# 需要輸入 PIL img -> tensor -> ..self.tf = transforms.Compose([transforms.Resize((128,128)),transforms.ToTensor(),transforms.Normalize(mean=[0.5, 0.5, 0.5], # 取決于數(shù)據(jù)集std=[0.5, 0.5, 0.5])])# 獲取第 index 的 數(shù)據(jù) 標(biāo)簽def __getitem__(self, index):img_path, label = self.imgInfo[index]img = Image.open(img_path)img = img.convert('RGB')data = self.tf(img)lable = int(label)return data, img_pathdef __len__(self):return len(self.imgInfo)if __name__ == '__main__':test_Dataset = Mydataset("./res/alldata.txt")print(test_Dataset[0])到這里對(duì)數(shù)據(jù)預(yù)處理已經(jīng)結(jié)束。
step -2 訓(xùn)練模型
大同小異不在贅述
import torch from torch.utils.data import Dataset from torch.utils.data import DataLoader import torchvision.transforms as transforms from torch.utils.tensorboard import SummaryWriter from PIL import Image import numpy as np from torch.utils.data.dataloader import DataLoader import torchvision.models as models from torch.utils.tensorboard import SummaryWriter import torch import time import os from module import yyq_module"""這里對(duì)數(shù)據(jù)處理:transforms.Resize((128,128)),transforms.ToTensor(), """class Mydataset(Dataset):def getImgInfo(self):imginfo = []with open(self.textpath, "r", encoding="utf-8") as f:img_str = f.readlines()# map( func , list[]) 相當(dāng)于利用function對(duì)list中每個(gè)元素進(jìn)行操作 返回值為函數(shù)結(jié)果# 這里返回的是一個(gè)列表# 參考:https://blog.csdn.net/qq_29666899/article/details/88623026# list()# lambda# list( map(lambda x: x * x, [y for y in range(3)]) )imginfo = list(map(lambda x: x.strip().split("\t"), img_str))with open(self.dealedTextPath, "r", encoding="utf-8") as f:img_str = f.readlines()for str in img_str:img=str.split("\t")imginfo.append(img)return imginfo# 構(gòu)造器self相當(dāng)于java-this# 其引用的為全局變量def __init__(self, dealedTextPath, textpath):# 文件路徑self.dealedTextPath = dealedTextPathself.textpath = textpath# 獲取圖片list(-list[data,label]----)集合self.imgInfo = self.getImgInfo()# 定義transforms# 需要輸入 PIL img -> tensor -> ..self.tf = transforms.Compose([transforms.Resize((128,128)),transforms.ToTensor(),transforms.Normalize(mean=[0.5, 0.5, 0.5], # 取決于數(shù)據(jù)集std=[0.5, 0.5, 0.5])])# 獲取第 index 的 數(shù)據(jù) 標(biāo)簽def __getitem__(self, index):img_path, label = self.imgInfo[index]img = Image.open(img_path)img = img.convert('RGB')data = self.tf(img)lable = int(label)return data, labledef __len__(self):return len(self.imgInfo)"""訓(xùn)練模型 """if __name__ == '__main__':os.environ["CUDA_VISIBLE_DEVICES"] = "0"start_time = time.time()# 設(shè)備device = torch.device("cuda" if torch.cuda.is_available() else "cpu")print("device use {}".format(device))"""構(gòu)建自己的數(shù)據(jù)集"""batchSize = 32# datasettrainDataSet = Mydataset("./DealRes/train.txt","./project2/res/train.txt")testDataSet = Mydataset("./DealRes/test.txt","./project2/res/test.txt")train_len = len(trainDataSet)test_len = len(testDataSet)print("訓(xùn)練集大小{}".format(train_len))print("測(cè)試集大小{}".format(test_len))# 導(dǎo)入dataLoadertrainDataLoader = DataLoader(dataset=trainDataSet, batch_size=batchSize, shuffle=True)testDataLoader = DataLoader(dataset=testDataSet, batch_size=batchSize, shuffle=True)"""創(chuàng)建網(wǎng)絡(luò)-修改yyq網(wǎng)絡(luò)"""yyq = yyq_module()# GPUyyq.to(device)print("網(wǎng)絡(luò)結(jié)構(gòu)")print(yyq)"""定義損失函數(shù)"""lossFun = torch.nn.CrossEntropyLoss()lossFun.to(device)"""定義優(yōu)化器"""learning_rate = 1e-2optim = torch.optim.SGD(params=yyq.parameters(), lr=learning_rate)"""訓(xùn)練"""# 訓(xùn)練輪數(shù) 每一輪是對(duì)整個(gè)數(shù)據(jù)集的一次遍歷epoch = 50# 圖像化 指定文件夾 ./logswriter = SummaryWriter("./logs")# 總的訓(xùn)練次數(shù)total_train_num = 0total_test_num = 0for i in range(0, epoch):print("開(kāi)始第{}輪-epoch".format(i + 1))# 定義訓(xùn)練次數(shù)total_train_step = 0total_test_step = 0# 訓(xùn)練yyq.train()for data in trainDataLoader:imgs, tagerts = dataimgs = imgs.to(device)tagerts = tagerts.to(device)outputs = yyq(imgs)loss = lossFun(outputs, tagerts)# 優(yōu)化器優(yōu)化optim.zero_grad()loss.backward()optim.step()total_train_step = total_train_step + 1total_train_num = total_train_num + 1if total_train_step % 100 == 0:print("訓(xùn)練次數(shù):{}/{}, Loss:{}".format(total_train_step * batchSize, train_len, loss))writer.add_scalar("train_loss", loss, total_train_num)# 訓(xùn)練集的總損失total_test_loss = 0# 預(yù)測(cè)正確次數(shù)total_accuracy = 0# 測(cè)試# 不需要梯度 不要更新參數(shù)yyq.eval()with torch.no_grad():for data in testDataLoader:imgs, targets = dataimgs = imgs.to(device)targets = targets.to(device)outputs = yyq(imgs)loss = lossFun(outputs, targets)# 總損失total_test_loss = total_test_loss + loss# 計(jì)算準(zhǔn)確率accuracy = (outputs.argmax(1) == targets).sum()total_accuracy = total_accuracy + accuracy# 總測(cè)試次數(shù)total_test_num = total_test_num + 1writer.add_scalar("test_loss", loss, total_test_num)print("整體測(cè)試集上AvgLoss: {}".format(total_test_loss / len(testDataLoader)))print("整體測(cè)試集上的Accuracy: {}%".format(100 * total_accuracy / test_len))writer.add_scalar("test_accuracy", 100 * total_accuracy / test_len, i + 1)end_time = time.time()print("第{}輪-epoch-用時(shí){:.2f}".format(i + 1, end_time - start_time))start_time = end_time# if (100 * total_accuracy / test_len)>99:# torch.save(yyq.state_dict(),# "yyq_dict_module_ep{}_ac{:.2f}.pth".format(i, (100 * total_accuracy / test_len)))writer.close()學(xué)習(xí)資料
最后附上一些可供學(xué)習(xí)的資料,強(qiáng)烈推薦土堆B站視頻!
1.PyTorch 深度學(xué)習(xí):60分鐘快速入門(mén)(官網(wǎng)翻譯)
“PyTorch 深度學(xué)習(xí):60分鐘快速入門(mén)”為PyTorch官網(wǎng)教程,網(wǎng)上已經(jīng)有部分翻譯作品,隨著PyTorch1.0版本的公布,這個(gè)教程有較大的代碼改動(dòng),本人對(duì)教程進(jìn)行重新翻譯,并測(cè)試運(yùn)行了官方代碼,制作成Jupyter Notebook文件(中文注釋)在github予以公布。
本文內(nèi)容較多,可以在線學(xué)習(xí),如果需要本地調(diào)試,請(qǐng)到github下載:
https://github.com/fengdu78/Data-Science-Notes/tree/master/8.deep-learning/PyTorch_beginner
此教程為翻譯官方地址:
https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html
**作者:**Soumith Chintala
本教程的目標(biāo):
2.土堆github
https://github.com/xiaotudui/pytorch-tutorial/tree/master/src
3.PyTorch 中文手冊(cè)(pytorch handbook)(github標(biāo)星7900+)
資源地址:
https://github.com/zergtant/pytorch-handbook
這是一本開(kāi)源的書(shū)籍,目標(biāo)是幫助那些希望和使用PyTorch進(jìn)行深度學(xué)習(xí)開(kāi)發(fā)和研究的朋友快速入門(mén)。我試了一下里面的ipynb代碼,非常全面,值得推薦。
資源目錄:
第一章 :PyTorch入門(mén)
第一節(jié) PyTorch 簡(jiǎn)介
第二節(jié) PyTorch 環(huán)境搭建
第三節(jié) PyTorch 深度學(xué)習(xí):60分鐘快速入門(mén)(官方)
張量
Autograd:自動(dòng)求導(dǎo)
神經(jīng)網(wǎng)絡(luò)
訓(xùn)練一個(gè)分類(lèi)器
選讀:數(shù)據(jù)并行處理(多GPU)
4.相關(guān)資源介紹
第二章 : 基礎(chǔ)
第一節(jié) PyTorch 基礎(chǔ)
張量自動(dòng)求導(dǎo)神經(jīng)網(wǎng)絡(luò)包nn和優(yōu)化器optm數(shù)據(jù)的加載和預(yù)處理
第二節(jié) 深度學(xué)習(xí)基礎(chǔ)及數(shù)學(xué)原理
深度學(xué)習(xí)基礎(chǔ)及數(shù)學(xué)原理
第三節(jié) 神經(jīng)網(wǎng)絡(luò)簡(jiǎn)介
神經(jīng)網(wǎng)絡(luò)簡(jiǎn)介
第四節(jié) 卷積神經(jīng)網(wǎng)絡(luò)
卷積神經(jīng)網(wǎng)絡(luò)
第五節(jié) 循環(huán)神經(jīng)網(wǎng)絡(luò)
循環(huán)神經(jīng)網(wǎng)絡(luò)
第三章 : 實(shí)踐
第一節(jié) logistic回歸
logistic回歸二元分類(lèi)
第二節(jié) CNN:MNIST數(shù)據(jù)集手寫(xiě)數(shù)字識(shí)別
CNN:MNIST數(shù)據(jù)集手寫(xiě)數(shù)字識(shí)別
第三節(jié) RNN實(shí)例:通過(guò)Sin預(yù)測(cè)Cos
RNN實(shí)例:通過(guò)Sin預(yù)測(cè)Cos
第四章 : 提高
第一節(jié) Fine-tuning
Fine-tuning
第二節(jié) 可視化
visdomtensorboardx可視化理解卷積神經(jīng)網(wǎng)絡(luò)
第三節(jié) Fast.ai
Fast.ai
第五節(jié) 多GPU并行訓(xùn)練
多GPU并行計(jì)算
第五章 : 應(yīng)用
第一節(jié) Kaggle介紹
Kaggle介紹
第二節(jié) 結(jié)構(gòu)化數(shù)據(jù)
第三節(jié) 計(jì)算機(jī)視覺(jué)
第四節(jié) 自然語(yǔ)言處理
4.Pytorch教程(github標(biāo)星13600+)
資源地址:
https://github.com/yunjey/pytorch-tutorial
資源介紹:
這個(gè)資源為深度學(xué)習(xí)研究人員提供了學(xué)習(xí)PyTorch的教程代碼大多數(shù)模型都使用少于30行代碼實(shí)現(xiàn)。在開(kāi)始本教程之前,建議先看完P(guān)ytorch官方教程。(大部分教程是PyTorch0.4實(shí)現(xiàn)的,代碼與1.0+稍微有點(diǎn)不同,總體影響不大)
配置環(huán)境:
python 2.7或者3.5以上,pytorch 0.4
資源目錄:
1.基礎(chǔ)知識(shí)
- PyTorch基礎(chǔ)知識(shí)
- 線性回歸
- Logistic回歸
- 前饋神經(jīng)網(wǎng)絡(luò)
2.中級(jí)
- 卷積神經(jīng)網(wǎng)絡(luò)
- 深度殘差網(wǎng)絡(luò)
- 遞歸神經(jīng)網(wǎng)絡(luò)
- 雙向遞歸神經(jīng)網(wǎng)絡(luò)
- 語(yǔ)言模型(RNN-LM)
3.高級(jí)
- 生成性對(duì)抗網(wǎng)絡(luò)
- 變分自動(dòng)編碼器
- 神經(jīng)風(fēng)格轉(zhuǎn)移
- 圖像字幕(CNN-RNN)
4.工具
- PyTorch中的TensorBoard
總結(jié)
以上是生活随笔為你收集整理的从零开始pytorch手写字母识别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: html-盒子模型及pading和mar
- 下一篇: nuget下载太慢的问题解决方案 多次尝