这两个都是putorch中常用的包,之前已经使用了很多torch的内容,下面我们介绍一下torchvision
torchvision包的朱要功能是实现数据的处理,导入和预览等,所以对于计算机视觉的相关处理非常方便
import torch
from torchvision import datasets,transforms
from torch.autograd import Variable
首先导入必要的包,在这里我们只需用到torchvision中的datasets和transforms两个包,因此只导入了他们两个,随后进行数据集的下载,使用datasets加上需要下载的数据集名称可以比较方便地下载,我们要使用的数据集叫做MINIST
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,),(0.5,))])
data_train=datasets.MNIST(root='./data/',transform=transform,train=True,download=True)
data_test=datasets.MNIST(root='./data/',transform=transform,train=False)
root用于指定下载后的存放路径,transform用于指定导入数据集时对数据进行哪种变换,train用于指定下载完成后需要载入哪些数据,如果为true就说明是训练集,需要载入,如果是false就是测试集
下面介绍transforms
transforms对载入的数据进行变换,举个例子,如果需要载入的数据集都是图片,那么实际计算中必须转化为tensor张量才能处理,或者是图片大小格式不一样,都可以使用transforms提供的操作进行归一化
transforms中有很大一部分可以用于数据增强,如果我们的数据集非常有限,那么就需要对已有数据进行翻转,裁剪等系列操作,来丰富数据集这里我们使用的数据集完全足够,因此不需要数据增强
我们将上面代码中的torchvision.tansforms.Compose看作一种容器,他能够对多种数据组合进行变换,传入的参数是一个列表,列表中的元素就是对载入的数据进行各种变换操作,在上述代码中,compose中用了一个类型转换操作ToTensor和一个数据标准化操作Normalize,这里使用的标准化变换也叫做标准差变换法,这种方式需要使用原始数据的均值mean和标准差来进行数据的标准化,变换之后数据满足均值为零,标准差为1的标准正态分布,不过这里我们指定的均值mean和标准差std都不是原始数据的,而是自行定义的,不过仍然能完成标准化操作,注意,此处定义的均值和标准差两个参数必须是一维的,因为MNIST图像是灰度的而不是RGB彩色图,因此只有一个图像通道,所以在归一化的时候只能定义一维的参数,否则不匹配,后面会报错下面列举一下transforms中的数据变换操作:
再数据载入后还要进行装载,可以理解为数据的载入就是对图片的处理,处理完之后装载就是打包发送给我们的训练模型
data_loader_train=torch.utils.data.DataLoader(dataset=data_train,batch_size=64,shuffle=True)
data_loader_test=torch.utils.data.DataLoader(dataset=data_test,batch_size=64,shuffle=True)
dataset用于指定装载的数据集,batch用于设置每个包图片个数,shuffle设置是否打乱顺序
在装载完成后我们可以选取一个数据批次进行预览
images,labels=next(iter(data_loader_train))
img=utils.make_grid(images)
img=img.numpy().transpose(1,2,0)
std=[0.5,0.5,0.5]
mean=[0.5,0.5,0.5]
img=img*std+mean
print([labels[i] for i in range(64)])
import matplotlib.pyplot as plt
%matplotlib inline
plt.imshow(img)
首先使用next和iter获取了一个批次图像的图片数据与对应标签,然后使用makegrid方法使其网格化,每个图片都是四维的,分别是数据个数,色彩通道,高度和宽度,通过makegrid之后变成了三维,因为图片都被整合到一起,所以数据个数参数失效,保留剩下的三个参数,我们使用matplotlib显示图片色彩通道必须在后面,因此使用numpy的transpose方法调整参数顺序,即0,1,2改成1,2,0这样色彩通道就成了最后一位,就可以使用imshow进行打印,加上inline声明是使其在notebook中也能显示,
输出如下:
每个数据标签对应的该位次图像
class Model(torch.nn.Module):
def __init__(self):
super(Model,self).__init__()
self.conv1=torch.nn.Sequential(torch.nn.Conv2d(1,64,kernel_size=3,stride=1,padding=1),torch.nn.ReLU(),torch.nn.Conv2d(64,128,kernel_size=3,stride=1,padding=1),torch.nn.ReLU(),\
torch.nn.MaxPool2d(stride=2,kernel_size=2))
self.dense=torch.nn.Sequential(torch.nn.Linear(14*14*128,1024),\
torch.nn.ReLU(),\
torch.nn.Dropout(p=0.5),\
torch.nn.Linear(1024,10))
def forward(self,x):
x=self.conv1(x)
x=x.view(-1,14*14*128)
x=self.dense(x)
return x
可以看出我们的网络是两层卷积网络伴随两次ReLU激活,然后一个最大池化层,最后两层全连接
model=Model()
cost=torch.nn.CrossEntropyLoss()
optimzer=torch.optim.Adam(model.parameters())
print(model)
训练过程如下:
nepochs=5
for epoch in range(nepochs):
running_loss=0.0
running_corrext=0.0
print("Epoch:{}/{}".format(epoch,nepochs))
for data in data_loader_train:
x_train,y_train=data
x_train,y_train=Variable(x_train),Variable(y_train)
outputs=model(x_train)
_,pred=torch.max(outputs.data,1)
optimzer.zero_grad()
loss=cost(outputs,y_train)
loss.backward()
optimzer.step()
running_loss+=loss.item()
running_corrext+=torch.sum(pred==y_train.data)
test_correct=0.0
for data in data_loader_test:
x_test,y_test=data
x_test,y_test=Variable(x_test),Variable(y_test)
outputs=model(x_test)
_,pred=torch.max(outputs.data,1)
test_correct+=torch.sum(pred==y_test.data)
print("Loss:{:.4f},train ac:{:.4f}%,test ac:{:.4f}%".format(running_loss/len(data_train),100*running_corrext/len(data_train),100*test_correct/len(data_test)))
不使用cuda加速的话时间会比较长,最后输出结果可以达到98%以上,我们可以用下面的代码验证预测
data_loader_test=torch.utils.data.DataLoader(dataset=data_test,batch_size=4,shuffle=True)
x_test,y_test=next(iter(data_loader_test))
inputs=Variable(x_test)
pred=model(inputs)
_,pred=torch.max(pred,1)
print("pred label is: ",[i for i in pred.data])
print("real label is : ",[i for i in y_test])
上面的预测的结果,下面是真实结果,多输出几次可以发现准确度还是很高的