本文重点:
视频学习
机器学习概述
从领域上来看,人工智能>机器学习>深度学习,深度学习是机器学习中应用了深度神经网络的一个分支。
学习过程
模型分类
深度学习概述
深度学习和机器学习最大的区别就是特征的设置,传统机器学习通常是人工设置特征,而深度学习一般利用机器去优化参数和特征。
神经网络发展
问题
当然深度学习目前也有一些问题,需要我们去解决
深度学习基础
基础结构
MP神经元——最基础的神经网络
单层感知器和多层感知器
单层感知器用来实现逻辑的与或非(线性),而多层感知器可以实现异或同或等(非线性)
BP神经网络
定理
万有逼近定理
如果一个隐层包含足够多的神经元,三层前馈神经网络(单隐层)能以任意精读逼近预定的连续函数(连续凹凸函数,双隐层能逼近任何函数
每层的作用
- 升降维度
- 放缩
- 旋转
- 平移
- 弯曲 :对应激活函数f(投影到一个高维空间)
节点数:维度,线性变换能力
层数:代表多个激活函数,非线性变换能力
神经网络学习的目标:利用激活函数的非线性变换能力和矩阵的线性变换能力投影到一个线性可分的空间
BP神经网络
首先说明一点,最简单的BP神经网络一般是指三层前馈神经网络,且使用了反向传播对权重等参数进行了调整。
现在使用的神经网络可以理解为这种结构的升级和变种,归根结底最核心的还是反向传播方法。
有个猜数字例子说的很不错,A猜数字,B给出是否正确。那么A给出的数字就是正向传播,而B给出的正确与否就是反向传播。
多层神经网络的问题:梯度消失
预训练
自编码器和受限玻尔兹曼机
自编码器 | RBM | |
---|---|---|
结构 | 编码和解码函数不同 | 权重矩阵相同,两个偏置向量 |
原理 | 非线性变换学习特征 | 输出只有两种状态,高层是底层特征的条件概率 |
训练优化 | 最损失函数最小化,BP优化求解 | 最大似然,通过采样进行估计 |
模型类别 | 直接对条件概率建模,判别式模型 | 对联合概率密度建模,是判别式模型 |
解决方案
训练流程
- 定义网络
- 自己定义一个Net
- 通常有一些可学习的参数(比如权重
- 通常需要定义前向传播(每一层的激活函数和矩阵的线性变换),而反向传播由函数background自动定义
- 可以直接引包,比如resnet等
- 数据集上迭代训练
- 通过神经网络处理输入
- 计算损失
- 有多种方式,如计算均方误差等(nn.MSEloss)
- 梯度反向传播
- 为了反向传播误差,我们所需做的是调用loss.backward().需要清除已存在的梯度,否则梯度将被累加到已存在的梯度。
- 更新参数
- 多种方式,最简单的如SGD(随机梯度下降
- 多种方式,最简单的如SGD(随机梯度下降
代码练习
首先先跟着文档学习一遍,弄明白了每段代码的含义。
pytorch的基础练习
pytorch的基础学习可分为两方面,定义数据和定义操作
定义数据
#定义数据一般使用张量,它可以是一个数,向量,矩阵,张量等
import torch
x=torch.tensor(233)
y=torch.ones(2,3,4)
#tensor也支持各种类型的数据,且创建的时候也有多种方法
x=tensor.empty(3,2)
x=tensor.rand(3,5)
y=x.new_ones(3,5)
定义操作
'''
凡是用Tensor进行各种运算的,都是Function
最终,还是需要用Tensor来进行计算的,计算无非是
基本运算,加减乘除,求幂求余
布尔运算,大于小于,最大最小
线性运算,矩阵乘法,求模,求行列式
基本运算包括: abs/sqrt/div/exp/fmod/pow ,及一些三角函数 cos/ sin/ asin/ atan2/ cosh,及 ceil/round/floor/trunc 等具体在使用的时候可以百度一下
布尔运算包括: gt/lt/ge/le/eq/ne,topk, sort, max/min
线性计算包括: trace, diag, mm/bmm,t,dot/cross,inverse,svd 等
'''
# 创建一个 2x4 的tensor
m = torch.Tensor([[2, 5, 3, 7],
[4, 2, 1, 9]])
# 返回 m 中元素的数量
print(m.numel())
# 返回 第0行,第2列的数
print(m[0][2])
# 返回 第1列的全部元素
print(m[:, 1])
# 返回 第0行的全部元素
print(m[0, :])
# Create tensor of numbers from 1 to 5
# 注意这里结果是1到4,没有5
v = torch.arange(1, 5)
print(v)
# 矩阵相乘
m @ v
#直接跑的话这一行会报错,报错原因是类型不一致了。
# 矩阵m第一行与v相乘
m[[0], :] @ v
#m加上同大小的随机数矩阵
m + torch.rand(2, 4)
#转置
m.t()
#在3和8中间均匀按序随机生成20个数
torch.linspace(3, 8, 20)
#x和y方向上拼接
# 创建两个 1x4 的tensor
a = torch.Tensor([[1, 2, 3, 4]])
b = torch.Tensor([[5, 6, 7, 8]])
x =torch.cat((a,b), 0)
螺旋分类神经网络
引包和下载绘图函数
#下载绘图函数
!wget https://raw.githubusercontent.com/Atcold/pytorch-Deep-Learning/master/res/plot_lib.py
#引包
import random
import torch
from torch import nn, optim
import math
from IPython import display
from plot_lib import plot_data, plot_model, set_default
准备样本和初始化样本特征
# 因为colab是支持GPU的,torch 将在 GPU 上运行
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print('device: ', device)
# 初始化随机数种子。神经网络的参数都是随机初始化的,
# 不同的初始化参数往往会导致不同的结果,当得到比较好的结果时我们通常希望这个结果是可以复现的,
# 因此,在pytorch中,通过设置随机数种子也可以达到这个目的
seed = 12345
random.seed(seed)
torch.manual_seed(seed)
N = 1000 # 每类样本的数量
D = 2 # 每个样本的特征维度
C = 3 # 样本的类别
H = 100 # 神经网络里隐层单元的数量
X = torch.zeros(N * C, D).to(device)
Y = torch.zeros(N * C, dtype=torch.long).to(device)
for c in range(C): #对每一类样本进行初始化
index = 0
t = torch.linspace(0, 1, N) # 在[0,1]间均匀的取10000个数,赋给t
# 下面的代码不用理解太多,总之是根据公式计算出三类样本(可以构成螺旋形)
# torch.randn(N) 是得到 N 个均值为0,方差为 1 的一组随机数,注意要和 rand 区分开
inner_var = torch.linspace( (2*math.pi/C)*c, (2*math.pi/C)*(2+c), N) + torch.randn(N) * 0.2
# 每个样本的(x,y)坐标都保存在 X 里
# Y 里存储的是样本的类别,分别为 [0, 1, 2]
for ix in range(N * c, N * (c + 1)):#对应样本的定义
X[ix] = t[index] * torch.FloatTensor((math.sin(inner_var[index]), math.cos(inner_var[index])))
Y[ix] = c
index += 1
print("Shapes:")
print("X:", X.size())
print("Y:", Y.size())
# visualise the data
plot_data(X, Y)
构建线性模型(只有两个全连接层)和定义损失函数和优化方法
learning_rate = 1e-3
lambda_l2 = 1e-5
# nn 包用来创建线性模型
# 每一个线性模型都包含 weight 和 bias
model = nn.Sequential(
nn.Linear(D, H),
nn.Linear(H, C)
)#用来存放神经网络,这里的神经网络只有两个全连接层
model.to(device) # 把模型放到GPU上
# nn 包含多种不同的损失函数,这里使用的是交叉熵(cross entropy loss)损失函数
criterion = torch.nn.CrossEntropyLoss()
# 这里使用 optim 包进行随机梯度下降(stochastic gradient descent)优化
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, weight_decay=lambda_l2)
开始训练
# 开始训练
for t in range(1000):
# 把数据输入模型,得到预测结果
y_pred = model(X)
# 计算损失和准确率
loss = criterion(y_pred, Y)
score, predicted = torch.max(y_pred, 1)
acc = (Y == predicted).sum().float() / len(Y)
print('[EPOCH]: %i, [LOSS]: %.6f, [ACCURACY]: %.3f' % (t, loss.item(), acc))
display.clear_output(wait=True)
# 反向传播前把梯度置 0
optimizer.zero_grad()
# 反向传播优化
loss.backward()
# 更新全部参数
optimizer.step()
测试分类结果
构建两层神经网络(加了个relu函数,使得神经网络拥有了非线性分类的能力
learning_rate = 1e-3
lambda_l2 = 1e-5
# 这里可以看到,和上面模型不同的是,在两层之间加入了一个 ReLU 激活函数
model = nn.Sequential(
nn.Linear(D, H),
nn.ReLU(),
nn.Linear(H, C)
)
model.to(device)
接下来的代码就是和上面一样,同样训练1000轮。
最后的结果
遇到的问题
demo02报错
在运行第一个02demo时,会有类型不一致报错。
按照教程在构建了m和v两个张量后,发现有报错
很明显发现这是类型不符合,前面使用构造的v张量的默认类型是long,导致发生了错误。
# Create tensor of numbers from 1 to 5
# 注意这里结果是1到4,没有5
v = torch.arange(1, 5)
print(v)
利用前面学到的类型设置,更改一下
# Create tensor of numbers from 1 to 5
# 注意这里结果是1到4,没有5
v = torch.arange(1, 5,dtype=torch.float)
print(v)
这样就没有报错了,成功运行
PS:经过同学提醒,这里应该是前文中m的生成使用了Tensor,至于Tensor和tensor的区别:
(1)torch.tensor是从数据中推断数据类型,而torch.Tensor是torch.empty(会随机产生垃圾数组,详见实例)和torch.tensor之间的一种混合。但是,当传入数据时,torch.Tensor使用全局默认dtype(FloatTensor);
(2)torch.tensor(1)返回一个固定值1,而torch.Tensor(1)返回一个大小为1的张量,它是初始化的随机值
这段话引自:Tensor和tensor
魔改网络
首先明确一个目标,这里我修改网络的激活函数等都是奔着去提高最终的准确率
。
对螺旋分类问题的激活函数进行更改
首先还是跑一下RELU的数据,作为对照组
ELU
model = nn.Sequential(
nn.Linear(D, H),
nn.ELU(),
nn.Linear(H, C)
)
GELU
PRELU
Hardshrink
Softshrink
通过以上几个不同的激活函数,发现Hardshrink和Softshrinkl的效果是最好的,对比一下hardshrink和Relu函数在坐标系下的图。
总结:之前学习到激活函数的作用是给数据进行非线性的变化,那在这个样本数据中,对于样本数据,是一群三螺旋曲线模型,三分类问题。
对于螺旋线,他的极坐标下方程为r=aθ,三螺旋线的方程应该为 r=a(θ+k*60),k=0,1,2,在极坐标系下为三条线性的曲线。
Hardshrink的极坐标方程,类似于θ=45°,是一条直线,因此才能取得最好的结果。
修改节点数和训练轮数
我对修改节点数的理解是增加了维度信息,但是维度不能太高,会影响整个网络的训练难度;而训练轮数的增加就是堆算力,训练轮数太高也不好,准确率会下降。
上个拉满的准确率
总结
这一周我学习了两个专知课程,了解了深度学习的发展历史和最基本的原理;同时根据高峰老师的demo,对pytorch的基础运算和神经网络的结构有了一定的理解,希望能在后续的学习和科研中更好的运用这些知识。