【代码吸猫】神经网络喵语识别

一起用代码吸猫!本文正在参与【喵星人征文活动】

喵语数据集

链接: 数据集 论文

米兰大学计算机系的研究人员收集了两个品种(缅因州库恩猫和欧洲短毛猫)的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()
复制代码

loss曲线

评估模型

最终模型识别的准确率只有 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 构建网络并进行训练,感觉训练速度很快,代码的编写流程和其他框架也很相似,还是很好上手的。

第一次使用,所以就只尝试了简单的全连接神经网络,得到的准确率也不是很好,之后可以尝试其他模型,提高准确率。

结束表情

猜你喜欢

转载自juejin.im/post/7031454634413654052