adaboost用于多分类 --- 实验代码

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)  # 对训练集

你可能感兴趣的:(python杂记,机器学习,python,算法,人工智能)