我不是主攻人工智能, 深度学习方向, 但是作为计算机相关领域的学习者, 如果不了解下, 总觉得已经跟不上时代了, 况且, 人工智能真的是大势所趋, 学会了, 能够尝试用在不同领域.
本文将使用回归的思想来求解二元一次方程的最佳解, 理解深度学习的根本思想.
假设, 对于二元一次方程:
y = a * x + b
假设我们能够采集到一组数据 (x,y), 这些值都是满足以上等式的, 但是, 现实生活中往往不能这样顺利(如果采集的值是精确值, 直接列方程组就能求出 a 和 b), 我们采集到的每组(x,y) 都存在一定偏差, 所以, 现实中采集到的数据应表示为:
y = a * x + b + r
r 表示偏差, 这个时候, 我们需要通过这一组数据, 来找到一组 a 和 b, 使得 y = a * x + b 和理想的情况越接近.
为了方便表示, 将 r 表示为:
r = y - (a * x +b)
因为这个值可能为负数, 所以用 r 的平方来表示这个偏差, 记为:
loss = [ y - (a * x + b)] 2
这里用 loss 记, 实际上就理解为模型训练过程中的 "损失", 我们需要找到到一组 a 和 b, 使得 loss 最小.
在数学中, 我们会用到极限的思想求解最小值, 但是, 在深度学习中, 是如何找到这个最小 loss 的呢?
这里就需要提到梯度下降的思想(这些内容在 《计算方法》 这门学科中有详细的说明), 通俗地理解, 在本文的二元一次方程中, 就是初始化一个 a 和 b, 然后进行一定次数的迭代, 在每次迭代中, 调整 a 和 b 的值.
将 loss 表示的函数分别对 a 和 b 求偏导数:
- dei a = 2 * [ y - ( a * x + b ) ] * x
- dei b = 2 * [ y - ( a * x + b ) ]
我们每次调整 a 和 b 的值使用如下方法:
- new a = a - dei a * learn_rate
- new b = b - dei b * learn_rate
实际上, 在每轮迭代中, 我们将会用收集到的每组数据都来计算 dei a 和 dei b, 最终使用平均值, 表示经过这一轮, 参数 a 和 b 需要被调整的大小.
但是, 我们发现, 调整参数的时候, dei a 和 dei b 还分别乘以了一个 learn_rate, 这个 learn_rate 在深度学习模型训练中叫学习率, 一般取一个比较小的值, 0.001,0.01 等, 可以通过尝试找到最优的值. 如果不乘以 learn_rate, 对 a 来说, 每次需要调整 dei a, 这个值是很大的, 而且会出现不能收敛的情况:
从上图中可以看到, 对同一个 loss 函数, 如果使用 0.05 的 learn_rate, 会导致 loss 在最小值附近波动, 不能找到最小值, 而使用 0.005 的学习率, 每次调整的范围更小, 且能正确地找到 loss 的最小值.
通过一定次数的迭代, 我们就能找到一组 a 和 b 的值, 这组 a,b 能够使得 loss 尽可能小, 甚至为 0, 我们近似认为这个方程就是理想情况下的方程:
y = a * x + b
这时, 如果给出一个值 a1, 就可以根据上式得到一个 y1 值, 这就是我们所说的预测值.
这个例子虽然比较简单, 但是包含了深度学习的精髓思想. 无论多大的网络模型, 数据量, 实际上都是对一组参数不断地进行调整, 使得在这组参数的情况下, 所得到的一个函数关系, 能够让 loss 的值尽可能小(当然, 这种标准可以根据不同需求进行修改), 换句话说, 就是找到一组参数, 使得一个关系式尽可能趋近给定的一组数据中的每个映射关系(数据和标签的映射), 然后再根据这个关系式, 对新给定的值, 给出相应计算结果, 这就是就是预测值.
附, 本文涉及的代码和数据:
- import numpy as np
- '''
- y = a*x+b + noise
- loss = (a*x+b - y)**2
- die a = 2(a*x+b-y)*x
- die b = 2(a*x+b-y)
- '''
- # 计算损失 loss, 神经网络模型训练过程中, 一般会在每一轮都输出一次, 查看训练效果
- def get_loss(a, b, points):
- sum = 0
- for i in points:
- x = i[0]
- y = i[1]
- t = (a * x + b - y) ** 2
- sum = sum + t
- # 因为有多组数据, 这里求平均值, 表示当前 a,b 情况下, 表达式和这组数据的平均偏差
- average_loss = sum / float(len(points))
- return average_loss
- # 求梯度, 调整 a,b 的值, 这是参数能够被 "训练" 的关键部分
- def step_grad(a, b, learn_rate, points):
- da_sum, db_sum = 0, 0
- for i in points:
- x = i[0]
- y = i[1]
- da_sum = da_sum + 2 * (a * x + b - y) * x
- db_sum = db_sum + 2 * (a * x + b - y)
- num = len(points)
- da = da_sum / float(num)
- db = db_sum / float(num)
- # 返回新的 a,b
- return a - learn_rate * da, b - learn_rate * db
- # totalnum 表示总共迭代次数
- def loop(a, b, learn_rate, points, totalnum):
- for i in range(0, totalnum):
- # 每次迭代都会得到一组新的 a,b, 将其作为下一次迭代的初始值
- a, b = step_grad(a, b, learn_rate, points)
- loss = get_loss(a, b, points)
- print("after", totalnum, "times, loss:", loss)
- print("a=", a, "b=", b)
- if __name__ == '__main__':
- points = np.genfromtxt("data.csv", delimiter=",")
- # a,b 初始化为 0,learn_rate 设置为 0.0001, 迭代 10000 次, points 理解为实际情况中, 采集到的数据
- loop(0, 0, 0.0001, points, 10000)
CSV 数据, 网盘链接: https://pan.baidu.com/s/1Sknt8dV7kA81IE2ij6bkYw 提取码: exf2
训练结果:
来源: https://www.cnblogs.com/sctb/p/12664011.html