开课吧的课程笔记,0.99元买的,老师是高民权。
第一天
不要变成那种知道很多概念但是基本功不行的人。课程的最终收获:建立自己的深度学习框架。
当你能自己创造的时候,你会彻底理解它的原理。
科研分三个类型:1.描述型。2.因果推理。3.未来预测。
最难的是预测。
案例:波士顿房价问题。
内容:
1.什么是机器学习?
2.KNN算法
3.回归算法
4.什么是损失函数,为什么它对机器学习任务很关键?
5.什么是梯度下降?
先加载数据:
1 | from sklearn.datasets import load_boston |
探索数据:
1 | print(dataset["feature_names"]) |
1 | ['CRIM' 'ZN' 'INDUS' 'CHAS' 'NOX' 'RM' 'AGE' 'DIS' 'RAD' 'TAX' 'PTRATIO' |
看具体描述
1 | print(dataset["DESCR"]) |
具体输出太长就不列出来了。
看数据的值(第六列)
1 | print(dataset["data"][:,5]) |
定义问题:假设你是一个地产销售,有人要卖房子,给出估价。
使用pandas分析处理数据。
1 | import pandas as pd |
有506列数据。
问题:什么特征对房价影响最大?
用dataframe.corr()来看特征之间的相关性。
看最后一列或最后一行。
画热点图看看。
1 | import seaborn as sns |
发现房屋卧室个数和房屋价格最成正相关。
如何依据房屋卧室的数量来估计房子面积?
将卧室数量与房屋价格做字典映射
1 | X_rm = dataframe["RM"].values |
作为一个优秀的工程师/算法工作者,代码的可读性一定是大于简洁性。
根据卧室数量找到最接近的房屋价格
1 | import numpy as np |
rm_to_price不要写死在函数里,因为只要其值一改变函数可能就出错了。
职业与非职业的区别就在细节里。
“代码是给人看的,偶尔运行一下。”
上面就是KNN算法——K-Neighbor-Nearest
什么是机器学习?
学习是为了预测。通过观察已有数据预测未来数据。回归产生数值,分类产生类别。机器学习就是用计算机来学习。
knn算法的问题:当数据量变大时,学习时间变长。lazy learning。
一个更加有效的方法:找到X和Y之间的函数关系,每次要计算时输入给这个函数,就能直接获得预测值。
先画散点图
1 | import matplotlib.pyplot as plt |
用直线y = kx+b来拟合,如何评判拟合的“好”?
用Loss函数,即在拟合的时候信息损失了多少,因此叫损失函数。
上述损失函数称为误差平方均值(Mean Square Error, MSE)。
1 | def loss(y, yhat): |
因此y_hats_2要拟合得更好。
获得最优的k和b呢?
1.直接用微积分的方法计算。
最小二乘法。
当损失函数极复杂时,无法求解。
2.用随机模拟方法。
1 | import random |
1 | 在0时刻我找到了更好的k:-26和b:22,此时的loss是:27524.80590943083 |
开始时更新很快,更新速度越来越慢。
如何更新?
k’ = k + -1×loss对k的偏导数/k的偏导数
即梯度下降。深度学习的核心,即通过梯度下降的方法,获得一组参数,使得损失函数最小。
程序实现
1 | def partial_k(x, y, k_n, b_n): |
结果
1 | 在0时刻我找到了更好的k:17.369569754624507和b:-20.333675889328063,此时的loss是:4472.292227873009 |
基本上每次都在更新参数。
画图看看
回归比knn快得多。
第二天
从简单线性回归到复杂神经网络
从手工编码求导到自动求导。
我们只能让计算机拟合简单的线性函数。
除了线性函数,还有一种常见的函数关系是S形的函数,sigmoid函数。sigmoid(x)=1/(1+e^(-x))
画图看看
1 | def sigmoid(x): |
将其进行平移拉伸就可以变换成其它形式。
1 | def sigmoid(x): |
画多条试试
1 | for _ in range(5): |
深度学习基本思想:用基本模块经过复合叠加来拟合复杂函数。这些基本模块就是所谓的激活函数(Active functions),其作用是让模型拟合非线性关系。没激活函数就只能拟合线性函数。
神经网络∈机器学习∈人工智能
数据量很小时,神经网络的效果不好。数据量变大时,才能使用层数超过3层的神经网络(即深度网络),使用深度网络的机器学习称为深度学习。
偏导数的求导:链式求导法则。
但是如何让计算机知道?
定义问题:给定一个模型定义,包含参数:{k1,k2,b1,b2},构建一个程序,让它能够求解k1,k2,b1,b2的偏导数是多少。
这实际上一个数据结构,图结构的问题。
用字典结构来存储各个节点和其后继节点。
1 | computing_graph = { |
∂loss/∂k1 = ∂loss/∂l2 × ∂l2/∂σ × ∂σ/∂l1 × ∂l1/k1
用程序根据计算图获得输出。
1 | def get_output(graph, node): |
如此依次在图中找到输出节点。
如何获得k1的偏导?
获得k1的输出节点
获得k1的输出节点的输出节点
直到我们找到最后一个节点。
1 | computing_order = [] |
输出:
1 | [('L1', 'k1'), ('sigmoid', 'L1'), ('L2', 'sigmoid'), ('Loss', 'L2')] |
再输出求导顺序
1 | order = [] |
下面就可以求各个参数的导数了。
中间步骤可能进行超过1次,可以记录相关结果,避免重复计算。
如何让计算机自己根据计算图获得计算顺序?拓扑排序。
步骤:
1.选择一个没有进入的节点。如有多个,随机选一个。如k1
2.在图中删去上一步选择的节点,作为访问的顺序。
3.检查图是否为空。如不为空,跳至第一步。
4.若为空,将访问顺序逆序,即为求导顺序。
这个其实就是所谓的反向传播。
第三天
主要是实现前两节课的内容
一个好习惯:代码自描述。最好的文档是源代码本身。
先实现拓扑排序
1 | # 拓扑排序 |
python3.9已经自带了拓扑排序。
下面来运用拓扑排序生成计算图。
先创建节点类。
1 | class Node: |
再将节点转化为计算图并拓扑排序
1 | from collections import defaultdict |
最后测试一下
1 | node_x = Node(name = "x") |
结果
1 | [x, y, k, b, linear, sigmoid, loss] |
再增加一个Placeholder类,继承Node,定于由人赋值的节点。
1 | class Placeholder(Node): |
结果
1 | 我是b,人类赋值。 |
再增加sigmoid等类,都是从Node继承的。
1 | # 线性函数 |
节点的定义也改一下
1 | node_x = Placeholder(name = "x") |
运行结果:
1 | 我是y,人类赋值,值为0.712600098521853。 |
现在知道了loss的值,接下来就是如何减小loss值的问题了。也就是后向传播的问题了。
下面实现反向求导。在节点类里增加backward()成员函数。
如Sigmoid类中
1 | # sigmoid函数 |
其它类与此类似。下面就可以进行更新步骤了。
用函数封装一下一次训练过程:
1 | def forward(compute_graph): |
这就完成了这个过程,输入是标量,向量版本的把运算换成矩阵运算就行了。课程还介绍了怎么把库打包发布到网上给别人用。这个我就跳过了。
下面练习我就自己实现一个看看。
具体代码看这儿https://github.com/zwdnet/JSMPwork/blob/main/MyFrame.py
用波士顿房价预测作为测试问题,分别用我的框架和pytorch框架来解,并记录训练时间。用的数据,超参数都是一样的。
我的框架:
main.testMyFrame的运行时间为 : 219.15557213081047秒 框架评分:1512498.8851033389
pytorch:
main.testPytorch的运行时间为 : 358.63247944414616秒 pytorch评分:1451729.25
比pytorch时间短,评分也高一些(越低越好)……当然使用上还是pytorch更容易一些,因为我没有实现类似nn.Module的类,预测要自己写,而且跟神经网络的结构有关,改结构要改很多代码。
再来看看预测结果。
我的框架的:
第二张图是预测值与真实值之差的连线。
pytorch的。
最后,再到github上看看pytorch的源代码。nn模块的大多数类都直接/间接继承于Module类,类似我们框架的Node类。深度学习框架最核心的自动求导功能,是用C++写的,貌似在这里,而且貌似是用python能调用的形式写的。我多年不用c++了,看着一片头大。先略过吧。
学这个课程,最主要的收获是初步知道了框架实现深度学习的流程,在这个过程中,框架为我们做了哪些事。其中最关键的是反向传播使用的梯度下降法,数学原理是求导的链式法则。程序实现的原理:将计算过程抽象为图,然后采用拓扑排序的算法得到求导顺序,然后逆序依次求导。课程是直播课,老师现场敲代码,讲得很好。并没有因为是引流课程就糊弄或藏着掖着。但我并没有打算去报进阶课程,因为毕竟只是业余爱好,钱还是留着去学我的口腔专业的培训课程吧。谢谢开课吧和高民权老师的分享!
下次,再回到正题,尝试用深度学习解决我们原来的问题吧。
我发文章的三个地方,欢迎大家在朋友圈等地方分享,欢迎点“在看”。
我的个人博客地址:https://zwdnet.github.io
我的知乎文章地址: https://www.zhihu.com/people/zhao-you-min/posts
我的微信个人订阅号:赵瑜敏的口腔医学学习园地