目錄
1.如何自定義數(shù)據(jù)集:
咱們以花朵數(shù)據(jù)集為例:
任務(wù)1:讀取txt文件中的路徑和標(biāo)簽
任務(wù)2:通過上面字典返回?cái)?shù)據(jù),分別把數(shù)據(jù)和標(biāo)簽都存在list里
任務(wù)3:圖像數(shù)據(jù)路徑得完整
任務(wù)4:把上面那幾個(gè)事得寫在一起,整合到一個(gè)類。
任務(wù)5:數(shù)據(jù)預(yù)處理(transform)?
任務(wù)6:根據(jù)寫好的class FlowerDataset(Dataset):來實(shí)例化咱們的dataloader
任務(wù)7:用之前先試試,整個(gè)數(shù)據(jù)和標(biāo)簽對(duì)應(yīng)下,看看對(duì)不對(duì)
任務(wù)8:把做到的數(shù)據(jù)往模型里傳
2.構(gòu)建損失函數(shù)和優(yōu)化器?
? ? ? 訓(xùn)練函數(shù)
1.如何自定義數(shù)據(jù)集:
- 1.數(shù)據(jù)和標(biāo)簽的目錄結(jié)構(gòu)先搞定(得知道到哪讀數(shù)據(jù))
- 2.寫好讀取數(shù)據(jù)路徑和標(biāo)簽路徑的函數(shù)(根據(jù)自己數(shù)據(jù)集情況來寫)
- 3.完成單個(gè)數(shù)據(jù)與標(biāo)簽讀取函數(shù)(給dataloader舉一個(gè)例子)
咱們以花朵數(shù)據(jù)集為例:
- 原來數(shù)據(jù)集都是以文件夾為類別ID,現(xiàn)在咱們換一個(gè)套路,用txt文件指定數(shù)據(jù)路徑與標(biāo)簽(實(shí)際情況基本都這樣)
- 這回咱們的任務(wù)就是在txt文件中獲取圖像路徑與標(biāo)簽,然后把他們交給dataloader
- 核心代碼非常簡單,按照對(duì)應(yīng)格式傳遞需要的數(shù)據(jù)和標(biāo)簽就可以啦
- 需要到的flower數(shù)據(jù)集鏈接:https://pan.baidu.com/s/1RVAlr-uTczP2ZEHgFfdmVw?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?提取碼:micx?
?
?
train.txt:? 指定圖片名字和分類標(biāo)簽
image_06734.jpg 0
image_06735.jpg 0
image_06736.jpg 0
image_06737.jpg 0
image_06738.jpg 0
image_06740.jpg 0
image_06741.jpg 0
import os
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import torch
from torch import nn
import torch.optim as optim
import torchvision
#pip install torchvision
from torchvision import transforms, models, datasets
#https://pytorch.org/docs/stable/torchvision/index.html
import imageio
import time
import warnings
import random
import sys
import copy
import json
from PIL import Image
任務(wù)1:讀取txt文件中的路徑和標(biāo)簽
- 第一個(gè)小任務(wù),從標(biāo)注文件中讀取數(shù)據(jù)和標(biāo)簽
- 至于你準(zhǔn)備存成什么格式,都可以的,一會(huì)能取出來東西就行
def load_annotations(ann_file):
data_infos = {}
with open(ann_file) as f: #打開文件
samples = [x.strip().split(' ') for x in f.readlines()] #一行行去讀,以空格作為切分,[ [xxx.jpg,'1' ],[xxx,jpg,'2' ] ]
for filename, gt_label in samples: # filename為xxx.jpg,gt_label為分類值
data_infos[filename] = np.array(gt_label, dtype=np.int64)#構(gòu)建字典,圖片名為key,分類值為value,組合
return data_infos #返回字典
?返回的字典內(nèi)容
關(guān)于strip()和split()函數(shù)用方法,參考博客Python中的strip().split(‘\t‘)的用法和解釋_AI學(xué)習(xí)的我的博客-CSDN博客
任務(wù)2:通過上面字典返回?cái)?shù)據(jù),分別把數(shù)據(jù)和標(biāo)簽都存在list里
- 不是我非讓你存list里,因?yàn)閐ataloader到時(shí)候會(huì)在這里取數(shù)據(jù)
- 按照人家要求來,不要耍個(gè)性,讓整list咱就給人家整
img_label = load_annotations('./flower_data/train.txt')
image_name = list(img_label.keys())
label = list(img_label.values())
?image_name 和 label 列表的內(nèi)容
?
任務(wù)3:圖像數(shù)據(jù)路徑得完整
- 因?yàn)橐粫?huì)咱得用這個(gè)路徑去讀數(shù)據(jù),所以路徑得加上前綴
- 以后大家任務(wù)不同,數(shù)據(jù)不同,怎么加你看著來就行,反正得能讀到圖像
data_dir = './flower_data/'
train_dir = data_dir + '/train_filelist'
valid_dir = data_dir + '/val_filelist'
image_path = [os.path.join(train_dir,img) for img in image_name] #根據(jù)圖像路徑和圖像名字加載圖片進(jìn)來
任務(wù)4:把上面那幾個(gè)事得寫在一起,整合到一個(gè)類。
- 1.注意要使用from torch.utils.data import Dataset, DataLoader
- 2.類名定義class FlowerDataset(Dataset),其中FlowerDataset可以改成自己的名字
- 3.def?init(self, root_dir, ann_file, transform=None):咱們要根據(jù)自己任務(wù)重寫
- 4.def?getitem(self, idx):根據(jù)自己任務(wù),返回圖像數(shù)據(jù)和標(biāo)簽數(shù)據(jù),傳給模型
from torch.utils.data import Dataset, DataLoader
class FlowerDataset(Dataset): #繼承Dataset 生成2個(gè)list,一個(gè)[包含圖片路徑],一個(gè)[圖像對(duì)應(yīng)的labels]
def __init__(self, root_dir, ann_file, transform=None):
self.ann_file = ann_file
self.root_dir = root_dir
self.img_label = self.load_annotations()#返回字典,圖片名為key,圖片label為value
self.img = [os.path.join(self.root_dir,img) for img in list(self.img_label.keys())]#一個(gè)[包含圖片路徑]的list
self.label = [label for label in list(self.img_label.values())]# [圖像對(duì)應(yīng)的labels] 的list
self.transform = transform
def __len__(self): #數(shù)據(jù)集樣本數(shù)量
return len(self.img)
# __getitem__會(huì)執(zhí)行 batch_size次,__getitem__返回的數(shù)據(jù)是給模型的
def __getitem__(self, idx):#圖像和標(biāo)簽在當(dāng)前l(fā)ist的索引,每次調(diào)用idx是隨機(jī)值,一個(gè)batch里的數(shù)據(jù)是隨機(jī)打亂的
image = Image.open(self.img[idx])
label = self.label[idx]
if self.transform: #取完圖片后,進(jìn)行預(yù)處理
image = self.transform(image)
label = torch.from_numpy(np.array(label)) #轉(zhuǎn)回Tensor格式
return image, label #返回實(shí)際圖像 ,按batch_size大小數(shù)據(jù)打包好返回
def load_annotations(self):
data_infos = {}
with open(self.ann_file) as f:
samples = [x.strip().split(' ') for x in f.readlines()]
for filename, gt_label in samples:
data_infos[filename] = np.array(gt_label, dtype=np.int64)#將圖片名和label組合成字典數(shù)據(jù)
return data_infos
任務(wù)5:數(shù)據(jù)預(yù)處理(transform)?
- 1.預(yù)處理的事都在上面的getitem中完成,需要對(duì)圖像和標(biāo)簽咋咋地的,要整啥事,都在上面整
- 2.返回的數(shù)據(jù)和標(biāo)簽就是建模時(shí)模型的輸入和損失函數(shù)中標(biāo)簽的輸入,一定整明白自己模型要啥
- 3.預(yù)處理這個(gè)事是你定的,不同的數(shù)據(jù)需要的方法也不一樣,下面給出的是比較通用的方法
data_transforms = {
'train':
transforms.Compose([
transforms.Resize(64),
transforms.RandomRotation(45),#隨機(jī)旋轉(zhuǎn),-45到45度之間隨機(jī)選
transforms.CenterCrop(64),#從中心開始裁剪
transforms.RandomHorizontalFlip(p=0.5),#隨機(jī)水平翻轉(zhuǎn) 選擇一個(gè)概率概率
transforms.RandomVerticalFlip(p=0.5),#隨機(jī)垂直翻轉(zhuǎn)
transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),#參數(shù)1為亮度,參數(shù)2為對(duì)比度,參數(shù)3為飽和度,參數(shù)4為色相
transforms.RandomGrayscale(p=0.025),#概率轉(zhuǎn)換成灰度率,3通道就是R=G=B
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])#均值,標(biāo)準(zhǔn)差
]),
'valid':
transforms.Compose([
transforms.Resize(64),
transforms.CenterCrop(64),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
任務(wù)6:根據(jù)寫好的class FlowerDataset(Dataset):來實(shí)例化咱們的dataloader
- 1.構(gòu)建數(shù)據(jù)集:分別創(chuàng)建訓(xùn)練和驗(yàn)證用的數(shù)據(jù)集(如果需要測試集也一樣的方法)
- 2.用Torch給的DataLoader方法來實(shí)例化(batch啥的自己定,根據(jù)你的顯存來選合適的)
- 3.打印看看數(shù)據(jù)里面是不是有東西了
train_dataset = FlowerDataset(root_dir=train_dir, ann_file = './flower_data/train.txt', transform=data_transforms['train'])
val_dataset = FlowerDataset(root_dir=valid_dir, ann_file = './flower_data/val.txt', transform=data_transforms['valid'])
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=64, shuffle=True)
任務(wù)7:用之前先試試,整個(gè)數(shù)據(jù)和標(biāo)簽對(duì)應(yīng)下,看看對(duì)不對(duì)
- 1.別著急往模型里傳,對(duì)不對(duì)都不知道呢
- 2.用這個(gè)方法:iter(train_loader).next()來試試,得到的數(shù)據(jù)和標(biāo)簽是啥
- 3.看不出來就把圖畫出來,標(biāo)簽打印出來,確保自己整的數(shù)據(jù)集沒啥問題
?
?
任務(wù)8:把做到的數(shù)據(jù)往模型里傳
- 下面這些事之前都嘮過了,按照自己習(xí)慣的方法整就得了
dataloaders = {'train':train_loader,'valid':val_loader}
model_name = 'resnet' #可選的比較多 ['resnet', 'alexnet', 'vgg', 'squeezenet', 'densenet', 'inception']
#是否用人家訓(xùn)練好的特征來做
feature_extract = True
# 是否用GPU訓(xùn)練
train_on_gpu = torch.cuda.is_available()
if not train_on_gpu:
print('CUDA is not available. Training on CPU ...')
else:
print('CUDA is available! Training on GPU ...')
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model_ft = models.resnet18() #上面先指定使用resnet,這里再指定使用多少層的模型
#重新定義輸出層
num_ftrs = model_ft.fc.in_features #獲取輸出層的輸入
model_ft.fc = nn.Sequential(nn.Linear(num_ftrs, 102))
input_size = 64 #輸入圖片的大小
2.構(gòu)建損失函數(shù)和優(yōu)化器?
# 優(yōu)化器設(shè)置
optimizer_ft = optim.Adam(model_ft.parameters(), lr=1e-3)
scheduler = optim.lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)#學(xué)習(xí)率每7個(gè)epoch衰減成原來的1/10
criterion = nn.CrossEntropyLoss()
? ? ? 訓(xùn)練函數(shù)
def train_model(model, dataloaders, criterion, optimizer, num_epochs=25, is_inception=False, filename='best.pth'):
since = time.time()
best_acc = 0
model.to(device)
val_acc_history = []
train_acc_history = []
train_losses = []
valid_losses = []
LRs = [optimizer.param_groups[0]['lr']]
best_model_wts = copy.deepcopy(model.state_dict())
for epoch in range(num_epochs):
print('Epoch {}/{}'.format(epoch, num_epochs - 1))
print('-' * 10)
# 訓(xùn)練和驗(yàn)證
for phase in ['train', 'valid']:
if phase == 'train':
model.train() # 訓(xùn)練
else:
model.eval() # 驗(yàn)證
running_loss = 0.0
running_corrects = 0
# 把數(shù)據(jù)都取個(gè)遍
for inputs, labels in dataloaders[phase]:
inputs = inputs.to(device)
labels = labels.to(device)
# 清零
optimizer.zero_grad()
# 只有訓(xùn)練的時(shí)候計(jì)算和更新梯度
with torch.set_grad_enabled(phase == 'train'):
outputs = model(inputs)
loss = criterion(outputs, labels)
_, preds = torch.max(outputs, 1)
#print(loss)
# 訓(xùn)練階段更新權(quán)重
if phase == 'train':
loss.backward()
optimizer.step()
# 計(jì)算損失
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / len(dataloaders[phase].dataset)
epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)
time_elapsed = time.time() - since
print('Time elapsed {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
# 得到最好那次的模型
if phase == 'valid' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
state = {
'state_dict': model.state_dict(),#字典里key就是各層的名字,值就是訓(xùn)練好的權(quán)重
'best_acc': best_acc,
'optimizer' : optimizer.state_dict(),#優(yōu)化器的狀態(tài)信息
}
torch.save(state, filename)
if phase == 'valid':
val_acc_history.append(epoch_acc)
valid_losses.append(epoch_loss)
scheduler.step(epoch_loss)#學(xué)習(xí)率衰減
if phase == 'train':
train_acc_history.append(epoch_acc)
train_losses.append(epoch_loss)
print('Optimizer learning rate : {:.7f}'.format(optimizer.param_groups[0]['lr']))
LRs.append(optimizer.param_groups[0]['lr'])
print()
time_elapsed = time.time() - since
print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
print('Best val Acc: {:4f}'.format(best_acc))
# 訓(xùn)練完后用最好的一次當(dāng)做模型最終的結(jié)果,等著一會(huì)測試
model.load_state_dict(best_model_wts)
return model, val_acc_history, train_acc_history, valid_losses, train_losses, LRs
? ? ? ?調(diào)用函數(shù)開始訓(xùn)練文章來源:http://www.zghlxwxcb.cn/news/detail-764635.html
model_ft, val_acc_history, train_acc_history, valid_losses, train_losses, LRs = train_model(model_ft, dataloaders, criterion, optimizer_ft, num_epochs=20, filename='best.pth')
? ? ? ?訓(xùn)練結(jié)果:文章來源地址http://www.zghlxwxcb.cn/news/detail-764635.html
Epoch 0/19
----------
Time elapsed 1m 48s
train Loss: 4.0150 Acc: 0.0804
Time elapsed 1m 55s
valid Loss: 3.5848 Acc: 0.1565
Optimizer learning rate : 0.0010000
Epoch 1/19
----------
Time elapsed 3m 37s
train Loss: 3.4320 Acc: 0.1601
Time elapsed 3m 44s
valid Loss: 3.4386 Acc: 0.1614
Optimizer learning rate : 0.0010000
Epoch 2/19
到了這里,關(guān)于pytorch實(shí)戰(zhàn)5——DataLoader數(shù)據(jù)集制作的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!