MindSpore模型验证

技术背景

在前面一篇博客中,我们介绍了MindSpore在机器学习过程中保存和加载模型的方法。这种将模型存储为静态文件的做法,使得我们可以更灵活的使用训练出来的模型,比如用于各种数据集的验证,或者是迁移学习等场景。

前言

这里使用的数据集和加载的模型,都来自于这篇博客。关于MindSpore的环境部署,可以参考这两篇博客:CPU版本安装GPU版本安装,当然,这两个方案都使用了Docker容器化部署的策略,这跟个人编程习惯有关。需要说明的是,在GPU版本中可以使用CPU版本的context,但是CPU版本中不能使用GPU版本的context。但是CPU版本的部署相比于GPU版本要容易很多,GPU版本的部署方案对本地Docker环境之外还有一些依赖,可以看个人需求来进行选取。关于性能问题,其实不好说GPU版本的一定就比CPU版本的更快,比如本文中所使用到的案例在CPU上运行的速度就比GPU上运行的速度要快。GPU由于其硬件架构的特殊性,需要在数据量达到一定程度之后,才能够发挥出并行的优势,小规模数据集使用CPU就足够了。有个坑点需要说明的是,MindSpore在CPU和GPU两者之间的算子和操作等兼容性做的不是很好,很多可以在GPU上面跑的代码,仅仅切换到CPU版本去运行的话就会报错。

同范围数据集验证

在这个案例中我们假定已经按照这篇博客中的步骤训练好了模型,并保存成了ckpt文件。前面使用的训练集是一个如下形式的方程:

\[f(x)=ax^2+b+noise,x\in[-1,1] \]

那么我们首先测试一个相同自变量范围的函数,作为测试集:

\[f(x)=ax^2+b,x\in[-1,1] \]

因为是测试集,所以这里我们暂时先去掉了\(noise\)这一项,对应的代码如下:

# load_model.py

from mindspore import context
context.set_context(mode=context.GRAPH_MODE, device_target="CPU")
import mindspore.dataset as ds
from mindspore import load_checkpoint, load_param_into_net
from mindspore import nn, Tensor, Model
from mindspore.train.callback import Callback, LossMonitor
import numpy as np

class LinearNet(nn.Cell): # 与训练模型相同
    def __init__(self):
        super(LinearNet, self).__init__()
        self.fc = nn.Dense(1,1,0.02,0.02)

    def construct(self, x):
        x = self.fc(x)
        return x

net = LinearNet()
net.set_train(False)
param_dict = load_checkpoint("CKP-1_200.ckpt") # 模型加载
load_param_into_net(net, param_dict) # 将模型参数加载到网络中

net_loss = nn.loss.MSELoss()
model = Model(net, net_loss, metrics={"loss"})

def get_data(num, a=2.0, b=3.0): # 与训练模型相同格式
    for _ in range(num):
        x = np.random.uniform(-1.0, 1.0)
        z = a * x ** 2 + b
        yield np.array([x**2]).astype(np.float32), np.array([z]).astype(np.float32)

def create_dataset(num_data, batch_size=16, repeat_size=1):
    input_data = ds.GeneratorDataset(list(get_data(num_data)), column_names=['x','z'])
    input_data = input_data.batch(batch_size)
    input_data = input_data.repeat(repeat_size)
    return input_data

data_number = 160 # 测试集规模一般小于训练集
batch_number = 1
repeat_number = 1

ds_valid = create_dataset(data_number, batch_size=batch_number, repeat_size=repeat_number) # 生成测试集

acc = model.eval(ds_valid, dataset_sink_mode=False) # 模型验证
print (acc)

需要注意的一点是,这里我们为了验证模型的准确性,model的metrics选用了loss这一方法,还有很多其他方法比如accuracy等可以应用于其他场景。相对应的docker容器启动指令如下:

