K近邻算法实现红酒聚类¶
本实验主要介绍使用MindSpore在部分wine数据集上进行KNN实验。
1、实验目的
- 了解KNN的基本概念;
- 了解如何使用MindSpore进行KNN实验。
2、K近邻算法原理介绍
K近邻算法(K-Nearest-Neighbor, KNN)是一种用于分类和回归的非参数统计方法,最初由 Cover和Hart于1968年提出(Cover等人,1967),是机器学习最基础的算法之一。它正是基于以上思想:要确定一个样本的类别,可以计算它与所有训练样本的距离,然后找出和该样本最接近的k个样本,统计出这些样本的类别并进行投票,票数最多的那个类就是分类的结果。KNN的三个基本要素:
-
K值,一个样本的分类是由K个邻居的“多数表决”确定的。K值越小,容易受噪声影响,反之,会使类别之间的界限变得模糊。
-
距离度量,反映了特征空间中两个样本间的相似度,距离越小,越相似。常用的有Lp距离(p=2时,即为欧式距离)、曼哈顿距离、海明距离等。
-
分类决策规则,通常是多数表决,或者基于距离加权的多数表决(权值与距离成反比)。
2.1 分类问题
预测算法(分类)的流程如下:
(1)在训练样本集中找出距离待测样本x_test最近的k个样本,并保存至集合N中;
(2)统计集合N中每一类样本的个数𝐶𝑖,𝑖=1,2,3,...,𝑐𝐶𝑖,𝑖=1,2,3,...,𝑐;
(3)最终的分类结果为argmax𝐶𝑖𝐶𝑖 (最大的对应的𝐶𝑖𝐶𝑖)那个类。
在上述实现过程中,k的取值尤为重要。它可以根据问题和数据特点来确定。在具体实现时,可以考虑样本的权重,即每个样本有不同的投票权重,这种方法称为带权重的k近邻算法,它是一种变种的k近邻算法。
2.2 回归问题
假设离测试样本最近的k个训练样本的标签值为𝑦𝑖𝑦𝑖,则对样本的回归预测输出值为:
即为所有邻居的标签均值。
带样本权重的回归预测函数为:
其中𝑤𝑖为第个𝑖样本的权重。
2.3 距离的定义
KNN算法的实现依赖于样本之间的距离,其中最常用的距离函数就是欧氏距离(欧几里得距离)。ℝ𝑛空间中的两点𝑥和𝑦,它们之间的欧氏距离定义为:
需要特别注意的是,使用欧氏距离时,应将特征向量的每个分量归一化,以减少因为特征值的尺度范围不同所带来的干扰,否则数值小的特征分量会被数值大的特征分量淹没。
其它的距离计算方式还有Mahalanobis距离、Bhattacharyya距离等。
3、实验环境
预备知识:
- 熟练使用Python。
- 具备一定的机器学习理论知识,如KNN、无监督学习、 欧式距离等。
实验环境:
- MindSpore 2.0(MindSpore版本会定期更新,本指导也会定期刷新,与版本配套);
- 本案例支持win_x86和Linux系统,CPU/GPU/Ascend均可运行。
- 如果在本地运行此实验,请参考《MindSpore环境搭建实验手册》在本地安装MindSpore。
4、数据处理
4.1 数据准备
Wine数据集是模式识别最著名的数据集之一,Wine数据集的官网:Wine Data Set。这些数据是对来自意大利同一地区但来自三个不同品种的葡萄酒进行化学分析的结果。数据集分析了三种葡萄酒中每种所含13种成分的量。这些13种属性是
- Alcohol,酒精
- Malic acid,苹果酸
- Ash,灰
- Alcalinity of ash,灰的碱度
- Magnesium,镁
- Total phenols,总酚
- Flavanoids,类黄酮
- Nonflavanoid phenols,非黄酮酚
- Proanthocyanins,原花青素
- Color intensity,色彩强度
- Hue,色调
- OD280/OD315 of diluted wines,稀释酒的OD280/OD315
- Proline,脯氨酸
- 方式一,从Wine数据集官网下载wine.data文件。
- 方式二,从华为云OBS中下载wine.data文件。
-
%%capture captured_output # 实验环境已经预装了mindspore==2.2.14,如需更换mindspore版本,可更改下面mindspore的版本号 !pip uninstall mindspore -y !pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore==2.2.14
from download import download # 下载红酒数据集 url = "https://ascend-professional-construction-dataset.obs.cn-north-4.myhuaweicloud.com:443/MachineLearning/wine.zip" path = download(url, "./", kind="zip", replace=True)
4.2 数据读取与处理
导入MindSpore模块和辅助模块
在生成数据之前,导入需要的Python库。
目前使用到os库,为方便理解,其他需要的库,我们在具体使用到时再说明。
详细的MindSpore的模块说明,可以在MindSpore API页面中搜索查询。
可以通过context.set_context来配置运行需要的信息,譬如运行模式、后端信息、硬件等信息。
导入context模块,配置运行需要的信息。
%matplotlib inline
import os
import csv
import numpy as np
import matplotlib.pyplot as plt
import mindspore as ms
from mindspore import nn, ops
ms.set_context(device_target="CPU")
读取Wine数据集wine.data
,并查看部分数据。
with open('wine.data') as csv_file:
data = list(csv.reader(csv_file, delimiter=','))
print(data[56:62]+data[130:133])
取三类样本(共178条),将数据集的13个属性作为自变量𝑋。将数据集的3个类别作为因变量𝑌。
attrs = ['Alcohol', 'Malic acid', 'Ash', 'Alcalinity of ash', 'Magnesium', 'Total phenols',
'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins', 'Color intensity', 'Hue',
'OD280/OD315 of diluted wines', 'Proline']
plt.figure(figsize=(10, 8))
for i in range(0, 4):
plt.subplot(2, 2, i+1)
a1, a2 = 2 * i, 2 * i + 1
plt.scatter(X[:59, a1], X[:59, a2], label='1')
plt.scatter(X[59:130, a1], X[59:130, a2], label='2')
plt.scatter(X[130:, a1], X[130:, a2], label='3')
plt.xlabel(attrs[a1])
plt.ylabel(attrs[a2])
plt.legend()
plt.show()
将数据集按128:50划分为训练集(已知类别样本)和验证集(待验证样本):
train_idx = np.random.choice(178, 128, replace=False)
test_idx = np.array(list(set(range(178)) - set(train_idx)))
X_train, Y_train = X[train_idx], Y[train_idx]
X_test, Y_test = X[test_idx], Y[test_idx]
5、模型构建--计算距离
利用MindSpore提供的tile, square, ReduceSum, sqrt, TopK
等算子,通过矩阵运算的方式同时计算输入样本x和已明确分类的其他样本X_train的距离,并计算出top k近邻
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
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
6、模型预测
在验证集上验证KNN算法的有效性,取𝑘=5,验证精度接近80%,说明KNN算法在该3分类任务上有效,能根据酒的13种属性判断出酒的品种。
acc = 0
knn_net = KnnNet(5)
for x, y in zip(X_test, Y_test):
pred = knn(knn_net, x, X_train, Y_train)
acc += (pred == y)
print('label: %d, prediction: %s' % (y, pred))
print('Validation accuracy is %f' % (acc/len(Y_test)))
实验小结
本实验使用MindSpore实现了KNN算法,用来解决3分类问题。取wine数据集上的3类样本,分为已知类别样本和待验证样本,从验证结果可以看出KNN算法在该任务上有效,能根据酒的13种属性判断出酒的品种。
基于MindNLP+MusicGen生成自己的个性化音乐
MusicGen是来自Meta AI的Jade Copet等人提出的基于单个语言模型(LM)的音乐生成模型,能够根据文本描述或音频提示生成高质量的音乐样本,相关研究成果参考论文《Simple and Controllable Music Generation》。
MusicGen模型基于Transformer结构,可以分解为三个不同的阶段:
- 用户输入的文本描述作为输入传递给一个固定的文本编码器模型,以获得一系列隐形状态表示。
- 训练MusicGen解码器来预测离散的隐形状态音频token。
- 对这些音频token使用音频压缩模型(如EnCodec)进行解码,以恢复音频波形。
MusicGen直接使用谷歌的t5-base及其权重作为文本编码器模型,并使用EnCodec 32kHz及其权重作为音频压缩模型。MusicGen解码器是一个语言模型架构,针对音乐生成任务从零开始进行训练。
MusicGen 模型的新颖之处在于音频代码的预测方式。传统上,每个码本都必须由一个单独的模型(即分层)或通过不断优化 Transformer 模型的输出(即上采样)进行预测。与传统方法不同,MusicGen采用单个stage的Transformer LM结合高效的token交织模式,取消了多层级的多个模型结构,例如分层或上采样,这使得MusicGen能够生成单声道和立体声的高质量音乐样本,同时提供更好的生成输出控制。MusicGen不仅能够生成符合文本描述的音乐,还能够通过旋律条件控制生成的音调结构。
下载模型
MusicGen提供了small、medium和big三种规格的预训练权重文件,本次指南默认使用small规格的权重,生成的音频质量较低,但是生成的速度是最快的:
%%capture captured_output
# 实验环境已经预装了mindspore==2.2.14,如需更换mindspore版本,可更改下面mindspore的版本号
!pip uninstall mindspore -y
!pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore==2.2.14
from mindnlp.transformers import MusicgenForConditionalGeneration
model = MusicgenForConditionalGeneration.from_pretrained("facebook/musicgen-small")
生成音乐
MusicGen支持两种生成模式:贪心(greedy)和采样(sampling)。在实际执行过程中,采样模式得到的结果要显著优于贪心模式。因此我们默认启用采样模式,并且可以在调用MusicgenForConditionalGeneration.generate
时设置do_sample=True
来显式指定使用采样模式。
无提示生成
我们可以通过方法 MusicgenForConditionalGeneration.get_unconditional_inputs
获得网络的随机输入,然后使用 .generate
方法进行自回归生成,指定 do_sample=True
来启用采样模式:
%%time
unconditional_inputs = model.get_unconditional_inputs(num_samples=1)
audio_values = model.generate(**unconditional_inputs, do_sample=True, max_new_tokens=256)
音频输出是格式是: a Torch tensor of shape (batch_size, num_channels, sequence_length)
。
使用第三方库scipy
将输出的音频保存为musicgen_out.wav
文件。
import scipy
sampling_rate = model.config.audio_encoder.sampling_rate
scipy.io.wavfile.write("musicgen_out.wav", rate=sampling_rate, data=audio_values[0, 0].asnumpy())
from IPython.display import Audio
# 要收听生成的音频样本,可以使用 Audio 在 notebook 进行播放
Audio(audio_values[0].asnumpy(), rate=sampling_rate)
参数 max_new_tokens
指定要生成 token
数。根据经验,可以使用 EnCodec
模型的帧速率计算出生成的音频样本的长度(以秒为单位):
audio_length_in_s = 256 / model.config.audio_encoder.frame_rate
audio_length_in_s
文本提示生成
首先基于文本提示,通过AutoProcessor
对输入进行预处理。然后将预处理后的输入传递给 .generate
方法以生成文本条件音频样本。同样,我们通过设置“do_sample=True”来启用采样模式。
其中,guidance_scale
用于无分类器指导(CFG),设置条件对数之间的权重(从文本提示中预测)和无条件对数(从无条件或空文本中预测)。guidance_scale
越高表示生成的模型与输入的文本更加紧密。通过设置guidance_scale > 1
来启用 CFG。为获得最佳效果,使用guidance_scale=3
(默认值)生成文本提示音频。
%%time
from mindnlp.transformers import AutoProcessor
processor = AutoProcessor.from_pretrained("facebook/musicgen-small")
inputs = processor(
text=["80s pop track with bassy drums and synth", "90s rock song with loud guitars and heavy drums"],
padding=True,
return_tensors="ms",
)
audio_values = model.generate(**inputs, do_sample=True, guidance_scale=3, max_new_tokens=256)
scipy.io.wavfile.write("musicgen_out_text.wav", rate=sampling_rate, data=audio_values[0, 0].asnumpy())
from IPython.display import Audio
# 要收听生成的音频样本,可以使用 Audio 在 notebook 进行播放
Audio(audio_values[0].asnumpy(), rate=sampling_rate)
音频提示生成
AutoProcessor
同样可以对用于音频预测的音频提示进行预处理。在以下示例中,我们首先加载音频文件,然后进行预处理,并将输入给到网络模型来进行音频生成。最后,我们将生成出来的音频文件保存为musicgen_out_audio.wav
%%time
from datasets import load_dataset
processor = AutoProcessor.from_pretrained("facebook/musicgen-small")
dataset = load_dataset("sanchit-gandhi/gtzan", split="train", streaming=True)
sample = next(iter(dataset))["audio"]
# take the first half of the audio sample
sample["array"] = sample["array"][: len(sample["array"]) // 2]
inputs = processor(
audio=sample["array"],
sampling_rate=sample["sampling_rate"],
text=["80s blues track with groovy saxophone"],
padding=True,
return_tensors="ms",
)
audio_values = model.generate(**inputs, do_sample=True, guidance_scale=3, max_new_tokens=256)
scipy.io.wavfile.write("musicgen_out_audio.wav", rate=sampling_rate, data=audio_values[0, 0].asnumpy())
from IPython.display import Audio
# 要收听生成的音频样本,可以使用 Audio 在 notebook 进行播放
Audio(audio_values[0].asnumpy(), rate=sampling_rate)
为了演示批量音频提示生成,我们将按两个不同的比例对样本音频进行切片,以提供两个不同长度的音频样本。由于输入音频提示的长度各不相同,因此在传递到模型之前,它们将被填充到批处理中最长的音频样本的长度。
要恢复最终音频样本,可以对生成的audio_values进行后处理,以再次使用处理器类删除填充:
sample = next(iter(dataset))["audio"]
# take the first quater of the audio sample
sample_1 = sample["array"][: len(sample["array"]) // 4]
# take the first half of the audio sample
sample_2 = sample["array"][: len(sample["array"]) // 2]
inputs = processor(
audio=[sample_1, sample_2],
sampling_rate=sample["sampling_rate"],
text=["80s blues track with groovy saxophone", "90s rock song with loud guitars and heavy drums"],
padding=True,
return_tensors="ms",
)
audio_values = model.generate(**inputs, do_sample=True, guidance_scale=3, max_new_tokens=256)
# post-process to remove padding from the batched audio
audio_values = processor.batch_decode(audio_values, padding_mask=inputs.padding_mask)
Audio(audio_values[0], rate=sampling_rate)
生成配置
控制生成过程的默认参数(例如采样、指导比例和生成的令牌数量)可以在模型的生成配置中找到,并根据需要进行更新。首先,我们检查默认的生成配置:
model.generation_config
我们看到模型默认使用采样模式 (do_sample=True),指导刻度为 3,最大生成长度为 1500(相当于 30 秒的音频)。你可以更新以下任一属性以更改默认生成参数:
# increase the guidance scale to 4.0
model.generation_config.guidance_scale = 4.0
# set the max new tokens to 256
model.generation_config.max_new_tokens = 256
# set the softmax sampling temperature to 1.5
model.generation_config.temperature = 1.5
现在重新运行生成将使用生成配置中新定义的值
audio_values = model.generate(**inputs)
请注意,传递给 generate 方法的任何参数都将取代生成配置中的参数,因此在调用 generate 中设置 do_sample=False 将取代生成配置中 model.generation_config.do_sample 的设置。
最后打卡今天的学习时间
心得
在昇思25天学习打卡营第13天中,我学习了K近邻算法(KNN)和MusicGen的应用。通过KNN算法,在部分红酒数据集上进行聚类实验,了解KNN的基本概念和在MindSpore中的实现。KNN是一种用于分类和回归的非参数统计方法,通过计算样本与训练样本的距离,找出最接近的k个样本进行分类。与此同时,我还学习了MusicGen,这是一种基于Transformer结构的音乐生成模型,能够根据文本描述或音频提示生成高质量的音乐。MusicGen通过单个语言模型架构,结合高效的token交织模式,实现了高质量的音乐生成,支持无提示生成和文本提示生成两种模式,提供了强大的音乐生成和控制能力。