adaboost 用于声纹128分类
将训练样本集中的某一类当成一类,其他的所有类当成另外一类,像上面的5类,我把最中间的一类当成是第一类,并重新赋予类标签为1,
而把四周的四类都认为是第二类,并重新赋予类标签维-1,好了现在的问题是不是就是二分类问题了?是的。那二分类好办,用之前的任何一个算法处理即可。
好了,这是把最中间的当成一类的情况下建立的一个分类器。同理,我们是不是也可以把四周任何一类自成一类,而把其他的统称为一类呀?当然可以,这样依次类推,
我们共建立了几个分类器?像上面5类就建立了5个分类器吧,好了到了这我们该怎么划分测试集的样本属于哪一类了?
注意测试集是假设不知道类标签的,那么来了一个测试样本,我把它依次输入到上述建立的5个分类器中,看看最终它属于哪一类的多,那它就属于哪一类了吧。
比如假设一个测试样本本来是属于中间的(假设为第5类吧),那么先输入第五类自成一类的情况,这个时候发现它属于第五类,记录一下5,
然后再输入左上角(假设为1类)自成一类的情况,那么发现这个样本时不属于1类的,而是属于2,3,4,5这几类合并在一起的一类中,那么它属于2,3,4,5中的谁呢?都有可能吧,
那么我都记一下,此时记一下2,3,4,5。好了再到有上角,此时又可以记一下这个样本输入1,3,4,5.依次类推,最后把这5个分类器都走一遍,就记了好多1~5的标签吧,
然后去统计他们的数量,比如这里统计1类,发现出现了3次,2,3,4都出现了3次,就5出现了5次,那么我们就有理由认为这个样本属于第五类
这些都是自己定义的函数文间,主要保存一些常量,将wav转化相应的mfcc:
import constants as c
from tools import get_mfcc, get_mfcc_1, get_f_bank_1
注意:这个是实验代码,只是阐述一下adaboost集成的思路,import的相关函数没有给出如何实现,仅仅知道输入和输出的结果就可以了,如果大家发现有什么地方代码错误,希望大家可以告诉我
# coding=utf-8
import os
import sys
import time
import numpy as np
import constants as c
import tensorflow as tf
from keras.models import load_model
from tools import get_mfcc, get_mfcc_1, get_f_bank_1
from model import conNet
import math
import torch
o_path = '/export/longfuhui/home/xin/npy_mfcc/src'
sys.path.append(o_path)
import tools_pt as npy_tool
import preprocess as npy_pre
o_path = '/export/longfuhui/home/xin/res__long/zeng/pytorch_version'
sys.path.append(o_path)
import ada_tools as res_tool
import ada_constants as res_con
import ada_mfcc_reader as res_wav
o_path = '/export/longfuhui/fpz/Voiceprint_recognition_rewrite-master/pytorch_version'
sys.path.append(o_path)
import ada_f_tools as fa_tool
import ada_f_constants as fa_con
import ada_f_mfcc_reader as fa_wav
'''
os.environ["MKL_NUM_THREADS"] = '12'
os.environ["NUMEXPR_NUM_THREADS"] = '12'
os.environ["OMP_NUM_THREADS"] = '12'
'''
'''
说话人识别
使用Acc作为指标
'''
'''
从中挑一类自成一类,然剩下的并不是自成一类,而是在挑一类自成一类,也就是说从训练样本中挑其中的两类来产生一个分类器。
像上述的5类,我先把1,2,类的训练样本挑出来,训练一个属于1,2,类的分类器,然后把1,3,挑出来训练一个分类器,再1,4再1,5再2,3,等等
(注意2,1与1,2一样的,所以省去了),那这样5类样本需要建立多少个分类器呢?n*(n-1)/2吧,这里就是5*4/2=10个分类器,可以看到比上面的5个分类器多了5个。
而且n越大,多的就越多。好了建立完分类器,剩下的问题同样采取投票机制,来一个样本,带到1,2建立的发现属于1,属于1类的累加器加一下,
带到1,3建立的发现也属于1,在加一下,等等等等。最后看看5个类的累加器哪个最大就属于哪一类
'''
'''
将训练样本集中的某一类当成一类,其他的所有类当成另外一类,像上面的5类,我把最中间的一类当成是第一类,并重新赋予类标签为1,
而把四周的四类都认为是第二类,并重新赋予类标签维-1,好了现在的问题是不是就是二分类问题了?是的。那二分类好办,用之前的任何一个算法处理即可。
好了,这是把最中间的当成一类的情况下建立的一个分类器。同理,我们是不是也可以把四周任何一类自成一类,而把其他的统称为一类呀?当然可以,这样依次类推,
我们共建立了几个分类器?像上面5类就建立了5个分类器吧,好了到了这我们该怎么划分测试集的样本属于哪一类了?
注意测试集是假设不知道类标签的,那么来了一个测试样本,我把它依次输入到上述建立的5个分类器中,看看最终它属于哪一类的多,那它就属于哪一类了吧。
比如假设一个测试样本本来是属于中间的(假设为第5类吧),那么先输入第五类自成一类的情况,这个时候发现它属于第五类,记录一下5,
然后再输入左上角(假设为1类)自成一类的情况,那么发现这个样本时不属于1类的,而是属于2,3,4,5这几类合并在一起的一类中,那么它属于2,3,4,5中的谁呢?都有可能吧,
那么我都记一下,此时记一下2,3,4,5。好了再到有上角,此时又可以记一下这个样本输入1,3,4,5.依次类推,最后把这5个分类器都走一遍,就记了好多1~5的标签吧,
然后去统计他们的数量,比如这里统计1类,发现出现了3次,2,3,4都出现了3次,就5出现了5次,那么我们就有理由认为这个样本属于第五类
'''
the_model_minE = 0.0004
the_model_minE = 0.5
MAX = 30 # 最大循环次数
Num_of_categories = c.N_CLASS # 几分类问题 设置为128
D = "/export/longfuhui/home/xin/mfcc_cnn"
npy_D = "/export/longfuhui/home/xin/npy_mfcc"
long_res = '/export/longfuhui/home/xin/res__long/zeng/pytorch_models/iden/m_128_batch32'
fa_mfcc = '/export/longfuhui/fpz/Voiceprint_recognition_rewrite-master/pytorch_models/iden/m_128/暂存/mfcc_wd5e-5_dp'
Us_Model = {
}
Us_Model["MFCC"] = {
'path': D + "/out/models/iden/iden_model_test_64" + '.h5'}
Us_Model["F-BANK"] = {
'path': D + "/out/models/iden/iden_model_test_F_64" + ".h5"}
Us_Model["npy_MFCC"] = {
'path': npy_D + "/out/models/iden/iden_model_richdata.h5"}
Us_Model["long_res"] = {
'path': long_res + "/mfcc_iden_model_128_lr0.0001_acc0.6515_loss2.5757.bin"}
Us_Model["fa_mfcc"] = {
'path': fa_mfcc + "/mfcc_iden_model_128_lr1e-05_acc0.8179_loss0.7357.bin"}
if torch.cuda.is_available():
print("\nusing cuda\n")
device = torch.device('cuda')
else:
device = torch.device('cpu')
# Us_Model[i] 为第几个训练好的模型
# 可能要修改 不同环境的加载代码不同
def load_all_model(): # 将已有模型全部一次加载进来
for i in Us_Model.keys():
print("Load model form {}".format(Us_Model[i]['path']))
if (i == "long_res"):
model = torch.load(Us_Model["long_res"]["path"]).to(device)
model.eval()
Us_Model[i]["model"] = model
elif (i == "fa_mfcc"):
model = torch.load(Us_Model["fa_mfcc"]["path"]).to(device)
model.eval()
Us_Model[i]["model"] = model
else:
Us_Model[i]["model"] = load_model(Us_Model[i]['path'], custom_objects={
'tf': tf})
# {'ss': {'path': 'aaa', 'model': 'aaa'}, 'saaa': {'path': 'bb', 'model': 'bb'}}
# 加入模型后需要修改这个
def com_all_model(md, train_or_test=True): # 返回对应模型的预测
if (md == "MFCC"):
print("MFCC")
elif (md == "F-BANK"):
print("F-bank")
elif (md == "npy_MFCC"):
print("npy_MFCC")
elif (md == "long_res"):
print("long_res")
elif (md == "fa_mfcc"):
print("fa_mfcc")
if (train_or_test):
com = Us_Model[md]["p_label"] # 得到对应弱分类器的预测
else:
com = Us_Model[md]["p_label_test"] # 得到对应弱分类器的预测
return com
# 加入模型后需要修改这个 这里面要修改两个地方
def pre_all_model(voice_list, train_or_test): # 将已有的全部模型的预测值得到
# res, p_labels, pf_labels = [], [], [] # p_label 保存的是为预测属于哪一类
if (train_or_test): # 当前为train一个adaboost
for i in Us_Model.keys():
Us_Model[i]["p_label"] = [] # 初始化
# {'mfcc':{..., 'p_label': []}}
# 修改
for cc, ID in enumerate(voice_list):
# if cc % 100 == 0: print('Finish identifying for {}/{}th wav.'.format(cc, total_length))
for i in Us_Model.keys():
if (i == "MFCC"):
mfcc = get_mfcc_1(ID)
v = Us_Model[i]["model"].predict(
mfcc.reshape(1, *mfcc.shape)) # mfcc.reshape(1, *mfcc.shape, 1) # 输入:测试数据 输出:预测结果
v = np.squeeze(v)
elif (i == "F-BANK"):
mfcc = get_f_bank_1(ID)
v = Us_Model[i]["model"].predict(
mfcc.reshape(1, *mfcc.shape)) # mfcc.reshape(1, *mfcc.shape, 1) # 输入:测试数据 输出:预测结果
v = np.squeeze(v)
elif (i == "npy_MFCC"):
# mfcc = npy_pre.transform_data(ID)
mfcc = npy_tool.get_mfcc_2(ID)
v = Us_Model[i]["model"].predict(
mfcc.view(1, *mfcc.shape).numpy())
v = np.squeeze(v)
elif (i == "long_res"):
reader = res_wav.WavtoMfcc(ID, 13, "test")
mfcc = reader.readwav().to(device)
mfcc = mfcc.type(torch.cuda.FloatTensor)
v = Us_Model[i]["model"](mfcc).cpu()
v = np.squeeze(v).detach().numpy()
elif (i == "fa_mfcc"):
reader = fa_wav.WavtoMfcc(ID, 13, "test")
mfcc = reader.readwav().to(device)
mfcc = mfcc.type(torch.cuda.FloatTensor)
v = Us_Model[i]["model"](mfcc, 0, 1, c.N_CLASS).cpu()
v = np.squeeze(v).detach().numpy()
Us_Model[i]["p_label"].append(np.argmax(v)) # pf_label 保存的是为预测属于哪一类 多分类
# 修改
else: # 当前为测试adaboost
for i in Us_Model.keys():
Us_Model[i]["p_label_test"] = []
# {'mfcc':{..., 'p_label': []}}
for cc, ID in enumerate(voice_list):
# if cc % 100 == 0: print('Finish identifying for {}/{}th wav.'.format(cc, total_length))
for i in Us_Model.keys():
if (i == "MFCC"):
mfcc = get_mfcc_1(ID)
v = Us_Model[i]["model"].predict(
mfcc.reshape(1, *mfcc.shape)) # mfcc.reshape(1, *mfcc.shape, 1) # 输入:测试数据 输出:预测结果
v = np.squeeze(v)
elif (i == "F-BANK"):
mfcc = get_f_bank_1(ID)
v = Us_Model[i]["model"].predict(
mfcc.reshape(1, *mfcc.shape)) # mfcc.reshape(1, *mfcc.shape, 1) # 输入:测试数据 输出:预测结果
v = np.squeeze(v)
elif (i == "npy_MFCC"):
mfcc = npy_tool.get_mfcc_2(ID)
v = Us_Model[i]["model"].predict(
mfcc.view(1, *mfcc.shape).numpy())
v = np.squeeze(v)
elif (i == "long_res"):
reader = res_wav.WavtoMfcc(ID, 13, "test")
mfcc = reader.readwav().to(device)
mfcc = mfcc.type(torch.cuda.FloatTensor)
v = Us_Model[i]["model"](mfcc).cpu()
v = np.squeeze(v).detach().numpy()
elif (i == "fa_mfcc"):
reader = fa_wav.WavtoMfcc(ID, 13, "test")
mfcc = reader.readwav().to(device)
mfcc = mfcc.type(torch.cuda.FloatTensor)
v = Us_Model[i]["model"](mfcc, 0, 1, c.N_CLASS).cpu()
v = np.squeeze(v).detach().numpy()
Us_Model[i]["p_label_test"].append(np.argmax(v)) # pf_label 保存的是为预测属于哪一类 多分类
# 转化成array
for i in Us_Model.keys():
if (train_or_test):
Us_Model[i]["p_label"] = np.array(Us_Model[i]["p_label"])
else:
Us_Model[i]["p_label_test"] = np.array(Us_Model[i]["p_label_test"])
def adaboost(voice_list, Model, labels):
total_length = len(voice_list) # 训练集的个数
Am = [] # 保存所有的二分类器adaboost权重 【【一个模型的子权重】,【】】
# 对多分类进行实现二分类的adaboost
# for Fir_class in range(Num_of_categories - 1): # 多分类问题,一个类构建一个二分类器
for Fir_class in range(Num_of_categories): # 多分类问题,一个类构建一个二分类器
am = [] # 模型的系数
# 对一次的二分类进行训练 注意此循环为二分类
wm = np.ones(total_length) / total_length # 初始化样本权重
for I in range(MAX): # 进行迭代
minE = np.inf # 初始的最小误差设为无穷
Best_pre = [] # 对训练集的预测 +1 -1 # 当模型预测为正确的值且这个值为我们的 Fir_class 的时候
# 对两个模型分别进行训练
for md in Us_Model.keys(): # 对与所有模型
Pre = [] # 在每次对这个预测清空
com = com_all_model(md) # 使用函数 得到对应弱分类器的预测
em = 0 # 找到误差最小的分类方式
err_0 = 0
err_1 = 0
for i in range(len(labels)):
if (labels[i] == Fir_class and com[i] != Fir_class) or (
labels[i] != Fir_class and com[i] == Fir_class): # 分错误 I(Gm(xi)≠yi)
em += wm[i]
Pre.append(-1)
if (labels[i] == Fir_class): # 说明把这一类的分出去了
err_0 += 1
elif (com[i] == Fir_class): # 说明把错误的分进来了
err_1 += 1
else:
Pre.append(1)
print("这一类的分出去了: ", err_0)
print("把错误的分进来了: ", err_1)
if em < minE:
minE = em
print("Model_min: ", md)
The_bese_md = md
Best_pre = Pre # 得到每个样本的在一个二分类子模型的 正误结果 退出循环时为最好的结果
Model.append(The_bese_md)
# 结束查找最合适的子模型
alpha = float(
0.5 * np.log((1 - em) / max(em, 1e-16))) # 计算弱分类器权重alpha 根据公式 max(error, 1e-16)) 是避免分母为0
print("alpha = ", alpha)
am.append(alpha) # 将弱分类器的权重保存
print(I, " minE is: ", minE)
print("minE = ", minE)
# 判断是否满足退出条件
if minE < the_model_minE: # 当em<0.5时结束
print("I is over: ", I)
break
# 计算样本权重
Zm = 0
for i in range(total_length):
if labels[i] == Fir_class:
yi = 1
else:
yi = -1
Zm += wm[i] * np.exp(-1 * yi * alpha * Best_pre[i]) # Zm=∑ni=1wmiexp(−yiαmGm(xi))
# 更新样本权重
wm = np.array([(wm[i] * np.exp(-1 * yi * alpha * Best_pre[i])) / Zm for i in range(len(wm))])
# 迭代结束,构造了一个adaboost二分类器
print('the 模型系数 am is ', am)
Am.append(am) # 保存下来为[[一个模型的所有子模型权重], []]
print("*" * 200)
return Am
# 结束了构造了多个adaboost二分类
def model_acc(Am, Model, labels, train_or_test):
# 对全部的模型遍历
right = 0
for one in range(len(labels)): # 对每个样本
statistics = [0] * (Num_of_categories) # 每个样本的预测分类
Finally = [0] * (Num_of_categories)
All_Am = [i for ee in Am for i in ee] # 让弱分类器的权重 全放在一个列表中
# 用sum bre计算当前为第几个分类的强分类器
sum = len(Am[0])
bre = 0
# Model 里面是所有的弱分类器
for I in range(len(Model)): # 遍历已经构造了多个的adaboost二分类模型 预测一个样本的标签 Model [, , , , ] Am [[一类强分类器中各个若模型权重], []]
# 构建的强分类器 中的 弱分类器每一个 进行得到 对应的预测com
if Model[I]: # 得到对应 子模型 的分类结果, 之后乘上对应模型的权重
com = com_all_model(Model[I], train_or_test)[one] # 使用函数 得到对应弱分类器的预测
# 计算当前为第几个分类的强分类器
if I >= sum:
bre += 1 # 这个是一个标签, 标记此时为为第几个类强分类 下的弱分类器
sum += len(Am[bre])
# print("bre", bre)
# 对所有的弱分类器,这些弱分类器 有的为一类的, 有的为另一类的 用bre标记为哪一类的弱分类器
# 用这个弱分类器预测, 其结果和
if com == bre: # 二分类的弱分类预测的为 1
statistics[bre] += All_Am[I]
else:
statistics[bre] -= All_Am[I]
####
####
# if (labels[one] == I and com[one] != I) or (
# labels[one] != I and com[one] == I): # 对one这个序号的样本 分类错误 I(Gm(xi)≠yi)
# statistics[one] -= am[I]
# else:
# statistics[one] += am[I]
# 判断对该样本是否分类正确
print(
one, " tatistics.index(max(statistics))", statistics.index(max(statistics)), " labels[one]",
labels[one])
if statistics.index(max(statistics)) == labels[one]:
right += 1
print()
print("the result = {%.2f}" % (right / len(labels)))
def iden(testfile, fa_data_dir, iden_model, mode):
Model = [] # 里面 保存了全部模型的弱分类器 【 , , ,】
Num_of_categories = c.N_CLASS
# 读入训练数据、标签
print("mode: ", mode)
print("Use {} for test".format(testfile))
iden_list = np.loadtxt(testfile, str, delimiter=",")
labels = np.array([int(i[1]) for i in iden_list])
voice_list = np.array([os.path.join(fa_data_dir, i[0]) for i in iden_list])
print("began start getting strong classifiers\n\n")
load_all_model() # 加载模型权重
train_or_test = True # 代表着train 训练adaboost test 当前为测试adaboost
pre_all_model(voice_list, train_or_test) # 进行得到弱分类器预测
Am = adaboost(voice_list, Model, labels) # 得到强分类器
print('*' * 10, " arr ", "*" * 10, '\n')
# statistics = [0] * (Num_of_categories) # 分类
model_acc(Am, Model, labels, train_or_test) # 强分类器求得acc
###### 测试 ######
print("test")
print("mode: ", c.MODE)
print("Use {} for test".format(c.IDEN_TEST_FILE))
iden_list = np.loadtxt(c.IDEN_TEST_FILE, str, delimiter=",")
labels = np.array([int(i[1]) for i in iden_list])
voice_list = np.array([os.path.join(c.FA_DIR, i[0]) for i in iden_list])
print("Start identifying...")
train_or_acc = False # 代表着train T 训练adaboost acc F 当前为测试adaboost
pre_all_model(voice_list, train_or_acc) # 进行得到弱分类器预测
train_or_test = False
model_acc(Am, Model, labels, train_or_test) # 对模型进行测试
if c.MODE == "train":
print("must be test mode!")
c.MODE = 'test'
iden(c.IDEN_TRAIN_LIST_FILE, c.FA_DIR, c.IDEN_MODEL_LOAD_PATH, c.MODE) # 对训练集