第一周学习:深度学习与pytorch基础代码实战

目录

part1:理论视频学习 

一.人工智能和深度学习概述

         1.人工智能定义及其三个层面

         2.机器学习

 2.1 机器学习定义

 2.2 机器学习过程

 2.2.1 模型分类

二 .深度学习概述

 1.人工智能、机器学习、深度学习之间的关系

 2.深度学习的不能

 3.浅层神经网络

 3.1激活函数 

 3.2万有逼近定理与神经网络

 3.3更宽or更深

 3.4反向传播误差 

 3.5梯度消失 

part2:代码练习

一.pytorch基础练习

1.定义数据

 2.定义操作

二.螺旋曲线分类

2.2构建线性模型分类 

2.3两层神经网络分类 

小结


part1:理论视频学习 

一.人工智能和深度学习概述

         1.人工智能定义及其三个层面

 人工智能(Artificial Intelligence) 使一部机器像人一样进行感知、认知、决策、执行的人工程序或系统。

计算智能:能进行存储和计算

感知智能:具备类似于人的视觉、听觉、触觉等感知能力,能听会说,能看会认

认知智能:实现类似于人的认知能力,能理解、会思考、能产生对策,概念、意识、观念都是认知智能的表现

         2.机器学习

 2.1 机器学习定义

最常用定义:计算机系统能够利用经验提高自身的性能

可操作定义:机器学习本质是一个基于经验数据的函数估计问题

统计学定义:提取重要模式、趋势,并理解数据,即从数据中学习

总之,机器学习就是从数据中自动提取知识的过程

 2.2 机器学习过程

第一周学习:深度学习与pytorch基础代码实战_第1张图片

 2.2.1 模型分类

 数据标记:监督学习模型、非监督学习模型

 数据分布:参数模型、非参数模型

 建模对象:判别模型、生成模型

数据标记 

无监督学习:样本没有标记。无监督学习从数据中学习模式,适用于描述数据,目的在于发现数据中模式/有意义信息。
监督学习:样本具有标记(输出目标)。监督学习从数据中学习标记分界面 (输入-输出的映射函数),适用于预测数据标记。
半监督学习:部分数据标记已知,是监督学习和无监督学习的混合。
强化学习:数据标记未知,但 知道与输出目标相关的反馈,适用决策类问题。

第一周学习:深度学习与pytorch基础代码实战_第2张图片

数据分布 

参数模型: 对数据分布进行假设,待求解的数据模式/映射可以用一组有限且固定数目 的参数进行刻画 。

非参数模型: 不对数据分布进行假设,数据的所有统计特性都来源于数据本身。

参数模型 非参数模型
优点                数据需求少、训练快速 对数据适应性强,可拟合不同的函数形式
缺点 模型复杂度有限,与真实目标函数拟合度小 数据需求大、容易过拟合

建模对象 

生成模型: 对输入和输出的联合分布(, )建模

判别模型: 对已知输入条件下输出Y的条件分布(|) 建模

生成模型
优点

提供更多信息(建模边缘分布-->采样生成样本)

样本量大时,更快收敛到真实分布

支持复杂训练情况(无监督训练、存在隐变量时)

缺点

数据需求大 

预测类问题准确率通常不如判别模

二 .深度学习概述

 1.人工智能、机器学习、深度学习之间的关系

人工智能>机器学习>深度学习 

第一周学习:深度学习与pytorch基础代码实战_第3张图片

 2.深度学习的不能

1.算法输出不稳定,容易被“攻击”(对抗样本,单像素攻击)
2.模型复杂度高,难以纠错和调试
3.模型层级复合程度高,参数不透明
4.端到端训练方式对数据依赖性强,模型增量性差(小样本问题)
5.专注直观感知类问题,对开放性推理问题无能为力
6.人类知识无法有效引入进行监督,机器偏见难以避免
 

 3.浅层神经网络

 3.1激活函数 

