PyTorch 使用自己的数据集
from __future__ import print_functionimport torchimport torch.nn as nnimport torch.nn.functional as Fimport torch.autograd.variable as Variableimport torch.optim as optimimport torchvisionimport torchvision.transforms as transformsimport numpy as npimport matplotlib.pyplot as plt
%matplotlib inline
保存 CIFAR10 为图片
CIFAR10 数据集说明
- 包含有
data_batch_1,…,data_batch_5,test_batch - 每一个batch文件包括一个字典,字典的元素是:
data:一个尺寸为 10000×3072,数据格式为uint8的numpy array,每一行数据存储了一张 32×32 彩色图片的数据,前 1024 位是图像的红色通道数据,接着是绿色通道和蓝色通道。label:一个包含 10000 个 0-9 数字的列表,对应data里每张图片的标签。
读取数据集并保存
重复执行会清空csv文件
from matplotlib.image import imsaveimport numpy as npimport csvimport osdef unpickle(file):import picklewith open(file, 'rb') as fo:dict = pickle.load(fo, encoding='bytes')return dictpath = './data/cifar10/cifar-10-batches-py/'root = './data/cifar10/cifar10/'header = ['label', 'index']rows = []for i in range(5):file = path + 'data_batch_' + str(i+1)Xtr = unpickle(file)print('正在处理训练集:', i)for j in range(10000): # 处理10k张图片img = np.reshape(Xtr[b'data'][j], (3, 32, 32)) # R:1024,G:1024,B:1024img = img.transpose(1, 2, 0) # 转置成为图片的格式(H,W,C)picName = './data/cifar10/cifar10/train/' + \str(int(i*10000+j)) + '.jpg'if not os.path.exists(picName):imsave(picName, img)rows.append((Xtr[b'labels'][j], j))with open(root+'train/train.csv', 'w', encoding='utf-8', newline='') as f:w = csv.writer(f)w.writerow(header)w.writerows(rows)rows = []Xte = unpickle(path+'test_batch')print('正在处理测试集: 0')for j in range(10000): # 处理10k张图片img = np.reshape(Xte[b'data'][j], (3, 32, 32))img = img.transpose(1, 2, 0) # 转置成为图片的格式(H,W,C)picName = './data/cifar10/cifar10/test/' + \str(j) + '.jpg'if not os.path.exists(picName):imsave(picName, img)rows.append((Xte[b'labels'][j], j))with open(root+'test/test.csv', 'w', encoding='utf-8', newline='') as f:w = csv.writer(f)w.writerow(header)w.writerows(rows)print('处理完毕')
正在处理训练集: 0正在处理训练集: 1正在处理训练集: 2正在处理训练集: 3正在处理训练集: 4
显示一张图片
from matplotlib.pyplot import imshow# show a single imageimg = np.reshape(Xtr[b'data'][0], (3, 32, 32)).transpose(1, 2, 0)imshow(img)
<matplotlib.image.AxesImage at 0x18d183d2400>
定义自己的类
定义自己的数据集类,主要是在继承(torch.utils.data.Dataset)后修改初始化(__init__(self))和读取图片(__getitem__(self, index))的函数(和 __len__(self))
- 训练集每张图片的命名规则为“number.jpg”,
train.csv标记了各个图片的类别 - 测试集每张图片的命名规则为“number.jpg”,
rain.csv标记了各个图片的类别
import osimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom torch.utils.data import Dataset# import csv# 数据保存在 ./data/cifar10/cifar10/train(test)/# root = './data/cifar10/cifar10/class myDataset(Dataset):def __init__(self, root, train=True, transform=None):'''Args:root : 根目录transform: 数据处理方式'''if train:self.root = root + 'train/'data = pd.read_csv(root + 'train/train.csv')else:self.root = root + 'test/'data = pd.read_csv(root + 'test/test.csv')self.imgs = data['index'].valuesself.labels = data['label'].valuesif transform:self.transform = transformdef __getitem__(self, index):target = self.labels[index]image = plt.imread(self.root+str(int(index))+'.jpg')if self.transform is not None:image = self.transform(image)return image, targetdef __len__(self):return len(self.imgs)
使用自己的类
from torch.utils.data import Dataset, DataLoaderbatch_size = 4epoch_size = 3transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])trainset = myDataset(root='./data/cifar10/cifar10/',train=True,transform=transform)trainloader = torch.utils.data.DataLoader(trainset,batch_size=batch_size,shuffle=True,num_workers=0)testset = myDataset(root='./data/cifar10/cifar10/',train=False,transform=transform)testloader = torch.utils.data.DataLoader(testset,batch_size=batch_size,shuffle=False,num_workers=0)classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')
BUG
当 shuffle 设置为 True 时,num_sample 报错
原因
因为之前的csv文件被清空导致数据为空
def imshow(img):img = img / 2 + 0.5 # 去标准化npimg = img.numpy() # 将torch.FloatTensor 转换为numpy# plt.axis("off") # 不显示坐标尺寸plt.imshow(np.transpose(npimg, (1, 2, 0))) # 进行转置plt.show() # 显示图片# get some random training imagesdataiter = iter(trainloader)images, labels = dataiter.next()# show imagesimshow(torchvision.utils.make_grid(images))# print labelsprint(' '.join('%11s' % classes[labels[j]] for j in range(batch_size)))

