Pytorch數據集讀取


Pytorch中數據集讀取
  在機器學習中,有很多形式的數據,我們就以最常用的幾種來看:
  在Pytorch中,他自帶了很多數據集,比如MNIST、CIFAR10等,這些自帶的數據集獲得和讀取十分簡便:
  

import torch
import torch.nn as nn
import torch.utils.data as Data
import torchvision
train_data = torchvision.datasets.MNIST(
  root='./mnist/', # 數據集存放的位置,他會先查找,如果該地沒有對應數據集,就下載(不連外網的話推薦從網上下載好后直接放到對應目錄)
            #比如這里root是"./mnist/" 那么下載好的數據放入./mnist/raw/下
  train=True, # 表示這是訓練集,如果是測試集就改為false   transform=torchvision.transforms.ToTensor(), # 表示數據轉換的格式   download=True, )

 


以上就獲得了對應的數據集,接下來就是讀取:
  

train_loader = Data.DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True) #使用自定義好的DataLoader函數來進行
for epoch in range(EPOCH):
for step, (b_x, b_y) in enumerate(train_loader): #  這里就可以遍歷數據集,進行訓練了
    XXXX
    XXXX    

 

 

可以看到,這樣獲得數據集確實方便,但是也有缺點:

  1、只能獲得固定的數據集,對於自己的特有的數據集,無法讀取。

  2、如果要對這些數據集處理,沒有辦法做到。

因此,我們需要一種方法來讀取本地的數據集:

先看看如何把從網上下載的文件轉換為圖片存儲:

 
         
import os
from skimage import io
import torchvision.datasets.mnist as mnist
import numpy

root = "data/MNIST/raw/"  #自己對應數據集的目錄
#獲得對應的訓練集的數據和標簽
train_set = (
    mnist.read_image_file(os.path.join(root, 'train-images-idx3-ubyte')),
    mnist.read_label_file(os.path.join(root, 'train-labels-idx1-ubyte'))
)
#獲得對應的測試機的數據和標簽
test_set = (
    mnist.read_image_file(os.path.join(root, 't10k-images-idx3-ubyte')),
    mnist.read_label_file(os.path.join(root, 't10k-labels-idx1-ubyte'))
)

print("train set:", train_set[0].size())
print("test set:", test_set[0].size())
#將數據轉換為圖片格式
def convert_to_img(train=True):
    if (train):
#如果是訓練集的話 就放到訓練集中
        f = open(root + 'train.txt', 'w')
#打開對應文件
        data_path = root + '/train/'
        if (not os.path.exists(data_path)):
            os.makedirs(data_path)
        for i, (img, label) in enumerate(zip(train_set[0], train_set[1])):
        # 拼合出圖片路徑
         img_path = data_path + str(i) + '.jpg'
     #將img這個獲取的數據轉換為numpy后存入,而因為文件存入后打開格式為.jpg,所以自動變成了圖片

            io.imsave(img_path, img.numpy())
      #存入標簽 
            int_label = str(label).replace('tensor(', '')
            int_label = int_label.replace(')', '')
            f.write(img_path + ' ' + str(int_label) + '\n')
        f.close()
    else:
        f = open(root + 'test.txt', 'w')
        data_path = root + '/test/'
        if (not os.path.exists(data_path)):
            os.makedirs(data_path)
        for i, (img, label) in enumerate(zip(test_set[0], test_set[1])):
            img_path = data_path + str(i) + '.jpg'
            io.imsave(img_path, img.numpy())
            int_label = str(label).replace('tensor(', '')
            int_label = int_label.replace(')', '')
            f.write(img_path + ' ' + str(int_label) + '\n')
        f.close()
convert_to_img(True)
convert_to_img(False)

 

這樣以后,得到的效果是:

    

在train.txt中,存放着文件的路徑和標簽

然后在文件路徑中,有如圖的圖片:

    

數據轉換成圖片格式了,那接下來看看如何將圖片讀取:

讀取數據的重點就是重寫torch.utils.data的Dataset方法,其中有三個重要的方法:__init__,__getitem__,__len__,這三個方法分別表示:對數據集的初始化,在循環的時候獲得數據,還有數據的長度。

我們就用已有的圖片數據集,來進行CNN的訓練:

首先要寫一個自己的數據集加載的類:

import torch
from torch import nn, optim
import torch.nn.functional as F
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import transforms
from PIL import Image
import FileLoader
from torch.utils import data
import numpy as np
import matplotlib.pyplot as plt
#定義對數據集的加載方式
def default_loader(path):
    return Image.open(path)
#繼承自data.Dataset,完成對方法的重寫
class MyImageFloder(data.Dataset):
    def __init__(self,FileName,transform = None,target_transform = None,loader = default_loader):
        #獲得對應的數據位置和標簽
     FilePlaces,LabelSet