激活函数 : 神经元继续传递信息、产生 新连接的概率(超过阈值被 激活,但不一定传递)

没有激活函数相当于矩阵相乘 ,通过激活函数可以实现非线性拟合。

常见激活函数 :

第一周学习:深度学习与pytorch基础代码实战_第4张图片

第一周学习:深度学习与pytorch基础代码实战_第5张图片

 3.2万有逼近定理与神经网络

万有逼近定理:如果一个隐层包含足够多的神经元,三层前馈神经网络(输入-隐层 -输出)能以任意精度逼近任意预定的连续函数。 

神经网络每一层的数学公式

神经网络学习如何利用矩阵的线性变换加激活函数的非线性变换, 将原始输入空间投影到线性可分的空间去分类/回归。

增加节点数:增加维度,即增加线性转换能力。

增加层数:增加激活函数的次数,即增加非线性转换次数

 3.3更宽or更深

在神经元总数相当的情况下,增加网络深度可以比增加宽度带来更强的网络表示能力:产生更多的线性区域。

深度和宽度对函数复杂度的贡献是不同的,深度的贡献是指数增长的,而宽度的贡献是线性的.

第一周学习:深度学习与pytorch基础代码实战_第6张图片

 3.4反向传播误差 

 第一周学习:深度学习与pytorch基础代码实战_第7张图片

 3.5梯度消失 

 第一周学习:深度学习与pytorch基础代码实战_第8张图片

 由于误差通过梯度传播,当梯度变得接近于0时,由于反向传播将与梯度相乘,得到的新梯度也接近为0,会使得梯度消失,误差无法传播,使数据得不到及时更新。

part2:代码练习

一.pytorch基础练习

1.定义数据

一般定义数据使用torch.Tensor , tensor的意思是张量,是数字各种形式的总称 

import torch

# tensor(data: Any, dtype: Optional[_dtype]=None, ... , requires_grad: _bool=False)
# 可以看出,data是任意数据,可以为一个数,一个list,二维数组等等
x = torch.tensor(666)  # 标量
print(x)  # tensor(666)
x = torch.tensor([2, 2], dtype=float)  # 一维张量
print(x)  # tensor([2., 2.], dtype=torch.float64)
x = torch.tensor([[2, 3], [4, 5]])  # 二维数组
print(x)  
# tensor([[2, 3],
#         [4, 5]])
# torch.ones()函数可以生成多维矩阵,矩阵元素初始化全为1
x = torch.ones(2, 3) # 二维数组
print(x)
x = torch.ones(5) #一维
print(x)
x = torch.ones(2, 3, 4) # 三维
print(x)

# tensor([[1., 1., 1.],
#         [1., 1., 1.]])

# tensor([1., 1., 1., 1., 1.])

# tensor([[[1., 1., 1., 1.],
#          [1., 1., 1., 1.],
#          [1., 1., 1., 1.]],

#         [[1., 1., 1., 1.],
#          [1., 1., 1., 1.],
#          [1., 1., 1., 1.]]])
# torch.empty() 创建空矩阵,内容未进行初始化,使用时要进行数据初始化
x = torch.empty(2, 3) # 2*3矩阵
print(x)
# tensor([[1.6209e-19, 1.8319e+25, 5.9423e-02],
#        [7.0374e+22, 1.6907e-01, 1.7743e+28]])

#torch.zeros() 与torch.ones()类似,区别是内容初始化为0
x = torch.zeros(1, 3, 3, dtype=torch.long) # 创建1*3*3的三维向量
print(x)
# tensor([[[0, 0, 0],
#          [0, 0, 0],
#         [0, 0, 0]]])


x1 = torch.rand(2, 4) # 2*4的随机数(0--1随机)
print(x)
x2 = torch.randn(2, 5)# 2*5符合正态分布的随机数
print(x)

# tensor([[0.8069, 0.9762, 0.6335, 0.5133],
#         [0.4084, 0.9876, 0.6013, 0.4617]])

