python 线性回归
答应老师做的一个系列教程,也是头一次花这吗大精力去写一篇基础的文档,里面虽然有不少的公式,但只要能顺着看下来会发现都是非常基础的公式都是特别简单的。
文章目录
- python 线性回归
-
-
- 计算回归任务的损失
- 梯度下降的原理
- 模型参数的更新过程
- python基础库实现
-
学习目标:
- 了解深度学学习的结构基本过程和原理
模型(函数):
数据集:
NO. | x | y |
---|---|---|
0 | 1 | 3 |
1 | 2 | 5 |
2 | 3 | 7 |
3 | 4 | 9 |
一个训练样本: 一组 例:第0组训练样本
x为输入数据,y为预测标签/目标值/希望被拟合的值
任务:寻找合适的和使得可以拟合上表中的数据
- 怎么具体描述拟合?
- 就是让所有训练样本中每个训练的样本的值经过模型(函数)之后的输出更接近其对应的看距离的变化,距离小证明拟合的效果越好,距离越大证明拟合的越差,在这个任务里我们选择用两个数据差的平方和也就是欧式距离来作为衡量指标,也被我们称为损失,那计算距离的函数也就被称作损失函数.
计算回归任务的损失
在,已知的情况下,模型(函数)可表示为
定义一个训练样本损失的计算函数
如果输入的数据为,其对应的目标值为则经过模型之后的损失可表示为:
我们选择用数据集中的前三组数据来作为训练数据,为了让模型能更好的拟合所有的数据,所以希望的是所有训练样本损失变小,我们的总体损失函数可表示为
即:
在输入数据和模型参数已知的情况下,模型的总体损失是一个固定值
接下来转换思路,现在训练样本已知,我们的目的是求使总体损失最小,则我们将作为自变量,构建一个随着变化的而变化的损失函数,然后去搜索使这个函数值最小的的值.
在已知的情况下,模型(函数)表示为
则重新定义一个训练样本的损失计算函数
则总体损失函数为:
将损失函数展开为:
将替换
将替换
梯度下降的原理
到这该思考怎么去搜索一组,为了理解的透彻我们举几个例子
先从一个最简单的问题上思考,已知一个有最小值点的函数,和一个初始值,则朝着哪个方向移动会使函数值更接近最小值点.
挑一个最简单的函数
设置初始点为
为了走向最小值点,我们的策略就是一直将往使函数值变小的方向一点点移动,那往哪个方向移动会使用使函数值见小呢根据简单的数学知识我们知道**如果朝着梯度(导数)的方向移动则函数值会增大,所以让朝着负梯度方向移动则函数值就会变小.因此先求在处的梯度(导数)
因为在点处的导数大于0梯度方向朝着x轴的正轴方向,所以如果向着正半轴移动则函数值会增大,向负半轴移动函数值会减小,移动多少就由负梯度乘以一个步长来决定,通过让步长乘以负梯度的方式可以调节变量实际移动距离让点在接近最小值点也就是导数为0的点时移动的距离变小,在导数大的地方移动加快,提高收敛速度,假设步长为则在点开始向右侧移动,我们将这次移动之后的位置记为,则 如我们所愿函数值减小了,同理求,朝着的反向再继续更新的值,最终的值会落在最小值的附近,通过这种方式我们最后搜索到了得到了一个让贴近或者等于最小值的值.
那如果有两个自变量呢假设我们要求最小值的函数为,初始点坐标
则在函数的初始值点的函数值,要想使三维空间中的点不断的逼近最小值那就是找,输入的二维坐标点的负梯度方向,对于多维函数,求梯度方向就是求每一个自变量的偏导数.
则用对求偏导
则在 点处的偏导数值为
因此如果分别朝着导数方向则函数值会增大,为了让函数值减小则同理同时向这负梯度方向则可以减小,同样设置步长为,则 通过这种方式不断的更新自变量的值,最终就可以搜索到一组的值使用函数值最小.
到这里其实可以明确一个概念深度学习的本质就是求函数的最小值
模型参数的更新过程
好回到之前回归任务求是自变量,沿着负梯度方向不断更新使下面这个函数值最小
接下来求函数对的导数,先将损失函数转换成未完全展开的模式.
先观察其中一个中的分量
然后我们观察这个定义这个分量的原函数
要求对的导数则需要求对的导数,然后求对的导数,通过链式求导法则最终得到
对的导数
根据
先求
然后根据
求得
所以可以算出
同理我们去求对的导数
对的导数不变,只需要再去求一下对的导数
则最终求出来的对的导数为
最终我们得到了学习参数过程中最重要的梯度计算公式
根据总体损失的公式
我们也就能算出对的梯度
有了更新公式之后,我们只需要设置一个初始的就可以根据梯度公式不断的更新我们设置步长
则可以写出的更新公式
接下来我们模拟一步更新过程
根据一开始的表个我们的训练数据分别为
假设初始值
根据下面的这个式子去算一下损失
将带入
接下来计算损失函数对的梯度
接下来使用更新公式对进行更新
接下来我们将新的参数带入进损失函数
可喜可贺损失变小了,接下来就是重复上面的步骤设置学习次数,学习到损失几乎不再下降为止.
接下来用python的基础库模拟出这个过程
python基础库实现
先初始化需要用到的变量
# 训练数据
train_data = [1,2,3]
# 训练标签
train_label = [3,5,7]
# 测试数据
test_data = [4]
# 测试标签
test_label = [9]
# 初始化权重
w = 1
b = 0
# 迭代次数/训练次数
iter = 10000
# 设置步长
lamb = 0.01
然后定义模型
# 回归模型
def f(x):
return w*x + b
定义用到的损失函数
# 计算一个样本的损失函数
def L(data,label):
return (data-label)**2
# 总体损失函数
def Loss(x,y):
loss = 0
k = len(x)
for i in range(k):
loss += L(f(x[i]),y[i])
return loss
定义计算梯度函数
# 计算梯度
def gradient(w,b,x,y):
dw,db = 0,0
k = len(x)
for i in range(k):
dw += 2*(w*x[i]+b-y[i])*x[i]
db += 2*(w*x[i]+b-y[i])
return dw,db
训练部分
# 训练
for i in range(iter):
dw,db = gradient(w,b,train_data, train_label)
w = w - lamb*dw
b = b - lamb*db
最后加上绘图代码最终的完整代码如下
import matplotlib.pyplot as plt
import numpy as np
# 训练数据
train_data = [1,2,3]
# 训练标签
train_label = [3,5,7]
# 测试数据
test_data = [4]
# 测试标签
test_label = [9]
# 初始化权重
w = 1
b = 0
# 迭代次数/训练次数
iter = 1000
# 设置步长
lamb = 0.01
# 回归模型
def f(x):
return w*x + b
# f = lambda x: w*x + b
# 计算一个样本的损失函数
def L(data,label):
return (data-label)**2
# 总体损失函数
def Loss(x,y):
loss = 0
k = len(x)
for i in range(k):
loss += L(f(x[i]),y[i])
return loss
# 计算梯度
def gradient(w,b,x,y):
dw,db = 0,0
k = len(x)
for i in range(k):
dw += 2*(w*x[i]+b-y[i])*x[i]
db += 2*(w*x[i]+b-y[i])
return dw,db
# 训练
for i in range(iter):
dw,db = gradient(w,b,train_data, train_label)
w = w - lamb*dw
b = b - lamb*db
# 打开网格
plt.grid()
# 绘制训练集点
plt.scatter(train_data,train_label,c='blue')
# 回执测试集点
plt.scatter(test_data,test_label,c='red')
#设置绘图范围
plt.xlim([0,5])
plt.ylim([0,10])
#绘制拟合直线
x = np.linspace(0,5,1000)
y = f(x)
plt.scatter(x,y,c='black',s=1)
plt.show()
#打印学习之后的w,b值
print('w=',w)
print('b=',b)
最终拟合的直线结果如下
w= 2.000148389025502
b= 0.9996626768662412
稍微变动一下数据让数据不都在一条线上,看一下最终的拟合结果会是什么样的
# 训练数据
train_data = [1,1.5,3]
# 训练标签
train_label = [3,5,7]
# 测试数据
test_data = [4]
# 测试标签
test_label = [9]
w= 1.846223184751381
b= 1.6152357121183563
版权声明:本文为博主作者:浩浩的科研笔记原创文章,版权归属原作者,如果侵权,请联系我们删除!
原文链接:https://blog.csdn.net/chrnhao/article/details/129078852