mindspore的线性回归模型

线性回归模型

一、基础版本

1、导入模块

import numpy as np
import random
import mindspore
import mindspore.dataset as ds
import mindspore.numpy as mnp
import mindspore.ops as ops
import mindspore.nn as nn
from mindspore import Tensor
from mindspore.common.initializer import Normal
from matplotlib import pyplot as plt

2、构建数据集

一般是导入数据集,这里采用自定义的方法构建数据集

# 真实的参数

true_w = np.array([2, -3.4])
true_b = 4.2
# 构建生成数据集的函数

def synthetic_data(w,b,n):
    """生成 y = Xw + b + 噪声"""
    np.random.seed(666)
    X = np.random.normal(0,1,(n, len(w)))  # X为期望为0,标准差为1的正态分布随机数
    noise = np.random.normal(0,0.01)       # 噪声为正态分布随机数,噪声可以视为模型预测和标签时的潜在观测误差
    y = np.dot(X,w) + b + noise
    return X.astype(np.float32), y.reshape((-1, 1)).astype(np.float32)  # astype(np.float32)修改数据类型,默认为 float64
                                                                        # np.dot(X,w)得到的是行向量,y.reshape((-1, 1))使得
                                                                        # 输出得y为列向量
# 创建一个迭代器类,在该类中定义 __init__ 、 __getitem__ 、 __len__ 三个方法
# 生成批量的特征和标签后,通过__getitem__的迭代作用每次可输出一组特征和标签值,用于后面输入mindspore的GeneratorDataset的数据源

class SyntheticData():  
    def __init__(self):
        self.features, self.labels = synthetic_data(true_w, true_b, 1000)

    def __getitem__(self, index):   # __getitem__(self, index) 一般用来迭代序列(常见序列如:列表、元组、字符串)
        return self.features[index], self.labels[index]
    
    def __len__(self):
        return len(self.labels)

# 迭代器的输出需要是numpy的array
# 迭代器必须要设置__len__方法,返回的结果一定要是真实的数据集大小,设置大了在getitem取值时会有问题。

mindspore.dataset.GeneratorDataset(source, column_names,shuffle)
自定义Python数据源,通过迭代该数据源构造数据集。生成的数据集的列名和列类型取决于用户定义的Python数据源

参数:
1、source=数据源,一个Python的可调用对象,可以是可迭代的Python对象,或支持随机访问的Python对象
2、column_names=指定数据集生成的列名
3、shuffle=是否混洗数据集。只有输入的 source 参数带有可随机访问属性(getitem)时,才可以指定该参数

属性:
1、batch(batch_size):batch_size表示每个批处理数据大小
2、create_tuple_iterator(columns=None, num_epochs=-1, output_numpy=False):基于数据集对象创建迭代器。输出数据numpy.ndarray 组成的列表
columns=用于指定输出的数据列和列的顺序。默认值:None,输出所有数据列。
num_epochs=迭代器可以迭代的最大次数。默认值:-1,迭代器可以迭代无限次。
output_numpy=输出的数据是否转为NumPy类型。如果为False,迭代器输出的每列数据类型为MindSpore.Tensor,否则为NumPy。默认值:False。

# 用GeneratorDataset封装迭代器类,调用框架中现有的API来读取数据源
# 定义一个load_array函数,用GeneratorDataset接收批量大小、特征矩阵和标签向量作为输入,输出大小为batch_size的小批量

def load_array(data_arrays, column_names, batch_size, is_train=True): # 布尔值is_train表示是否希望数据迭代器对象在每个迭代周期内打乱数据 
    dataset = ds.GeneratorDataset(data_arrays, column_names, shuffle=is_train,python_multiprocessing=False)  
    dataset = dataset.batch(batch_size)
    return dataset
batch_size = 10  # 批量大小
data_iter = SyntheticData()  
dataset = load_array(data_iter, ['features', 'labels'], batch_size)

# 在自定义数据集时需要给每一个输出设置一个名字,如上面的["data", "label"],
# 表示迭代器的第一个输出列叫data,第二个叫label。在后续的数据增强以及数据迭代获取阶段,可以通过名字来分别对不同列进行处理
# 验证是否正常工作
# 使用iter构造Python迭代器,并使用next从迭代器中获取第一项

next(iter(data_iter))
(array([0.82418805, 0.479966  ], dtype=float32),
 array([4.2085605], dtype=float32))
# 直观观察到features和labels之间的线性关系

plt.figure(figsize=(4,3))
plt.scatter(data_iter.features[:, (1)], data_iter.labels, 1);

在这里插入图片描述

