简单实现机器学习(一):线性回归(二)

                         QQ:3020889729                                                                                 小蔡

本文可供学习,有什么疑问可以联系。

模型思路

线性模型

在这里插入图片描述
1.ω是权重向量/矩阵
2.x 是所有的输入
利用矩阵乘法,就得到多个输入对应的输出。

损失函数

最小化L的值,得到接近最优的解:
在这里插入图片描述

梯度下降优化公式

梯度计算:
在这里插入图片描述
在这里插入图片描述
应用梯度进行优化:
在这里插入图片描述
在这里插入图片描述

算法结构

  1. 构建参数初始化部分 – 初始化模型开始前的权重w和偏置b。
  2. 构建损失计算部分–计算输入对应的输出以及loss,得到相应梯度。
  3. 整和参数初始化以及loss计算部分构建完成的训练过程。

参数初始化

根据输入参数的个数,初始化等维度大小的权重w——即一个输入有n个参数(特征),那么对应n个权重w;同时加上一个偏置b,得到一个完整的输出。
这就相当于一个输入为n个参数,输出为1个参数的映射关系(全连接层):
在这里插入图片描述
在模型训练中,可以从图中看出来,输出的结果除了与输入参数x有关外,还与w与b密切相关。所以通常在模型训练过程中,参数初始化如果处理得好,那么训练将会事半功倍。

好了,不多说,上一下代码吧:

import numpy as np
# 参数初始化函数
def initialize_params(input_dims, output_dims):
    '''
        input: input_dims -> 每一次输入数据的维度大小--特征个数或者元素个数
               output_dims -> 每一次输出数据对应的维度大小 -- 即输出个数
        eg:
            X = (x1, x2, x3)  -> input_dims = 3
            Y = (y1, y2)  -> output_dims = 2
            
        return: 权重(w) -> 维度形状:(input_dims, output_dims)  == 方便矢量运算(矩阵相关运算)
                偏置(b) -> 维度形状: (output_dims, 1)  == 维度与输出个数相关
    '''
    
    init_w = np.ones((input_dims, output_dims))   # 全一初始化
    init_b = np.ones((output_dims, 1))
    
    return init_w, init_b  # 返回初始化好的参数

测试结果:
在这里插入图片描述

这部分的重点在于,理解矩阵乘法和运用numpy库下的dot矩阵乘法方法计算输出。
例子对应的乘法公式对应如下:
在这里插入图片描述

损失函数

计算输入得到的输出与真实值的损失值(误差值),并计算相应的梯度值,为梯度更新优化提供可能。
这部分对线性函数以及矩阵有些了解,理解起来应该不会很难,所以就直接给代码咯:

def linear_loss(x, y, w, b):
    '''
        input: x -> 输入:(N, feature_num)
               y -> 真实值:(N, label_num)   # 每一个输入x对应的真实值个数:label_num
               w -> 当前的权重: (feature_num, label_num)  # label_num 对应模型最终一次输出多少个参数
               b -> 当前的偏置: (label_num, 1)  # n个输出就n个偏置
        
        return y_pred, loss, dw, db
    '''
    if isinstance(x, np.ndarray) is False:  # 自动判断并转换数据类型
        x = np.asarray(x)
        assert len(x.shape) == 2, 'Error: input_x\'s shape is false(len(x.shape!=2)), please input the length of x\'s shape == 2 !'
    if isinstance(y, np.ndarray) is False:
        y = np.asarray(y)
        assert len(y.shape) == 2, 'Error: input_y\'s shape is false(len(y.shape!=2)), please input the length of y\'s shape == 2 !'

    batch_num = x.shape[0]   # 获取一次传入的数据个数(非特征数)
    feature_num = x.shape[1]  # 获取每个输入的数据所包含的特征数
    
    # 根据之前的公式: f = x*w + b 计算当前w和b下的输出
    y_pred = np.dot(x, w) + b
    
    # 计算损失
    loss = np.sum(np.sqrt((y_pred - y)**2)) / batch_num
    
    # 参数求梯度
    # x.shape: (N, feature_num)
    # (y_pred - y).shape: (N, label_num)
    dw = np.dot(x.T, (y_pred - y)) / batch_num   # w的梯度
    
    # sum((y_pred - y)).shape: (1, label_num)
    db = np.sum((y_pred - y)) / batch_num        # b的梯度
    
    return y_pred, loss, dw, db

测试结果:
在这里插入图片描述

完整的模型训练

这部分简单来说,就是整合初始化和计算损失,再做简单调整即可:

# 训练函数
def linear_train(x, y, learning_rate, epoches):
    '''
    
    '''
    if isinstance(x, np.ndarray) is False:  # 自动判断并转换数据类型
        x = np.asarray(x)
        assert len(x.shape) == 2, 'Error: input_x\'s shape is false(len(x.shape!=2)), please input the length of x\'s shape == 2 !'
    if isinstance(y, np.ndarray) is False:
        y = np.asarray(y)
        assert len(y.shape) == 2, 'Error: input_y\'s shape is false(len(y.shape!=2)), please input the length of y\'s shape == 2 !'
    
    w, b = initialize_params(x.shape[1], y.shape[1])  # 创建相应的初始化参数
    
    loss_list = []  # 损失参数记录
    
    for i in range(epoches):  # 训练epoches轮次
        y_pred, loss, dw, db = linear_loss(x, y, w, b)
        
        loss_list.append(loss)   # 保存当前损失
        
        w += -learning_rate*dw  # 根据输入的学习率进行参数调整
        b += -learning_rate*db
        
        if (i+1) % 10000 == 0:  # 一万次打印一次训练信息
            print('Epoches: {0}, Loss: {1}'.format(i+1, loss))
        
        params = {
            'w': w,
            'b': b
        }  # 及时保存训练的参数
        
        grads = {
            'dw':dw,
            'db':db
        }  # 及时保存梯度参数
        
    # 训练结束,返回训练损失记录、当前最后轮次的损失,模型参数以及最后一次训练得到的梯度
    return loss_list, loss, params, grads

测试结果:
在这里插入图片描述

使用训练好的参数进行预测(输出)

这部分就是利用已经训练好的参数进行预测输出(套用计算损失部分的函数结构即可):
在这里插入图片描述
代码如下:

def linear_pre(x, y, w, b):
    assert x.shape[0] == y.shape[0], 'Error: x.batch_size is not eval(!=) x.batch_size!'
    assert w.shape[0] == x.shape[1], 'Error: w is not fit of x!'   # 特征数要匹配权重的行数
    assert w.shape[1] == y.shape[1], 'Error: w is not fit of y!'   # 每一个输入的真实值个数要匹配权重的列数(模型输出个数)
    assert b.shape[0] == y.shape[1], 'Error: b is not fit of y!'   # 偏置数匹配每一个输入的真实值个数
    
    
    # 根据之前的公式: f = x*w + b 计算当前w和b下的输出
    y_pred = np.dot(x, w) + b
    
    return y_pred

测试结果:
在这里插入图片描述

将设计好的模型进行封装(待续)

目的是得到一个可重复使用的线性拟合类,用于拟合一般的线性数据(在功能上不抵已有框架那么方便使用,这里主要是为了阐述线性模型的实现,去熟悉矩阵运算和一般训练步骤和需要的部件损失函数,模型函数、优化方法(梯度下降)

由于笔者文笔有限,如有表达不清楚,请评论或者联系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NULL not error

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值