# tensor([[-1.4031,  0.2296,  0.6661,  0.6075, -0.0034],
#         [-0.1969,  1.7592, -0.1239, -1.6503, -0.9498]])
# 利用原有的tensor创建新tensor,可以利用dtype,device,size等属性信息
x = torch.zeros(2, 3, dtype=int)
print("x:{}".format(x))
y = x.new_ones(2, 3)
print("y:{}".format(y))
# x:tensor([[0, 0, 0],
#           [0, 0, 0]])
# y:tensor([[1, 1, 1],
#           [1, 1, 1]])

# 利用之前tensor的大小,重新定义dtype
z = torch.randn_like(x, dtype=torch.float)
print("z:{}".format(z))
# z:tensor([[-0.8123,  0.0407,  0.4976],
#           [1.7102,  2.0772,  0.4945]])

 2.定义操作

凡是用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 等

import torch

s = torch.tensor([[1, 3, 5, 7], [2, 4, 6, 8]])
print(s.size(0), s.size(1), s.size(), sep="---")
# 2---4---torch.Size([2, 4])
print(s.numel())  # s中元素个数
# 8
print(s[0][2])  # s的第0行第2列元素(从0开始)
# tensor(5)
print(s[:, 1])  # s第一列所有元素
# tensor([3, 4])
print(s[1, :])  # s第一行所有元素
# tensor([2, 4, 6, 8])
t = torch.arange(1, 5)  # 生成2从1——5不包括5公差为1的序列
print(t)
# tensor([1, 2, 3, 4])
print(s @ t)  # 两矩阵叉乘
# tensor([50, 60])
print(s[0, :] * t)  # *表示对应两两相乘
# tensor([ 1,  6, 15, 28])
print(s[0, :] @ t)  # @表示矩阵叉乘
# tensor(50)
print(s + torch.rand(2, 4))  # s矩阵加上一个2*4随机矩阵
# tensor([[1.5769, 3.6351, 5.5506, 7.0818],
#         [2.9022, 4.8702, 6.7515, 8.1953]])

print(s.t())  # 矩阵转置
# tensor([[1, 2],
#         [3, 4],
#         [5, 6],
#         [7, 8]])
print(s.transpose(0, 1))  # transpose函数内参数为带转置的两个维度
# tensor([[1, 2],
#         [3, 4],
#         [5, 6],
#         [7, 8]])

# 从3到8生成20个符合等差数列的数 start:3,end:8,step:20
r = torch.linspace(3, 8, 20)
print(r)
# tensor([3.0000, 3.2632, 3.5263, 3.7895, 4.0526, 4.3158, 4.5789, 4.8421, 5.1053,
#         5.3684, 5.6316, 5.8947, 6.1579, 6.4211, 6.6842, 6.9474, 7.2105, 7.4737,
#         7.7368, 8.0000])
# 创建两个1*4的tensor
a = torch.tensor([[1, 2, 3, 4]])
b = torch.tensor([[4, 3, 2, 1]])
print(torch.cat((a, b), 0))  # 从第0维上拼接
# tensor([[1, 2, 3, 4],
#         [4, 3, 2, 1]])
print(torch.cat((a, b), 1))  # 从第1维上拼接
# tensor([[1, 2, 3, 4, 4, 3, 2, 1]])

from matplotlib import pyplot as plt

# matlabplotlib 只能显示numpy类型的数据,下面展示了转换数据类型,然后显示
# 注意 randn 是生成均值为 0, 方差为 1 的随机数
# 下面是生成 1000 个随机数,并按照 100 个 bin 统计直方图
plt.hist(torch.randn(1000).numpy(), 100, color='k')
plt.show()

 第一周学习:深度学习与pytorch基础代码实战_第9张图片

# 当数据非常非常多的时候,正态分布会体现的非常明显
plt.hist(torch.randn(10**6).numpy(), 100,color='k')
plt.show()

第一周学习:深度学习与pytorch基础代码实战_第10张图片

二.螺旋曲线分类

