pytorch实现音频分类代码
这两天学习了下pytorch,动手练习练习数据集:来源是KAGGLE的一个音频分类的比赛数据集介绍:(需要梯子)https://urbansounddataset.weebly.com/urbansound8k.html数据集分为10类:代表不同的声音 在我下载的文件里面是这样的结构 外面是一个train 里面是train.csv 以及Train Train里面包含了一堆音频WAV文件训练集文件结构train.csv文件结构
Keras实现
话说还是Keras好用,可能我才接触torch的原因吧,BUG改来改去的写了一堆,还不及Keras几行代码管用。 这里先上下Keras的实现代码网络结构 跑出来的效果,看的出来效果还是可以的 ,过我在写torch的时候发现交叉熵损失居然不支持one-hot编码,害我改了半天BUG,被迫使用了均方误差,最终跑出来效果差了很多,只有92%的acc随机选取一条测试的结果
torch实现分类代码以及详细解释
首先导入一波必要的库
import IPython
.display
as ipd
import librosa
import glob
import os
import pandas
as pd
import random
import librosa
.display
import matplotlib
.pyplot
as plt
import numpy
as np
from sklearn
.preprocessing
import LabelEncoder
from keras
.utils
import np_utils
from torch
.utils
.data
import Dataset
,DataLoader
,TensorDataset
import torch
import torch
.nn
.functional
as F
import torch
.nn
as nn
import torch
.optim
as optim
import pickle
随机抽取数据查看
接下来读取下csv文件,并随机抽取一条出来看看数据是什么样子的数据集的数据基本都是4s,我这里用的都是是默认采样率22050/s,包括后面的特征提取也是用的默认采样率
train
=pd
.read_csv
("train/train.csv",sep
=',')
查看训练集分布
看完数据再让我们看看数据集的分布,这里利用了pandas的计算类别的功能数据稍微有点不平衡,不过影响不大
对数据批量预处理以及保存
提取音频数据的特征的方式有很多,我这里比较简单用的是mfcc,固定40个 train.apply是pandas中批处理的一个方法,会返回一个pandas.DataFrame对象,里面存放着feature和label
def parser(row
):
file_name
=os
.path
.join
('train','Train',str(row
.ID
)+'.wav')
try:
x
,sample_rate
=librosa
.load
(file_name
)
mfccs
= np
.mean
(librosa
.feature
.mfcc
(y
=x
, sr
=sample_rate
, n_mfcc
=40).T
,axis
=0)
except Exception
as e
:
print("error",file)
return None,None
features
=mfccs
label
=row
.Class
return [features
,label
]
temp
=train
.apply(parser
,axis
=1,result_type
='expand')
在上面的apply跑完以后我们就可以得到temp对象,查看一下这个数据 由于数据比较多,处理要几分钟,每次打开都跑一遍不方便,所以我用pickle把变量保存下来方便以后读取pickle是个好东西,谁用谁知道,使用方法如下
处理标签为one-hot编码
由于这里的标签还是str类型的东西,我这里把他处理为one-hot编码而torch并没有这种方法,所以我只能使用keras的工具类来处理了
定义dataloader以及网络结构
定义的dataloader
class Dataset(Dataset
):
def __init__(self
,x
,y
,use_gpu
):
self
.x
=torch
.tensor
(x
)
self
.y
=torch
.tensor
(y
)
if use_gpu
:
self
.x
=self
.x
.to
("cuda")
self
.y
=self
.y
.to
("cuda")
self
.len=x
.shape
[0]
def __getitem__(self
,index
):
return self
.x
[index
],self
.y
[index
]
def __len__(self
):
return self
.len
定义的分类网络结构
class Classify(nn
.Module
):
def __init__(self
):
super(Classify
,self
).__init__
()
self
.fc1
=nn
.Linear
(40,64)
self
.dp
=nn
.Dropout
(0.03)
self
.fc2
=nn
.Linear
(64,20)
self
.fc3
=nn
.Linear
(20,10)
def forward(self
,x
):
x
=F
.relu
(self
.fc1
(x
))
x
=self
.dp
(x
)
x
=F
.relu
(self
.fc2
(x
))
x
=F
.relu
(self
.fc3
(x
))
x
=F
.softmax
(x
,dim
=1)
return x
定义训函数和测试函数
训练函数
def train(train_loader
,model
,loss_fun
,optimizer
,epoches
,use_gpu
):
if use_gpu
:
model
=model
.cuda
()
loss_fun
=loss_fun
.cuda
()
acc
=0
all_loss
=0
for i
in range(epoches
):
for j
,data
in enumerate(train_loader
):
x
,y
=data
y_pre
=model
(x
)
loss
=loss_fun
(y_pre
,y
)
all_loss
+=loss
.item
()
values
,indices
=torch
.topk
(y_pre
,k
=1)
values2
,indices2
=torch
.topk
(y
,k
=1)
res
=(indices
==indices2
)
acc
+=torch
.sum(res
).item
()
optimizer
.zero_grad
()
loss
.backward
()
optimizer
.step
()
print("epoch{}--acc:{}-{:.4%}--loss:{}".format(i
,acc
,acc
/all_data_en
,all_loss
))
acc
=0
all_loss
=0
定义验证函数
def validate(val_loader
,model
,use_gpu
):
if use_gpu
:
model
=model
.cuda
()
model
.eval()
acc
=0
with torch
.no_grad
():
for _
,(inputs
,y
) in enumerate(val_loader
):
if use_gpu
:
inputs
=inputs
.cuda
()
y
=y
.cuda
()
y_pre
=model
(inputs
)
values
,indices
=torch
.topk
(y_pre
,k
=1)
values2
,indices2
=torch
.topk
(y
,k
=1)
res
=(indices
==indices2
)
acc
+=torch
.sum(res
).item
()
print("acc:{:.4%}".format(acc
/all_data_en
))
训练模型
定义一些初始变量
use_gpu
=True if torch
.cuda
.is_available
() else False
model
=Classify
()
optimizer
=torch
.optim
.Adam
(model
.parameters
())
loss_fun
=nn
.MSELoss
()
epoches
=100
dataset
=Dataset
(x
,y
,use_gpu
)
train_loader
=DataLoader
(dataset
,batch_size
=6)
开始训练
train
(train_loader
,model
,loss_fun
,optimizer
,epoches
,use_gpu
)
训练结果、这是我跑了几次后再跑的,所以一开始acc就很高
保存、加载模型与测试
保存模型
torch
.save
(model
,"torchmodel.pth")
加载模型话说torch的加载模型,如果在其他文件中load居然还要重新定义一遍网络结构?还是keras直接load方便,啥都不用管。这里由于还是同一个文件所以直接load就ok了
model
=torch
.load
("torchmodel.pth")
测试模型
use_gpu
=True if torch
.cuda
.is_available
() else False
train_loader
=DataLoader
(dataset
,batch_size
=all_data_en
)
validate
(train_loader
,model
,use_gpu
)
吐了,写这么多代码效果一般般