sudo docker run --rm -v /dev/shm:/dev/shm -v /home/dechin/projects/gitlab/dechin/src/mindspore/:/home/ --runtime=nvidia --privileged=true swr.cn-south-1.myhuaweicloud.com/mindspore/mindspore-gpu:1.2.0 /bin/bash -c "cd /home && python load_model.py"
[WARNING] DEBUG(1,python):2021-05-18-03:25:53.600.802 [mindspore/ccsrc/debug/debugger/debugger.cc:80] Debugger] Not enabling debugger. Debugger does not support CPU.
{'loss': 0.0029351555945297037}

打印出来的是一个字典格式的loss值,这个值的计算方法为:

\[loss=\frac{\sum_n\left(f(x_i)-net(x_i)\right)^2}{n} \]

计算的结果是误差平方的平均值,这里在相同范围内的测试集的损失值为0.0029,还是一个相对比较好的结果。

扩大范围数据集验证

如果我们想推广这个范围,因为我们知道一个原始的模型一般都是具有比较好的普适性的,但是训练出来的神经网络很大程度上会收到训练集的影响。让我们直接看这样的一个例子:

\[f(x)=ax^2+b,x\in[-10,10] \]

在这个新的测试集生成模型中,我们只是把原本的\([-1,1]\)的范围改成了\([-10,10]\)的范围。对应的代码如下所示:

# load_model.py

from mindspore import context
context.set_context(mode=context.GRAPH_MODE, device_target="CPU")
import mindspore.dataset as ds
from mindspore import load_checkpoint, load_param_into_net
from mindspore import nn, Tensor, Model
from mindspore.train.callback import Callback, LossMonitor
import numpy as np

class LinearNet(nn.Cell):
    def __init__(self):
        super(LinearNet, self).__init__()
        self.fc = nn.Dense(1,1,0.02,0.02)

    def construct(self, x):
        x = self.fc(x)
        return x

net = LinearNet()
net.set_train(False)
param_dict = load_checkpoint("CKP-1_200.ckpt")
load_param_into_net(net, param_dict)

net_loss = nn.loss.MSELoss()
model = Model(net, net_loss, metrics={"loss"})

def get_data(num, a=2.0, b=3.0):
    for _ in range(num):
        x = np.random.uniform(-10.0, 10.0)
        z = a * x ** 2 + b
        yield np.array([x**2]).astype(np.float32), np.array([z]).astype(np.float32)

def create_dataset(num_data, batch_size=16, repeat_size=1):
    input_data = ds.GeneratorDataset(list(get_data(num_data)), column_names=['x','z'])
    input_data = input_data.batch(batch_size)
    input_data = input_data.repeat(repeat_size)
    return input_data

data_number = 160
batch_number = 1
repeat_number = 1

ds_valid = create_dataset(data_number, batch_size=batch_number, repeat_size=repeat_number)

acc = model.eval(ds_valid, dataset_sink_mode=False)
print (acc)

同样的,用docker的方式拉起运行:

sudo docker run --rm -v /dev/shm:/dev/shm -v /home/dechin/projects/gitlab/dechin/src/mindspore/:/home/ --runtime=nvidia --privileged=true swr.cn-south-1.myhuaweicloud.com/mindspore/mindspore-gpu:1.2.0 /bin/bash -c "cd /home && python load_model.py"
[WARNING] DEBUG(1,python):2021-05-18-03:26:29.528.892 [mindspore/ccsrc/debug/debugger/debugger.cc:80] Debugger] Not enabling debugger. Debugger does not support CPU.
{'loss': 52.90038294600496}

此时我们看到平均的误差变成了52.9,这个值就比较大了。

总结概要

在这篇文章中,我们接着前面的博客继续讲MindSpore在训练好机器学习的模型并且保存成文件之后,如何加载并使用测试集加以验证。从测试结果中我们得到的启发是,机器学习的模型的有效性会很大程度上收到训练集的影响,因此最好是能够保障训练集的广泛性。如果测试集的范围大大超出了训练集所能够表示的范围,那么训练的模型误差就会很大。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/valid.html
作者ID:DechinPhy
更多原著文章请参考:https://www.cnblogs.com/dechinphy/

上一篇:看MindSpore加持下,如何「炼出」首个千亿参数中文预训练语言模型?


下一篇:有没有什么可以节省大量时间的 Deep Learning 效率神器?