Linear Regression in mojo with NDBuffer

The linear regression is the simplest machine learning algorithm. In this article I will use mojo NDBuffer to implement a simple linear regression algorithm from scratch. I will use NDArray class which was developed by in the previous article. First import the necessary libs and NDArray definition:

# common import
from String import String
from Bool import Bool
from List import VariadicList
from Buffer import NDBuffer
from List import DimList
from DType import DType
from Pointer import DTypePointer
from TargetInfo import dtype_sizeof, dtype_simd_width
from Index import StaticIntTuple
from Random import rand

alias nelts = dtype_simd_width[DType.f32]()

struct NDArray[rank:Int, dims:DimList, dtype:DType]:
    var ndb:NDBuffer[rank, dims, dtype]
    
    fn __init__(inout self, size:Int):
        let data = DTypePointer[dtype].alloc(size)
        self.ndb = NDBuffer[rank, dims, dtype](data)
        
    fn __getitem__(self, idxs:StaticIntTuple[rank]) -> SIMD[dtype,1]:
        return self.ndb.simd_load[1](idxs)
    
    fn __setitem__(self, idxs:StaticIntTuple[rank], val:SIMD[dtype,1]):
        self.ndb.simd_store[1](idxs, val)

Let’s assume we want to figure out this function:
y=W⋅X y = W \cdot X y=WX
Where:

  • W is the parameter
  • X is the sample design matrix. Each row is a sample. Each sample is a n dimension vector x∈Rn\boldsymbol{x} \in R^{n}xRn. If we have m samples then X∈Rm×nX \in R^{m \times n}XRm×n
    Here we will deal with a very simple toy problem. We assume n=3n=3n=3 and m=5m=5m=5. Let’s define the ith sample:
    x(i)=[x1(i)x2(i)x3(i)]∈R3×1,i∈{1,2,3,4,5} \boldsymbol{x}^{(i)} = \begin{bmatrix} x^{(i)}_1 \\ x^{(i)}_2 \\ x^{(i)}_3 \end{bmatrix} \in R^{3 \times 1}, i \in \{ 1, 2, 3, 4, 5\} x(i)=x1(i)x2(i)x3(i)R3×1,i{1,2,3,4,5}
    Notes:
  • i is the index of the sample;
  • 1, 2, 3 is the subscript of the feature dimension;
  • m is the total number of samples. In this case m=5;
  • n is the dimension of the feature vector. in this case n=3;

Let’s generate the dataset:

alias X_rank = 2
alias r1 = 5
alias r2 = 3
var X_size = r1 * r2
var X = NDArray[X_rank, DimList(r1, r2), DType.f32](X_size)
# geneate random number and set to X
var rvs = DTypePointer[DType.f32].alloc(X_size)
rand[DType.f32](rvs, X_size)
for d1 in range(r1):
    for d2 in range(r2):
        X[StaticIntTuple[X_rank](d1, d2)] = rvs.load(d1*r2+d2)*5.0 + 1.0

Let’s define the parameter w\boldsymbol{w}w:
w=[1.11.21.3] \boldsymbol{w} = \begin{bmatrix} 1.1 \\ 1.2 \\ 1.3 \end{bmatrix} w=1.11.21.3

Let define the ground truth hypothesis function:
y=wT⋅x+b=[1.12.23.3]⋅[x1x2x3]+b=1.1⋅x1+2.2⋅x2+3.3⋅x3+1.8 y = \boldsymbol{w}^{T} \cdot \boldsymbol{x} + b =\begin{bmatrix} 1.1 \\ 2.2 \\ 3.3 \end{bmatrix} \cdot \begin{bmatrix} x_{1} \\ x_{2} \\ x_{3} \end{bmatrix} + b = 1.1 \cdot x_{1} + 2.2 \cdot x_{2} + 3.3 \cdot x_{3} + 1.8 y=wTx+b=1.12.23.3x1x2x3+b=1.1x1+2.2x2+3.3x3+1.8

Let’s define the paramter w\boldsymbol{w}w:

alias w_rank = 2
alias w_r1 = 3
alias w_r2 = 1
var w = NDArray[w_rank, DimList(w_r1, w_r2), DType.f32](w_r1 * w_r2)
w[StaticIntTuple[w_rank](0,0)] = 0.01
w[StaticIntTuple[w_rank](1,0)] = 0.02
w[StaticIntTuple[w_rank](2,0)] = 0.03
var b = SIMD[DType.f32, 1](0.0)

Now we can get the ground truch label 𝑦:

alias y_rank = 1
alias y_r1 = 5
var y = NDArray[y_rank, DimList(y_r1), DType.f32](y_r1)
for d1 in range(y_r1):
    y[StaticIntTuple[y_rank](d1)] = 1.1 * X[StaticIntTuple[X_rank](d1,0)] + 
                2.2 * X[StaticIntTuple[X_rank](d1,1)] + 
                3.3 * X[StaticIntTuple[X_rank](d1,2)] + 1.8

Let define the function get_batch to get a mini batch from the training dataset:

alias batch_size = 2
alias batch_rank = 2
# idx can only be 0,1 We will ignore the last element in X.
fn get_batch(inout batch_X:NDArray[batch_rank, DimList(batch_size, r2), DType.f32],
             inout batch_y:NDArray[y_rank, DimList(batch_size), DType.f32],
             X:NDArray[X_rank, DimList(r1, r2), DType.f32], 
             y:NDArray[y_rank, DimList(y_r1), DType.f32],
             batch_idx:Int):
    for b_idx in range(batch_size):
        batch_y[StaticIntTuple[y_rank](b_idx)] = y[StaticIntTuple[y_rank]
        		(batch_size*batch_idx+b_idx)]
        for c_idx in range(r2):
            batch_X[StaticIntTuple[batch_rank](b_idx, c_idx)] = 
            		X[StaticIntTuple[X_rank](batch_size*batch_idx+b_idx,c_idx)]

Let’s discuss the math theory of linear regress. For ith sample we will omit the (i) subscript for simplicity. The calculated label y^\hat{y}y^:
y^=w1⋅x1+w2⋅x2+w3⋅x3+b \hat{y} = w_{1} \cdot x_{1} + w_{2} \cdot x_{2} + w_{3} \cdot x_{3} + b y^=w1x1+w2x2+w3x3+b
As we have the ground truth label y we define the loss function as:
l=12(y^−y)2=12(w1⋅x1+w2⋅x2+w3⋅x3+b−y)2 \mathcal{l} = \frac{1}{2}(\hat{y}-y)^{2} = \frac{1}{2}(w_{1} \cdot x_{1} + w_{2} \cdot x_{2} + w_{3} \cdot x_{3} + b - y)^{2} l=21(y^y)2=21(w1x1+w2x2+w3x3+by)2
According to linear regression algorithm we will set random value to parameter w\boldsymbol{w}w and zero to bbb. We will calculate y by using these parameters setting. Then we calculate the loss which represent how good our parameters are. Our task is to find the best parameters setting to let the loss minmum:
arg⁡min⁡w,bl \arg\min_{\boldsymbol{w},b} \mathcal{l} argw,bminl

To get the minmum parameter we will get each individual parameter’s gradient of loss and adjust the parameter against the gradient direction. This is the gradient descent algorithm. So let get parameter w1w_{1}w1 gradient of loss:
∂l∂w1=∂(12(w1⋅x1+w2⋅x2+w3⋅x3+b−y)2)∂w1=∂(12(w1⋅x1+w2⋅x2+w3⋅x3+b−y)2)∂((w1⋅x1+w2⋅x2+w3⋅x3+b−y))⋅∂(w1⋅x1+w2⋅x2+w3⋅x3+b−y)∂w1=(w1⋅x1+w2⋅x2+w3⋅x3+b−y)⋅x1 \frac{\partial{\mathcal{l}}}{\partial{w_{1}}} = \frac{\partial{ \big( \frac{1}{2}(w_{1} \cdot x_{1} + w_{2} \cdot x_{2} + w_{3} \cdot x_{3} + b - y)^{2} \big) }}{\partial{w_{1}}} \\ = \frac{\partial{ \big( \frac{1}{2}(w_{1} \cdot x_{1} + w_{2} \cdot x_{2} + w_{3} \cdot x_{3} + b - y)^{2} \big) }}{\partial{ \big( (w_{1} \cdot x_{1} + w_{2} \cdot x_{2} + w_{3} \cdot x_{3} + b - y) \big) }} \cdot \frac{\partial{ (w_{1} \cdot x_{1} + w_{2} \cdot x_{2} + w_{3} \cdot x_{3} + b - y) }} { \partial{w_{1}} } \\ = (w_{1} \cdot x_{1} + w_{2} \cdot x_{2} + w_{3} \cdot x_{3} + b - y) \cdot x_{1} w1l=w1(21(w1x1+w2x2+w3x3+by)2)=((w1x1+w2x2+w3x3+by))(21(w1x1+w2x2+w3x3+by)2)w1(w1x1+w2x2+w3x3+by)=(w1x1+w2x2+w3x3+by)x1
We use the chain rule of gradient in the above formula. We can get all parameters gradient of loss in the same way:
∂l∂w1=(w1⋅x1+w2⋅x2+w3⋅x3+b−y)⋅x1∂l∂w2=(w1⋅x1+w2⋅x2+w3⋅x3+b−y)⋅x2∂l∂w3=(w1⋅x1+w2⋅x2+w3⋅x3+b−y)⋅x3∂l∂b=(w1⋅x1+w2⋅x2+w3⋅x3+b−y) \frac{\partial{\mathcal{l}}}{\partial{w_{1}}} = (w_{1} \cdot x_{1} + w_{2} \cdot x_{2} + w_{3} \cdot x_{3} + b - y) \cdot x_{1} \\ \frac{\partial{\mathcal{l}}}{\partial{w_{2}}} = (w_{1} \cdot x_{1} + w_{2} \cdot x_{2} + w_{3} \cdot x_{3} + b - y) \cdot x_{2} \\ \frac{\partial{\mathcal{l}}}{\partial{w_{3}}} = (w_{1} \cdot x_{1} + w_{2} \cdot x_{2} + w_{3} \cdot x_{3} + b - y) \cdot x_{3} \\ \frac{\partial{\mathcal{l}}}{\partial{b}} = (w_{1} \cdot x_{1} + w_{2} \cdot x_{2} + w_{3} \cdot x_{3} + b - y) w1l=(w1x1+w2x2+w3x3+by)x1w2l=(w1x1+w2x2+w3x3+by)x2w3l=(w1x1+w2x2+w3x3+by)x3bl=(w1x1+w2x2+w3x3+by)

Assume the learning rate is α\alphaα then we can update the parameters:
w1:=w1−α⋅l∂w1w2:=w2−α⋅l∂w2w3:=w3−α⋅l∂w3b:=b−α⋅l∂b w_{1} := w_{1} - \alpha \cdot \frac{\mathcal{l}}{\partial{w_{1}}} \\ w_{2} := w_{2} - \alpha \cdot \frac{\mathcal{l}}{\partial{w_{2}}} \\ w_{3} := w_{3} - \alpha \cdot \frac{\mathcal{l}}{\partial{w_{3}}} \\ b := b - \alpha \cdot \frac{\mathcal{l}}{\partial{b}} w1:=w1αw1lw2:=w2αw2lw3:=w3αw3lb:=bαbl

let epochs = 1000
var y_hat = NDArray[y_rank, DimList(batch_size), DType.f32](batch_size)
alias loss_rank = 1
var loss = NDArray[loss_rank, DimList(batch_size), DType.f32](batch_size)
var coff = 0.5
var Xi = NDArray[batch_rank, DimList(batch_size, r2), DType.f32](batch_size*r2)
var yi = NDArray[y_rank, DimList(batch_size), DType.f32](batch_size)
var lr = 0.001
for epoch in range(epochs):
    for bidx in range(batch_size):
        get_batch(Xi, yi, X, y, bidx)
        # forward pass
        y_hat[StaticIntTuple[y_rank](0)] = 
        			w[StaticIntTuple[w_rank](0,0)]*Xi[StaticIntTuple[X_rank](0,0)] + 
                    w[StaticIntTuple[w_rank](1,0)]*Xi[StaticIntTuple[X_rank](0,1)] + 
                    w[StaticIntTuple[w_rank](2,0)]*Xi[StaticIntTuple[X_rank](0,2)] +
                    b
        y_hat[StaticIntTuple[y_rank](1)] = 
        			w[StaticIntTuple[w_rank](0,0)]*Xi[StaticIntTuple[X_rank](1,0)] + 
                    w[StaticIntTuple[w_rank](1,0)]*Xi[StaticIntTuple[X_rank](1,1)] + 
                    w[StaticIntTuple[w_rank](2,0)]*Xi[StaticIntTuple[X_rank](1,2)] +
                    b
        # calculate the loss
        loss[StaticIntTuple[loss_rank](0)] = coff *(
                (y[StaticIntTuple[y_rank](0)]-y_hat[StaticIntTuple[y_rank](0)])*
                (y[StaticIntTuple[y_rank](0)]-y_hat[StaticIntTuple[y_rank](0)])
        )
        loss[StaticIntTuple[loss_rank](1)] = coff *(
                (y[StaticIntTuple[y_rank](1)]-y_hat[StaticIntTuple[y_rank](1)])*
                (y[StaticIntTuple[y_rank](1)]-
                y_hat[StaticIntTuple[y_rank](1)])
        )
        g_w1 = (y_hat[StaticIntTuple[y_rank](0)]-
        		y[StaticIntTuple[y_rank](0)])*Xi[StaticIntTuple[X_rank](0,0)] + 
                (y_hat[StaticIntTuple[y_rank](1)]-
                y[StaticIntTuple[y_rank](1)])*Xi[StaticIntTuple[X_rank](1,0)]
        w[StaticIntTuple[w_rank](0,0)] -= lr*g_w1
        g_w2 = (y_hat[StaticIntTuple[y_rank](0)]-
        		y[StaticIntTuple[y_rank](0)])*Xi[StaticIntTuple[X_rank](0,1)] + 
                (y_hat[StaticIntTuple[y_rank](1)]-
                y[StaticIntTuple[y_rank](1)])*Xi[StaticIntTuple[X_rank](1,1)]
        w[StaticIntTuple[w_rank](1,0)] -= lr*g_w2
        g_w3 = (y_hat[StaticIntTuple[y_rank](0)]-
        y[StaticIntTuple[y_rank](0)])*Xi[StaticIntTuple[X_rank](0,2)] + 
                (y_hat[StaticIntTuple[y_rank](1)]-
                y[StaticIntTuple[y_rank](1)])*Xi[StaticIntTuple[X_rank](1,2)]
        w[StaticIntTuple[w_rank](2,0)] -= lr*g_w3
        g_b = (y_hat[StaticIntTuple[y_rank](0)]-y[StaticIntTuple[y_rank](0)]) + 
                (y_hat[StaticIntTuple[y_rank](1)]-y[StaticIntTuple[y_rank](1)])
        b -= lr*g_b
        loss_val = loss[StaticIntTuple[loss_rank](0)] + 
        		loss[StaticIntTuple[loss_rank](0)]
        print('epoch_', epoch, ': idx=', bidx, ' loss=', loss_val, 
        		'; w1=', w[StaticIntTuple[w_rank](0,0)], 
              ', w2=', w[StaticIntTuple[w_rank](1,0)], 
              ', w3=', w[StaticIntTuple[w_rank](2,0)], ', b=', b, ';')
内容概要:本文围绕“基于多面体聚合与闵可夫斯基和的电动汽车可调能力评估研究”展开,系统提出一种基于多面体建模与几何运算的聚合方法,用于量化大规模电动汽车集群的可调节能力。通过构建单车充电可行域的凸多面体表示,并利用闵可夫斯基和实现群体调控潜力的数学聚合,形成统一的等效灵活资源集合,从而精确刻画电动汽车集群在时间与功率维度上的整体调节边界。该方法结合Matlab代码实现,支持对聚合结果的可视化呈现与边界分析,为电力系统中的需求响应、虚拟电厂运营及分布式能源调度提供了高精度建模工具。研究强调科研应兼顾严谨逻辑与创新思维,倡导借助YALMIP等优化工具提升建模效率与求解可靠性。; 适合人群:具备电力系统分析、凸优化理论或运筹学背景,从事新能源并网、电动汽车调度、综合能源系统等方向的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握多面体建模与闵可夫斯基和在电力系统灵活性聚合中的数学原理与实现方法;②学习利用Matlab完成电动汽车集群可调能力的建模、聚合与可视化分析;③应用于虚拟电厂资源聚合、需求响应潜力评估、配电网柔性负荷调控等实际场景的建模与优化决策。; 阅读建议:建议读者结合文中Matlab代码逐模块复现算法流程,重点理解多面体定义、约束处理及闵可夫斯基和的近似计算实现,同时参考提供的YALMIP工具包资源,深入掌握优化建模技巧,以全面提升对复杂系统聚合建模的能力。
内容概要:本文系统研究了基于Wasserstein生成对抗网络(W-GAN)的光伏出力场景生成方法,旨在应对新能源出力的高度不确定性。相较于传统GAN,W-GAN通过引入Wasserstein距离与梯度惩罚机制,显著提升了模型训练的稳定性与生成数据的质量,能够更精确地捕捉光伏功率时序数据的波动性与时序相关性。研究详细阐述了模型架构设计、损失函数构建、梯度惩罚项(GP)的实现细节,并通过Python代码实现了完整的数据预处理、模型训练、场景生成与后评估流程。生成的高保真光伏场景在统计特性(如分布形态、波动幅度、日内趋势)上与真实数据高度吻合,有效满足了电力系统对不确定性建模的严苛要求。; 适合人群:具备Python编程能力和深度学习基础知识,从事新能源发电预测、电力系统规划、运行调度、储能配置及风险管理等领域的研究生、科研人员和工程技术人员。; 使用场景及目标:①为含高比例光伏的电力系统进行可靠性评估、优化调度与安全校核提供高质量、多样化的输入场景;②支撑储能系统容量配置、需求响应策略制定等决策,以应对光伏出力的波动性;③作为深度学习在能源领域应用的典型案例,服务于相关课题的教学、科研与项目开发。; 阅读建议:建议读者深入研读并运行所提供的Python代码,重点关注W-GAN中判别器(Critic)的构造、梯度惩罚项的编码实现以及训练过程中的超参数(如学习率、惩罚系数)调优策略,可通过对比生成场景与真实场景的可视化结果来评估模型性能,并尝试将其扩展至条件W-GAN(CW-GAN)以生成特定气象条件下的光伏场景。
内容概要:本文围绕基于生成对抗网络(GAN)与Wasserstein GAN(W-GAN)的光伏场景生成展开研究,重点介绍如何利用Python代码实现W-GAN模型,以生成高质量、高稳定性的光伏发电出力场景数据。相较于传统GAN,W-GAN通过引入Wasserstein距离和梯度惩罚机制,有效缓解了训练过程中的模式崩溃与梯度消失问题,显著提升了生成数据的真实性和多样性。该方法在新能源出力不确定性建模、电力系统仿真分析等领域具有重要应用价值。文中提供了完整的实现流程,涵盖数据预处理、网络结构设计、损失函数构建、模型训练优化及生成结果可视化等关键环节。; 适合人群:具备一定Python编程能力和深度学习基础,从事新能源发电预测、电力系统规划、智能电网仿真或人工智能算法应用等相关方向的研究人员及高校研究生。; 使用场景及目标:①用于构建高精度的光伏出力不确定性场景集,支撑电力系统调度决策、储能配置与风险评估;②为高比例可再生能源接入下的电力系统提供可靠、多样化的输入场景,提升仿真与优化模型的鲁棒性;③帮助研究者深入理解W-GAN的理论机制与工程实现,推动其在能源系统建模中的创新应用。; 阅读建议:建议读者结合提供的代码进行动手实践,重点关注判别器与生成器的网络架构设计、Wasserstein损失函数的实现方式以及梯度惩罚项的添加技巧,同时可在不同气候区域或时间尺度的光伏数据集上进行迁移实验,进一步验证模型泛化能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值