pytorch刘二大人——第二遍

从简到难

纯手工:

一、穷举参数求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

pytorch系列nn.Modlue中call的进一步解释

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()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值