3、搭建模型

mindspore.nn.SequentialCell(*args)
构造神经网络的基本构成单元Cell顺序容器

参数:
args=仅包含Cell子类的列表或有序字典


mindspore.nn.Dense(in_channels, out_channels, weight_init=‘normal’, bias_init=‘zeros’, has_bias=True, activation=None)
全连接层
适用于输入的密集连接层。公式:outputs=activation(X∗kernel+bias)
其中X是输入Tensor,activation是激活函数,kernel是一个权重矩阵,其数据类型与 X相同,bias是一个偏置向量,其数据类型与X相同(仅当has_bias为True时)

参数:
in_channels=Dense层输入Tensor的空间维度。
out_channels=Dense层输出Tensor的空间维度。
weight_init=权重参数的初始化方法。数据类型与 x 相同。str的值引用自函数 initializer。默认值:’normal’。
bias_init=偏置参数的初始化方法。数据类型与 x 相同。str的值引用自函数 initializer。默认值:’zeros’。
has_bias=是否使用偏置向量 bias。默认值:True。
activation=应用于全连接层输出的激活函数。可指定激活函数名,如’relu’,或具体激活函数,如mindspore.nn.ReLU()。默认值:None。

# 骨干网络模型
net = nn.SequentialCell([nn.Dense(len(true_w), 1, weight_init=Normal(0.01, 0), bias_init='zero')])

mindspore.nn.MSELoss
用于计算预测值与标签值之间的均方误差

# 损失函数(采用均方误差)
loss = nn.MSELoss()

WithLossCell
包含损失函数的训练网络Cell。封装骨干网络和计算损失函数。此Cell接受数据和标签(类型为Tensor)作为输入,并将返回损失函数作为计算结果。

# 将net与loss连接
net_with_loss = nn.WithLossCell(net, loss)

mindspore.nn.SGD(params, learning_rate=0.1)
随机梯度下降的实现

# 优化器(采用随机梯度下降)
optim = nn.SGD(net.trainable_params(), learning_rate=0.03)

mindspore.nn.TrainOneStepCell(network, optimizer)
训练网络封装类。封装训练网络和优化器。构建一个输入*inputs的用于训练的Cell。

# 将net,loss,optim连接,生成训练模型
trainer = nn.TrainOneStepCell(net_with_loss, optim)

4、训练模型

num_epochs = 1  # num_epochs 迭代周期个数
cnt=0           # cnt 记录损失loss的更新次数
y=np.array([])  # y数组储存损失loss每次更新的值
dataset_iter = dataset.create_tuple_iterator(num_epochs=num_epochs) 
# create_tuple_iterator基于数据集对象创建迭代器,输出数据为 numpy.ndarray 组成的列表。
# 可以通过参数 columns 指定输出的所有列名及列的顺序。如果columns未指定,列的顺序将保持不变

for epoch in range(num_epochs):
    for data in dataset_iter:
        loss = trainer(*data)   
        cnt+=1
        y=np.append(y,float(loss))
    loss = net_with_loss(mindspore.Tensor(data_iter.features), mindspore.Tensor(data_iter.labels))
# 比较真实参数和通过训练学到的参数来评估训练的成功程度

w = net[0].weight.data
print('w的估计误差:', true_w - w.reshape(true_w.shape))
b = net[0].bias.data
print('b的估计误差:', true_b - b)
w的估计误差: [Tensor(shape=[], dtype=Float32, value= 0.00406218)
 Tensor(shape=[], dtype=Float32, value= -0.00433683)]
b的估计误差: [0.01404667]

5、loss-step曲线

# 构建loss-step曲线可了解loss随step的变化情况

plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False

x=np.linspace(1,cnt,len(y))

plt.figure(figsize=(4,3)) 
plt.xlabel(u"步数")
plt.ylabel(u"损失值")
plt.plot(x, y)

在这里插入图片描述

二、高级版本(某大佬的)

import mindspore as ms
import numpy as np
from mindspore import nn  # nn: 1) 调用优化器SGD,Adam,Momentum,RMSProp 2) 调用均方误差损失函数MSELoss 3) 调用Dense
from mindspore import dataset as ds   # dataset: 储存所创建的数据集
from mindspore.train.callback import Callback   # Callback:记录损失值的回调函数
from matplotlib import pyplot as plt    # pyplot:绘制图像
import seaborn as sns    # seaborn:让图像更美观

1. 数据集生成函数

