一起用代码吸猫!本文正在参与【喵星人征文活动】。
喵语数据集
米兰大学计算机系的研究人员收集了两个品种(缅因州库恩猫和欧洲短毛猫)的21只喵星人的440份声音。
这些喵星人处在3种状态之下:
- 刷牙:猫被主人在家中刷牙
- 在陌生环境中隔离:猫被主人转移到陌生环境中。(尽量缩短距离,采用常规运输方式,以避免给动物带来不适。旅程持续不到30分钟,猫被允许与主人一起不超过30分钟,以从运输中恢复过来,然后被隔离在不熟悉的环境中,在那里它们最多独处5分钟)
- 等待食物:主人在猫咪熟悉的正常环境中开始准备喂食的操作
另外,每条声音文件提供的信息还包括:
- 猫的唯一ID;
- 品种
- 性别(女性,完整;女性,绝育;男性,完整;男性,绝育)
- 猫主人的唯一ID
- 录音场次
- 发声计数
神经网络喵语识别
接下来,利用该喵语数据集,使用 MegEngine 构建神经网络进行分类,根据喵叫声判断喵星人所处的状态。
数据处理
将下载好的喵语数据集放到路径 ./data/
中。首先将声音文件转换为特征值。
声音文件长度为 1~2 秒,转换之后可以得到至少 8600 个特征值。掐头去尾,取中间 8000 个值作为特征。
取 80% 的文件作为训练集,其他作为测试集。
代码如下:
import os
import wave
import numpy as np
import random
def file_name(file_dir):
"""
获取文件夹中所有文件文件名
"""
for _, _, files in os.walk(file_dir):
return files
def Read_WAV(wav_path):
"""
将声音文件转换为特征值
"""
wav_file = wave.open(wav_path,'r')
numframes = wav_file.getnframes() # 采样点数
Wav_Data = wav_file.readframes(numframes)
Wav_Data = np.fromstring(Wav_Data,dtype=np.int16)
return Wav_Data
# 读取数据
data = []
data_path = "./dataset/"
for f in file_name(data_path):
s = Read_WAV(data_path + f)
s = (s - min(s)) / (max(s) - min(s)) # 归一化处理
# 制作标签
if f[0] == 'B':
label = 0
elif f[0] == 'F':
label = 1
elif f[0] == 'I':
label = 2
else:
print("error " + f)
continue
# 取中间 8000 个值作为特征
begin = (s.shape[0] - 8000) // 2
s = s[begin : begin + 8000]
data.append([s, label])
random.shuffle(data) # 打乱数据
# 划分训练集和测试集
train_data = data[:352]
test_data = data[:352:]
复制代码
创建数据读取器
需要自定义一个 DataSet 类,并重写 __len__
和 __getitem__
方法
from megengine.data import DataLoader
from megengine.data.dataset import Dataset
from megengine.data.sampler import RandomSampler, SequentialSampler
# 自定义DataSet
class myDataSet(Dataset):
def __init__(self, data):
self.data = data
def __len__(self):
return len(self.data)
def __getitem__(self, index):
return self.data[index][0], self.data[index][1]
trainData = myDataSet(train_data)
testData = myDataSet(test_data)
batch_size=64
train_sampler = RandomSampler(trainData, batch_size=batch_size)
test_sampler = SequentialSampler(testData, batch_size=batch_size)
train_dataloader = DataLoader(trainData, train_sampler)
test_dataloader = DataLoader(testData, test_sampler)
复制代码
构建神经网络
构建一个简单的全连接神经网络。
import megengine.module as M
import megengine.functional as F
class myNet(M.Module):
def __init__(self):
super().__init__()
self.fc1 = M.Linear(8000, 2048)
self.fc2 = M.Linear(2048, 512)
self.fc3 = M.Linear(512, 64)
self.classifier = M.Linear(64, 3)
self.relu = M.ReLU()
def forward(self, x):
x = F.flatten(x, 1)
x = self.relu(self.fc1(x))
x = self.relu(self.fc2(x))
x = self.relu(self.fc3(x))
x = self.classifier(x)
return x
# 实例化网络
net = myNet()
复制代码
训练
开始训练网络了~
from megengine.optimizer import SGD
from megengine.autodiff import GradManager
import numpy as np
import megengine as mge
optimizer = SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=5e-4)
gm = GradManager().attach(net.parameters())
losses = []
net.train()
total_epochs = 300
for epoch in range(total_epochs):
total_loss = 0
for step, (batch_data, batch_label) in enumerate(train_dataloader):
batch_data = mge.tensor(batch_data)
batch_label = mge.tensor(batch_label).astype(np.int32)
with gm:
pred = net(batch_data)
loss = F.loss.cross_entropy(pred, batch_label)
gm.backward(loss)
optimizer.step().clear_grad()
total_loss += loss.numpy().item()
if epoch % 50 == 0:
print("epoch: {}, loss {}".format(epoch, total_loss/len(trainData)))
losses.append(total_loss/len(train_data))
复制代码
绘制 loss 曲线
可以看到,训练 300 个 epoch 后,loss 已经趋于稳定
但是 loss 并没有明显的下降...
import matplotlib.pyplot as plt
x = [i for i in range(len(losses))]
plt.plot(x, losses)
plt.show()
复制代码
评估模型
最终模型识别的准确率只有 51.42% QAQ
比起论文里其他方法 95% 的准确率,差得有点远
net.eval()
correct = 0
for step, (batch_data, batch_label) in enumerate(train_dataloader):
batch_data = mge.tensor(batch_data)
pred = net(batch_data)
pred = pred.numpy()
correct += np.sum(np.argmax(pred, axis= 1) == batch_label)
print(correct / len(test_data) * 100)
复制代码
总结
第一次使用 MegEngine 构建网络并进行训练,感觉训练速度很快,代码的编写流程和其他框架也很相似,还是很好上手的。
第一次使用,所以就只尝试了简单的全连接神经网络,得到的准确率也不是很好,之后可以尝试其他模型,提高准确率。