一、绪论

1.深度学习

是一种特殊的机器学习方法,它应用了深度神经网络,通过在输入中先提取出简单的特征,再计算出更为复杂的特征,最后映射出输出结果。然而深度学习仍有一些问题亟待解决,如深度学习的算法输出不稳定,容易受到攻击;复杂度高难以调试,参数不透明,模型增量型差;容易产生机器偏见等。此外,深度学习与知识图谱逐渐从对立走向协同发展的方向。

2.神经网络

最早源于生物学概念,是一种模仿动物神经网络行为特征,进行分布式并行信息处理的算法数学模型。三层前馈神经网络能以任意精度逼近任意预定的连续函数。神经网络学习如何利用矩阵的线性变换和激活函数的的非线性变换,将原始输入空间投影到线性可分空间,从而进行分类或回归。

3.人工智能的三个层面

  • 计算智能:能存储,会计算
  • 感知智能:能听会说、能看会认。类似于人的视觉、听觉、触觉等感知能力
  • 认知智能:能理解、会思考。概念、意识、观念都是认知智能的表现

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

第一周学习任务:深度学习和pytorch基础 - 图2

5.逻辑演绎 vs 归纳总结第一周学习任务:深度学习和pytorch基础 - 图3

6.知识工程 vs 机器学习

知识工程

  • 基于手工设计规则建立专家系统(~80年代末期)
  • 结果容易解释
  • 系统构建费时费力
  • 依赖专家主观经验,难以保证一致性和准确性

机器学习

  • 基于数据自动学习(90年代中期~)
  • 减少人工繁杂工作,但结果可能不易解释
  • 提高信息处理的效率,且准确率较高
  • 来源于真实数据,减少人工规则主观性,可信度高

7.机器学习

定义

  • 最常用定义:计算机系统能够利用经验提高自身的性能
  • 可操作定义:机器学习本质是一个基于经验数据的函数估计问题
  • 统计学定义:提取重要模式、趋势,并理解数据,即从数据中学习

怎么学
第一周学习任务:深度学习和pytorch基础 - 图4
模型分类
第一周学习任务:深度学习和pytorch基础 - 图5
1.数据标记:监督 vs 无监督学习模型

  • 无监督学习:样本没有标记。无监督学习从数据中学习模式,适用于描述数据,目的在于发现数据中模式/有意义信息
  • 监督学习:样本具有标记(输出目标)。监督学习从数据中学习标记分界面 (输入-输出的映射函数),适用于预测数据标记

半监督学习、强化学习

  • 半监督学习:部分数据标记已知,是监督学习和无监督学习的混合
  • 强化学习:数据标记未知,但 知道与输出目标相关的反馈,适用决策类问题

2.数据分布:参数 vs 无参数模型
第一周学习任务:深度学习和pytorch基础 - 图6

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

3.建模对象:判别 vs 生成模型第一周学习任务:深度学习和pytorch基础 - 图7

二、深度学习概述

1.神经网络结构的发展

第一周学习任务:深度学习和pytorch基础 - 图8

2.深度学习的不能

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

三、pytorch 基础练习

