昇思25天学习打卡营第9天|应用实践之基于MindSpore实现的红酒分类实验

时间:2024-07-10 07:19:13

基本介绍

        今日要学习的是使用KNN算法进行红酒分类,实践是基于MindSpore平台的,采用模式识别著名的数据集之一,Wine Data Set数据集。今日所学习的并不难,KNN是一个很成熟的算法了,网上教程很多,使用MindSpore的API可以很快速的搭建出KNN算法,而且数据集无需做额外的处理,简单可视化一下,划分一下数据即可,最后进行训练验证。KNN算法算是传统的机器学习算法,与深度学习超多参数不一样,KNN训练和推理速度都很快,也不需要NPU、GPU,所以本次实验使用了CPU,当然也可以使用NPU和GPU,不过因为数据集也很小,使用NPU或GPU反而可能因为数据传输等问题更慢些。

KNN基本原理

        K近邻算法(K-Nearest-Neighbor, KNN)是一种用于分类和回归的非参数统计方法,最初由 Cover和Hart于1968年提出(Cover等人,1967),是机器学习最基础的算法之一。它正是基于以上思想:要确定一个样本的类别,可以计算它与所有训练样本的距离,然后找出和该样本最接近的k个样本,统计出这些样本的类别并进行投票,票数最多的那个类就是分类的结果。KNN的三个基本要素:

  • K值,一个样本的分类是由K个邻居的“多数表决”确定的。K值越小,容易受噪声影响,反之,会使类别之间的界限变得模糊。

  • 距离度量,反映了特征空间中两个样本间的相似度,距离越小,越相似。常用的有Lp距离(p=2时,即为欧式距离)、曼哈顿距离、海明距离等,今日实践使用的是欧式距离。

  • 分类决策规则,通常是多数表决,或者基于距离加权的多数表决(权值与距离成反比)。

        今日使用KNN用于分类任务,所以只简单介绍分类流程,具体流程如下:

(1)在训练样本集中找出距离待测样本x_test最近的k个样本,并保存至集合N中;

(2)统计集合N中每一类样本的个数C_i,i=1,2,3,...,c;

(3)最终的分类结果为argmax C_i(最大的对应的C_i)那个类。

  在上述实现过程中,k的取值尤为重要。它可以根据问题和数据特点来确定。在具体实现时,可以考虑样本的权重,即每个样本有不同的投票权重,这种方法称为带权重的k近邻算法,它是一种变种的k近邻算法。

KNN实践运行

数据准备

        数据采用的是开源的红酒数据集,该数据集有三种葡萄酒,每种有13个属性,总共178条数据样本(真的很少),可以从官网或者华为云OBS下载,我选择后者,因为后者更快。下载后将其读取到内存中,部分数据情况如下:

由于数据的属性超过3个,很难将其可视化,于是选用其中两个属性进行可视化,可视化结果如下:

最后将数据划分为训练集和预测集,数目分别是128和50

模型搭建

        数据集准备很容易,接着就是使用MindSpore搭建KNN模型,核心也非常简单,就是计算距离即可,代码如下:

class KnnNet(nn.Cell):
    def __init__(self, k):
        super(KnnNet, self).__init__()
        self.k = k

    def construct(self, x, X_train):
        #平铺输入x以匹配X_train中的样本数
        x_tile = ops.tile(x, (128, 1))
        square_diff = ops.square(x_tile - X_train)
        square_dist = ops.sum(square_diff, 1)
        dist = ops.sqrt(square_dist)
        #-dist表示值越大,样本就越接近
        values, indices = ops.topk(-dist, self.k)
        return indices

模型训练与预测

        其实对于KNN来说训练和验证是一起的,二者一般不会严格区分。在开始之前,需要先实现分类流程,代码如下:

def knn(knn_net, x, X_train, Y_train):
    x, X_train = ms.Tensor(x), ms.Tensor(X_train)
    indices = knn_net(x, X_train)
    topk_cls = [0]*len(indices.asnumpy())
    for idx in indices.asnumpy():
        topk_cls[Y_train[idx]] += 1
    cls = np.argmax(topk_cls)
    return cls

之后便可进行训练预测,采用的是准确率作为评价指标,我在NPU和CPU平台上都跑了,发现前者慢一些,但是准确更高,后者快一些,但是准确率较低,很是奇怪。关于运行速度,大概率是数据传输的原因,我多次在NPU平台上运行代码,只有第一次很慢,剩余几次都和CPU一样快。但是准确率差不少,如下的上图是NPU结果,下图是CPU结果,两个准确率高达8%,很是吓人。

Jupyter运行情况