零基础入门声音识别

前言

这个项目是我高级人工智能的大作业,也是我第一次参加此类比赛,作为初学者,经过几天的学习,主要是参考大佬在论坛发的贴子,感觉收获很大,在这里记录一下,希望以后能像大佬们独立写出所有的代码。

参考代码:

零基础入门语音识别-食物声音识别-第六名比赛攻略_天池notebook-阿里云天池

  比赛入口:

零基础入门语音识别-食物声音识别_学习赛_天池大赛-阿里云天池的赛制 (aliyun.com)

项目任务

先对语音数据进行特征提取,搭建一个声音分类网络,进行分类任务,完成一个食物咀嚼的分类任务。

一、环境配置

import os
import librosa
import numpy as np
import pandas as pd
from tensorflow.keras.layers import Dense, Dropout
from tensorflow.keras.models import Sequential
from tensorflow.keras.models import load_model
from tensorflow.keras.utils import to_categorical
from tqdm import tqdm

二、数据查看

voice_path = 'train'

def look_data():
    # 音频类别文件夹个数
    print(f'音频文件夹的个数: {len(os.listdir(voice_path))}')

    voice_total = 0
    single_label = {}
    for ind, label_name in enumerate(os.listdir(voice_path)):
        file_path = voice_path + '/' + label_name
        single_num = len(os.listdir(file_path))
        single_label[label_name] = single_num
        voice_total += single_num

    print(f'音频文件总量: {voice_total}')
    print(f'{"序号":<5}{"类别":<15}{"数量":<10}{"占比"}')
    for ind, (key, value) in enumerate(single_label.items()):
        print(f'{ind:<5}{key:<20}{value:<10}{value / voice_total:.2%}')

look_data()

# 建立类别标签,不同类别对应不同的数字。
label = ['aloe', 'burger', 'cabbage', 'candied_fruits',
         'carrots', 'chips', 'chocolate', 'drinks', 'fries',
         'grapes', 'gummies', 'ice-cream', 'jelly', 'noodles', 'pickles',
         'pizza', 'ribs', 'salmon', 'soup', 'wings']
label_dict = dict(zip(label, range(len(label))))
label_dict

三、特征提取

首先是提取单个音频的特征,输入音频路径,输出(1,128)的特征。

def extract_features(path, rates=(1.0,)):
    """
    提取特征
    :param path: 音频文件路径
    :param rates: 拉伸系数,对音频进行缩放,音调不变。这里为了做数据增强
    :return: 不同的rate提取的特征
    """
    y_0, sr = librosa.load(path)
    # 缩放后的y
    y_list = [librosa.effects.time_stretch(y_0, rate=rate) for rate in rates]
    features = []
    for y in y_list:
        # 这里使用mfcc
        mel = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=128).T
        features.append(np.mean(mel, axis=0))
    return np.array(features)

提取训练集特征,返回音频特征X,音频特征Y。

def extract_features_train(parent_dir, max_file=10):
    """
    训练集提取特征
    :param parent_dir: 训练集文件夹的路径
    :param max_file: 每个类别最多处理的文件数
    :return: 训练集的X和Y
    """
    X, Y = [], []
    for sub_dir in label:
        _, _, filenames = next(os.walk(os.path.join(parent_dir, sub_dir)))
        for filename in tqdm(filenames[:max_file]):
            # 这里做了数据增强,拉伸系数0.5, 0.7, 1.0, 1.4, 2.0
            features = extract_features(os.path.join(parent_dir, sub_dir, filename), (0.5, 0.7, 1.0, 1.4, 2.0))
            for feature in features:
                X.append(feature)
                Y.append(label_dict[sub_dir])
    return [np.array(X), np.array(Y)]
root, dir, file_name = next(os.walk(path))
#os.walk 接收路径,返回3个迭代器:根目录、子目录、文件名
#next()接受迭代器,返回迭代器的下一个对象

提取测试集特征

def extract_features_test(parent_dir):
    """
    测试集提取特征
    :param parent_dir: 测试集路径
    :return: 测试集的X
    """
    X = []
    _, _, filenames = next(os.walk(parent_dir))
    for filename in tqdm(filenames):
        # 测试集不需要数据增强,所以没有传rates
        X.append(extract_features(os.path.join(parent_dir, filename))[0])
    return np.array(X)

 保存测试集的所有文件名字

def save_name():
    """
    将测试集的所有文件名保存为一个文件。
    因为数据集都为音频文件,占用空间过大,所以先预处理好,需要使用的时候,直接读取文件
    :return:
    """
    _, _, filenames = next(os.walk('./test_a'))
    with open('path', 'w') as f:
        f.writelines([filename + '\n' for filename in filenames])

 将训练集、测试集的特征提取之后,保存为npy文件

def save_features():
    """
    将训练集和测试集的特征提取之后,保存为npy文件。
    原因同save_name方法
    :return:
    """
    save_name()
    X, Y = extract_features_train('./train', 1000)
    print(X.shape)
    print(Y.shape)
    np.save('X.npy', X)
    np.save('Y.npy', Y)
    X_ = extract_features_test('./test_a')
    print(X_.shape)
    np.save('X_.npy', X_)

加载特征 npy文件

def load_features():
    """
    从文件加载保存的特征
    :return: 训练集X和Y,测试集X_
    """
    X = np.load('X.npy')
    Y = np.load('Y.npy')
    X_ = np.load('X_.npy')
    return X, Y, X_

三、建立模型 

def classifier():
    """
    建立模型
    :return: 模型
    """
    model = Sequential()
    # 由于n_mfcc=128,所以这里的Dense输入也为128维,激活函数使用的relu,经过尝试,效果好于tanh
    model.add(Dense(1024, input_dim=128, activation="relu"))
    # Dropout主要为了防止过拟合,这里随机去掉一半的特征进行预测
    model.add(Dropout(0.5))
    model.add(Dense(1024, activation="relu"))
    # 音频的分类为20类
    model.add(Dense(20, activation="softmax"))
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
    model.summary()
    return model

将结果保存为csv文件

def to_csv(model, X_, save_path='submit.csv'):
    """
    将结果保存为csv文件
    :param model: 训练好的模型
    :param X_: 测试集的特征
    :param save_path: 文件保存的路径
    :return:
    """
    predictions = model.predict(X_)
    preds = np.argmax(predictions, axis=1)
    preds = [label[x] for x in preds]
    path = []
    # 此处的path文件是save_name方法保存的
    with open("path") as f:
        for line in f:
            path.append(line.strip())
    result = pd.DataFrame({'name': path, 'label': preds})
    result.to_csv(save_path, index=False)

四、实施代码 

# 处理数据集,并保存为文件
save_features()
# 从文件中加载特征
X, Y, X_ = load_features()
# 对特征进行标准化处理
train_mean = np.mean(X, axis=0)
train_std = np.std(X, axis=0)
X = (X - train_mean) / train_std
X_ = (X_ - train_mean) / train_std
# 将类别转换为one-hot
Y = to_categorical(Y)
# 训练测试数据分离
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_ratio=0.1, seed=666)
# 建立模型
model = classifier()
# model.fit(X_train, y_train, epochs=200, batch_size=200, validation_data=(X_test, y_test))
# 此处由于模型已确定,所以使用所有的数据进行训练,而没有仅使用X_train, y_train
model.fit(X, Y, epochs=1000, batch_size=5000, validation_data=(X_test, y_test))
# model_path = 'model_1000_5000.h5'
# model.save(model_path)
# model = load_model(model_path)
to_csv(model, X_, 'submit.csv')

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值