代码练习 notebook 地址

  1. """
  2. ## 什么是 PyTorch ?
  3. PyTorch是一个python库,它主要提供了两个高级功能:
  4. - GPU加速的张量计算
  5. - 构建在反向自动求导系统上的深度神经网络
  6. ## 1. 定义数据
  7. 一般定义数据使用torch.Tensor , tensor的意思是张量,是数字各种形式的总称
  8. """
  9. import torch
  10. # 可以是一个数
  11. x = torch.tensor(666)
  12. print(x)
  13. # 可以是一维数组(向量)
  14. x = torch.tensor([1,2,3,4,5,6])
  15. print(x)
  16. # 可以是二维数组(矩阵)
  17. x = torch.ones(2,3)
  18. print(x)
  19. # 可以是任意维度的数组(张量)
  20. x = torch.ones(2,3,4)
  21. print(x)
  22. """
  23. Tensor支持各种各样类型的数据,包括:
  24. torch.float32, torch.float64, torch.float16, torch.uint8, torch.int8, torch.int16, torch.int32, torch.int64 。这里不过多描述。
  25. 创建Tensor有多种方法,包括:ones, zeros, eye, arange, linspace, rand, randn, normal, uniform, randperm, 使用的时候可以在线搜,下面主要通过代码展示。
  26. """
  27. # 创建一个空张量
  28. x = torch.empty(5,3)
  29. print(x)
  30. # 创建一个随机初始化的张量
  31. x = torch.rand(5,3)
  32. print(x)
  33. # 创建一个全0的张量,里面的数据类型为 long
  34. x = torch.zeros(5,3,dtype=torch.long)
  35. print(x)
  36. # 基于现有的tensor,创建一个新tensor,
  37. # 从而可以利用原有的tensor的dtype,device,size之类的属性信息
  38. y = x.new_ones(5,3) #tensor new_* 方法,利用原来tensor的dtype,device
  39. print(y)
  40. z = torch.randn_like(x, dtype=torch.float) # 利用原来的tensor的大小,但是重新定义了dtype
  41. print(z)
  42. """
  43. ## 2. 定义操作
  44. 凡是用Tensor进行各种运算的,都是Function
  45. 最终,还是需要用Tensor来进行计算的,计算无非是
  46. - 基本运算,加减乘除,求幂求余
  47. - 布尔运算,大于小于,最大最小
  48. - 线性运算,矩阵乘法,求模,求行列式
  49. **基本运算包括:** abs/sqrt/div/exp/fmod/pow ,及一些三角函数 cos/ sin/ asin/ atan2/ cosh,及 ceil/round/floor/trunc 等具体在使用的时候可以百度一下
  50. **布尔运算包括:** gt/lt/ge/le/eq/ne,topk, sort, max/min
  51. **线性计算包括:** trace, diag, mm/bmm,t,dot/cross,inverse,svd 等
  52. 下面用具体的代码案例来学习。
  53. """
  54. # 创建一个 2x4 的tensor
  55. m = torch.Tensor([[2, 5, 3, 7],
  56. [4, 2, 1, 9]])
  57. print(m.size(0), m.size(1), m.size(), sep=' -- ')
  58. # 返回 m 中元素的数量
  59. print(m.numel())
  60. # 返回 第0行,第2列的数
  61. print(m[0][2])
  62. # 返回 第1列的全部元素
  63. print(m[:, 1])
  64. # 返回 第0行的全部元素
  65. print(m[0, :])
  66. # Create tensor of numbers from 1 to 5
  67. # 注意这里结果是1到4,没有5
  68. v = torch.arange(1, 5)
  69. print(v)
  70. # 这里需要类型转换,才能进行后面的操作
  71. m = m.type(torch.LongTensor)
  72. print(m.type())
  73. print(v.type())
  74. # Scalar product
  75. print(m)
  76. print(v)
  77. m @ v
  78. # Calculated by 1*2 + 2*5 + 3*3 + 4*7
  79. print(m[[0], :])
  80. m[[0], :] @ v
  81. # Add a random tensor of size 2x4 to m
  82. m + torch.rand(2, 4)
  83. # 转置,由 2x4 变为 4x2
  84. print(m.t())
  85. # 使用 transpose 也可以达到相同的效果,具体使用方法可以百度
  86. print(m.transpose(0, 1))
  87. # returns a 1D tensor of steps equally spaced points between start=3, end=8 and steps=20
  88. torch.linspace(3, 8, 20)
  89. from matplotlib import pyplot as plt
  90. # matlabplotlib 只能显示numpy类型的数据,下面展示了转换数据类型,然后显示
  91. # 注意 randn 是生成均值为 0, 方差为 1 的随机数
  92. # 下面是生成 1000 个随机数,并按照 100 个 bin 统计直方图
  93. plt.hist(torch.randn(1000).numpy(), 100);
  94. # 当数据非常非常多的时候,正态分布会体现的非常明显
  95. plt.hist(torch.randn(10**6).numpy(), 100);
  96. # 创建两个 1x4 的tensor
  97. a = torch.Tensor([[1, 2, 3, 4]])
  98. b = torch.Tensor([[5, 6, 7, 8]])
  99. # 在 0 方向拼接 (即在 Y 方各上拼接), 会得到 2x4 的矩阵
  100. print( torch.cat((a,b), 0))
  101. # 在 1 方向拼接 (即在 X 方各上拼接), 会得到 1x8 的矩阵
  102. print( torch.cat((a,b), 1))