第一周学习:深度学习与pytorch基础代码实战_第11张图片

引入基本的库,然后定义参数

第一周学习:深度学习与pytorch基础代码实战_第12张图片

初始化 X 和 Y。 X 可以理解为特征矩阵,Y可以理解为样本标签。 结合代码可以看到,X的为一个 NxC 行, D 列的矩阵。C 类样本,每类样本是 N个,所以是 N*C 行。每个样本的特征维度是2,所以是 2列。

在 python 中,调用 zeros 类似的函数,第一个参数是 y方向的,即矩阵的行;第二个参数是 x方向的,即矩阵的列,大家得注意下,不要搞反了。下面结合代码看看 3000个样本的特征是如何初始化的。

X = torch.zeros(N * C, D).to(device)
Y = torch.zeros(N * C, dtype=torch.long).to(device)
for c in range(C):#C与c不同
    index = 0
    t = torch.linspace(0, 1, N) # 在[0,1]间均匀的取1000个数,赋给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())

 显示图像

第一周学习:深度学习与pytorch基础代码实战_第13张图片

2.2构建线性模型分类 

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

精确度只有50%左右 

print(y_pred.shape)
print(y_pred[10, :])
print(score[10])
print(predicted[10])

 第一周学习:深度学习与pytorch基础代码实战_第14张图片

# Plot trained model
print(model)
plot_model(X, Y, model)

第一周学习:深度学习与pytorch基础代码实战_第15张图片

2.3两层神经网络分类 

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)

# 下面的代码和之前是完全一样的,这里不过多叙述
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate, weight_decay=lambda_l2) # built-in 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)
    
    # zero the gradients before running the backward pass.
    optimizer.zero_grad()
    # Backward pass to compute the gradient
    loss.backward()
    # Update params
    optimizer.step()

第一周学习:深度学习与pytorch基础代码实战_第16张图片

使用ReLu作为激活函数,精确度达到了95.8%

 如果使用sigmoid()作为激活函数

model = nn.Sequential(
    nn.Linear(D, H),
    nn.Sigmoid(),
    nn.Linear(H, C)
)
model.to(device)

第一周学习:深度学习与pytorch基础代码实战_第17张图片

 可以看出,精确度与ReLu函数相比,Sigmoid函数精确度只有50.3%

LeakyRelu()作为激活函数

model = nn.Sequential(
    nn.Linear(D, H),
    nn.LeakyReLU(),
    nn.Linear(H, C)
)
model.to(device)

 

 LeakyReLu函数的精确度为94.4%第一周学习:深度学习与pytorch基础代码实战_第18张图片

tanh()作为激活函数 

model = nn.Sequential(
    nn.Linear(D, H),
    nn.Tanh(),
    nn.Linear(H, C)
)
model.to(device)

Tanh激活函数的精确度为83.6% 

第一周学习:深度学习与pytorch基础代码实战_第19张图片

 增加隐层使用两层sigmoid()函数

model = nn.Sequential(
    nn.Linear(D, H),
    nn.Sigmoid(),
    nn.Linear(H, 60),
    nn.Sigmoid(),
    nn.Linear(60, C)

  
)

增加隐层多用一次Sigmoid函数的精确度为97.0% 

第一周学习:深度学习与pytorch基础代码实战_第20张图片

不同的激活函数对比: 

Loss Accuracy
无激活函数 0.869014 0.494
ReLu 0.161963 0.958
Simoid 0.763233 0.503
LeakyReLu 0.181599 0.944
Tanh 0.317361 0.836
两层Sigmoid 0.131681 0.970

小结

Sigmoid()函数作为激活函数如果只嵌套一层相比于ReLu等其他的激活函数则其精确度较弱,但如果增加隐层再次使用Sigmoid函数,那么其精确度会大幅度上升,不同的激活函数会有不同的精准度,使用时应该多尝试,哪个效果好用哪个。

你可能感兴趣的:(深度学习,pytorch,学习)