1、导入数据(torch.utils.data.DataLoader)
在内部定义数据的路径(os.path.join(data_dir, data_name)、对数据进行处理等(transfrom(旋转,totensor,标准化)、batch_size,shuffle等)。
2、定义模型,损失(交叉熵损失nll_loss(log_softmax)或者CrossEntropyLoss()),优化函数,学习率,动量等超参数等。
3、定义训练函数(model.train() ,数据,预测,损失函数,优化,epoch等)
4、定义测试函数(model.eval(),数据,预测,损失函数,衡量标准(Loss、准确率等)
5、迭代运算,几个epoch(此时将数据写入函数)
在进行MNIST数据分析时,可以自行下载mnist数据,也可以通过torchvision 的 datasets导入数据。
但是一般导入数据较为慢,可自行先下载好数据之后,再进行处理。
百度云自取mnist数据:
https://pan.baidu.com/s/1ZOknxUEmWPTKMveBbw_erg
提取码:8t8e
import torch
import numpy as np
import torch.nn as nn
import torch.utils.data
from torchvision import datasets,transforms
import torch.nn.functional as F
在导入必要的包之后,一般需要对数据进行处理(标准化),使得数据的训练更快、更容易收敛。
因为mnist数据集为单通道图像(灰色图像,多通道为RGB图像等),所以此时可以用以下方法计算训练数据集的均值和标准差。
minist_data=datasets.MNIST("./MNIST_data",train=True,download=True,transform=transforms.Compose([transforms.ToTensor(),])) # 下载数据,如果不存在会自动下载,并将其转化为tensor(若下载好数据此处download为false)
print(minist_data) # 了解数据的信息
print(minist_data[0][0].shape) # 了解数据的size,此时为[1,28,28]
# 计算均值和方差(将数据转为numpy格式)
data=[d[0].data.cpu().numpy() for d in minist_data]
mean=np.mean(data)
std=np.std(data)
print(mean,std)
此处导入数据为固定的格式 用(torch.utils.data.DataLoader)
batch_size=32
train_dataloader=torch.utils.data.DataLoader(
datasets.MNIST("./MNIST_data",train=True,download=False,
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((mean,),(std,))])),
batch_size=batch_size,shuffle=True,pin_memory=True)
test_dataloader=torch.utils.data.DataLoader(
datasets.MNIST("./MNIST_data",train=False,download=False,
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((mean,),(std,))])),
batch_size=batch_size,shuffle=True,pin_memory=True)
此处通过类定义模型的内部参数(固定使用class Net(nn.Module))
# 定义卷积神经网络内部的参数
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__() # 继承init
self.conv1=nn.Conv2d(1,20,5,1) # 28*28的1通道转为 24*24的20通道的数据
self.conv2=nn.Conv2d(20,50,5,1) # 卷积核为5*5 步长为1 输入20通道 输出50通道
self.fc1=nn.Linear(4*4*50,500)
self.fc2=nn.Linear(500,10)
def forward(self, x):
# 开始输入为x=1*28*28
x=F.relu(self.conv1(x)) # 20*24*24
x=F.max_pool2d(x,2,2) # 20*12*12
x=F.relu(self.conv2(x)) # 50*8*8
x=F.max_pool2d(x,2,2) # 50*4*4
x=x.view(-1,4*4*50) #reshape 将其转化为一维数据(-1为batch处理的量)用于全连接层
x=F.relu(self.fc1(x))
x=self.fc2(x)
return F.log_softmax(x,dim=1) # 每个图片归于每一类的概率
# 定义训练的各种参数
device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
lr=0.01
momentum=0.5
model=Net().to(device) # 将其弄到GPU上进行训练(速度快,并行)
optimizer=torch.optim.SGD(model.parameters(),lr=lr,momentum=momentum) # 定义优化方法,用SGD方法进行优化
num_epoch=2
1.训练函数
def train(model,device,train_loader,optimizer,epoch):
model.train()
for idx,(data,target) in enumerate(train_loader): #idx为第几个数据 (data,target)为相应的数据值 enumerate可以自己给数据加索引值,一般均用此方法对数据进行批量处理
data,target=data.to(device),target.to(device)
pred=model(data)
loss=F.nll_loss(pred,target) # 此时由于先log(softmax),所以和直接使用交叉熵损失函数一样的效果
# SGD
optimizer.zero_grad() # 先将梯度置0,否则在计算过程中,梯度会越来越大
loss.backward() # 反向计算梯度
optimizer.step()
# 打印出损失值
if idx%100==0:
print("Train Epoch:{},iteration:{},Loss:{}".format(epoch,idx,loss.item()))
2.测试函数
def test(model,device,test_loader):
model.eval()
total_loss=0.
correct=0.
with torch.no_grad(): # 测试函数无需计算梯度
for idx,(data,target) in enumerate(test_loader):
data,target=data.to(device),target.to(device)
output=model(data) # batch_size*10
total_loss+=F.nll_loss(output,target,reduction="sum").item() # 计算总的损失值
pred=output.argmax(dim=1) # batch_size*1 # 将数据取最大的概率值
correct+=pred.eq(target.view_as(pred)).sum().item() # 将预测值和真实值进行比较,此时维度需要设置为一样
total_loss/=len(test_loader.dataset) # 计算损失
acc=correct/len(test_loader.dataset) # 计算准确率
print("Test loss: {},Accuracy: {}".format(total_loss,acc))
# 迭代进行运算 循环几个epoch
for epoch in range(num_epoch):
train(model,device,train_dataloader,optimizer,epoch)
test(model, device,test_dataloader)
# 将训练的模型进行保存
torch.save(model.state_dict(),"mnist_cnn.pt")
import torch
import numpy as np
import torch.nn as nn
import torch.utils.data
from torchvision import datasets,transforms
import torch.nn.functional as F
# 计算均值和方差
minist_data=datasets.MNIST("./MNIST_data",train=True,download=True,transform=transforms.Compose([transforms.ToTensor(),])) # 下载数据,如果不存在会自动下载,并将其转化为tensor
print(minist_data)
print(minist_data[0][0].shape)
data=[d[0].data.cpu().numpy() for d in minist_data]
mean=np.mean(data)
std=np.std(data)
print("数据的均值为:{},方差为:{}".format(mean,std))
# 定义训练和测试过程
def train(model,device,train_loader,optimizer,epoch):
model.train()
for idx,(data,target) in enumerate(train_loader): #idx为第几个数据 (data,target)为相应的数据值 enumerate可以自己给数据加索引值
data,target=data.to(device),target.to(device)
pred=model(data)
loss=F.nll_loss(pred,target)
# SGD
optimizer.zero_grad()
loss.backward()
optimizer.step()
if idx%100==0:
print("Train Epoch:{},iteration:{},Loss:{}".format(epoch,idx,loss.item()))
def test(model,device,test_loader):
model.eval()
total_loss=0.
correct=0.
with torch.no_grad():
for idx,(data,target) in enumerate(test_loader):
data,target=data.to(device),target.to(device)
output=model(data) # batch_size*10
total_loss+=F.nll_loss(output,target,reduction="sum").item()
pred=output.argmax(dim=1) # batch_size*1
correct+=pred.eq(target.view_as(pred)).sum().item()
total_loss/=len(test_loader.dataset)
acc=correct/len(test_loader.dataset)
print("Test loss: {},Accuracy: {}".format(total_loss,acc))
# 定义卷积神经网络内部的参数
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
self.conv1=nn.Conv2d(1,20,5,1) # 28*28的1通道转为 24*24的20通道的数据
self.conv2=nn.Conv2d(20,50,5,1) # 卷积核为5*5 步长为1 输入20通道 输出50通道
self.fc1=nn.Linear(4*4*50,500)
self.fc2=nn.Linear(500,10)
def forward(self, x):
# 开始输入为x=1*28*28
x=F.relu(self.conv1(x)) # 20*24*24
x=F.max_pool2d(x,2,2) # 20*12*12
x=F.relu(self.conv2(x)) # 50*8*8
x=F.max_pool2d(x,2,2) # 50*4*4
x=x.view(-1,4*4*50) #reshape 将其转化为一维数据(-1为batch处理的量)
x=F.relu(self.fc1(x))
x=self.fc2(x)
return F.log_softmax(x,dim=1) # 每个图片归于每一类的概率
# 定义训练的各种参数
device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
batch_size=32
lr=0.01
momentum=0.5
model=Net().to(device)
optimizer=torch.optim.SGD(model.parameters(),lr=lr,momentum=momentum)
num_epoch=2
# 批量导入测试数据和训练数据
train_dataloader=torch.utils.data.DataLoader(
datasets.MNIST("./MNIST_data",train=True,download=True,
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((mean,),(std,))])),
batch_size=batch_size,shuffle=True,pin_memory=True)
test_dataloader=torch.utils.data.DataLoader(
datasets.MNIST("./MNIST_data",train=False,download=True,
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((mean,),(std,))])),
batch_size=batch_size,shuffle=True,pin_memory=True)
# 迭代进行运算 循环几个epoch
for epoch in range(num_epoch):
train(model,device,train_dataloader,optimizer,epoch)
test(model, device,test_dataloader)
# 将训练的模型进行保存
torch.save(model.state_dict(),"mnist_cnn.pt")
torchvision还有一种数据为FashionMNIST,其比MNIST更为复杂,但是其格式和MNIST完全一样 1* 28 *28 ,最后分类也是分为十种类型,也可用于基础深度学习训练。