👑主页:吾名招财
👓简介:工科学硕,研究方向机器视觉,爱好较广泛…
💫签名:面朝大海,春暖花开!
pytorch快速入门——手写数字分类GPU加速
一、tensor
1,理解tensor
Tensor就是一个N维矩阵
(1)一维矩阵(向量)
(2)二维矩阵(单通道灰度图像)
二维矩阵:单通道图像,Excel数据等
(3)三维矩阵(彩色三通道图像)
2,创建tensor
create_tensor.py
(1)导入pytorch库
import torch
print(torch.cuda.is_available())
(2)创建一维矩阵
#一维向量
data = torch.tensor([1,2,3,4])
print(data)
#tensor([1, 2, 3, 4])
(3)创建两行四列的二维矩阵
#两行四列的二维矩阵
data = torch.tensor([[1,2,3,4],[2,3,4,5]])
print(data)
# tensor([[1, 2, 3, 4],
# [2, 3, 4, 5]])
(4)生成两行五列的随机矩阵
#生成两行五列的随机矩阵
data = torch.randn(2, 5)
print(data)
# tensor([[ 1.4212, 0.0784, -1.0818, -0.6843, 0.9947],
# [-1.3718, 0.9556, 1.1089, -0.8161, -0.2081]])
(5)生成两行五列全为1的随机矩阵
#生成两行五列全是一的矩阵
data = torch.ones(2, 5)
print(data)
# tensor([[1., 1., 1., 1., 1.],
# [1., 1., 1., 1., 1.]])
(6)生成两行五列全为0的随机矩阵
#生成两行五列全是0的矩阵
data = torch.zeros(2, 5)
print(data)
# tensor([[0., 0., 0., 0., 0.],
# [0., 0., 0., 0., 0.]])
#tensor中非常重要的一些属性
data = torch.zeros(2, 5)
3,tensor基本属性
(1)形状shape
#1,形状
print(data.shape)
# torch.Size([2, 5])
print(data.shape[0],data.shape[1]) #2 5 (两行五列)
(2)数据类型dtype
#2,数据类型默认float32
print(data.dtype)
#torch.float32
(3)转换数据类型data.to()
#更改数据类型
data = data.to(torch.int)
print(data)
# tensor([[0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0]], dtype=torch.int32)
print(data.dtype)
# torch.int32
4,tensor的基本操作
(1)通过下标获取对应的值(data[0][4].item())
import torch
#通过下标获取对应的值
data = torch.tensor([[1,2,3,4,5],[2,3,4,5,6]])
data = data.to(torch.int)
print(data)
print(data.dtype)
#拿到第0行4列的值(但还是tensor类型的)
print(data[0][4])
# tensor(5, dtype=torch.int32)
#将tensor转成真正要的数据
print(data[0][4].item()) #5
(2)加减乘除运算(+ - * /)
#加法运算,对应位置相加
data_a = torch.ones([3,3])
data_b = torch.zeros([3,3])
print(data_a+data_b) #加完 后还是1
data_a = torch.ones([3,3])
data_b = torch.tensor([[1,2,3],[2,3,4],[3,4,5]])
print(data_a+data_b) #加完
# tensor([[2., 3., 4.],
# [3., 4., 5.],
# [4., 5., 6.]])
print(data_a-data_b)
# tensor([[ 0., -1., -2.],
# [-1., -2., -3.],
# [-2., -3., -4.]])
print(data_a*data_b)
# tensor([[1., 2., 3.],
# [2., 3., 4.],
# [3., 4., 5.]])
print(data_a/data_b)
# tensor([[1.0000, 0.5000, 0.3333],
# [0.5000, 0.3333, 0.2500],
# [0.3333, 0.2500, 0.2000]])
print(data_a/3)
# tensor([[0.3333, 0.3333, 0.3333],
# [0.3333, 0.3333, 0.3333],
# [0.3333, 0.3333, 0.3333]])
(3)求所有值的和torch.sum()
#求所有的值的和
data_b = torch.tensor([[1,2,3],[2,3,14],[3,4,25]])
print(torch.sum(data_b))
# tensor(27)
# 1 2 3
# 2 3 14
# 3 4 25
print(torch.sum(data_b,axis=0)) #axis=0表示竖着相加
# tensor([ 6, 9, 42])
print(torch.sum(data_b,axis=1)) #axis=1表示横着相加
# tensor([ 6, 19, 32])
(4)求平均值torch.mean()
#求平均值(输入类型必须为浮点型或者复数)
print(torch.mean(data_b.to(torch.float),axis=1))
# tensor([ 2.0000, 6.3333, 10.6667])
#
#假设下方为模型预测的结果
predict = torch.tensor([1,0,1,0,2,0,1,0,1,2])
#假设下方为标签即所知的标准答案
label = torch.tensor([0,1,1,0,0,0,1,0,2,2])
#这里计算一下预测出来的东西和标准答案之间有多少是重合的
#判断大于号
print(predict > label)
#tensor([ True, False, False, False, True, False, False, False, False, False])
#判断等于号是否为真
print(predict == label)
# tensor([False, False, True, True, False, True, True, True, False, True])
#查看10个中总共对了几个(True认为1,Flase认为0)
print(torch.sum(predict == label))
#tensor(6) 总共6个是预测值与标签相等的
#使用mean来求其准确率
print(torch.mean((predict == label).to(torch.float)).item())
#0.6000000238418579
(5)索引排序torch.argsort()
#argsort将tensor值中从小到大的排序的索引拿到
data = torch.tensor([1,2,3,0,9,8,-1,-10])
print(torch.argsort(data))
# tensor([7, 6, 3, 0, 1, 2, 5, 4])
(6)最小值最大值索引(argmin,argmax)
#数据中最小的值的索引得到
print(torch.argmin(data))
# tensor(7)
#数据中最大的值的索引得到
print(torch.argmax(data))
# tensor(4)
#arg也可以接受轴的概念
data = torch.tensor([[1,2,3,0,9,8,-1,-10],[5,2,3,6,9,8,11,-10]])
print(torch.argmax(data, axis=0))
# tensor([1, 0, 0, 1, 0, 0, 1, 0]) #第一列5大,5是索引1。
(7)变形操作(如将其2行8列变成8行2列等)
##最后说一个操作变形
data = data.view(8,2) #将其2行8列变成8行两列
print(data)
# tensor([[ 1, 2],
# [ 3, 0],
# [ 9, 8],
# [ -1, -10],
# [ 5, 2],
# [ 3, 6],
# [ 9, 8],
# [ 11, -10]])
##最后说一个操作变形
data = data.view(8,-1) #第2列写个-1表示根据8行自动推断有多少列
print(data)
##最后说一个操作变形
data = data.view(-1,2) #第1列写个-1表示根据2列自动推断有多少行
print(data)
#将二维矩阵变为一个向量,直接-1即可
data = data.view(-1)
print(data)
# tensor([ 1, 2, 3, 0, 9, 8, -1, -10, 5, 2, 3, 6, 9, 8,
# 11, -10])
二、理解神经网络
1,分类、回归、聚类
神经网络、深度学习本质上就是数学再加上玄学
但我们仅仅是个开发者,我们要做的就是使用知名的框架如pytorch等来实现功能
至于里面的数学公式、神经网络结构为什么这样,最底层的机理暂时不用管,只要知道这样,这样 就能达到这样的效果即可
什么是分类、什么是回归、什么是聚类,这些都是机器学习或者深度学习中最简单的任务了
左边这些就是数据,右侧就是结果
阅片无数的宅男(看做是神经网络、模型)
(1)分类
对离散值的预测就是分类
(2)回归
对连续值的预测就是回归
颜值打分神器
(3)聚类
还是阅片无数的宅男,但是记性不太好,不认识这些人,潜移默化的将这些照片归类,会发现好看的在一类,不好看的一类
但是不知道这个类别叫什么,也不知道 这个类别叫什么,这种任务就是聚类
分类与聚类都是把数据进行区分,但是最大的一个区别就是聚类中的数据是没有所谓的标签的
2,区分猫狗
(1)差异计算
把两张图片的像素矩阵算一个差异程度,算完差异度后跟谁的差异度最小就是那个类别
区分是猫还是狗
(2)线性分类
更好的解决方案线性分类
假设有个函数,f()
x就是像素值,W、b
是函数中的参数,如果W、b确定了,随便一张图x进来都能给这张图算出一个结果,结果表示 如下方右侧
这个函数能分出10类
437.9是这里面最大的,所以这张图就是狗,如果w、b比较厉害的话,那么随便哪个都能预测的准确
(3)softmax
得到了得分,分数越高代表,但没有好的解释性,怎么看437.9到底高还是不高,使用
Softmax将得分变成概率
Softmax怎么算的
就是算个比例吧
现在的w、b就是最好的了吗
(4)损失函数
怎么度量这个结果的好坏标准,使用损失函数
交叉熵损失函数
可以看到这个损失值是比较大的,那么怎么让他的损失值变小呢,这里就需要靠梯度下降
(5)梯度下降
梯度下降就是为了算出(w、b)
(6)非线性分类
线性分类是尝试使用直线将猫狗分割开,但是如果其分布如下非线性的话
就无法将其分割开了
接下来就是使用神经网络将其分隔开
神经网络就是在搭积木
有两个全连接层,除了最上面的和最下面的,搭积木一样
(7)激活函数
每个格子都有(w*x+b)(激活函数)
如下三角形和圆圈,找不到任何直线将其区分开
那如果使用一个线性分类器,线性分类的方式将其分隔开,会有漏判
没激活函数的nn 要画n条直线
有激活函数的NN 拟合一条曲线
激活函数种类如下
神经网络就是一个个的格子,去算一个w、b再算一个激活函数
接下来看其怎么预测的
(8)预测
Relu激活函数,若是大于0等于其本身 ,若是小于则等于0
-8套一个激活函数就是0
(9)训练
神经网络的训练流程就是找到一组合适的w、b使得损失值最小
三、手写数字分类
接下来的几集视频会带着大家用pytorch搭建一个神经网络
实现一个图像分类的任务
使用的数据为train.csv
资源链接:https://download.csdn.net/download/qq_44870829/90487677
使用Excel表格打开后如下整个数据集有42000张图片,每张图片都是由784个像素点组成的灰度图,label数据是从0~9。
一共784列即784个像素点,每行代表一张灰度图,一共42000行即42000张图片
若是使用pytorch搭建神经网络来做这样一个图像分类任务的话,先捋一下逻辑
1,定义网络结构
#3神经网络,可以将其看成黑盒子,或者一个 python函数,这个函数有了输入就有了输出
#784个像素点构成的灰度图——》函数——》10个概率(0 1 2 3 4 5 6 7 8 9的概率)
#那么函数该怎么定义呢,这个步骤就是定义网络结构的步骤
#定义网络结构
#[1,784]*[784,444] = [1,444]*[444,512] = [1,512]*[512,512] = [1,512]*[512,10] = [1,10]
#输入层 in_channel 784 out_channel 444
#隐藏层1 in_channel 444 out_channel 512
#隐藏层2 in_channel 512 out_channel 512
#输出层 in_channel 512 out_channel 10
(无论中间层是多少,都会有输出层)
全连接层有两个最重要的属性一个叫in_channel 一个叫out_channel,输入输出频道看做成有多少个点,或者 叫多少个特征,或者叫多少个数据
能被数据所确定的只有输入层的in_channel,输出层的out_channel,中间层的输入输出频道都是可以 自定义的
接下来就是使用pytorch将上方的网络搭建起来了,使用torch.nn模块中的东西
#定义nn神经网络
import torch
import torch.nn as nn
#3神经网络,可以将其看成黑盒子,或者一个 python函数,这个函数有了输入就有了输出
#784个像素点构成的灰度图——》函数——》10个概率(0 1 2 3 4 5 6 7 8 9的概率)
#那么函数该怎么定义呢,这个步骤就是定义网络结构的步骤
#定义网络结构
#[1,784]*[784,444] = [1,444]*[444,512] = [1,512]*[512,512] = [1,512]*[512,10] = [1,10]
#输入层 in_channel 784 out_channel 444
#隐藏层1 in_channel 444 out_channel 512
#隐藏层2 in_channel 512 out_channel 512
#输出层 in_channel 512 out_channel 10
#伪造个随机数据
data = torch.rand(1, 784) #共784个像素,将其转为一行784列的数据
#序列化(搭积木),里面可以放入任意想要的层,从前向后
model = nn.Sequential(
nn.Linear(784, 444), #Linear全连接层或者称线性层
nn.ReLU(), #加入激活层
nn.Linear(444, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
nn.Softmax() #将值转换成概率
)
#这个函数可以返回一个模型对象给我们
print(model)
# Sequential(
# (0): Linear(in_features=784, out_features=444, bias=True)
# (1): ReLU()
# (2): Linear(in_features=444, out_features=512, bias=True)
# (3): ReLU()
# (4): Linear(in_features=512, out_features=512, bias=True)
# (5): ReLU()
# (6): Linear(in_features=512, out_features=10, bias=True)
# (7): Softmax(dim=None)
# )
#现在的model已经是一个模型了 ,但是现在模型里面的w和b是随机值,是不好用的
#后面还需要通过数据驱动其进行训练(但是训练之前还要做一件事情要验证一下此模型搭建出来合不合理)
#随机一个数据进行能否得到输出的十个概率值
predict = model(data) #进行相关的算
print(predict)
# tensor([[0.0944, 0.0975, 0.1039, 0.0938, 0.1050, 0.1013, 0.1024, 0.1010, 0.0998,
# 0.1011]], grad_fn=<SoftmaxBackward0>)
2,整理数据集
接下来就是读取数据并对其进行一定的整理
训练是需要数据推动的
import pandas as pd
raw_df = pd.read_csv('train.csv')
print(raw_df.head())
# label pixel0 pixel1 pixel2 ... pixel780 pixel781 pixel782 pixel783
# 0 1 0 0 0 ... 0 0 0 0
# 1 0 0 0 0 ... 0 0 0 0
# 2 1 0 0 0 ... 0 0 0 0
# 3 4 0 0 0 ... 0 0 0 0
# 4 0 0 0 0 ... 0 0 0 0
#
# [5 rows x 785 columns]
#将标签那列数据拿出来
label = raw_df['label']
print(label)
# 0 1
# 1 0
# 2 1
# 3 4
# 4 0
# ..
# 41995 0
# 41996 1
# 41997 7
# 41998 6
# 41999 9
# Name: label, Length: 42000, dtype: int64
#将df的数据类型转成numpy的,去掉索引
label = raw_df['label'].values
print(label)
# [1 0 1 ... 7 6 9]
#特征(删除label列,剩下的就是特征
raw_df = raw_df.drop(['label'], axis=1) #axis=1表示y轴
feature = raw_df.values
print(len(label),len(feature))
#将整个数据集划分成两个数据集,一个训练集、一个测试集,80%是用来神经网络训练的
#训练集相当于日常作业,测试集就是考试,日常作业做的好不代表考试做的好,所以还需要测试
#这里的数据集实际上已经被打乱过了,现在直接做个切片即可
train_feature = feature[:int(0.8*len(feature))]
train_label = label[:int(0.8*len(label))]
test_feature = feature[int(0.8*len(feature)):]
test_label = label[int(0.8*len(label)):]
print(len(train_feature),len(train_label),len(test_feature),len(test_label))
#33600 33600 8400 8400
3,训练模型
import pandas as pd
#定义nn神经网络
import torch
import torch.nn as nn
raw_df = pd.read_csv('train.csv')
print(raw_df.head())
# label pixel0 pixel1 pixel2 ... pixel780 pixel781 pixel782 pixel783
# 0 1 0 0 0 ... 0 0 0 0
# 1 0 0 0 0 ... 0 0 0 0
# 2 1 0 0 0 ... 0 0 0 0
# 3 4 0 0 0 ... 0 0 0 0
# 4 0 0 0 0 ... 0 0 0 0
#
# [5 rows x 785 columns]
#将标签那列数据拿出来
label = raw_df['label']
print(label)
# 0 1
# 1 0
# 2 1
# 3 4
# 4 0
# ..
# 41995 0
# 41996 1
# 41997 7
# 41998 6
# 41999 9
# Name: label, Length: 42000, dtype: int64
#将df的数据类型转成numpy的,去掉索引
label = raw_df['label'].values
print(label)
# [1 0 1 ... 7 6 9]
#特征(删除label列,剩下的就是特征
raw_df = raw_df.drop(['label'], axis=1) #axis=1表示y轴
feature = raw_df.values
print(len(label),len(feature))
#将整个数据集划分成两个数据集,一个训练集、一个测试集,80%是用来神经网络训练的
#训练集相当于日常作业,测试集就是考试,日常作业做的好不代表考试做的好,所以还需要测试
#这里的数据集实际上已经被打乱过了,现在直接做个切片即可
train_feature = feature[:int(0.8*len(feature))]
train_label = label[:int(0.8*len(label))]
test_feature = feature[int(0.8*len(feature)):]
test_label = label[int(0.8*len(label)):]
print(len(train_feature),len(train_label),len(test_feature),len(test_label))
#33600 33600 8400 8400
#将numpy转为tensor,还要将其数据类型变为float
train_feature = torch.tensor(train_feature).to(torch.float) #数据应该是浮点数
train_label = torch.tensor(train_label) #标签 应该是整数
test_feature = torch.tensor(test_feature).to(torch.float)
test_label = torch.tensor(test_label)
#3神经网络,可以将其看成黑盒子,或者一个 python函数,这个函数有了输入就有了输出
#784个像素点构成的灰度图——》函数——》10个概率(0 1 2 3 4 5 6 7 8 9的概率)
#那么函数该怎么定义呢,这个步骤就是定义网络结构的步骤
#定义网络结构
#[1,784]*[784,444] = [1,444]*[444,512] = [1,512]*[512,512] = [1,512]*[512,10] = [1,10]
#输入层 in_channel 784 out_channel 444
#隐藏层1 in_channel 444 out_channel 512
#隐藏层2 in_channel 512 out_channel 512
#输出层 in_channel 512 out_channel 10
#伪造个随机数据
data = torch.rand(1, 784) #共784个像素,将其转为一行784列的数据
#序列化(搭积木),里面可以放入任意想要的层,从前向后
model = nn.Sequential(
nn.Linear(784, 444), #Linear全连接层或者称线性层
nn.ReLU(), #加入激活层
nn.Linear(444, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
nn.Softmax() #将值转换成概率
)
#这个函数可以返回一个模型对象给我们
print(model)
# Sequential(
# (0): Linear(in_features=784, out_features=444, bias=True)
# (1): ReLU()
# (2): Linear(in_features=444, out_features=512, bias=True)
# (3): ReLU()
# (4): Linear(in_features=512, out_features=512, bias=True)
# (5): ReLU()
# (6): Linear(in_features=512, out_features=10, bias=True)
# (7): Softmax(dim=None)
# )
#现在的model已经是一个模型了 ,但是现在模型里面的w和b是随机值,是不好用的
#后面还需要通过数据驱动其进行训练(但是训练之前还要做一件事情要验证一下此模型搭建出来合不合理)
#随机一个数据进行能否得到输出的十个概率值
# predict = model(data) #进行相关的算
# print(predict)
# # tensor([[0.0944, 0.0975, 0.1039, 0.0938, 0.1050, 0.1013, 0.1024, 0.1010, 0.0998,
# # 0.1011]], grad_fn=<SoftmaxBackward0>)
# 梯度下降(找到一组合适的w和b,让损失值越小越好),w和b再上面的模型结构中已经定义好了,但是损失值并不知道
# 损失值 使用损失函数,一般都使用交叉熵损失函数
# 瞎子下山
lossfunction = nn.CrossEntropyLoss()
#训练的时候要使用什么样的优化器,一般使用Adam
optimizer = torch.optim.Adam(params=model.parameters(), lr=0.001) #params参数优化,学习率lr(步子)
#训练的轮数
for i in range(100):
#清空优化器的梯度(偏导),Adam会存放一些历史的一些偏导数,所以我们要把它们清空
optimizer.zero_grad()
#接着走前向传播的流程(即预测的流程)
predict = model(train_feature)
#将概率转换成0~10的索引并打印
result = torch.argmax(predict, axis=1)
# print(result) #tensor([5, 0, 7, ..., 0, 5, 5])
train_acc = torch.mean((result == train_label).to(torch.float))
#算预测结果与标准结果之间有多少误差,即损失值
loss = lossfunction(predict, train_label)
#有了损失值后要做梯度下降
# (在神经网络中要做梯度下降,要干的事情是先做反向传播)
loss.backward()
#梯度下降在optimizer中进行的
optimizer.step() #梯度下降一步
#到此整个更新过程就都完事了,每一轮训练完了,他的损失值和准确率是多少
# print(loss.item()) #损失值随着训练和迭代是越来越小的,那说明这里面的w和b越来越好
#接下来还有个东西就是准确率,准确率怎么搞呢,先分析这个predict出来的是什么
print('train loss:{} train acc:{}'.format(loss.item(),train_acc.item()))
#清空一下优化器的梯度,再对测试集数据进行预测
optimizer.zero_grad()
predict = model(test_feature)
result = torch.argmax(predict, axis=1)
test_acc = torch.mean((result == test_label).to(torch.float))
loss = lossfunction(predict, test_label)
#测试的时候是不需要更新的,loss.backward() optimizer.step() 就不用写了
print('test loss:{} test acc:{}'.format(loss.item(), test_acc.item()))
4,勘误
当我们用神经网络做分类的时候
如对手写数字图片进行分类,那在做分类的时候呢,一般是在最后加入softmax的运算
但由于pytorch它的交叉熵损失loss_fn = nn.CrossEntropyLoss()
它里面会默认把算出来的结果进行一次softmax的运算,所以一般来说nn的softmax是多余的,可以删除掉
若是不将其删掉,上面做了一次softmax, nn.CrossEntropyLoss()又会计算了一次损失
loss_fn = nn.CrossEntropyLoss()
当然如果你的网络数据和网络结构都比较简单,那么做两次softmax也能收敛
但当这个数据比较复杂,任务复杂,网络也比较复杂的时候呢,做两次softmax,那么他的一个收敛的可能性就会大大降低
所以当你的损失函数是CrossEntropyLoss时,最后是不需要加入softmax的
5,保存模型
如果没保存模型的话一退出就没了,所以保存模型加个torch.save()
torch.save(model.state_dict(), 'model.pt') #model.state_dict()就是模型中的w和b
6,加载模型并预测
我们保存模型的真正目的其实是为了我们在预测的时候可以加载我们之前已经训练好的模型,直接拿过来用
而不是我在预测之前还要重新训练一下模型
#加载模型文件里的参数w、b
import torch
import torch.nn as nn
import pandas as pd
raw_df = pd.read_csv('train.csv')
print(raw_df.head())
# label pixel0 pixel1 pixel2 ... pixel780 pixel781 pixel782 pixel783
# 0 1 0 0 0 ... 0 0 0 0
# 1 0 0 0 0 ... 0 0 0 0
# 2 1 0 0 0 ... 0 0 0 0
# 3 4 0 0 0 ... 0 0 0 0
# 4 0 0 0 0 ... 0 0 0 0
#
# [5 rows x 785 columns]
#将标签那列数据拿出来
label = raw_df['label']
print(label)
# 0 1
# 1 0
# 2 1
# 3 4
# 4 0
# ..
# 41995 0
# 41996 1
# 41997 7
# 41998 6
# 41999 9
# Name: label, Length: 42000, dtype: int64
#将df的数据类型转成numpy的,去掉索引
label = raw_df['label'].values
print(label)
# [1 0 1 ... 7 6 9]
#特征(删除label列,剩下的就是特征
raw_df = raw_df.drop(['label'], axis=1) #axis=1表示y轴
feature = raw_df.values
print(len(label),len(feature))
#将整个数据集划分成两个数据集,一个训练集、一个测试集,80%是用来神经网络训练的
#训练集相当于日常作业,测试集就是考试,日常作业做的好不代表考试做的好,所以还需要测试
#这里的数据集实际上已经被打乱过了,现在直接做个切片即可
train_feature = feature[:int(0.8*len(feature))]
train_label = label[:int(0.8*len(label))]
test_feature = feature[int(0.8*len(feature)):]
test_label = label[int(0.8*len(label)):]
#将numpy转为tensor,还要将其数据类型变为float
train_feature = torch.tensor(train_feature).to(torch.float) #数据应该是浮点数
train_label = torch.tensor(train_label) #标签 应该是整数
test_feature = torch.tensor(test_feature).to(torch.float)
test_label = torch.tensor(test_label)
#把参数塞进模型里面
#首先要有一个模型对象,模型结构
#序列化(搭积木),里面可以放入任意想要的层,从前向后
model = nn.Sequential(
nn.Linear(784, 444), #Linear全连接层或者称线性层
nn.ReLU(), #加入激活层
nn.Linear(444, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
nn.Softmax() #将值转换成概率
)
#加载模型文件参数
params = torch.load("model.pt")
model.load_state_dict(params) #把模型中的参数全部塞到model中去了
#加载完模型后就是预测了
new_test_data = test_feature[100:111]
new_test_label = test_label[100:111]
predict = model(new_test_data)
result = torch.argmax(predict,axis=1)
print(new_test_label)
print(result)
#对比两者结果是差不多的,可以看到如下所示,有个别预测不对
# tensor([5, 1, 8, 3, 6, 2, 7, 9, 6, 3, 6])
# tensor([5, 1, 8, 8, 6, 2, 4, 4, 6, 5, 6])
7,使用GPU加速
Pytorch的
能够定义模型结构,能够加载模型,能够使用模型进行预测
但是这里面还有一个功能是欠缺的,就是使用GPU进行加速
这个时候有人问了,不是装好了GPU版本的pytorch吗
如果没有在代码中真正调用GPU加速的命令,它是不会把数据放到显存里面去存储,并且使用GPU进行计算的
import pandas as pd
#定义nn神经网络
import torch
import torch.nn as nn
raw_df = pd.read_csv('train.csv')
print(raw_df.head())
# label pixel0 pixel1 pixel2 ... pixel780 pixel781 pixel782 pixel783
# 0 1 0 0 0 ... 0 0 0 0
# 1 0 0 0 0 ... 0 0 0 0
# 2 1 0 0 0 ... 0 0 0 0
# 3 4 0 0 0 ... 0 0 0 0
# 4 0 0 0 0 ... 0 0 0 0
#
# [5 rows x 785 columns]
#将标签那列数据拿出来
label = raw_df['label']
print(label)
# 0 1
# 1 0
# 2 1
# 3 4
# 4 0
# ..
# 41995 0
# 41996 1
# 41997 7
# 41998 6
# 41999 9
# Name: label, Length: 42000, dtype: int64
#将df的数据类型转成numpy的,去掉索引
label = raw_df['label'].values
print(label)
# [1 0 1 ... 7 6 9]
#特征(删除label列,剩下的就是特征
raw_df = raw_df.drop(['label'], axis=1) #axis=1表示y轴
feature = raw_df.values
print(len(label),len(feature))
#将整个数据集划分成两个数据集,一个训练集、一个测试集,80%是用来神经网络训练的
#训练集相当于日常作业,测试集就是考试,日常作业做的好不代表考试做的好,所以还需要测试
#这里的数据集实际上已经被打乱过了,现在直接做个切片即可
train_feature = feature[:int(0.8*len(feature))]
train_label = label[:int(0.8*len(label))]
test_feature = feature[int(0.8*len(feature)):]
test_label = label[int(0.8*len(label)):]
print(len(train_feature),len(train_label),len(test_feature),len(test_label))
#33600 33600 8400 8400
#
#将numpy转为tensor,还要将其数据类型变为float
train_feature = torch.tensor(train_feature).to(torch.float) #数据应该是浮点数
train_label = torch.tensor(train_label) #标签 应该是整数
test_feature = torch.tensor(test_feature).to(torch.float)
test_label = torch.tensor(test_label)
#将数据存放到显存中
train_feature = train_feature.cuda()
train_label = train_label.cuda()
test_feature = test_feature.cuda()
test_label = test_label.cuda()
#3神经网络,可以将其看成黑盒子,或者一个 python函数,这个函数有了输入就有了输出
#784个像素点构成的灰度图——》函数——》10个概率(0 1 2 3 4 5 6 7 8 9的概率)
#那么函数该怎么定义呢,这个步骤就是定义网络结构的步骤
#定义网络结构
#[1,784]*[784,444] = [1,444]*[444,512] = [1,512]*[512,512] = [1,512]*[512,10] = [1,10]
#输入层 in_channel 784 out_channel 444
#隐藏层1 in_channel 444 out_channel 512
#隐藏层2 in_channel 512 out_channel 512
#输出层 in_channel 512 out_channel 10
#伪造个随机数据
data = torch.rand(1, 784) #共784个像素,将其转为一行784列的数据
#序列化(搭积木),里面可以放入任意想要的层,从前向后
model = nn.Sequential(
nn.Linear(784, 444), #Linear全连接层或者称线性层
nn.ReLU(), #加入激活层
nn.Linear(444, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
#nn.Softmax() #将值转换成概率
)
model = model.cuda() #将model的数据从内存转到显存中
#这个函数可以返回一个模型对象给我们
print(model)
# Sequential(
# (0): Linear(in_features=784, out_features=444, bias=True)
# (1): ReLU()
# (2): Linear(in_features=444, out_features=512, bias=True)
# (3): ReLU()
# (4): Linear(in_features=512, out_features=512, bias=True)
# (5): ReLU()
# (6): Linear(in_features=512, out_features=10, bias=True)
# (7): Softmax(dim=None)
# )
#现在的model已经是一个模型了 ,但是现在模型里面的w和b是随机值,是不好用的
#后面还需要通过数据驱动其进行训练(但是训练之前还要做一件事情要验证一下此模型搭建出来合不合理)
#随机一个数据进行能否得到输出的十个概率值
# predict = model(data) #进行相关的算
# print(predict)
# # tensor([[0.0944, 0.0975, 0.1039, 0.0938, 0.1050, 0.1013, 0.1024, 0.1010, 0.0998,
# # 0.1011]], grad_fn=<SoftmaxBackward0>)
# 梯度下降(找到一组合适的w和b,让损失值越小越好),w和b再上面的模型结构中已经定义好了,但是损失值并不知道
# 损失值 使用损失函数,一般都使用交叉熵损失函数
# 瞎子下山
lossfunction = nn.CrossEntropyLoss()
#训练的时候要使用什么样的优化器,一般使用Adam
optimizer = torch.optim.Adam(params=model.parameters(), lr=0.001) #params参数优化,学习率lr(步子)
#训练的轮数
for i in range(100):
#清空优化器的梯度(偏导),Adam会存放一些历史的一些偏导数,所以我们要把它们清空
optimizer.zero_grad()
#接着走前向传播的流程(即预测的流程)
predict = model(train_feature)
#将概率转换成0~10的索引并打印
result = torch.argmax(predict, axis=1)
# print(result) #tensor([5, 0, 7, ..., 0, 5, 5])
train_acc = torch.mean((result == train_label).to(torch.float))
#算预测结果与标准结果之间有多少误差,即损失值
loss = lossfunction(predict, train_label)
#有了损失值后要做梯度下降
# (在神经网络中要做梯度下降,要干的事情是先做反向传播)
loss.backward()
#梯度下降在optimizer中进行的
optimizer.step() #梯度下降一步
#到此整个更新过程就都完事了,每一轮训练完了,他的损失值和准确率是多少
# print(loss.item()) #损失值随着训练和迭代是越来越小的,那说明这里面的w和b越来越好
#接下来还有个东西就是准确率,准确率怎么搞呢,先分析这个predict出来的是什么
print('train loss:{} train acc:{}'.format(loss.item(),train_acc.item()))
#清空一下优化器的梯度,再对测试集数据进行预测
optimizer.zero_grad()
predict = model(test_feature)
result = torch.argmax(predict, axis=1)
test_acc = torch.mean((result == test_label).to(torch.float))
loss = lossfunction(predict, test_label)
#测试的时候是不需要更新的,loss.backward() optimizer.step() 就不用写了
print('test loss:{} test acc:{}'.format(loss.item(), test_acc.item()))
torch.save(model.state_dict(), 'model.pt') #model.state_dict()就是模型中的w和b