从简到难
纯手工:
一、穷举参数求cost最小
二、梯度下降法
三、随机梯度下降法
开始调库:
四、反向传播(梯度)算法
五、Pytorch代码风格
六、pytorch实现线性回归
一、简单线性模型(穷举wb方法)一般不可取
代码:
#coding=utf-8
'''
数据集:
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
线性模型:y=wx
思路:取遍一个区间内的多个w,测试哪个w对应的误差最小
重要知识:
np.arange()用法
zip()用法
画图显示折线图方法
'''
import numpy as np
import matplotlib.pyplot as plt
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w_list=[]
cost_list=[]
for w in np.arange(0,4.1,0.1):
cost=0
for x,y in zip(x_data,y_data):
loss=pow((y-w*x),2)
cost=cost+loss
w_list.append(w)
cost_list.append(cost)
plt.plot(w_list,cost_list)
plt.xlabel("w")
plt.ylabel("cost")
plt.show()
结果:
作业1:
作业题目:实现线性模型(y=wx+b)并输出loss的3D图像。
代码:
#coding=utf-8
'''
作业题目:实现线性模型(y=wx+b)并输出loss的3D图像。
数据集:
x_data = [1.0, 2.0, 3.0]
y_data = [5.0, 8.0, 11.0]
线性模型:y=wx+b
思路:取遍一个区间内的多个w,b,测试哪个w,b对应的误差最小
重要知识:
np.meshgrid(x_data,y_data)函数可以将 横坐标和纵坐标的一维数组,构建网格坐标
[w,b]=np.meshgrid(x_data,y_data),w与b中保存的均是矩阵,w与b对应位置各取一个就是网格坐标,即所有的w与b值
两矩阵A,B,矩阵乘法分为A*B(对应位置相乘)与A@B(标准矩阵乘法),注意区别
在meshgrid基础上,如何画出3维图像
'''
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
x_data = [1.0, 2.0, 3.0]
y_data = [5.0, 8.0, 11.0]
w_list=np.arange(0,4.1,0.1)
b_list=np.arange(0,4.1,0.1)
[w,b]=np.meshgrid(w_list,b_list)#meshgrid用法
MSE=0
for x,y in zip(x_data,y_data):
cost= (x*w+b-y)*(x*w+b-y)#用矩阵运算求出w,b取特定值时,整个数据集的
MSE=MSE+cost
MSE=MSE/3 #三个样本
fig = plt.figure()
ax = Axes3D(fig)
ax.plot_surface(w, b, MSE/3)
plt.show()
结果:
二、简单线性模型(梯度下降法)
代码:
#coding=utf-8
'''
要求:通过(全体)梯度下降法求解最优参数
数据集:
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
线性模型:y=wx
思路:1。先随机初始化一个w 2.梯度下降法更新w
重要知识:
梯度的定义?谁对谁的梯度?
如何更新?
'''
import numpy as np
import matplotlib.pyplot as plt
#将数据集转为numpy计算更方便
x_data = np.array([1.0, 2.0, 3.0])
y_data = np.array([2.0, 4.0, 6.0])
w=1#随机初始化w,全局变量
learning_rate=0.01#设置学习率
def cost(x,y):
y=np.array(y)
cost_val=sum((y-w*x)**2)
return cost_val
'''
cost计算方法是cost=(wx1-y1)**2+(wx2-y2)**2+(wx3-y3)**2+...
因此可以绘制cost与w的关系图
进而求取cost对w的梯度
'''
def grad(w):#表示w时,cost对w的梯度
grad_val=2*(w*x_data-y_data)*x_data
return grad_val
cost_list=[]
#先写主程序
for epoch in range(100) :#迭代更新1001
cost_val=cost(x_data,y_data) #求得w时,整体数据的cost
w=w-learning_rate*grad(w)#更新
cost_list.append(cost_val)
plt.plot(range(100),cost_list)
plt.xlabel("epoch")
plt.ylabel("cost")
plt.show()
结果:
三、简单线性模型(随机梯度下降法)
代码:
#coding=utf-8
'''
数据集:
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
线性模型:y=wx
思路:初始化w;每一个epoch中,计算整体损失,后对每一组数据(x,y)的损失loss,求对w的梯度grad,后更新w
重要知识:
目标都是 使得整体的损失cost最小
随机梯度下降与梯度下降区别:前者是一个个样本丢进去计算loss更新参数,后者是所有样本一起丢进去计算loss更新参数
'''
import numpy as np
import matplotlib.pyplot as plt
#全局变量
x_data = [1.0, 2.0, 3.0]
x_data=np.array(x_data)
y_data = [2.0, 4.0, 6.0]
y_data=np.array(y_data)
w=1#初始化w
learning_rate=0.01#初始化学习率
def cost_func(x,y):
cost_val=sum((y-w*x)**2)
return cost_val
def grad_func(w,x,y):#随机梯度算法,计算单个样本loss对w梯度,loss=(wx-y)**2
grad_val=2*(w*x-y)*x
return grad_val
cost_list=[]
#先写主程序
for epoch in range(100):
cost_val=cost_func(x_data,y_data)
cost_list.append(cost_val)
for x,y in zip(x_data,y_data):
w=w-learning_rate*grad_func(w,x,y)
plt.plot(range(100),cost_list)
plt.xlabel("epoch")
plt.ylabel("cost")
plt.show()
结果:
四、反向传播算法
1.简单线性模型
代码:
#coding=utf-8
'''
数据集:
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
简单线性模型:y=wx
思路:1.弄清谁对谁的梯度,此题中是loss对w的梯度,因此需要loss.backward(),w.requires_frad=True 2.设置w需要求梯度————求出loss————loss反向传播————更新w————计算图梯度置为0
重要知识:
tensor([1.], requires_grad=True)与tensor([1.])区别
1、张量tensor必须是个向量即不能是一个数,比如a=torch.tensor([1.0])需要计算梯度的张量中包含data(不需要计算梯度的张量)与grad(也是需要计算梯度的张量张量,因此更新时候需要用grad.data),如果a.requires_grad=True,则后续与a相关的所有均需要计算梯度
2、torch.tensor()与torch.Tensor()区别:torch.Tensor其实就是torch.FloatTensor() ,而torch.tensor()可以根据括号内元素类型进行转化;比如torch.tensor([1,2])类型是 torch
.LongTensor torch.tensor([1.,2.])类型是torch.FloatTensor
3、w是张量,则后面与w相关的都是张量,loss是张量,与张量有关的构建计算图,loss.backward()会把所有张量的梯度计算出来,目的是计算loss对requires_grad设为True,最终计算图被释放;grad.data不会构造计算图
4.更新完一次后,将计算图中梯度归0,防止下一次计算图梯度与上一次累加:w.grad.data.zero_() 注意:zero_()
4.张量与numpy转化
tensor到numpy:w.data.numpy() 这是w需要计算梯度时候;w.numpy() 这是w不需要计算梯度时候
numpy到tensor:浅拷贝 torch.from_numpy() 深拷贝:torch.tensor()
'''
import numpy as np
import torch
import matplotlib.pyplot as plt
x_data = np.array([1.0, 2.0, 3.0])
y_data = np.array([2.0, 4.0, 6.0])
w=torch.tensor([1.0])#相当于是torch.FloatTensor
w.requires_grad=True
learning_rate=0.01
def cost_func(x,y):
cost_val=sum((y-w.data.numpy()*x)**2)
return cost_val
cost_list=[]
#先写主程序
for epoch in range(100):
cost_val=cost_func(x_data,y_data)
cost_list.append(cost_val)
for x,y in zip(x_data,y_data):
loss=(w*x-y)**2
loss.backward()#反向传播,计算loss对 w到loss相关的所有变量 的梯度(注意是tensor类)
w.data=w.data-w.grad.data*learning_rate#更新w
w.grad.data.zero_()
plt.plot(range(100),cost_list)
plt.show()
结果:
思路:
2.二次模型
代码:
#coding=utf-8
'''
数据集:
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
简单二次模型:y=w1*x**2+w2*x+b
思路:1.弄清谁对谁的梯度,此题中是loss对w1,w2,b的梯度,因此需要loss.backward(),3个变量.requires_frad=True 2.设置3变量求梯度————求出loss————loss反向传播————更新w1,w2,b————计算图梯度全部置为0
重要知识:
tensor([1.], requires_grad=True)与tensor([1.])区别
1、张量tensor必须是个向量即不能是一个数,比如a=torch.tensor([1.0])需要计算梯度的张量中包含data(不需要计算梯度的张量)与grad(也是需要计算梯度的张量张量,因此更新时候需要用grad.data),如果a.requires_grad=True,则后续与a相关的所有均需要计算梯度
2、torch.tensor()与torch.Tensor()区别:torch.Tensor其实就是torch.FloatTensor() ,而torch.tensor()可以根据括号内元素类型进行转化;比如torch.tensor([1,2])类型是 torch
.LongTensor torch.tensor([1.,2.])类型是torch.FloatTensor
3、w是张量,则后面与w相关的都是张量,loss是张量,与张量有关的构建计算图,loss.backward()会把所有张量的梯度计算出来,目的是计算loss对requires_grad设为True,最终计算图被释放;grad.data不会构造计算图
4.更新完一次后,将计算图中梯度归0,防止下一次计算图梯度与上一次累加:w.grad.data.zero_() 注意:zero_()
5.张量与numpy转化
tensor到numpy:w.data.numpy() 这是w需要计算梯度时候;w.numpy() 这是w不需要计算梯度时候
numpy到tensor:浅拷贝 torch.from_numpy() 深拷贝:torch.tensor()
6.w.data与w.item()区别,第一个仍是tensor,第二个是取值(tensor中只有一个值时候)
'''
import numpy as np
import torch
import matplotlib.pyplot as plt
x_data = np.array([1.0, 2.0, 3.0])
y_data = np.array([2.0, 4.0, 6.0])
w1=torch.tensor([1.0])#相当于是torch.FloatTensor
w1.requires_grad=True
w2=torch.tensor([1.0])#相当于是torch.FloatTensor
w2.requires_grad=True
b=torch.tensor([1.0])#相当于是torch.FloatTensor
b.requires_grad=True
learning_rate=0.01
cost_list=[]
def cost_func(x,y):
cost_val=sum((w1.item()*(x**2)+w2.item()*x+b.item()-y)**2)
return cost_val
for epoch in range(100):
cost_val=cost_func(x_data,y_data)
cost_list.append(cost_val)
for x,y in zip(x_data,y_data):
loss=(w1*(x**2)+w2*x+b-y)**2
loss.backward()
w1.data=w1.data-w1.grad.data*learning_rate
w2.data=w2.data-w2.grad.data*learning_rate
b.data=b.data-b.grad.data*learning_rate
w1.grad.data.zero_()
w2.grad.data.zero_()
b.grad.data.zero_()
plt.plot(range(100),cost_list)
plt.xlabel("epoch")
plt.ylabel("cost")
plt.show()
结果:
五、Pytorch代码风格
1.准备数据集
2. 建立模型
目的是前向传播,计算y_hat
3.建立loss和optimizer
loss目的是反向传播,optimizer是用于梯度更新
4.训练
其中包括 前馈 后馈 更新参数
模型网络层次越深,学习能力越强,有可能会把输入样本中噪声的规律也学到。我们要学习数据本身真实数据的规律,学习能力要有泛化能力。
一些说明:
1.call函数可以使得对象有函数的性质,pytrorch内对象比如mymodel,criterion等都有函数性质
关于魔法函数call在PyTorch中的应用的进一步解释:
pytorch 之 __call__, __init__,forward
2.梯度下降算法使用的是随机梯度下降,还是批量梯度下降,还是mini-batch梯度下降,用的API都是 torch.optim.SGD
3.torch.nn.MSELoss也跟torch.nn.Module有关,参与计算图的构建,torch.optim.SGD与torch.nn.Module无关,不参与构建计算图。
六、Pytorch实现线性回归
代码:
#coding=utf-8
'''
数据集:
x_data = torch.tensor([[1.0], [2.0], [3.0]])
y_data = torch.tensor([[2.0], [4.0], [6.0]])
线性模型:y=w*x+b
思路:1.数据集 2.建立模型 3.loss和optimizer 4.训练
重要知识:
1.数据集部分
数据集必须是矩阵张量,样本数量和特征数
2.模型部分
1)模型需继承torch.nn.Module
2)需要定义两个函数__init__()、forward()
3)__init__()里面定义 多个模型及对应模型输入、输出特征的维度
4)forward()里面求得 y_hat
3.loss与optimizer部分
梯度得清0
'''
import torch
import matplotlib.pyplot as plt
#1、数据集
#必须是矩阵形式
#说明数据集仅有一个特征
x_data = torch.tensor([[1.0], [2.0], [3.0]])
y_data = torch.tensor([[2.0], [4.0], [6.0]])
#2、建立模型
class LinearModel(torch.nn.Module):
def __init__(self):
super(LinearModel,self).__init__()
self.linear1=torch.nn.Linear(1,1)
def forward(self,x):
y_pred=self.linear1(x)#只需知道一个特征转为一个特征
return y_pred
mymodel=LinearModel()#创建一个模型对象
#3.loss与opitimzer
criterion=torch.nn.MSELoss(reduction='sum')#MSE误差对象
optimizer=torch.optim.SGD(mymodel.parameters(),lr=0.01)#梯度下降优化器对象
loss_list=[]
#4.训练
for epoch in range(100):
y_pred=mymodel(x_data) #前馈计算y_pred,Linear(1,1)所以行数列数均不变,列数均为1,行数都为3
loss=criterion(y_pred,y_data)#前馈计算loss
loss_list.append(loss)
print(epoch,loss.item())
optimizer.zero_grad()#梯度清0
loss.backward()#构造计算图,反向传播求梯度
optimizer.step()#更新参数
plt.plot(range(100),loss_list)
plt.xlabel("epoch")
plt.ylabel("loss")
plt.show()
x_test=torch.tensor([[4.0]])#数据集一定得是矩阵,包含样本数和特征数
y_test=mymodel(x_test)
print('y_pred=',y_test)
结果:
七、Pytorch实现Logistic回归
一.单个特征二分类
1.与线性回归不同点:线性模型后,添加了激活函数(非线性变换);损失函数用的是交叉熵,而线性回归用的是MSE
代码:
#coding=utf-8
'''
数据集:
x_data = torch.tensor([[1.0], [2.0], [3.0]])
y_data = torch.tensor([[0], [0], [1]])
二分类模型
思路:1.数据集 2.建立模型 3.loss和optimizer 4.训练
重要知识:
1.数据集部分
数据集必须是矩阵张量,样本数量和特征数
2.模型部分
1)模型需继承torch.nn.Module
2)需要定义两个函数__init__()、forward()
3)__init__()里面定义 多个模型及对应模型输入、输出特征的维度
4)forward()里面求得 y_hat
3.loss与optimizer部分
梯度得清0
'''
import torch
import matplotlib.pyplot as plt
#1、数据集
#必须是矩阵形式
#说明数据集仅有一个特征
x_data = torch.Tensor([[1.0], [2.0], [3.0]])
y_data = torch.Tensor([[0], [0], [1]])
#2、建立模型
class LogisticModel(torch.nn.Module):
def __init__(self):
super(LogisticModel,self).__init__()
self.linear1=torch.nn.Linear(1,1)
def forward(self,x):
y_pred=torch.sigmoid(self.linear1(x))#只需知道一个特征转为一个特征,sigmoid函数是torch.sigmoid()
return y_pred
mymodel=LogisticModel()#创建一个模型对象
#3.loss与opitimzer
# criterion=torch.nn.CrossEntropyLoss(size_average=False)#多分类使用,会自动加入softmax层,后面会讲
criterion=torch.nn.BCELoss(size_average=False)#二分类使用
optimizer=torch.optim.SGD(mymodel.parameters(),lr=0.01)#梯度下降优化器对象
loss_list=[]
#4.训练
for epoch in range(1000):
y_pred=mymodel(x_data) #前馈计算y_pred,Linear(1,1)所以行数列数均不变,列数均为1,行数都为3,sigmoid函数处理后得到y_pred
loss=criterion(y_pred,y_data)#前馈计算loss,交叉熵损失
loss_list.append(loss)
optimizer.zero_grad()#梯度清0
loss.backward()#构造计算图,反向传播求梯度
optimizer.step()#更新参数
print("w=",mymodel.linear1.weight.item())
print("b=", mymodel.linear1.bias.item())
plt.plot(range(1000),loss_list)
plt.xlabel("epoch")
plt.ylabel("loss")
plt.show()
x_test=torch.tensor([[4.0]])#数据集一定得是矩阵,包含样本数和特征数
y_test=mymodel(x_test)
print('y_pred=',y_test.data)
结果:
二.多个特征二分类
1.要求按以下模型编写代码
代码:
#coding=utf-8
'''
数据集:糖尿病数据集
模型:多特征的二分类模型
思路:1.利用np创建数据集,转为tensor 2.建立模型,实例化模型 3.损失器与优化器(注意损失器里的参数为reduction="mean") 4.训练模型
重要知识:
利用np加载csv文件
数据集也得是tensor量,否则linear()会报错
损失器BCE内部参数
'''
#1.数据集
import numpy as np
import torch
import matplotlib.pyplot as plt
dataset=np.loadtxt("diabetes.csv",delimiter=",",dtype=np.str)
X=dataset[1:,1:-1].astype(np.float32)#numpy中数据转换astype(float32)函数
X=torch.from_numpy(X)
Y=dataset[1:,[-1]].astype(np.float32)#[-1]而不是1是因为所有的都需要矩阵形式
Y=torch.from_numpy(Y)
#2.建立模型
class Multi_feature_binary_classification(torch.nn.Module):
def __init__(self):
super(Multi_feature_binary_classification,self).__init__()
self.linear1=torch.nn.Linear(8,6)
self.linear2=torch.nn.Linear(6,4)
self.linear3=torch.nn.Linear(4,1)
def forward(self,x):#前向传播,求得y_pred
x=torch.sigmoid(self.linear1(x))
x=torch.sigmoid(self.linear2(x))
x=torch.sigmoid(self.linear3(x))
return x
myModel=Multi_feature_binary_classification()#建立一个模型对象
#3.损失器和优化器
criterion=torch.nn.BCELoss(reduction="mean")#损失器
optimizer=torch.optim.SGD(myModel.parameters(),lr=0.01)#需要了解模型里所有的参数以及学习率,才能进行梯度更新,optimizer里面包含模型所有的参数、梯度以及学习率信息
loss_list=[]
#4.训练
for epoch in range(1000):#每一轮迭代,模型里的参数都会发生改变
#正向传播求预测值以及损失值
y_pred=myModel(X)
loss=criterion(y_pred,Y)
loss_list.append(loss)
#反向传播
optimizer.zero_grad()#每一轮迭代,记得将梯度归0,否则下一次会累加梯度
loss.backward()
#参数更新
optimizer.step()
plt.plot(range(1000),loss_list)
plt.xlabel("epoch")
plt.ylabel("loss")
plt.show()
结果:
八、Dataset与DataLoader类
1.Dataset 是一个抽象类,不可被实例化【下标、长度】,不可a=Dataset(),只能被继承
必须实现以下函数:
__init__函数 里面需要有所有的(x,y)
__getitem__函数 需要return一对(x,y)
__len__函数需要return len
2.DataLoader可以被实例化
import torch
import numpy as np
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
#数据集
class DiabetesDataset(Dataset):#Dataset只能被继承,三个函数必须要有
def __init__(self, filepath):#所有的(x,y)
xy = np.loadtxt(filepath, delimiter=',', dtype=np.float32)
self.len = xy.shape[0] # shape(多少行,多少列)
self.x_data = torch.from_numpy(xy[:, :-1])
self.y_data = torch.from_numpy(xy[:, [-1]])
def __getitem__(self, index):#取一条(x,y)
return self.x_data[index], self.y_data[index]
def __len__(self):#返回长度
return self.len
dataset = DiabetesDataset('diabetes.csv')
train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True, num_workers=0) # num_workers 多线程,DataLoader可以被实例化
九、多分类问题——加了softmax层
1.softmax的输入不需要再做非线性变换,也就是说softmax之前不再需要激活函数(relu)。softmax两个作用,如果在进行softmax前的input有负数,通过指数变换,得到正数。所有类的概率求和为1。
2.用pytorch代码实现以下模型
代码:
#coding=utf-8
'''
数据集:Minist手写数字数据集
模型:多特征 多分类模型
思路:
1.数据集
1)Dataset、DataLoader类的使用;
2)使用transforms将图像转为更容易被pytorch处理的张量;
2.建立模型
1)利用view()函数将图像对应的c*w*h张量转为c*Features张量;
2)注意最后一层不需要加激活函数;
3)交叉熵函数调用后会自动在最后一层加入softmax层,自动构造计算图;
3.损失器和优化器
1)交叉熵损失函数;
2)SGD优化器
4.训练+测试
1)训练
设置epoch;对train_loader里面每一批样本进行操作,前馈(计算y_pred和loss(此时myModel里面才有softmax层和后面的一些计算图))、反馈、更新参数
2)测试
对testloader里面每一批样本进行操作,注意:不构建计算图需加上with torch.no_grad():
交叉熵函数会将标签转化为0,1,2,3,...,一个样本输出概率最大的下标即是预测的标签值,比如1个样本预测出的概率为0。1,0.2,0.4.0.3 则模型预测出的标签是2
重要知识:
1.teansforms库的使用
torchvision.transforms是pytorch中的图像预处理包。一般用Compose把多个步骤整合到一起:
比如说:
transforms.Compose([transforms.CenterCrop(10),transforms.ToTensor(),])
这样就把两个步骤整合到了一起。
transforms.ToTensor()作用是吧把numpy类型转化为能快速被pytorch处理的tensor变量,将图像w*h*c转化为c*w*h,并且把0-255像素值转为0-1的
'''
from torchvision import datasets
import torch
from torch.utils.data import Dataset,DataLoader
from torchvision import transforms
#1.数据集
batch_size = 64#一批有64个样本,minibatch一次样本数为64
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]) # 转为tensor,并且归一化,均值和方差
train_dataset = datasets.MNIST(root='/dataset/mnist/', train=True, download=True, transform=transform)#所有的训练集
train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)#将所有的训练集分批,一批有64个样本,一起训练。for data in train_loader 每一个data就是一批样本64个样本的集合
test_dataset = datasets.MNIST(root='/dataset/mnist/', train=False, download=True, transform=transform)#所有的测试集
test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size)#将所有的测试集分批,一批有64个样本,一起测试
print(train_dataset)#训练集
print(test_dataset)#测试集
#2.建模
class Multi_classification(torch.nn.Module):
def __init__(self):#此处只写模型,softmax层包含在交叉熵函数里了,因此此处不需要加
super(Multi_classification,self).__init__()
self.linear1=torch.nn.Linear(784,512)#输入是784个特征数,输出是512个特征数,与样本数无关
self.linear2 = torch.nn.Linear(512, 256)
self.linear3 = torch.nn.Linear(256, 128)
self.linear4 = torch.nn.Linear(128, 64)
self.linear5 = torch.nn.Linear(64, 10)
self.sigmoid=torch.nn.Sigmoid()
def forward(self,x):
x=x.view(-1,784)#28*28的张量转为1*784的张量(注意是向量)
x=self.sigmoid(self.linear1(x))
x = self.sigmoid(self.linear2(x))
x = self.sigmoid(self.linear3(x))
x = self.sigmoid(self.linear4(x))
x = self.linear5(x)#最后一层不加激活函数,因为softmax层里面有激活函数
return x
#创建一个模型对象
myModel=Multi_classification()#此时,myModel里面还没有softmax层
#3.损失函数和优化器
criterion=torch.nn.CrossEntropyLoss(reduction="mean")
optimizer=torch.optim.SGD(myModel.parameters(),lr=0.01)
cost_list=[]
#4.训练
def train(epoch):
cost=0
for i,data in enumerate(train_loader):
inputs,target=data
#前馈
y_pred=myModel(inputs) #inputs规格是64*28*28,view后转为64*784
loss=criterion(y_pred,target)#计算64个样本的损失;此时myModel里面才有softmax层,能输出概率
cost=cost+loss.item()#损失器中的值有梯度,所以需要加上item()以防构造计算图
#反馈
optimizer.zero_grad()#将梯度全置为0
loss.backward()
optimizer.step()#将模型里面的参数值全更新
print(cost)
cost_list.append(cost)
def test():
correct=0
total=0
with torch.no_grad():#表示不构造计算图
for data in test_loader:
images,labels=data
outputs=myModel(images)#输出的是64*10的张量,每一行表示一个样本为0-10的概率
_,predicted=torch.max(outputs,dim=1)#返回两个值,第一个是每一行最大值,第二个是每一行最大值的下标,最终张量为64*1
total+=labels.size(0)
correct+=(predicted==labels).sum().item()
print("精确度:",correct/total)
if __name__=='__main__':
for epoch in range(10):
train(epoch)
test()
十、卷积神经网络篇
一.基础篇
1.全连接神经网络:多个线性层串联起来
对于图像分类来说,如果运用全连接层训练,则会丧失空间的特性
卷积+下采样 称为特征提取器
下采样是池化层
全连接层称为 分类器
下采样:减少数据量,降低后续运算
图像whc必须转为cwh
2.卷积的定义
1)卷积也指特征提取,即feature extraction
2)对于一副c*w*h的图像来说,卷积核它的通道数c要求和输入通道数c是一样的。卷积后,图像通道数c肯定会变,w与h可变可不变,取决于padding,padding=卷积核长//2的时候卷积后图像w*h不变
3)卷积层要求输入输出的都是4维张量(B,c,w,h),全连接层输入输出的都是二维张量(B,features_numbers),其中B是样本数,c是一个样本的通道数,w是宽,h是高
3.部分代码
1)torch.nn.Conv2d(c_input,c_output,kernel_size=3,stride=2,bias=False)
卷积关注卷积核大小、通道数的变化、步长、是否有偏置
4.根据以下模型编写代码
5.代码
#coding=utf-8
'''
数据集:Minist手写数字数据集
模型:多特征 多分类模型
思路:
1.数据集
1)Dataset、DataLoader类的使用;
2)使用transforms将图像转为更容易被pytorch处理的张量;
2.建立模型
1)利用view()函数将图像对应的c*w*h张量转为c*Features张量;
2)注意最后一层不需要加激活函数;
3)交叉熵函数调用后会自动在最后一层加入softmax层,自动构造计算图;
3.损失器和优化器
1)交叉熵损失函数;
2)SGD优化器
4.训练+测试
1)训练
设置epoch;对train_loader里面每一批样本进行操作,前馈(计算y_pred和loss)、反馈、更新参数
2)测试
对testloader里面每一批样本进行操作,注意:不构建计算图需加上with torch.no_grad():
交叉熵函数会将标签转化为0,1,2,3,...,一个样本输出概率最大的下标即是预测的标签值,比如1个样本预测出的概率为0。1,0.2,0.4.0.3 则模型预测出的标签是2
重要知识:
1.teansforms库的使用
torchvision.transforms是pytorch中的图像预处理包。一般用Compose把多个步骤整合到一起:
比如说:
transforms.Compose([transforms.CenterCrop(10),transforms.ToTensor(),])
这样就把两个步骤整合到了一起。
transforms.ToTensor()作用是吧把numpy类型转化为能快速被pytorch处理的tensor变量,将图像w*h*c转化为c*w*h,并且把0-255像素值转为0-1的
2.torch.nn.Conv2d()参数关注c的变化,卷积核大小
torch.
torch.nn.Linear()参数关注features_number的变化
torch.nn.MaxPool2d(2) 参数2是池化的卷积核是2*2的
'''
from torchvision import datasets
import torch
from torch.utils.data import Dataset,DataLoader
from torchvision import transforms
#1.数据集
batch_size = 64#一批有64个样本,minibatch一次样本数为64
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]) # 转为tensor,并且归一化,均值和方差
train_dataset = datasets.MNIST(root='/dataset/mnist/', train=True, download=True, transform=transform)#所有的训练集
train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)#将所有的训练集分批,一批有64个样本,一起训练。for data in train_loader 每一个data就是一批样本64个样本的集合
test_dataset = datasets.MNIST(root='/dataset/mnist/', train=False, download=True, transform=transform)#所有的测试集
test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size)#将所有的测试集分批,一批有64个样本,一起测试
print(train_dataset)#训练集
print(test_dataset)#测试集
#2.模型建立
class CNN_Number(torch.nn.Module):
def __init__(self):
super(CNN_Number, self).__init__()
self.conv1=torch.nn.Conv2d(1,10,(5,5),bias=False)
self.pool=torch.nn.MaxPool2d(2)#2*2的池化
self.conv2=torch.nn.Conv2d(10,20,(5,5),bias=False)
self.linear=torch.nn.Linear(320,10)
def forward(self,x):
x=self.pool(self.conv1(x))
x=self.pool(self.conv2(x))
x=x.view(-1,320)
x=self.linear(x)
return x
#实例化一个模型
myModel=CNN_Number()
#3.构造损失器和优化器
criterion=torch.nn.CrossEntropyLoss(reduction="mean")
optimizer=torch.optim.SGD(myModel.parameters(),lr=0.01)
#4.训练
for epoch in range(100):
cost=0
for i,data in enumerate(train_loader):
inputs,labels=data
#前馈
y_pred=myModel(inputs)#这里输出的是未经过softmax,经过linear层的输出
loss=criterion(y_pred,labels)#criterion内个参数有梯度
cost=cost+loss
#反馈
optimizer.zero_grad()
loss.backward()
#更新参数
optimizer.step()#更新myModel里面所有参数
#4.测试
corret=0
total=0
with torch.no_grad():
for i,data in enumerate(test_loader):
inputs,lables=data
outputs=myModel(inputs)
_,preds=torch.max(outputs.data,dim=1)#第一个输出是保存每行最大值,第二个输出是保存每行最大值值的下标
total=total+labels.size(0)
corret+=(preds==lables).sum().item()
print("精确度为:",corret/total)
二.高级篇1——解决代码冗余问题
1.简单的串行卷积网络
2.对于复杂的神经网络,这时候需要借助类,来减少代码冗余
3.1*1的卷积核作用:可以改变(减少)通道数c,减少运算量
4.卷积核超参数选择困难,使得模型自动找到卷积的最佳组合
5.GoogleNet的Inception Moudel由4个分支组成,要分清哪些是在Init里定义,哪些是在forward里调用。4个分支在dim=1(channels)上进行concatenate。24+16+24+24 = 88
代码:
#coding=utf-8
'''
数据集:Minist手写数字数据集
模型:多特征 多分类模型
思路:
1.数据集
1)Dataset、DataLoader类的使用;
2)使用transforms将图像转为更容易被pytorch处理的张量;
2.建立模型
1)利用view()函数将图像对应的c*w*h张量转为c*Features张量;
2)注意最后一层不需要加激活函数;
3)交叉熵函数调用后会自动在最后一层加入softmax层,自动构造计算图;
3.损失器和优化器
1)交叉熵损失函数;
2)SGD优化器
4.训练+测试
1)训练
设置epoch;对train_loader里面每一批样本进行操作,前馈(计算y_pred和loss)、反馈、更新参数
2)测试
对testloader里面每一批样本进行操作,注意:不构建计算图需加上with torch.no_grad():
交叉熵函数会将标签转化为0,1,2,3,...,一个样本输出概率最大的下标即是预测的标签值,比如1个样本预测出的概率为0。1,0.2,0.4.0.3 则模型预测出的标签是2
重要知识:
1.teansforms库的使用
torchvision.transforms是pytorch中的图像预处理包。一般用Compose把多个步骤整合到一起:
比如说:
transforms.Compose([transforms.CenterCrop(10),transforms.ToTensor(),])
这样就把两个步骤整合到了一起。
transforms.ToTensor()作用是吧把numpy类型转化为能快速被pytorch处理的tensor变量,将图像w*h*c转化为c*w*h,并且把0-255像素值转为0-1的
2.torch.nn.Conv2d()参数关注c的变化,卷积核大小
torch.
torch.nn.Linear()参数关注features_number的变化
torch.nn.MaxPool2d(2) 参数2是池化的卷积核是2*2的
3.将类似的模型封装在一个Inception类里面
'''
import torch
import torch.nn as nn
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim
# prepare dataset
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]) # 归一化,均值和方差
train_dataset = datasets.MNIST(root='../dataset/mnist/', train=True, download=True, transform=transform)
train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)
test_dataset = datasets.MNIST(root='../dataset/mnist/', train=False, download=True, transform=transform)
test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size)
# design model using class
class InceptionA(nn.Module):
def __init__(self, in_channels):#实例初始化使用
super(InceptionA, self).__init__()
self.branch1x1 = nn.Conv2d(in_channels, 16, kernel_size=1)
self.branch5x5_1 = nn.Conv2d(in_channels, 16, kernel_size=1)
self.branch5x5_2 = nn.Conv2d(16, 24, kernel_size=5, padding=2)
self.branch3x3_1 = nn.Conv2d(in_channels, 16, kernel_size=1)
self.branch3x3_2 = nn.Conv2d(16, 24, kernel_size=3, padding=1)
self.branch3x3_3 = nn.Conv2d(24, 24, kernel_size=3, padding=1)
self.branch_pool = nn.Conv2d(in_channels, 24, kernel_size=1)
def forward(self, x):#对应输入与输出
branch1x1 = self.branch1x1(x)
branch5x5 = self.branch5x5_1(x)
branch5x5 = self.branch5x5_2(branch5x5)
branch3x3 = self.branch3x3_1(x)
branch3x3 = self.branch3x3_2(branch3x3)
branch3x3 = self.branch3x3_3(branch3x3)
branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)
branch_pool = self.branch_pool(branch_pool)
outputs = [branch1x1, branch5x5, branch3x3, branch_pool]
return torch.cat(outputs, dim=1) # b,c,w,h c对应的是dim=1
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = nn.Conv2d(88, 20, kernel_size=5) # 88 = 24x3 + 16
self.incep1 = InceptionA(in_channels=10) # 与conv1 中的10对应,实例化InceptionA模型
self.incep2 = InceptionA(in_channels=20) # 与conv2 中的20对应,实例化InceptionA模型
self.mp = nn.MaxPool2d(2)
self.fc = nn.Linear(1408, 10)
def forward(self, x):
in_size = x.size(0)
x = F.relu(self.mp(self.conv1(x)))
x = self.incep1(x)
x = F.relu(self.mp(self.conv2(x)))
x = self.incep2(x)
x = x.view(in_size, -1)
x = self.fc(x)
return x
model = Net()
# construct loss and optimizer
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
# training cycle forward, backward, update
def train(epoch):
running_loss = 0.0
for batch_idx, data in enumerate(train_loader, 0):
inputs, target = data
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, target)
loss.backward()
optimizer.step()
running_loss += loss.item()
if batch_idx % 300 == 299:
print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
running_loss = 0.0
def test():
correct = 0
total = 0
with torch.no_grad():
for data in test_loader:
images, labels = data
outputs = model(images)
_, predicted = torch.max(outputs.data, dim=1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('accuracy on test set: %d %% ' % (100 * correct / total))
if __name__ == '__main__':
for epoch in range(10):
train(epoch)
test()
二、高级篇2——ResidualNet,解决梯度消失的问题
代码:
说明:先是1个卷积层(conv,maxpooling,relu),然后ResidualBlock模块,接下来又是一个卷积层(conv,mp,relu),然后esidualBlock模块模块,最后一个全连接层(fc)。
import torch
import torch.nn as nn
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim
# prepare dataset
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]) # 归一化,均值和方差
train_dataset = datasets.MNIST(root='../dataset/mnist/', train=True, download=True, transform=transform)
train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)
test_dataset = datasets.MNIST(root='../dataset/mnist/', train=False, download=True, transform=transform)
test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size)
# design model using class
class ResidualBlock(nn.Module):
def __init__(self, channels):
super(ResidualBlock, self).__init__()
self.channels = channels
self.conv1 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
def forward(self, x):
y = F.relu(self.conv1(x))
y = self.conv2(y)
return F.relu(x + y)
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 16, kernel_size=5)
self.conv2 = nn.Conv2d(16, 32, kernel_size=5) # 88 = 24x3 + 16
self.rblock1 = ResidualBlock(16)
self.rblock2 = ResidualBlock(32)
self.mp = nn.MaxPool2d(2)
self.fc = nn.Linear(512, 10) # 暂时不知道1408咋能自动出来的
def forward(self, x):
in_size = x.size(0)
x = self.mp(F.relu(self.conv1(x)))
x = self.rblock1(x)
x = self.mp(F.relu(self.conv2(x)))
x = self.rblock2(x)
x = x.view(in_size, -1)
x = self.fc(x)
return x
model = Net()
# construct loss and optimizer
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
# training cycle forward, backward, update
def train(epoch):
running_loss = 0.0
for batch_idx, data in enumerate(train_loader, 0):
inputs, target = data
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, target)
loss.backward()
optimizer.step()
running_loss += loss.item()
if batch_idx % 300 == 299:
print('[%d, %5d] loss: %.3f' % (epoch+1, batch_idx+1, running_loss/300))
running_loss = 0.0
def test():
correct = 0
total = 0
with torch.no_grad():
for data in test_loader:
images, labels = data
outputs = model(images)
_, predicted = torch.max(outputs.data, dim=1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('accuracy on test set: %d %% ' % (100*correct/total))
if __name__ == '__main__':
for epoch in range(10):
train(epoch)
test()