传送门:B站 刘二大人1. Overview_哔哩哔哩_bilibili
第一节 Overview
表示学习presentation learning(高维空间需要的数据量成倍增长,费钱,所以可以把高维变成低维,但是要保证数据的特征基本不变)
Manifold 流形
深度学习,端到端的学习方法
SVM的局限性
神经网络
感知机
反向传播(Back Propagation):核心是计算图(求偏导、前馈、链式法则)
第二节 线性模型
步骤:1.准备数据集 2.模型的设计 3.训练 4.推理
监督学习
过拟合、泛化,把训练集用作训练和开发(提前测试一下)
权重,先随机取一个权重,结果与真实值比较,需要一个数值来评估误差(loss损失函数)
每一个权重对应一个数值,可以用穷举法求出loss最小的权重值(视频中有代码)
MSZ(平均平方误差)
深度学习重视可视化(Visdom),比如可以看见过拟合过程。
作业是穷举法画出y=ax+b(a,b为权重)的损失图(平面上的图)
第三节 梯度下降算法
分治法也可以求出使loss最小的权重值,寻找目标函数最小值即为优化问题(损失函数就是有画面目标)
学习率,贪心算法(可以得到局部最优解,不一定全局最优),非凸函数存在局部最优点。好在深度学习网络没有太多的局部最优点,但是有鞍点(平了)没法继续迭代了。
梯度下降,因为可以继承前一次的计算结果,因此时间复杂度底,但性能底。(视频中有代码)
随机梯度下降,时间复杂度高,性能高。取一个样本,有可能由于噪声跨过鞍点。(视频中有代码)
综合用Batch:取小批量样本做一次梯度下降。
第四章 反向传播
两层的神经网络,会合并,所以加入偏置
前馈求出loss,反馈算出梯度
pytorch中如何进行反向传播
各种维度的数值保存在Tensor中,Tensor中的Data保存权重值,Grad保存loss对于权重w的导数值。
import torch
x_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]
w = torch.Tensor([1.0]) # 相当于npl.arry 选择一个权重,创建一个Tensor变量,值为1.0
w.requires_grad = True # 需要计算梯度 (默认不计算梯度)
def forward(x):
return x*w # w是tensor类型的,x会自动类型转换为tensor
def loss(x,y): # 每调用一次loss,就是在动态构建一次计算图
y_pred = forward(x)
return (y_pred-y)**2
print('predict before training',4,forward(4).item()) # predict before training 4 4.0
# 训练过程(随机梯度下降)
for epoch in range(100):
for x,y in zip(x_data,y_data):
l=loss(x,y) # 前馈只需计算loss
l.backward() # 每进行一次反向传播,梯度存到w里,计算图即被释放
print('\tgrad:',x,y,w.grad.item())
w.data -= 0.01*w.grad.data#只做纯数值的修改,不用求梯度,所以用data取数值,不建立计算图,建图直接用张量
w.grad.data.zero_() # 把权重里的梯度数据清零
print("progress:",epoch,l.item()) #会得到每次循环的损失值
print('predict after training',4,forward(4).item()) # predict after training 4 7.999998569488525
第五章 用PyTorch实现线性回归
基本步骤包括:数据集准备、模型定义并实例化、损失函数和优化器、模型训练测试(前馈反馈更新)
损失要变成标量才能反向传播,
import torch
# step1 准备数据集
x_data = torch.Tensor([[1.0],[2.0],[3.0]]) #x,y必须为矩阵
y_data = torch.Tensor([[2.0],[4.0],[6.0]])
# step2 设计模型
class LinearModel(torch.nn.Module): # LinearModel继承nn.Module这个父类,自动实现反向传播,所以无需定义。若无法自动计算反向传播,可从forward继承,则需要定义反向传播。
def __init__(self): # 构造函数(初始化对象时默认调用)
super(LinearModel,self).__init__() # super调用父类的构造,这步一定要有
self.linear = torch.nn.Linear(1,1) # nn.Linear类,也继承在Module父类,构造对象,包含权重w和偏置b两个tensor,自动计算y= wx+b
def forward(self,x): # 前馈时要执行的计算
y_pred = self.linear(x) #计算y= wx+b
return y_pred
model = LinearModel() # 实例化
# step3 损失函数和优化器
criterion = torch.nn.MSELoss(size_average=False) # nn.MSELoss继承自nn.Module
optimizer = torch.optim.SGD(model.parameters(),lr=0.01) #第一个部分。提取权重;第二个部分,学习率
# step4 训练循环
for epoch in range(1000):
y_pred = model(x_data) # 前馈:预测,算y_pred
loss = criterion(y_pred,y_data) # 前馈:损失,算loss
print(epoch,loss) # loss自动调用__str__(),不会产生计算图
optimizer.zero_grad() # 梯度归零
loss.backward() # 反向传播
optimizer.step() # 更新
# 输出权重和偏置
print('w=',model.linear.weight.item()) #.item不打印矩阵,只打印数值
print('b=',model.linear.bias.item())
# 测试模型
x_test = torch.Tensor([[4.0]])
y_test = model(x_test)
print('y_pred=',y_test.data)
不同的优化器
第六章 逻辑斯蒂回归
对于回归问题,输出值连续,对于分类问题,输出值分散。
解决分类问题:分类问题中输出的是属于每一个分类的概率。
分类任务常用数据集,可用torchvision下载训练集。
import torchvision
train_set = torchvision.datasets.MNIST(root='../dataset/mnist',train=True,download=True)
test_set = torchvision.datasets.MNIST(root='../dataset/mnist',train=False,download=True)
Sigmoid函数 满足3个条件:(1)函数值有极限(2)单调增(3)饱合函数
其中最出名的是 logistic 函数
import torch
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt
# 准备数据集
x_data = torch.Tensor([[1.0],[2.0],[3.0]])
y_data = torch.Tensor([[0],[0],[1]])
# 设计模型(从nn.Module继承)
class LogisticRegressionModel(torch.nn.Module):
def __init__(self):
super(LogisticRegressionModel,self).__init__()
self.linear=torch.nn.Linear(1,1)
def forward(self,x):
y_pred=F.sigmoid(self.linear(x))
return y_pred
model = LogisticRegressionModel()
# 构造损失函数BCE(二分类交叉熵)用于二分类问题和优化器(使用Pytorch API)
criterion = torch.nn.BCELoss(size_average=False)
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
# 训练周期:前馈、反馈、更新
for epoch in range(1000):
y_pred = model(x_data)
loss = criterion(y_pred,y_data)
print(epoch,loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 测试
x = np.linspace(0,10,200) # 0-10h采样200个点
x_t = torch.Tensor(x).view((200,1)) # 变为200行1列的矩阵,类似于numpy里的reshape
y_t = model(x_t)
y = y_t.data.numpy() # 拿到数组
plt.plot(x,y)
plt.plot([0,10],[0.5,0.5],c='r')
plt.xlabel('Hours')
plt.ylabel('Probability of Pass')
plt.grid() # 网格
plt.show()
第七章 处理多维特征的输入
映射不一定是线性的,用多个线性变换层,通过找到最优的权重,把它们组合起来,模拟非线性变换。神经网络的本质是寻找非线性空间的变换函数 。
激活函数:给线性变换增加非线性因子,从而拟合非线性变换。
人工神经网络
# 准备数据集
import torch
import numpy as np
xy = np.loadtxt('diabetes.csv.gz',delimiter=',',dtype=np.float32) # 用numpy的函数loadtxt读取数据集内容,delimiter为分隔符,神经网络计算用32位浮点数
# torch.from_numpy()创建Tensor
x_data = torch.from_numpy(xy[:,:-1]) # 所有行,第1列开始,最后1列不要
y_data = torch.from_numpy(xy[:,[-1]]) # -1外面加[]是为了保证拿出来是一个矩阵,不加的话拿出来是一个向量
# 定义模型(输入8维—>线性层1—>6维—>线性层2—>4维—>线性层3—>输出1维)
class Model(torch.nn.Module):
def __init__(self):
super(Model,self).__init__()
self.linear1 = torch.nn.Linear(8,6)
self.linear2 = torch.nn.Linear(6,4)
self.linear3 = torch.nn.Linear(4,1)
self.sigmoid = torch.nn.Sigmoid() # 给模型添加一个非线性变换,继承自Module;另一种写法:torch.nn.Functional.Sigmoid()
def forward(self,x):
x = self.sigmoid(self.linear1(x))
x = self.sigmoid(self.linear2(x))
x = self.sigmoid(self.linear3(x))
return x
model = Model()
# 构建损失和优化器
criterion = torch.nn.BCELoss(size_average=True) # loss取平均值变小了,学习率最好调大一点
optimizer = torch.optim.SGD(model.parameters(),lr=0.1)
# 训练周期(训练时尚未使用Mini-Batch)
for epoch in range(100):
# 前馈
y_pred = model(x_data)
loss = criterion(y_pred,y_data)
print(epoch,loss.item())
# 反馈
optimizer.zero_grad()
loss.backward()
# 更新
optimizer.step()
可以变换激活函数,
如将激活函数换成 ReLU 时的代码:
import torch
class Model(torch.nn.Module):
def __init__(self):
super(Model,self).__init__()
self.linear = torch.nn.Linear(8,6)
self.linear = torch.nn.Linear(6,4)
self.linear = torch.nn.Linear(4,1)
self.activate = torch.nn.ReLU()
def forward(self,x):
x = self.activate(self.linear1(x))
x = self.activate(self.linear2(x))
x = self.activate(self.linear3(x))
return x
model = Model()
第八章 加载数据集
Epoch:所有训练样本经历了一次前向传播和反向传播的过程(嵌套循环)
Batch-Size:每次训练时用的样本数量
Iteration:Batch分了多少个迭代次数
import torch
from torch.utils.data import Dataset # Dataset是一个抽象类,不能实例化,只能被其他子类继承
from torch.utils.data import DataLoader # DataLoader类(加载器)可以实例,加载数据(shuffle和batch_size自动完成)
class DiabetesDataset(Dataset): # DiabetesDataset是自己定义的类,继承自Dataset类
def __init__(self):
pass
def __getitem__(self,index): # 实例化对象后支持下标操作,通过索引拿出数据
pass
def __len__(self): # 返回数据集里的数据条数,即整个数据的数量
pass
dataset = DiabetesDataset() # 实例化为数据对象
train_loader = DataLoader(dataset=dataset,batch_size=32,shuffle=True,num_workers=2)
# DataLoader加载器初始化时至少传4个量,num_workers:读数据、构成Mini-Batch时是否多线程(并行化),并行化可提高读取的效率
import numpy as np
import torch
from torch.utils.data import Dataset,DataLoader
# 1、准备数据(不再是加载全部数据)
class DiabetesDataset(Dataset):
def __init__(self,filepath):
xy = np.loadtxt(filepath,delimiter=',',dtype=np.float32)
self.len = xy.shape[0] # xy为N行9列(N行:数据样本个数;9列:8个特征列,1个目标列)
self.x_data = torch.from_numpy(xy[:,:-1]) # 前8列
self.y_data = torch.from_numpy(xy[:,[-1]]) # 最后1列
def __getitem__(self,index):
return self.x_data[index],self.y_data[index] # 返回的是一个元组
def __len__(self):
return self.len
dataset = DiabetesDataset('diabetes.csv.gz')#路径
train_loader = DataLoader(dataset=dataset,batch_size=32,shuffle=True,num_workers=0)#加载器
# 2、设计模型
class Model(torch.nn.Module):
def __init__(self):
super(Model,self).__init__()
self.linear1 = torch.nn.Linear(8,6)
self.linear2 = torch.nn.Linear(6,4)
self.linear3 = torch.nn.Linear(4,1)
self.sigmoid = torch.nn.Sigmoid()
def forward(self,x):
x = self.sigmoid(self.linear1(x))
x = self.sigmoid(self.linear2(x))
x = self.sigmoid(self.linear3(x))
return x
model = Model()
# 3、构建损失和优化器
criterion = torch.nn.BCELoss(size_average=True)
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
# 4、训练周期(变为了嵌套循环,以便使用Mini-Batch)
# 嵌套循环
for epoch in range(100):
# enumerate()获得当前是第几次迭代
for i,data in enumerate(train_loader,0): # data为元组(x,y)
# 1. 准备数据
inputs,labels = data #也可以把上一行写成for i(inputs,labels) in enumerate(train_loader,0),主要目的是把x,y解构出来
# 2. 前馈
y_pred = model(inputs)
loss = criterion(y_pred,labels)
print(epoch,i,loss.item())
# 3. 反馈
optimizer.zero_grad()
loss.backward()
# 4. 更新
optimizer.step()
import torch
from torch.utils.data import DataLoader
from torchvision import transforms # PIL Image —> Tensor
from torchvision import datasets
train_dataset = datasets.MNIST(root='../dataset/mnist',train=True,transform=transform.ToTensor(),download=True)
test_dataset = datasets.MNIST(root='../dataset/mnist',train=False,transform=transform.ToTensor(),download=True)
train_loader = DataLoader(dataset=train_dataset,batch_size=32,shuffle=True)
test_loader = DataLoader(dataset=test_dataset,batch_size=32,shuffle=False) # 测试数据一般不需要shuffle
for epoch in range(100):
for batch_idx,(inputs,target) in enumerate(train_loader):
...
第九章 多分类问题
十分类问题有几种解决思路。
以下代码中模型设计、训练、测试有具体思路和语法解释。
# 0.导包
import torch
from torchvision import transforms # 对图像进行原始处理的工具
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F # 为了使用函数 relu()
import torch.optim as optim # 为了构建优化器
# 1.准备数据
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(), # PIL Image 转换为 Pytorch里的张量(图像有通道,把0~225变成0~1)Tensor
transforms.Normalize((0.1307, ),(0.3081, ))]) # 归一化到0-1分布,其中mean均值=0.1307,std标准差=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)
# 2.设计模型
class Net(torch.nn.Module):
def __init__(self):
super(Net,self).__init__()
# 线性层
self.l1 = torch.nn.Linear(784,512)
self.l2 = torch.nn.Linear(512,256)
self.l3 = torch.nn.Linear(256,128)
self.l4 = torch.nn.Linear(128,64)
self.l5 = torch.nn.Linear(64,10)
def forward(self,x):
x = x.view(-1,784)
x = F.relu(self.l1(x))
x = F.relu(self.l2(x))
x = F.relu(self.l3(x))
x = F.relu(self.l4(x))
return self.l5(x) # 最后一层不做激活,直接接到softmax
model = Net()
# 3.构建损失和优化器
criterion = torch.nn.CrossEntropyLoss() #交叉熵损失
optimizer = optim.SGD(model.parameters(),lr=0.01,momentum=0.5) #带冲量的
# 4.训练
def train(epoch): # 把一轮循环封装到函数里
running_loss = 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: # 每300批量输出一次
print('[%d,%5d]loss: %.3f' % (epoch+1,batch_idx+1,running_loss/300))
running_loss = 0
# 5.测试
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) # 求每一行里max的下标,对应着分类,其中dim=1为行,dim=0为列
total += labels.size(0) # (N,1),取N
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() # 训练一轮,测试一轮
# 若想每训练10轮测试1次,可在test()前面加一行 if epoch % 10 == 9: