手撸线性回归
涉及到的数学知识包括:
①线性回归模型结构;②最优化算法-梯度下降法(方向导数、梯度)
我这里没有封装线性回归,只是把核心组件写了。手撸机器学习模型事实上可以包括几个组分:
①参数初始化部分(得确定模型的形式,有哪些参数);
②计算模型的损失(数学上确定损失函数);
③确定根据损失迭代更新参数的方式(训练部分,核心是确定学习算法);
基本上就是这几步了。只要明白模型的数学或逻辑结构、明确损失函数、确定学习算法,一个机器学习模型就掌握了。手撸的过程是强化对整个模型的认知。最后使用的时候调用sklearn就好。sklearn是个好东西,既有算法又有数据的。
#-*-coding:utf-8-*-
#Circle手撸线性回归
#numpy用于手撸模型,load_diabetes用于导入sklearn自带的糖尿病数据集,shuffle是数据打乱函数
import numpy as np
from sklearn.datasets import load_diabetes
from sklearn.utils import shuffle
#定义线性回归参数初始化函数
def initialize_params(dims):
"""
:rtype: object
w:初始化权重参数值
b:初始化偏差参数值
:param dims: 输入特征维度
"""
#把所有参数都初始化为0
w=np.zeros((dims,1))
b=0
return w,b
#定义线性回归模型的损失计算函数
def linear_loss(X,y,w,b):
"""
:param X: 数据的特征矩阵(数据)
:param y: 数据的值向量(数据)
:param w: 模型权重向量(参数)
:param b: 模型偏差值(参数)
"""
num_train=X.shape[0]
num_feature=X.shape[1]
#计算预测y值
y_hat=np.dot(X,w)+b
#采用均方误差(MSE)计算损失
loss=np.sum((y_hat-y)**2)/num_train
#针对损失函数,求参数w,b的偏导
dw=np.dot(X.T,(y_hat-y))*2/num_train
db=(y_hat-y)*2/num_train
return y_hat,loss,dw,db
# 定义线性回归模型的训练函数
def linear_train(X,y,learning_rate,epochs):
"""
:param X: 数据的特征矩阵(数据)
:param y: 数据的值向量(数据)
:param learning_rate: 梯度下降寻优算法的学习率,实际上就是每次迭代参数变化的步长
:param epochs: 训练(迭代)次数
:return params: 当前参数更新结果
:return grads: 当前梯度计算结果
"""
#初始化模型参数
w,b=initialize_params(X.shape[1])
loss_list=[]
#迭代训练
for i in range(1,epochs):
y_hat,loss,dw,db=linear_loss(X,y,w,b)
loss_list.append(loss)
#基于梯度下降的参数更新过程
w-=learning_rate*dw
b-=learning_rate*db
#对迭代过程进行输出
if not i%1000:
print('epoch %d loss %f'%(i,loss))
#保存模型参数与梯度
params={'w':w,'b':b}
grads={'dw':dw,'db':db}
return loss_list,loss,params,grads
if __name__ == '__main__':
diabetes=load_diabetes()
data=diabetes.data
target=diabetes.target
X,y=shuffle(data,target,random_state=13)
#暂时性搁置,由于项目原因,本周的集中尽力搞项目。