目錄
前言
一、Cifar10數(shù)據(jù)集
class torch.utils.data.Dataset
?torch.utils.data.DataLoader
二、定義神經(jīng)網(wǎng)絡(luò)
普通神經(jīng)網(wǎng)絡(luò):
定義損失函數(shù)和優(yōu)化器
?訓(xùn)練網(wǎng)絡(luò)-Net
CPU訓(xùn)練
模型準(zhǔn)確率
?編輯
GPU訓(xùn)練
訓(xùn)練網(wǎng)絡(luò)-LeNet
模型準(zhǔn)確率
點(diǎn)關(guān)注,防走丟,如有紕漏之處,請(qǐng)留言指教,非常感謝
前言
PyTorch可以說(shuō)是三大主流框架中最適合初學(xué)者學(xué)習(xí)的了,相較于其他主流框架,PyTorch的簡(jiǎn)單易用性使其成為初學(xué)者們的首選。這樣我想要強(qiáng)調(diào)的一點(diǎn)是,框架可以類比為編程語(yǔ)言,僅為我們實(shí)現(xiàn)項(xiàng)目效果的工具,也就是我們?cè)燔囀褂玫妮喿?,我們重點(diǎn)需要的是理解如何使用Torch去實(shí)現(xiàn)功能而不要過(guò)度在意輪子是要怎么做出來(lái)的,那樣會(huì)牽扯我們太多學(xué)習(xí)時(shí)間。以后就出一系列專門細(xì)解深度學(xué)習(xí)框架的文章,但是那是較后期我們對(duì)深度學(xué)習(xí)的理論知識(shí)和實(shí)踐操作都比較熟悉才好開(kāi)始學(xué)習(xí),現(xiàn)階段我們最需要的是學(xué)會(huì)如何使用這些工具。
深度學(xué)習(xí)的內(nèi)容不是那么好掌握的,包含大量的數(shù)學(xué)理論知識(shí)以及大量的計(jì)算公式原理需要推理。且如果不進(jìn)行實(shí)際操作很難夠理解我們寫的代碼究極在神經(jīng)網(wǎng)絡(luò)計(jì)算框架中代表什么作用。不過(guò)我會(huì)盡可能將知識(shí)簡(jiǎn)化,轉(zhuǎn)換為我們比較熟悉的內(nèi)容,我將盡力讓大家了解并熟悉神經(jīng)網(wǎng)絡(luò)框架,保證能夠理解通暢以及推演順利的條件之下,盡量不使用過(guò)多的數(shù)學(xué)公式和專業(yè)理論知識(shí)。以一篇文章快速了解并實(shí)現(xiàn)該算法,以效率最高的方式熟練這些知識(shí)。
博主專注數(shù)據(jù)建模四年,參與過(guò)大大小小數(shù)十來(lái)次數(shù)學(xué)建模,理解各類模型原理以及每種模型的建模流程和各類題目分析方法。此專欄的目的就是為了讓零基礎(chǔ)快速使用各類數(shù)學(xué)模型、機(jī)器學(xué)習(xí)和深度學(xué)習(xí)以及代碼,每一篇文章都包含實(shí)戰(zhàn)項(xiàng)目以及可運(yùn)行代碼。博主緊跟各類數(shù)模比賽,每場(chǎng)數(shù)模競(jìng)賽博主都會(huì)將最新的思路和代碼寫進(jìn)此專欄以及詳細(xì)思路和完全代碼。希望有需求的小伙伴不要錯(cuò)過(guò)筆者精心打造的專欄:一文速學(xué)-數(shù)學(xué)建模常用模型
一、Cifar10數(shù)據(jù)集
CIFAR-10是一個(gè)廣泛用于測(cè)試和驗(yàn)證圖像分類算法的基準(zhǔn)數(shù)據(jù)集之一,因其相對(duì)較小的規(guī)模和豐富的多樣性而備受研究者關(guān)注。在深度學(xué)習(xí)領(lǐng)域,許多研究和論文都會(huì)以CIFAR-10作為測(cè)試數(shù)據(jù)集,以評(píng)估他們的模型性能。這些類別分別是:
- 飛機(jī)(airplane)
- 汽車(automobile)
- 鳥(niǎo)類(bird)
- 貓(cat)
- 鹿(deer)
- 狗(dog)
- 青蛙(frog)
- 馬(horse)
- 船(ship)
- 卡車(truck)
數(shù)據(jù)集被分為訓(xùn)練集和測(cè)試集,其中訓(xùn)練集包含50,000張圖片,測(cè)試集包含10,000張圖片。每張圖片都是,也即3-通道彩色圖片,分辨率為。此外,還有一個(gè)CIFAR-100的數(shù)據(jù)集,由于CIFAR-10和CIFAR-100除了分類類別數(shù)不一樣外,其他差別不大,此處僅拿CIFAR-10這個(gè)相對(duì)小點(diǎn)的數(shù)據(jù)集來(lái)進(jìn)行介紹,介紹用pytorch來(lái)進(jìn)行圖像分類的一般思路和方法。
官方下載網(wǎng)址:CIFAR-10 and CIFAR-100 datasets
使用torch.utils.data加載數(shù)據(jù):
import numpy as np
import torch
import torchvision.transforms as transforms
import os
from torch.utils.data import DataLoader
from torchvision.transforms import ToPILImage
show = ToPILImage() # 可以把Tensor轉(zhuǎn)成Image,方便可視化
import torchvision.datasets as dsets
batch_size = 100
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
# 定義對(duì)數(shù)據(jù)的預(yù)處理
transform = transforms.Compose([
transforms.ToTensor(), # 轉(zhuǎn)為Tensor
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), # 歸一化 先將輸入歸一化到(0,1),再使用公式”(x-mean)/std”,將每個(gè)元素分布到(-1,1)
])
#Cifar110 dataset
train_dataset = dsets.CIFAR10(root='/ml/pycifar',
train = True,
download = True,
transform=transform
)
test_dataset = dsets.CIFAR10(root='/ml/pycifar',
train = False,
download = True,
transform=transform
)
#加載數(shù)據(jù)
train_loader=torch.utils.data.DataLoader(dataset=train_dataset,
batch_size = batch_size,
shuffle = True
)
test_loader = torch.utils.data.DataLoader(dataset = test_dataset,
batch_size=batch_size,
shuffle=True
)
數(shù)據(jù)展示:
import matplotlib.pyplot as plt
fig = plt.figure()
classes=['plane','car','bird','cat','deer','dog','frog','horse','ship','truck']
for i in range(12):
plt.subplot(3, 4, i+1)
plt.tight_layout()
(_, label) = train_dataset[i]
plt.imshow(train_loader.dataset.data[i],cmap=plt.cm.binary)
plt.title("Labels: {}".format(classes[label]))
plt.xticks([])
plt.yticks([])
plt.show()
?
?數(shù)據(jù)集分為五個(gè)訓(xùn)練批次和一個(gè)測(cè)試批次,每個(gè)批次有10000張圖像。測(cè)試批次包含從每個(gè)類別中隨機(jī)選擇的1000幅圖像。訓(xùn)練批包含隨機(jī)順序的剩余圖像,但一些訓(xùn)練批可能包含一個(gè)類中的圖像多于另一個(gè)類的圖像。在它們之間,訓(xùn)練批次包含每個(gè)類別的正好5000個(gè)圖像。
數(shù)據(jù)集我們已經(jīng)導(dǎo)入成功,需要說(shuō)明的是我們之前已經(jīng)對(duì)數(shù)據(jù)進(jìn)行了預(yù)處理,并使數(shù)據(jù)歸一化,補(bǔ)充一下兩個(gè)需要了解的數(shù)據(jù)加載基類Dataset和DataLoader:
class torch.utils.data.Dataset
PyTorch的Dataset
是一個(gè)抽象類,用于表示數(shù)據(jù)集。它允許你自定義數(shù)據(jù)集的加載方式,以便于在訓(xùn)練和測(cè)試過(guò)程中使用。
-
數(shù)據(jù)加載與預(yù)處理:
Dataset
允許你自定義數(shù)據(jù)的加載方式,可以從文件、數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)等來(lái)源加載數(shù)據(jù)。你可以在__getitem__
方法中實(shí)現(xiàn)數(shù)據(jù)的預(yù)處理、轉(zhuǎn)換等操作,以滿足模型的輸入要求。 -
支持索引: 通過(guò)實(shí)現(xiàn)
__getitem__
方法,Dataset
可以通過(guò)索引(如dataset[i]
)獲取數(shù)據(jù)樣本。這允許你按需讀取數(shù)據(jù),適用于大規(guī)模數(shù)據(jù)集,避免一次性加載所有數(shù)據(jù)。 -
返回樣本總數(shù):
len(dataset)
返回?cái)?shù)據(jù)集中樣本的總數(shù),便于在訓(xùn)練過(guò)程中設(shè)置合適的迭代次數(shù)。 -
可迭代:
Dataset
可以像Python列表一樣進(jìn)行迭代,這意味著你可以在數(shù)據(jù)集上使用for
循環(huán)。 -
與DataLoader結(jié)合使用:
Dataset
通常與PyTorch的DataLoader
一起使用,DataLoader
可以將數(shù)據(jù)批量加載到模型中,實(shí)現(xiàn)了數(shù)據(jù)的批處理。 -
實(shí)現(xiàn)自定義數(shù)據(jù)集: 你可以繼承
Dataset
類,根據(jù)自己的需求創(chuàng)建自定義的數(shù)據(jù)集。
可以重構(gòu)為:
from torch.utils.data import Dataset
class CustomDataset(Dataset):
def __init__(self, data):
self.data = data
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
sample = self.data[idx]
# 這里可以進(jìn)行數(shù)據(jù)預(yù)處理或轉(zhuǎn)換
return sample
# 使用示例
data = [1, 2, 3, 4, 5]
custom_dataset = CustomDataset(data)
print(len(custom_dataset)) # 輸出: 5
print(custom_dataset[2]) # 輸出: 3
?torch.utils.data.DataLoader
?torch.utils.data.DataLoader比較復(fù)雜一點(diǎn),torch提供了很多參數(shù)可以用,常用的參數(shù)需要掌握:
-
dataset (Dataset): 要加載的數(shù)據(jù)集。通常是一個(gè)繼承自
torch.utils.data.Dataset
的自定義數(shù)據(jù)集對(duì)象。 -
batch_size (int, optional): 每個(gè)批次的樣本數(shù)量。默認(rèn)值為 1。
-
shuffle (bool, optional): 是否在每個(gè) epoch 開(kāi)始時(shí)隨機(jī)打亂數(shù)據(jù)。默認(rèn)值為 False。
-
sampler (Sampler, optional): 定義從數(shù)據(jù)集中采樣樣本的策略。如果指定了此參數(shù),
shuffle
參數(shù)將被忽略。 -
batch_sampler (Sampler, optional): 與
sampler
相似,但返回的是一個(gè) batch 的索引列表。 -
num_workers (int, optional): 用于數(shù)據(jù)加載的子進(jìn)程數(shù)量。默認(rèn)值為 0,表示所有數(shù)據(jù)將在主進(jìn)程中加載。設(shè)置為大于 0 的值將啟動(dòng)相應(yīng)數(shù)量的子進(jìn)程來(lái)加載數(shù)據(jù),可以加速數(shù)據(jù)加載。
-
collate_fn (callable, optional): 用于將一個(gè)個(gè)樣本打包成一個(gè) batch 的函數(shù)。通常在輸入數(shù)據(jù)具有不同大小時(shí)使用。
-
pin_memory (bool, optional): 如果為 True,則數(shù)據(jù)加載器會(huì)將數(shù)據(jù)存儲(chǔ)在 CUDA 固定內(nèi)存中,可以加速數(shù)據(jù)傳輸?shù)?GPU。默認(rèn)值為 False。
-
drop_last (bool, optional): 如果為 True,則在最后一個(gè) batch 的大小小于
batch_size
時(shí),該 batch 將被丟棄。默認(rèn)值為 False。 -
timeout (numeric, optional): 在等待新數(shù)據(jù)時(shí)的超時(shí)時(shí)間(以秒為單位)。如果設(shè)置為 None,則會(huì)一直等待,直到數(shù)據(jù)準(zhǔn)備好。默認(rèn)值為 0。
-
worker_init_fn (callable, optional): 每個(gè) worker 在開(kāi)始加載數(shù)據(jù)之前會(huì)調(diào)用此函數(shù)??梢杂糜谠?worker 中初始化一些特定的設(shè)置。
這些參數(shù)可以根據(jù)實(shí)際情況來(lái)調(diào)整,以滿足數(shù)據(jù)集和模型訓(xùn)練的需求。例如,可以根據(jù)數(shù)據(jù)集大小、模型結(jié)構(gòu)等來(lái)設(shè)置 batch_size
、num_workers
等參數(shù),以獲得最佳的訓(xùn)練性能。
二、定義神經(jīng)網(wǎng)絡(luò)
我們可以用兩種網(wǎng)絡(luò)來(lái)對(duì)比其分類能力,一種是普通Net網(wǎng)絡(luò),另外用LeNet卷積網(wǎng)絡(luò)來(lái)對(duì)比:
普通神經(jīng)網(wǎng)絡(luò):
import torch.nn as nn
import torch
input_size = 3072 #3*32*32
hidden_size1 = 500 #第一次隱藏層個(gè)數(shù)
hidden_size2 = 200 #第二次隱藏層個(gè)數(shù)
num_classes = 10 #分類個(gè)數(shù)
num_epochs = 5 #批次次數(shù)
batch_size = 100 #批次大小
learning_rate =1e-3
#定義兩層神經(jīng)網(wǎng)絡(luò)
class Net(nn.Module):
def __init__(self,input_size,hidden_size1,hidden_size2,num_classes):
super(Net,self).__init__()
self.layer1 = nn.Linear(input_size,hidden_size1)#輸入
self.layer2 = nn.Linear(hidden_size1,hidden_size2)#兩層隱藏層計(jì)算
self.layer3 = nn.Linear(hidden_size2,num_classes)#輸出
def forward(self,x):
out = torch.relu(self.layer1(x)) #隱藏層1
out = torch.relu(self.layer2(out)) #隱藏層2
out = self.layer3(out)
return out
net =Net(input_size,hidden_size1,hidden_size2,num_classes)
Net( (layer1): Linear(in_features=3072, out_features=500, bias=True) (layer2): Linear(in_features=500, out_features=200, bias=True) (layer3): Linear(in_features=200, out_features=10, bias=True) )
定義損失函數(shù)和優(yōu)化器
from torch import optim
criterion = nn.CrossEntropyLoss() # 交叉熵?fù)p失函數(shù)
optimizer = optim.SGD(net.parameters(), lr=learning_rate)
?訓(xùn)練網(wǎng)絡(luò)-Net
神經(jīng)網(wǎng)絡(luò)的訓(xùn)練流程基本都是類似的:
- 輸入數(shù)據(jù)
- 前向傳播+反向傳播
- 更新參數(shù)
CPU訓(xùn)練
Pytorch是默認(rèn)在 CPU 上運(yùn)行:
batch_size = 1000 #批次大小
for epoch in range(num_epochs):
print('current epoch + %d' % epoch)
running_loss = 0.0
for i ,(images,labels) in enumerate(train_loader,0):
images=images.view(images.size(0),-1)
labels = torch.tensor(labels, dtype=torch.long)
# 梯度清零
optimizer.zero_grad()
outputs = net(images) #將數(shù)據(jù)集傳入網(wǎng)絡(luò)做前向計(jì)算
loss = criterion(outputs ,labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 1000 == 0: # 每1000個(gè)batch打印一下訓(xùn)練狀態(tài)
print('[%d, %5d] loss: %.3f' \
% (epoch+1, i+1, running_loss))
running_loss = 0.0
print('Finished Training')
current epoch + 0 [1, 0] loss: 2.149 current epoch + 1 [2, 0] loss: 2.025 current epoch + 2 [3, 0] loss: 1.987 current epoch + 3 [4, 0] loss: 2.020 current epoch + 4 [5, 0] loss: 1.970 Finished Training
模型準(zhǔn)確率
#prediction
total = 0
correct =0
acc_list_test = []
for images,labels in test_loader:
images=images.view(images.size(0),-1)
outputs = net(images) #將數(shù)據(jù)集傳入網(wǎng)絡(luò)做前向計(jì)算
_,predicts = torch.max(outputs.data,1)
total += labels.size(0)
correct += (predicts == labels).sum()
acc_list_test.append(100 * correct / total)
print('Accuracy = %.2f'%(100 * correct / total))
plt.plot(acc_list_test)
plt.xlabel('Epoch')
plt.ylabel('Accuracy On TestSet')
plt.show()
準(zhǔn)確率只有33.06%,實(shí)際上一張圖片直接給我們?nèi)藖?lái)猜的話有10%概率猜對(duì),所以這樣看來(lái)神經(jīng)網(wǎng)絡(luò)還是可以有所提升的,那我們?cè)僭囋嚲矸e網(wǎng)絡(luò)看看。
GPU訓(xùn)練
使用GPU訓(xùn)練只需要將torch的驅(qū)動(dòng)device切換為GPU,且將顯式地將張量(Tensors)和模型(Models)移動(dòng)到 GPU 上就可:
batch_size = 1000 #批次大小
net_gpu =Net(input_size,hidden_size1,hidden_size2,num_classes)
net_gpu.cuda()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
for epoch in range(num_epochs):
print('current epoch + %d' % epoch)
running_loss = 0.0
for i ,(images,labels) in enumerate(train_loader,0):
images = images.to(device)
labels = labels.to(device)
images=images.view(images.size(0),-1)
labels = torch.tensor(labels, dtype=torch.long)
# 梯度清零
optimizer.zero_grad()
outputs = net_gpu(images) #將數(shù)據(jù)集傳入網(wǎng)絡(luò)做前向計(jì)算
loss = criterion(outputs ,labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 1000 == 0: # 每2000個(gè)batch打印一下訓(xùn)練狀態(tài)
print('[%d, %5d] loss: %.3f' \
% (epoch+1, i, running_loss ))
running_loss = 0.0
print('Finished Training')
效果是一樣的,這里不再繼續(xù)復(fù)寫。
訓(xùn)練網(wǎng)絡(luò)-LeNet
我們?cè)賮?lái)訓(xùn)練一個(gè)卷積網(wǎng)絡(luò)再來(lái)看看效果,可能這里講述卷積網(wǎng)絡(luò)有點(diǎn)跳躍,之后我會(huì)詳細(xì)講述卷積神經(jīng)網(wǎng)絡(luò)的全部?jī)?nèi)容,這里大家只需要知道每個(gè)網(wǎng)絡(luò)的性能是不同的。
import torch.nn as nn
import torch.nn.functional as F
input_size = 3072 #3*32*32
hidden_size1 = 500 #第一次隱藏層個(gè)數(shù)
hidden_size2 = 200 #第二次隱藏層個(gè)數(shù)
num_classes = 10 #分類個(gè)數(shù)
num_epochs = 5 #批次次數(shù)
batch_size = 100 #批次大小
learning_rate =1e-3
class LeNet(nn.Module):
def __init__(self,input_size,hidden_size1,hidden_size2,num_classes):
super(LeNet, self).__init__()
# 卷積層 '1'表示輸入圖片為單通道, '6'表示輸出通道數(shù),'5'表示卷積核為5*5
self.conv1=nn.Conv2d(3,6,5)
# 卷積層
self.conv2 = nn.Conv2d(6, 16, 5)
# 仿射層/全連接層,y = Wx + b
self.fc1 = nn.Linear(input_size, hidden_size1)
self.fc2 = nn.Linear(hidden_size1, hidden_size2)
self.fc3 = nn.Linear(hidden_size2, num_classes)
def forward(self,x):
# 卷積 -> 激活 -> 池化
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
# reshape,‘-1’表示自適應(yīng)
x = x.view(x.size()[0], -1)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net =LeNet(input_size,hidden_size1,hidden_size2,num_classes)
LeNet( (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1)) (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1)) (fc1): Linear(in_features=3072, out_features=500, bias=True) (fc2): Linear(in_features=500, out_features=200, bias=True) (fc3): Linear(in_features=200, out_features=10, bias=True) )
以上為整個(gè)卷積網(wǎng)絡(luò)的結(jié)構(gòu),接下來(lái)直接訓(xùn)練看看效果:
batch_size = 1000 #批次大小
for epoch in range(num_epochs):
print('current epoch + %d' % epoch)
running_loss = 0.0
for i ,(images,labels) in enumerate(train_loader,0):
#images=images.view(images.size(0),-1) 單通道不需要
labels = torch.tensor(labels, dtype=torch.long)
# 梯度清零
optimizer.zero_grad()
outputs = net(images) #將數(shù)據(jù)集傳入網(wǎng)絡(luò)做前向計(jì)算
loss = criterion(outputs ,labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 1000 == 0: # 每1000個(gè)batch打印一下訓(xùn)練狀態(tài)
print('[%d, %5d] loss: %.3f' \
% (epoch+1, i, running_loss ))
running_loss = 0.0
print('Finished Training')
[1, 0] loss: 2.310 current epoch + 1 [2, 0] loss: 2.301 current epoch + 2 [3, 0] loss: 2.305 current epoch + 3 [4, 0] loss: 2.303 current epoch + 4 [5, 0] loss: 2.304 Finished Training
模型準(zhǔn)確率
#prediction
total = 0
correct =0
acc_list_test = []
for images,labels in test_loader:
#images=images.view(images.size(0),-1)
outputs = net(images) #將數(shù)據(jù)集傳入網(wǎng)絡(luò)做前向計(jì)算
_,predicts = torch.max(outputs,1)
total += labels.size(0)
correct += (predicts == labels).sum()
acc_list_test.append(100 * correct / total)
print('Accuracy = %.2f'%(100 * correct / total))
plt.plot(acc_list_test)
plt.xlabel('Epoch')
plt.ylabel('Accuracy On TestSet')
plt.show()
?
?比普通的神經(jīng)網(wǎng)絡(luò)要好很多。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-731894.html
點(diǎn)關(guān)注,防走丟,如有紕漏之處,請(qǐng)留言指教,非常感謝
以上就是本期全部?jī)?nèi)容。我是fanstuck ,有問(wèn)題大家隨時(shí)留言討論 ,我們下期見(jiàn)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-731894.html
到了這里,關(guān)于PyTorch實(shí)戰(zhàn):實(shí)現(xiàn)Cifar10彩色圖片分類的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!