文章目录
Pytorch框架的使用
摘要
在工程方面:学习了Pytorch框架的使用,在数据处理上,用Dataset从文件中读取数据并编号,用Dataloader对数据分批次打包,便于训练时使用小批量梯度下降对model进行优化;在可视化上,用Tensorboard实现了搭建model的可视化和训练数据的可视化实践;在model上,搭建了CNN-DNN模型对手写数字识别进行了分类,在没任何调参和对model完善的情况下准确率80%左右。
在学术方面:本周详细看了欧拉观点和拉格朗日观点对流体运动的描述,进行了部分推导,部分学习了SVM如何将低纬度的数据映射到高纬度进行分类的数学推导。
一、数据处理
在Pytorch中,读取数据主要涉及两个类—Dataset和Dataloader:
- Dataset常用于文件中数据读取,读取每个数据及其对应的Label(标签)。
- Dataloader对Dataset读取的数据进行打包,分Batch送入神经网络。
1.1 Dataset的重载
Dataset官方文档
创建类Mydataset,继承父类Dataset,重写初始化函数、__getitem__函数和__len__函数。下面代码的效果是,读取上一级目录文件dataset/val/中ants和bees的图片数据。其中函数的作用:
- os.path.join: 输入文件地址,将地址连接后输出,如:os.path.join(“dataset”, “val”) = dataset/val
- os.listdir: 输入文件地址,输出该地址中的文件名列表。
- Image.open: 输入图片地址,输出该图片。
import os.path
from PIL import Image
from torch.utils.data import Dataset
class Mydataset(Dataset):
def __init__(self, root_dir, label_dir):
self.label_dir = label_dir
self.root_label_dir = os.path.join(root_dir, label_dir)
self.imgs_dir_list = os.listdir(self.root_label_dir)
def __getitem__(self, idex):#输入图片索引,返回图片及其label
img_path = self.imgs_dir_list[idex]
img = Image.open(os.path.join(self.root_label_dir, img_path))
img_label = self.label_dir
return img, img_label
def __len__(self):#返回图片的长度
return len(self.imgs_dir_list)
root_dir = "../dataset/val"
ants_dir = "ants"
bees_dir = "bees"
ants_dataset = Mydataset(root_dir, ants_dir)
bees_dataset = Mydataset(root_dir, bees_dir)
img, label = ants_dataset.__getitem__(2)
img.show()
print(label)
1.2 DataLoader
DataLoader官方文档
作用:将数据分批次打包
import torch
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
trans_tensor = torchvision.transforms.ToTensor() #实例化图片转tensor的类
train_data = torchvision.datasets.MNIST("./data_minst", train=True, transform=trans_tensor, download=True)
test_data = torchvision.datasets.MNIST("./data_minst", train=False, transform=trans_tensor, download=True)
writer =SummaryWriter("./logs")
batch = 50
train_data_batch = DataLoader(train_data, batch_size=batch)
test_data_batch = DataLoader(test_data, batch_size=batch)
i = 0
for data in train_data_batch:
img, label = data
print(img.shape)
img = torch.reshape(img, (batch, 1, 28, 28))
writer.add_images("手写数字", img, i)
i += 1
writer.close()
二、可视化
2.1 Tensorboard的使用
2.1.1 Tensorboard根据数据绘图
from torch.utils.tensorboard import SummaryWriter#从tensorboard中导入类SummaryWriter
writer = SummaryWriter("./logs")#类的实例化
for i in range(100):
writer.add_scalar("y=x^2", i**2, i)#添加数据
writer.close()
2.1.2 Tensorboard显示图片
- writer.add_images: 输入张量格式为(n, m, h, w),n代表图片数量,m代表通道数,h,w代表图片像素。
import torch
from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter("./logs")
img = Image.open("./image/0013035.jpg")
tensor_trans = transforms.ToTensor()
img = tensor_trans(img)
print(img.shape)
img = torch.reshape(img,(1,3,512,768))
writer.add_images("image", img)
writer.close()
2.1.3 Tensorboard显示model网络结构
- writer.add_graph():输入model类和model的输入。
import torch
from torch import nn
from torch.utils.tensorboard import SummaryWriter
class CnnModel(nn.Module):
def __init__(self):
super(CnnModel, self).__init__()
self.conv1 = nn.Conv2d(in_channels=1, out_channels=3, kernel_size=3, stride=1, padding=0)
self.pool1 = nn.MaxPool2d(2)
self.conv2 = nn.Conv2d(3, 3, 3, 1, 0)
self.pool2 = nn.MaxPool2d(2)
self.flaten = nn.Flatten()
self.linear = nn.Linear(75, 10)
self.sofmax = nn.Softmax(1)
def forward(self, x):
x = self.conv1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.pool2(x)
x = self.flaten(x)
x = self.linear(x)
x = self.sofmax(x)
return x
if __name__ == '__main__': #测试model是否正确
x = torch.ones(1, 1, 28, 28)
model = CnnModel()
output = model.forward(x)
writer = SummaryWriter("./logs_model")
writer.add_graph(model, x)
writer.close()
三、模型实践
3.1 手写数字识别
从torchvision中读取手写数据集,用torchvision.transforms.ToTensor将图片转换为张量,用DataLoader将数据集分批次打包,从nn.Module中继承模型类,用nn.Conv2d搭建卷积层,nn.MaxPool2dl搭建池化层,nn.Linear搭建线性层,nn.Flatten()将数据拉平,nn.Sofemax()作为激活函数。搭建的模型用tensorboard可视化如下图:
3.1.1 Model程序
import torch
from torch import nn
class CnnModel(nn.Module):
def __init__(self):
super(CnnModel, self).__init__()
self.conv1 = nn.Conv2d(in_channels=1, out_channels=3, kernel_size=3, stride=1, padding=0)
self.pool1 = nn.MaxPool2d(2)
self.conv2 = nn.Conv2d(3, 3, 3, 1, 0)
self.pool2 = nn.MaxPool2d(2)
self.flaten = nn.Flatten()
self.linear = nn.Linear(75, 10)
self.sofmax = nn.Softmax(1)
def forward(self, x):
x = self.conv1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.pool2(x)
x = self.flaten(x)
x = self.linear(x)
x = self.sofmax(x)
return x
if __name__ == '__main__': #测试model是否正确
x = torch.ones(1, 1, 28, 28)
model = CnnModel()
output = model.forward(x)
print(output.shape)
print(output)
3.1.2 主函数程序
读取数据集并将image数据转换为张量,每50张图片作为一个批次,丢入model进行训练,用交叉熵作为损失函数,记录model每个批次的loss值和每一个epoach数据集全部的损失值,训练完后,用torch.save保持训练好后model的全部参数。
import torch
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from Model import * #导入Model
#读取图片并转换为tensor型数据
trans_tensor = torchvision.transforms.ToTensor() #实例化图片转tensor的类
train_data = torchvision.datasets.MNIST("./data_minst", train=True, transform=trans_tensor, download=True)
test_data = torchvision.datasets.MNIST("./data_minst", train=False, transform=trans_tensor, download=True)
writer =SummaryWriter("./logs")
#将数据分批量打包
batch = 50
train_data_batch = DataLoader(train_data, batch_size=batch)
test_data_batch = DataLoader(test_data, batch_size=batch)
#模型实例化
MinModel = CnnModel()
#优化器实例化
learingrate = 1e-2
optimizer = torch.optim.SGD(MinModel.parameters(), lr=learingrate)
#损失函数
loss_f = nn.CrossEntropyLoss()
epoach = 20
train_size = 1
for i in range(epoach):
total_loss = 0
print("——————————第{}轮训练开始——————————————".format(i+1))
for data in train_data_batch:
img, label = data #取出img和label
y = MinModel(img) #得到model输出
loss = loss_f(y, label) #计算损失值
writer.add_scalar("Loss值随训练次数的变化", loss, train_size)
total_loss += loss #每一轮的累计损失值
optimizer.zero_grad() #每一次训练将梯度清0
loss.backward() #自动求导
optimizer.step() #用优化器自动更新参数
acc_train = ((y.argmax(1)==label).sum())/batch
writer.add_scalar("准确率随训练次数的变化", acc_train, train_size)
if(train_size%100==0): #每训练100次输出此batch的损失值
print("第{}次训练的loss值为{}".format(train_size, loss))
train_size += 1
print("********第{}轮训练全部的loss值是:{}***********".format(i+1, total_loss))
torch.save(MinModel, "./Model_save/model.pth") #保持model
writer.close()
总结
实现了用pytorch框架从0开始搭建网络,用手写数字的数据集进行了实践,掌握了用tensorboard实现model和训练数据的可视化。在论文方面,较系统的认识了欧拉和拉格朗日对流体运动的观点。