= FileLoader.filePlace_loader(FileName) # 對標簽進行修改,因為讀進來變成了str類型,要修改成long類型 LabelSet = [np.long(i) for i in LabelSet] LabelSet = torch.Tensor(LabelSet).long() self.imgs_place = FilePlaces self.LabelSet = LabelSet self.transform = transform self.target_transform = target_transform self.loader = loader # 這里是對數據進行讀取 使用之前定義的loader方法來執行 def __getitem__(self, item): img_place = self.imgs_place[item] label = self.LabelSet[item] img = self.loader(img_place) if self.transform is not None: img = self.transform(img) return img,label def __len__(self): return len(self.imgs_place)

 

這里的重點就是,一定看好了讀取以后的格式和維度,還有類型,在實際使用的時候,經常報錯,要根據提示來修改對應的代碼!

import torch
from torch import nn, optim
import torch.nn.functional as F
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import transforms
from PIL import Image
import FileLoader
from torch.utils import data
import numpy as np
import matplotlib.pyplot as plt
import MyImageLoader
batch_size = 64


mytransform = transforms.Compose([
    transforms.ToTensor()
    ]
)
batch_size = 64

train_loader = DataLoader(MyImageLoader.MyImageFloder(FileName='data/MNIST/raw/train.txt',transform=mytransform), batch_size=batch_size,
                                           shuffle=True)

test_loader = DataLoader(MyImageLoader.MyImageFloder(FileName='data/MNIST/raw/test.txt',transform=mytransform), batch_size=batch_size,
                                           shuffle=True)




class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # 輸入1通道,輸出10通道,kernel 5*5
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=10, kernel_size=5)
        self.conv2 = nn.Conv2d(10, 20, 5)
        self.conv3 = nn.Conv2d(20, 40, 3)

        self.mp = nn.MaxPool2d(2)
        # fully connect
        self.fc = nn.Linear(40, 10)#(in_features, out_features)

    def forward(self, x):
        # in_size = 64
        in_size = x.size(0) # one batch     此時的x是包含batchsize維度為4的tensor,即(batchsize,channels,x,y),x.size(0)指batchsize的值    把batchsize的值作為網絡的in_size
        # x: 64*1*28*28
        x = F.relu(self.mp(self.conv1(x)))
        # x: 64*10*12*12  feature map =[(28-4)/2]^2=12*12
        x = F.relu(self.mp(self.conv2(x)))
        # x: 64*20*4*4
        x = F.relu(self.mp(self.conv3(x)))

        x = x.view(in_size, -1) # flatten the tensor 相當於resharp
        # print(x.size())
        # x: 64*320
        x = self.fc(x)
        # x:64*10
        # print(x.size())
        return F.log_softmax(x)  #64*10

model = Net()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

losses =[]
test_losses = []
test_acces = []

def train(epoch):
    loss=0;

    for batch_idx, (data, target) in enumerate(train_loader):#batch_idx是enumerate()函數自帶的索引,從0開始
        # data.size():[64, 1, 28, 28]
        # target.size():[64]

        output = model(data)
        #output:64*10


        # target = [np.long(i) for i in target]
        # target = torch.Tensor(target).long()


        loss = F.nll_loss(output, target)

        if batch_idx % 200 == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))

        optimizer.zero_grad()   # 所有參數的梯度清零
        loss.backward()         #即反向傳播求梯度
        optimizer.step()        #調用optimizer進行梯度下降更新參數
        # 每次訓練完一整輪,記錄一次
    losses.append(loss.item())




def test():
    test_loss = 0
    correct = 0
    for data, target in test_loader:
        # target = [np.long(i) for i in target]
        # target = torch.Tensor(target).long()
        with torch.no_grad():
            data, target = Variable(data), Variable(target)
            output = model(data)
            # sum up batch loss
            test_loss += F.nll_loss(output, target, size_average=False).item()
            # get the index of the max log-probability
            pred = output.data.max(1, keepdim=True)[1]

            correct += pred.eq(target.data.view_as(pred)).cpu().sum()

    test_loss /= len(test_loader.dataset)
    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))

    test_losses.append(test_loss)
    print(correct.item())
    test_acces.append(correct.item() / len(test_loader.dataset))

for epoch in range(1, 5):
    train(epoch)
    test()



plt.figure(22)

x_loss = list(range(len(losses)))
x_acc = list(range(len(test_acces)))

plt.subplot(221)
plt.title('train loss ')
plt.plot(x_loss, losses)

plt.subplot(222)
plt.title('test loss')
plt.plot(x_loss, test_losses)

plt.subplot(212)
plt.plot(x_acc, test_acces)
plt.title('test acc')
plt.show()

 

這里直接套用CNN的代碼即可。

關於此問題比較好的方法可以參考:https://blog.csdn.net/qq_36852276/article/details/94588656

                https://blog.csdn.net/sjtuxx_lee/article/details/83031718

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM