【单层神经网络】基于MXNet的线性回归实现(底层实现)

写在前面

  1. 基于亚马逊的MXNet库
  2. 本专栏是对李沐博士的《动手学深度学习》的笔记,仅用于分享个人学习思考
  3. 以下是本专栏所需的环境(放进一个environment.yml,然后用conda虚拟环境统一配置即可)
  4. 刚开始先从普通的寻优算法开始,熟悉一下学习训练过程
  5. 下面将使用梯度下降法寻优,但这大概只能是局部最优,它并不是一个十分优秀的寻优算法
yml 复制代码
name: gluon
dependencies:
- python=3.6
- pip:
  - mxnet==1.5.0
  - d2lzh==1.0.0
  - jupyter==1.0.0
  - matplotlib==2.2.2
  - pandas==0.23.4

整体流程

  1. 生成训练数据集(实际工程中,需要从实际对象身上采集数据)
  2. 确定模型及其参数(输入输出个数、阶次,偏置等)
  3. 确定学习方式(损失函数、优化算法,学习率,训练次数,终止条件等)
  4. 读取数据集(不同的读取方式会影响最终的训练效果)
  5. 训练模型

完整程序及注释

python 复制代码
from IPython import display
from matplotlib import pyplot as plt
from mxnet import autograd, nd
import random


'''
获取(生成)训练集
'''
input_num = 2				# 输入个数
examples_num = 1000			# 生成样本个数
# 确定真实模型参数
real_W = [10.9, -8.7]		
real_bias = 6.5	

features = nd.random.normal(scale=1, shape=(examples_num, input_num))       # 标准差=1,均值缺省=0
labels = real_W[0]*features[:,0] + real_W[1]*features[:,1] + real_bias		# 根据特征和参数生成对应标签
labels_noise = labels + nd.random.normal(scale=0.1, shape=labels.shape)		# 为标签附加噪声,模拟真实情况

# 绘制标签和特征的散点图(矢量图)
# def use_svg_display():
#     display.set_matplotlib_formats('svg')

# def set_figure_size(figsize=(3.5,2.5)):
#     use_svg_display()
#     plt.rcParams['figure.figsize'] = figsize

# set_figure_size()
# plt.scatter(features[:,0].asnumpy(), labels_noise.asnumpy(), 1)
# plt.scatter(features[:,1].asnumpy(), labels_noise.asnumpy(), 1)
# plt.show()


# 创建一个迭代器(确定从数据集获取数据的方式)
def data_iter(batch_size, features, labels):
    num = len(features)
    indices = list(range(num))                                  # 生成索引数组
    random.shuffle(indices)                                     # 打乱indices
    # 该遍历方式同时确保了随机采样和无遗漏
    for i in range(0, num, batch_size):
        j = nd.array(indices[i: min(i+batch_size, num)])        # 对indices从i开始取,取batch_size个样本,并转换为列表
        yield features.take(j), labels.take(j)                  # take方法使用索引数组,从features和labels提取所需数据


"""
训练的基础准备
"""
# 声明训练变量,并赋高斯随机初始值
w = nd.random.normal(scale=0.01, shape=(input_num))
b = nd.zeros(shape=(1,))
# b = nd.zeros(1)       # 不同写法,等价于上面的
w.attach_grad()         # 为需要迭代的参数申请求梯度空间
b.attach_grad()

# 定义模型
def linreg(X, w, b):
    return nd.dot(X,w)+b

# 定义损失函数
def squared_loss(y_hat, y):
    return (y_hat - y.reshape(y_hat.shape)) **2 /2
    
# 定义寻优算法
def sgd(params, learning_rate, batch_size):
    for param in params:
        # 新参数 = 原参数 - 学习率*当前批量的参数梯度/当前批量的大小
        param[:] = param - learning_rate * param.grad / batch_size

# 确定超参数和学习方式
lr = 0.03
num_iterations = 5
net = linreg				# 目标模型
loss = squared_loss			# 代价函数(损失函数)
batch_size = 10				# 每次随机小批量的大小

'''
开始训练
'''
for iteration in range(num_iterations):		# 确定迭代次数
    for x, y in data_iter(batch_size, features, labels):
        with autograd.record():
            l = loss(net(x,w,b), y)			# 求当前小批量的总损失
        l.backward()						# 求梯度
        sgd([w,b], lr, batch_size)			# 梯度更新参数
    train_l = loss(net(features,w,b), labels)

    print("iteration %d, loss %f" % (iteration+1, train_l.mean().asnumpy()))
# 打印比较真实参数和训练得到的参数
print("real_w " + str(real_W) + "\n train_w " + str(w))
print("real_w " + str(real_bias) + "\n train_b " + str(b))

具体程序解释

param[:] = param - learning_rate * param.grad / batch_size

将batch_size与参数调整相关联的原因,是为了使得每次更新的步长不受批次大小的影响

具体来说,当计算一批数据的损失函数的梯度时,实际上是将这批数据中每个样本对损失函数的贡献累加起来。这意味着如果批次较大,梯度的模也会相应增大

故更新权值时,使用的是数据集的平均梯度,而不是总和

相关推荐
㓗冽11 分钟前
60题之内难题分析
开发语言·c++·算法
大江东去浪淘尽千古风流人物12 分钟前
【VLN】VLN仿真与训练三要素 Dataset,Simulators,Benchmarks(2)
深度学习·算法·机器人·概率论·slam
铉铉这波能秀40 分钟前
LeetCode Hot100数据结构背景知识之字典(Dictionary)Python2026新版
数据结构·python·算法·leetcode·字典·dictionary
蜡笔小马1 小时前
10.Boost.Geometry R-tree 空间索引详解
开发语言·c++·算法·r-tree
唐梓航-求职中1 小时前
编程-技术-算法-leetcode-288. 单词的唯一缩写
算法·leetcode·c#
仟濹1 小时前
【算法打卡day3 | 2026-02-08 周日 | 算法: BFS】3_卡码网99_计数孤岛_BFS | 4_卡码网100_最大岛屿的面积DFS
算法·深度优先·宽度优先
Ll13045252981 小时前
Leetcode二叉树part4
算法·leetcode·职场和发展
颜酱1 小时前
二叉树遍历思维实战
javascript·后端·算法
宝贝儿好1 小时前
第二章: 图像处理基本操作
算法
小陈phd1 小时前
多模态大模型学习笔记(二)——机器学习十大经典算法:一张表看懂分类 / 回归 / 聚类 / 降维
学习·算法·机器学习