四、螺旋数据分类

理论学习地址

我的代码练习 notebook 地址

  1. """
  2. ## Spiral classifciation
  3. 本次的代码教程里解决 sprial classification 问题,教程有配套的文字版讲解理论,地址为:https://atcold.github.io/pytorch-Deep-Learning/chapters/02-3/ 基础一般的同学可以适当看看理论
  4. 下面代码是下载绘图函数到本地。(画点的过程中要用到里面的一些函数)
  5. """
  6. !wget https://raw.githubusercontent.com/Atcold/pytorch-Deep-Learning/master/res/plot_lib.py
  7. """引入基本的库,然后初始化重要参数"""
  8. import random
  9. import torch
  10. from torch import nn, optim
  11. import math
  12. from IPython import display
  13. from plot_lib import plot_data, plot_model, set_default
  14. # 因为colab是支持GPU的,torch 将在 GPU 上运行
  15. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
  16. print('device: ', device)
  17. # 初始化随机数种子。神经网络的参数都是随机初始化的,
  18. # 不同的初始化参数往往会导致不同的结果,当得到比较好的结果时我们通常希望这个结果是可以复现的,
  19. # 因此,在pytorch中,通过设置随机数种子也可以达到这个目的
  20. seed = 12345
  21. random.seed(seed)
  22. torch.manual_seed(seed)
  23. N = 1000 # 每类样本的数量
  24. D = 2 # 每个样本的特征维度
  25. C = 3 # 样本的类别
  26. H = 100 # 神经网络里隐层单元的数量
  27. """
  28. 初始化 X 和 Y。 X 可以理解为特征矩阵,Y可以理解为样本标签。
  29. 结合代码可以看到,X的为一个 NxC 行, D 列的矩阵。C 类样本,每类样本是 N个,所以是 N*C 行。每个样本的特征维度是2,所以是 2列。
  30. 在 python 中,调用 zeros 类似的函数,第一个参数是 y方向的,即矩阵的行;第二个参数是 x方向的,即矩阵的列,大家得注意下,不要搞反了。下面结合代码看看 3000个样本的特征是如何初始化的。
  31. """
  32. X = torch.zeros(N * C, D).to(device)
  33. Y = torch.zeros(N * C, dtype=torch.long).to(device)
  34. for c in range(C):
  35. index = 0
  36. t = torch.linspace(0, 1, N) # 在[0,1]间均匀的取10000个数,赋给t
  37. # 下面的代码不用理解太多,总之是根据公式计算出三类样本(可以构成螺旋形)
  38. # torch.randn(N) 是得到 N 个均值为0,方差为 1 的一组随机数,注意要和 rand 区分开
  39. inner_var = torch.linspace( (2*math.pi/C)*c, (2*math.pi/C)*(2+c), N) + torch.randn(N) * 0.2
  40. # 每个样本的(x,y)坐标都保存在 X 里
  41. # Y 里存储的是样本的类别,分别为 [0, 1, 2]
  42. for ix in range(N * c, N * (c + 1)):
  43. X[ix] = t[index] * torch.FloatTensor((math.sin(inner_var[index]), math.cos(inner_var[index])))
  44. Y[ix] = c
  45. index += 1
  46. print("Shapes:")
  47. print("X:", X.size())
  48. print("Y:", Y.size())
  49. # visualise the data
  50. plot_data(X, Y)
  51. """## 1. 构建线性模型分类"""
  52. learning_rate = 1e-3 # 学习率
  53. lambda_l2 = 1e-5 # 权重衰减超参数:正则项权重lambda
  54. # nn 包用来创建线性模型
  55. # 每一个线性模型都包含 weight 和 bias
  56. model = nn.Sequential(
  57. nn.Linear(D, H),
  58. nn.Linear(H, C)
  59. )
  60. model.to(device) # 把模型放到GPU上
  61. # nn 包含多种不同的损失函数,这里使用的是交叉熵(cross entropy loss)损失函数
  62. criterion = torch.nn.CrossEntropyLoss()
  63. # 这里使用 optim 包进行随机梯度下降(stochastic gradient descent)优化
  64. optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, weight_decay=lambda_l2)
  65. # 开始训练
  66. for t in range(1000):
  67. # 把数据输入模型,得到预测结果
  68. y_pred = model(X)
  69. # 计算损失和准确率
  70. loss = criterion(y_pred, Y)
  71. score, predicted = torch.max(y_pred, 1)
  72. acc = (Y == predicted).sum().float() / len(Y)
  73. print('[EPOCH]: %i, [LOSS]: %.6f, [ACCURACY]: %.3f' % (t, loss.item(), acc))
  74. display.clear_output(wait=True)
  75. # 反向传播前把梯度置 0
  76. optimizer.zero_grad()
  77. # 反向传播优化
  78. loss.backward()
  79. # 更新全部参数
  80. optimizer.step()
  81. """
  82. 这里对上面的一些关键函数进行说明:
  83. 使用 print(y_pred.shape) 可以看到模型的预测结果,为[3000, 3]的矩阵。每个样本的预测结果为3个,保存在 y_pred 的一行里。值最大的一个,即为预测该样本属于的类别
  84. score, predicted = torch.max(y_pred, 1) 是沿着第二个方向(即X方向)提取最大值。最大的那个值存在 score 中,所在的位置(即第几列的最大)保存在 predicted 中。下面代码把第10行的情况输出,供解释说明
  85. 此外,可以看到,每一次反向传播前,都要把梯度清零,这个在知乎上有一个回答,大家可以参考:https://www.zhihu.com/question/303070254
  86. """
  87. print(y_pred.shape)
  88. print(y_pred[10, :])
  89. print(score[10])
  90. print(predicted[10])
  91. # Plot trained model
  92. print(model)
  93. plot_model(X, Y, model)
  94. """
  95. 上面使用 print(model) 把模型输出,可以看到有两层:
  96. - 第一层输入为 2(因为特征维度为主2),输出为 100;
  97. - 第二层输入为 100 (上一层的输出),输出为 3(类别数)
  98. 从上面图示可以看出,线性模型的准确率最高只能达到 50% 左右,对于这样复杂的一个数据分布,线性模型难以实现准确分类。
  99. ## 2. 构建两层神经网络分类
  100. """
  101. learning_rate = 1e-3
  102. lambda_l2 = 1e-5
  103. # 这里可以看到,和上面模型不同的是,在两层之间加入了一个 ReLU 激活函数
  104. model = nn.Sequential(
  105. nn.Linear(D, H),
  106. nn.ReLU(),
  107. nn.Linear(H, C)
  108. )
  109. model.to(device)
  110. # 下面的代码和之前是完全一样的,这里不过多叙述
  111. criterion = torch.nn.CrossEntropyLoss()
  112. optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate, weight_decay=lambda_l2) # built-in L2
  113. # 训练模型,和之前的代码是完全一样的
  114. for t in range(1000):
  115. y_pred = model(X)
  116. loss = criterion(y_pred, Y)
  117. score, predicted = torch.max(y_pred, 1)
  118. acc = ((Y == predicted).sum().float() / len(Y))
  119. print("[EPOCH]: %i, [LOSS]: %.6f, [ACCURACY]: %.3f" % (t, loss.item(), acc))
  120. display.clear_output(wait=True)
  121. # zero the gradients before running the backward pass.
  122. optimizer.zero_grad()
  123. # Backward pass to compute the gradient
  124. loss.backward()
  125. # Update params
  126. optimizer.step()
  127. # Plot trained model
  128. print(model)
  129. plot_model(X, Y, model)
  130. """
  131. 可以看到,在两层神经网络里加入 ReLU 激活函数以后,分类的准确率得到了显著提高。
  132. """