plane dog truck frog
torchvision.datasets.ImageFolder
保存/加载模型
保存模型
# 模型保存torch.save(net.state_dict(), './model/learn0.pt') # .pt or .pth
定义网络
# 网络结构class Net(nn.Module): # nn.Module 是所有神经网络的基类,自定义的网络应该继承自它def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(3, 6, 5)self.pool = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):x = self.pool(F.relu(self.conv1(x)))x = self.pool(F.relu(self.conv2(x)))x = x.view(-1, 16 * 5 * 5)x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return x
加载模型
model = Net().to('cuda')model.load_state_dict(torch.load('./model/learn0.pt'))model.eval()
Net((conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))(pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))(fc1): Linear(in_features=400, out_features=120, bias=True)(fc2): Linear(in_features=120, out_features=84, bias=True)(fc3): Linear(in_features=84, out_features=10, bias=True))
model.load_state_dict(torch.load(‘./model/learn0.pt’))
IncompatibleKeys(missing_keys=[], unexpected_keys=[])
猜测是加载模型正确,没有遗漏和错误。
测试模型
# 加载测试集test_set = torchvision.datasets.CIFAR10(root='./data/cifar10',train=False,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5),(0.5, 0.5, 0.5))]))testloader = torch.utils.data.DataLoader(test_set,batch_size=4,shuffle=True,num_workers=2)classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# 测试dataiter = iter(testloader)images, labels = dataiter.next()def imshow(img):img = img / 2 + 0.5 # 去标准化npimg = img.numpy() # 将torch.FloatTensor 转换为numpy# plt.axis("off") # 不显示坐标尺寸plt.imshow(np.transpose(npimg, (1, 2, 0))) # 进行转置plt.show() # 显示图片# print imagesprint('GroundTruth:')imshow(torchvision.utils.make_grid(images))print(' '.join('%11s' % classes[labels[j]] for j in range(4)))# 测试一次outputs = model(images.to('cuda'))_, predicted = torch.max(outputs, 1)print('Predicted:\n', ' '.join('%11s' % classes[predicted[j]]for j in range(4)))
GroundTruth:

dog deer dog birdPredicted:cat car cat bird
测试自己的图片
网络输入尺寸是 32x32,因此需要把自己的图片进行预处理,之后才可以进行测试
需要注意的是,如果使用 plt.imread() 读入图片,返回的是 np.ndarray 类型,此时需要用 transforms.ToPILImage() 转化为 PIL 类型
采用 PIL.Image(Pillow for Python3.x) 则无需进行转化
img_path = './data/cifar10/mytest/car-1.jpg' # √# img_path = './data/cifar10/mytest/dog-1.jpg' # ×# # 采用 plt.imread() 读入图片# img = plt.imread(img_path)# print('图片尺寸:',np.array(img).shape,type(img))# transform = transforms.Compose(# [transforms.ToPILImage(),# transforms.Resize([32,32]),# transforms.ToTensor(),# transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])# 采用 PIL.Image 读取图片from PIL import Imageimg = Image.open(img_path)print('未 transform 的图片尺寸:',np.array(img).shape,' 图片类型:',type(img))plt.imshow(np.array(img))plt.show()transform = transforms.Compose([transforms.Resize([32,32]),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])img = transform(img).reshape(-1,3,32,32)print('已 transpose 的图片尺寸:',np.array(img).shape,' 图片类型:',type(img))# plt.imshow(img)imshow(torchvision.utils.make_grid(img))output = model(img.to('cuda'))_, predicted = torch.max(output, 1)print('模型输出为:',classes[predicted])
未 transform 的图片尺寸: (435, 728, 3) 图片类型: <class 'PIL.JpegImagePlugin.JpegImageFile'>

已 transpose 的图片尺寸: (1, 3, 32, 32) 图片类型: <class 'torch.Tensor'>

模型输出为: car
!pip install Pillow
Looking in indexes: https://pypi.doubanio.com/simple/Requirement already satisfied: Pillow in d:\office\office\python\python3.6.2\lib\site-packages (4.3.0)Requirement already satisfied: olefile in d:\office\office\python\python3.6.2\lib\site-packages (from Pillow) (0.44)
格式转换
# !jupyter nbconvert --to html --template full learn.ipynb# !jupyter nbconvert --to markdown learn.ipynb!jupyter nbconvert --to html --template full learn-1.ipynb!jupyter nbconvert --to markdown learn-1.ipynb
[NbConvertApp] Converting notebook learn-1.ipynb to html[NbConvertApp] Writing 335545 bytes to learn-1.html[NbConvertApp] Converting notebook learn-1.ipynb to markdown[NbConvertApp] Support files will be in learn-1_files\[NbConvertApp] Making directory learn-1_files[NbConvertApp] Making directory learn-1_files[NbConvertApp] Writing 8365 bytes to learn-1.md

