# 1加载必要的库
import torch
import torch.nn as nn #加入网络模型torch.nn,用nn作为代号,他是专门用于神经网络设计的模块化接口。有nn.Parameter;nn.linear;nn.functionann.Module;nn.Sequential
import torch.nn.functional as F #创建了神经网络里面常用的处理函数。如没有激活函数的神经元,各种激活函数等等
#https://blog.csdn.net/HiWangWenBing/article/details/120614234?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169837708216800188571816%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=169837708216800188571816&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-120614234-null-null.142^v96^pc_search_result_base9&utm_term=torch.nn%E5%BA%93&spm=1018.2226.3001.4187
import torch.optim as optim #主要包含模型训练的优化器Optimizer,主要优化算法有SGD,adam,adagrad等等
from torchvision import datasets,transforms #对数据库进行操作,包括transformation提供支持
torch.__version__
from torch.utils.data import DataLoader#datasets提供常用的数据集加载,transforms,提供常用的数据预处理操作
# 2定义超参数
BATCH_SIZE = 512 #每一批处理的数据
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") #如果有gpu就用设备gpu,否则就用cpu
EPOCHS = 10 #训练数据集的轮数
# 3构建pipeline(transforms),对图像做处理
pipeline = transforms.Compose([
transforms.ToTensor(),#将图片转化为tensor
transforms.Normalize((0.137,),(0.3081,))#正则化,防止模型出现过拟合的时候降低模型复杂度
])
#下载、加载数据
from torch.utils.data import DataLoader
#下载数据
train_set = datasets.MNIST("data",train=True,download =True,transform=pipeline)
#从MNIST里面下载训练数据,放入data文件里面,用pipe对图像做处理
test_set = datasets.MNIST("data",train=False,download =True,transform=pipeline)
#和上面类似
#加载数据
train_loader = DataLoader(train_set,batch_size= BATCH_SIZE,shuffle =True)
test_loader = DataLoader(test_set,batch_size=BATCH_SIZE,shuffle =True)
#4 插入代码,显示MNIST的图片
with open("./data/MNIST/raw/train-images-idx3-ubyte","rb") as f:
file =f.read()
#读取图片
imagel = [int(str(item).encode('ascii'),16) for item in file [16:16+784]] #16+784存储的是图片
print(imagel) #输出图片
#显示保存
import cv2
import numpy as np
imagel_np = np.array(imagel,dtype=np.uint8).reshape(28,28,1) #先转化为数组形式,类型是无符号整型,因为是灰度,所以通道是1不是3
print(imagel_np.shape)#打印出来图片的高宽
cv2.imwrite("digit.jpg",imagel_np) #保存图片
#5 构建网络模型
class Digit(nn.Module): #构建一个Digit的网络模型,继承于父类Moudle
def __init__(self): #构造方法
super().__init__() #调用父类构造方法
#卷积层
self.conv1 = nn.Conv2d(1,10,5) # 1:灰度图片的通道,也就是输入通道, 10:输出通道 5:卷积核
self.conv2 = nn.Conv2d(10,20,3) # 10: 输入通道 20:输出通道 3 :卷积核
#全连接层
self.fc1 = nn.Linear (20*10*10 ,500) #20*10*10 输入通道, 500 输出通道
self.fc2 = nn.Linear (500,10) #500:输入通道 10:输出通道
def forward(self ,x): #前向传播
input_size = x.size(0) #取得是batch_size ,取的是第一个 格式是 batch_size x1 x28 x28
#卷积
x = self.conv1(x) #把数据丢进刚刚建立的卷积层里面去
#输入:batch*1*28*28 ,输出 :batch*10*24*24(28-5+1=24)
#激活
x =F.relu(x)
#池化
x = F.max_pool2d(x,2,2) #对图片进行压缩,减少数据量 卷积核2,步长2
#输入:batch*10*24*24 输出:batch*10*12*12 (24/2)
#重复卷积激活池化
x =self.conv2(x) #输入:batch*10*12*12 输出:batch*20*10*10(12-3+1)
x =F.relu(x)
x =x.view(input_size,-1) #将图片拉平,因为这里图片还是二维的,将其送入全连接层的输入需要转化成一维数据
#-1的意思就是自动计算维度,这里其实就是20*10*10=2000
#送入全连接层
x =self.fc1(x) #输入 :batch *2000 输出:batch*500 上面已经构造好了的
x =F.relu(x) #激活,shape不变 这里第一层就结束了
x =self.fc2(x) #输入:batch *500 ,输出 10
#返回是哪个数字最大的概率
output= F.log_softmax(x,dim=1)
return output
# 6定义优化器
model = Digit().to(DEVICE)
optimizer =optim.Adam(model.parameters())
#7 定义训练方法
def train_model (model ,device ,train_loader,optimizer,epoch):#把模型,设备和训练集,优化器,epoch传入进去
#模型训练
model.train()
for batch_index,(data,target) in enumerate(train_loader): #batch_index,数据下标;从train_loader里面读取数据,一个是data(图片),一个是target(标签)
#enmuerate函数如下
#部署到DEVICE上面
data,target =data.to(device),target.to(device)
#梯度初始化为0
optimizer.zero_grad()
#训练后的结果
output =model(data)
#计算损失,用output和target计算
loss =F.cross_entropy(output,target)
#反向传播
loss.backward()
#参数优化
optimizer.step()
if batch_index % 3000 ==0:
print("Train Epoch :{} \t Loss : {:.6f}".format(epoch,loss.item()))
#8 定义测试方法
def test_model(model,device,test_loader): #把模型,设备和测试集传入进去
#模型验证
model.eval()
#正确率
correct =0.0
#测试损失
test_loss =0.0
with torch.no_grad(): #不会计算梯度,也不会进行反向传播
for data ,target in test_loader:
#部署到device上
data,target = data.to(device) ,target.to(device)
#测试数据
output = model(data)
#计算测试损失
test_loss +=F.cross_entropy(output,target).item()
pred = torch.max(output.data ,1)[1]
correct += pred.eq(target.view_as(pred)).sum().item()
#找到概率值的最大下标
#pred =output.max(1,keepdim=True)#值,索引
#计算正确的值
#correct += pred.eq(target.view_as(pred)).sum().item()
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)))
# print("Test--Average loss:{:.4f},Accuracy :{:3.f}\n".format(
# test_loss,100.0*correct / len(test_loader.dataset)))
# 9 调用 方法7/8
for epoch in range (1,EPOCHS+1):
train_model(model,DEVICE,train_loader,optimizer,epoch)
test_model(model,DEVICE,test_loader)
结果:
Train Epoch :1 Loss : 2.312109 Test set: Average loss: 0.0002, Accuracy: 9748.0/10000 (97%) Train Epoch :2 Loss : 0.118887 Test set: Average loss: 0.0001, Accuracy: 9848.0/10000 (98%) Train Epoch :3 Loss : 0.052688 Test set: Average loss: 0.0001, Accuracy: 9846.0/10000 (98%) Train Epoch :4 Loss : 0.018144 Test set: Average loss: 0.0001, Accuracy: 9829.0/10000 (98%) Train Epoch :5 Loss : 0.043597 Test set: Average loss: 0.0001, Accuracy: 9879.0/10000 (99%) Train Epoch :6 Loss : 0.024002 Test set: Average loss: 0.0001, Accuracy: 9874.0/10000 (99%) Train Epoch :7 Loss : 0.018111 Test set: Average loss: 0.0001, Accuracy: 9895.0/10000 (99%) Train Epoch :8 Loss : 0.015440 Test set: Average loss: 0.0001, Accuracy: 9912.0/10000 (99%) Train Epoch :9 Loss : 0.027070 Test set: Average loss: 0.0001, Accuracy: 9889.0/10000 (99%) Train Epoch :10 Loss : 0.013400 Test set: Average loss: 0.0001, Accuracy: 9859.0/10000 (99%)