赞
踩
文章目录
最近有朋友问到我,损失函数与激活函数的问题,由于工作等原因有段时间没接触深度学习没有回答的很好。我最近也是浅浅复习了下深度学习,正好分享下自己对深度学习的理解。
大家可以思考下, y =(x-3)**2+1 ,y的最小值怎么求的。这里常规做法应该是:
1、因为(x-3)**2>=0 所以y>=1 所以最小值1
2、对x求导,令 dy/dx = 2(x-3) 等于0 ,求导x=3 极值点,根据导数判断当x<3,dy/dx <0,递减,x>3,dy/dx>0递增。带入原方程算得极小值为1,简单判断下,这个极小值就是最小值。
3、来看看我们利用梯度下降的思想如何做(导数与梯度是不同的,一个标量一个矢量。为了便于说明,我们后面直接说梯度)
先观察下函数图像。
给个任意初始值x,如 x = -1,我们想要找到x = 3,如何做呢。根据导数dy/dx,我们可以对x迭代。x = x - dy/dx ,由于我们 dy/dx 计算的值比较大,就相当于我们每次迭代 x 一步跨的很长。所以我们设定一个参数 lr (learning rate)也就是我们所说的"学习率"或者"步长"。
x = x-lr*dy/dx
我们写段代码看下。
- import matplotlib.pyplot as plt
- import numpy as np
-
- # 先画下 y = (x-3)**2 + 1 曲线图
- m = np.linspace(-1,7,1000)
- n = m**2 - 6*m + 10
- plt.plot(m,n)
-
- x = -1 # 给个x的初始值
- lr = 0.01 # 学习率
- list_x,list_y= [],[]
-
- for epoch in range(200):
- y_d = 2*x - 6 # y对x的导数 y_d
- list_x.append(x)
- list_y.append(x**2 - 6*x + 10) # 把每次的数据存下,后面可视化
- x = x - y_d*lr
-
- # 每次迭代散点图
- plt.scatter(list_x,list_y,color="red")
- plt.show()
1、可以发现,我们在迭代过程中,逐渐接近我们想要的值。迭代的这个过程x = x-lr*dy/dx 是极其关键。我们可以理解为 往下走楼梯,一步一步逐渐接近于我们的目标。
2、当我们要求极大值时,比如求 - (x-3)**2+1 的极大值,我们只需要上述式子 负号变为正号就可以了 x = x + lr*dy/dx ,这个过程 我们称为 梯度上升。我们平常讲的都是梯度下降,因为我们要的就是求最小值。我们要建立的模型是 y = F(x),要求模型输出的值越接近实际值,也就是误差(损失)最小。后面会举个实例说明。
3、大家可以自行调整上述代码的两个参数 lr 、 迭代次数。
比如 我现在设置 lr = 1.0 ,会发现什么?无论迭代次数是多少,总会在两个点来回震荡。
关于参数这个就不过多说明了,大家可以自己实践下。
梯度这个概念相信大家都知道,不记得的可以百度看下。
举个例子:求 z = x**2 + y**2 + 1 最小值 ,把导数换成各个参数的偏导,其他类似。直接上代码
- import matplotlib.pyplot as plt
- import numpy as np
- from mpl_toolkits.mplot3d import Axes3D
-
-
- # 计算z = x**2+ y**2 + 1 的最小值
- '''
- 可视化3D图
- '''
- fig = plt.figure()
- ax1 = plt.axes(projection="3d")
- x = np.linspace(-1.5,1.5,1000)
- y = np.linspace(-1.5,1.5,1000)
- x,y = np.meshgrid(x,y)
- z = x**2 + y**2 + 1
- ax1.plot_surface(x,y,z,cmap="rainbow")
- plt.show()
-
- x,y = -2,-2 # 随机给个初始值
- lr = 0.02 # 学习率
-
- for i in range(100):
- z_x = 2*x # z对x偏导
- z_y = 2*y # z对y偏导
- x = x-z_x*lr
- y = y-z_y*lr
- print(x,y) # 打印看下发现(x,y)越来越接近(0,0)
还是来个例子演示一遍
特征1数据 : x_data = [1,2,3,4,5]
特征2数据 : y_data = [6,5,4,3,2]
结果:result = [12,9,6,3,0]
现用梯度下降思想来演示一下。
假设 用方程 z = w1*x + w2*y + b 去拟合
- def linear_function(x, y):
- return w1 * x + w2 * y + b
-
-
- """
- 定义一个误差函数,比如绝对值损失,均方损失,交叉熵损失。
- 实际上我们定义的这个my_loss就是均方误差,也就是我们所说的MSE。
- """
- def my_loss(x, y, z):
- loss = 0
- n = len(x) # n代表数据组数
- for xi, yi, zi in zip(x, y, z):
- z_pred = linear_function(xi, yi)
- loss += (z_pred - zi) ** 2 / n # 平方和平均
- return loss
-
-
- # 定义个梯度函数
- def my_gradient(x, y, z):
- n = len(x) # 多少组数
- a, b, c = 0, 0, 0
- for xi, yi, zi in zip(x, y, z):
- z_pred = linear_function(xi, yi)
- """
- 现在目标是求损失值最小,我们定义的损失为(z-(w1*x + w2*y + b))**2/n
- 问题是我们在求解每组数据都会有一个梯度,如何处理呢。简单介绍三种做法。
- 我们这里用的第一种
- 1、对每一组梯度进行一个求和,就是我们所说的批量梯度下降,所有组的梯度累加。
- 特点:全局最优,但是速度慢。
- 2、随机梯度下降,每组数据单独算梯度。每组数据单独计算。
- 特点:每个参数迭代速度快,但是容易陷局部最优
- 3、小批量梯度下降,选取一部分组梯度下降。比如我们这里截取前几组数据。
- """
- a += 2 * xi * (z_pred - zi) / n
- b += 2 * yi * (z_pred - zi) / n
- c += 2 * (z_pred - zi) / n
- return a, b, c
-
-
- if __name__ == "__main__":
- w1, w2, b = 0, 0, 0 # 随机给初始值
- x_data = [1, 2, 3, 4, 5]
- y_data = [6, 5, 4, 3, 2]
- result = [12, 9, 6, 3, 0]
- ls = 0.01 # 学习率
- for epoch in range(500):
- loss = my_loss(x_data, y_data, result) # 记录损失值
- grad = my_gradient(x_data, y_data, result)
- # 批量梯度下降,每次更新每个参数
- w1 -= ls * grad[0]
- w2 -= ls * grad[1]
- b -= ls * grad[2]
- print("epoch={},loss={}".format(epoch, loss))
- print("result", result)
- # 打印看下我们求得的结果值与目标值
- for x, y in zip(x_data, y_data):
- print(w1 * x + w2 * y + b, end=" ")
-
- """
- epoch=496,loss=9.387598846525591e-30
- epoch=497,loss=9.387598846525591e-30
- epoch=498,loss=9.387598846525591e-30
- epoch=499,loss=9.387598846525591e-30
- result [12, 9, 6, 3, 0]
- 11.999999999999995 8.999999999999998 5.999999999999999 3.0000000000000013 3.58046925441613e-15
- """
看的出来,效果挺好的。这里又会有个新的问题。
我们怎么知道它是 z = w1*x + w2*y + b ,或者说我们为什么这样假设呢?如果我假设是多次呢?
这就是交给我们的神经网络了。假设我不是线性的呢,这就跟我们激活函数有关了。这次分享的东西可谓是冰山一角中的一角的。。。突然想到校训"求索"。路漫漫其修远兮,吾将上下而求索。
祝大家假期愉快!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。