# 真实的 w 与 b
true_w = np.array([-1, 2, -3])
true_b = 4
# 利用生成器函数生成随机数据
def get_data(num_data, w, b):
    np.random.seed(666)    # 随机数种子
    for _ in range(num_data):
        x = np.random.uniform(-10.0, 10.0, len(w))    # x为均匀分布随机数
        noise = np.random.normal(0, 0.05)    # 噪声为正态分布随机数
        y = w @ x + b + noise
        yield np.array(x).astype(np.float32) , np.array([y]).astype(np.float32)  # 采用生成器返回(生成器也是迭代器)
#创建数据集
def create_dataset(num_data, w, b, batch_size=10):
    dataset = ds.GeneratorDataset(list(get_data(num_data, w, b)), column_names=['features', 'labels'], python_multiprocessing=False)
    dataset = dataset.batch(batch_size)                                            # 加上python_multiprocessing=False这个,因为windows下没法多进程会warning
    return dataset   

2. Loss图像生成函数

Callback是回调函数的意思,但它其实不是一个函数而是一个类,用户可以使用回调函数来观察训练过程中网络内部的状态和相关信息,或在特定时期执行特定动作。 例如监控loss、保存模型参数、动态调整参数、提前终止训练任务等

#记 录损失值的回调函数,将loss和step信息记录在steps_loss中
class StepLossInfo(Callback):
    def __init__(self, steps_loss):
        self.steps_loss = steps_loss

    def on_train_step_end(self, run_context):
        cb_params = run_context.original_args()   # original_args获取模型相关信息的对象
        cur_step = cb_params.cur_step_num   # cur_step_num训练步数
        self.steps_loss["loss_value"].append(str(cb_params.net_outputs))  # net_outputs训练或推理的网络输出
        self.steps_loss["step"].append(str(cur_step))
#图像显示设置
plt.style.use('bmh')  #设置风格
sns.set(rc={'font.sans-serif': 'SimHei','axes.unicode_minus': False})  #设置中文、负号显示

#绘制Loss曲线        
def draw_loss_graph(losses, opts):
    #依次画出每个优化器的loss曲线
    for steps_loss in losses:
        steps = steps_loss["step"]
        loss_value = steps_loss["loss_value"]
        steps = list(map(int, steps))
        loss_value = list(map(float, loss_value))
        plt.plot(steps, loss_value)
    
    plt.xlabel("步数")
    plt.ylabel("损失值")
    plt.legend(opts)  #优化器名称标签
    plt.title("各模型训练损失值变化")
    plt.tight_layout()
    plt.show()

3. 模型训练函数

#模型训练函数
def train(opt_name, opt, lr):    # 参数依次为:优化器名称,优化器,学习率
    opt_names.append(opt_name)
    
    #生成数据集
    dataset = create_dataset(1000, true_w, true_b)
    
    #创建模型
    loss = nn.MSELoss()  #均方误差损失函数
    net = nn.Dense(len(true_w), 1, ms.Tensor([[1]*len(true_w)], dtype=ms.float32), ms.Tensor([1], dtype=ms.float32))  #全连接层(线性层) w和b全部初始化为1
    #Momentum优化器必须有momentum参数,这里做个判断
    opt = opt(net.trainable_params(), learning_rate=lr, momentum=0.9) if opt == nn.Momentum else opt(net.trainable_params(), learning_rate=lr)
    model = ms.Model(net, loss, opt)

    #记录Loss
    steps_loss = {"step": [], "loss_value": []} 
    step_loss_acc_info = StepLossInfo(steps_loss)  #回调函数,记录损失值
    
    #训练
    epoches = 1 #这里1周期就足够了
    model.train(epoches, dataset,callbacks=step_loss_acc_info, dataset_sink_mode=False)
                               # 这里要加上那个callback来获取loss值
    #训练结果
    steps_losses.append(steps_loss)
    print(opt_name + '误差:\tw:', round(abs(net.trainable_params()[0].asnumpy().reshape(len(true_w)) - true_w).sum(), 5),
          '\tb:', round(abs(net.trainable_params()[1].asnumpy() - true_b).sum(), 5))

4. 正式训练

#画图所需
opt_names = []
steps_losses = []

#开始训练
train('SGD', nn.SGD, 0.02)
train('Momentum', nn.Momentum, 0.003)
train('RMSProp', nn.RMSProp, 0.06)
train('Adam', nn.Adam, 0.1)

#画出loss曲线
draw_loss_graph(steps_losses, opt_names)
SGD误差:	w: 0.01026 	b: 0.04276
Momentum误差:	w: 0.16888 	b: 0.03461
RMSProp误差:	w: 0.01212 	b: 0.09769
Adam误差:	w: 0.04166 	b: 0.24604

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值