hw-2 李宏毅2022年作业2 phoneme识别 单strong-hmm详细解释。
目录
系列文章
目录
前言 :
作业二 真的很难 。而且会出现训练集没办法过拟合的情况 也就是训练集准确度没办法到百分之百 数据太多了 。 向实验室申请了一台服务器来跑这个作业,最后在kaggle上 pub达到了strong pri没有 哭了 试了好久都不太行。
但还是试着写写思路吧。git地址 和kaggle网址
项目:
我的习惯 一般会把一个小项目做成下面的几个模块 这样非常的清晰
第一个就是数据模块 , 这部分的作用是读入数据。 接口输入是数据地址 返回的是各种loader
第二个是模型模块 。没啥好说的 ,就是创造模型。接口输入是特征数和分类数(分类任务), 出口是模型。
第三个是训练模块 。 这一部分要传入训练集 验证集 和超参数。步骤就是 梯度归0 模型前向过程得到预测结果 预测和标签比得到loss loss回传。模型更新。还有一些记录。 训练过后有一个验证过程 , 让模型在验证集上跑 ,最后得到验证集准确率。
第四个是验证模块。一般负责从模型和测试数据出发,得到想要验证的数据 。
第五个是main函数 。 整合各个模块 进行数据模型的传递。
我觉得模块化是非常有必要的 ,我一直想做一个万能模块。特别是数据部分,后来发现,想多了,面对每一个项目 总是免不了微调。大家可以逐渐形成自己的模块。
一: 数据 :
看到 数据一段编码好了的 声音片段 。 每一段是39长度的向量。 然后会给出前后五段的 数据 也就是我们有11*39 = 429 维度的一个特征 根据这个特征去做分类 。 有多少类呢 ?有39类 。数据被放在一个.npy的numpy文件中 。跟上次一样, 先创建一个读数据的dataset
把x,y读进来 把y转为int型
dataset 是非常基础的 init负责把数据读进来 getitem 负责在访问数据集时返回数据 我们返回的是float类型的特征数据 和longtensor的标签 len负责返回长度 。。 用这个文件做数据很简单。直接放完整代码 。 这部分被我放在model.utils 中的data里
二: 模型
很基础的一个模型 就是fc+relu+dropout 我不知道怎么样去改出来一个好模型 只是感觉 都差不多。
这部分被我放在model.utils 中的model里
三 : 训练和评估
这部分和之前几乎一样 。我就不放代码了 可以去git下
四:main函数和训练过程
超参和模型设置 以及创造loader
创造优化器和loss 然后训练
1 训练过程中 会发现训练集的准确率比测试集还高。 这是因为我们有drop过程。
2 验证准确度会与drop率有关 大家不要迷信准确率。 最后我上面这个模型验证准确在百分之88.5左右就上不去了 。我是训练了 1000个epoch。
3 换了好几个优化器 换了好几个lr 最后结果总是上不去, 然后上传到kaggle 上 得到的分数是 0.741
五 后处理 。
很早就得到了这个结果 却差别人一大截。 然后在网上找到了一个大佬做的视频。
然后跟着大佬的思路 (抄他的代码),把结果提了两个点。 然后我来尽量讲一下这个思路 。 实在是太难了 。这个思路就是HMM, hmm是什么 大家可以参考这里。记得跟着这个链接里的算一次。就算没看懂,也要把他是怎么算出结果的。用手把步骤写出来、下面我尽量带大家理解我的想法。好吧 我也不确定我的想法对。
其实hmm感觉上是什么呢 ? 就感觉是天下大势和小家之势的相互关系。 天下有大势,当你实力强时,你就可以不完全被大势挟裹,但是如果你实力微弱,就会被卷入其中。
后处理的代码如下。这串代码非常的难看懂。一定要仔细调试并与上面的例子结合起来看。
1 加载训练标签。
2 统计转移矩阵。 trains_table[i,j]位置的元素 表示在所有标签里,从i到j的个数。统计后,在每行进行归一化, 就得到从当现在的标签是i 他下一个是其他标签各个的概率。
3:得到发射矩阵。 这就是小家小势了 。也就是模型预测的置信度多高。如果你模型预测一个结果的置信度是0.99 那么相信天下大势也很难影响你。test_ln_softmax有451552行 每行都是每一类的预测概率。
4:将他们log化 这里应该是为了乘起来快一点。 大家都知道 log的加就相等于数字相乘。反正我们只是比较相对大小。所以这里log后可以用加法代替乘法。
5: 定义路径和初始状态。
6: 计算过程 开始计算了 。
这一句相当于上面例子里的这一段。前一个是y0的概率然后乘以从y0转到yi的概率 再乘以现在这个表现为yi的概率。 我们就得到了在前一个表现为y0的情况下,这个表现为yi的概率。 我们会得到39个。我们来细看 这一句到底是怎么算的。
laststate 就是前面一天 表现为yi的概率 。 长度是39 代表了每一类。但是这里有 reshape(39,1) 就表示变成了39行。 transtabnle是一个39乘以39的矩阵。这两个矩阵相加,就要对latestate进行行扩充。 下面的0 就表示 预测值为0的概率。
再看 下面两个的相加 我们知道 其实就是相乘 tran的每个位置i,j都是i到j的概率。那么 相加之后的矩阵意思就是 如果上一天是yi 今天表现为yj的概率。
test_ln_softmax[i] 是一个1*39长的向量 他每个位置意思是不管天下大势 我表现为 y?的概率 。由于他要和39*39的矩阵相加 所以他也要扩充。
所以这三个矩阵相加 i,j位置的值 就表示 综合了天下大势和小家局势。 后 前一天是i今天是j的概率。
取列的最大值。 那么固定的是j的值 如果j=0 就是意思找 昨天预测值是多少时 今天能得到0的概率最高。 此时那个概率的值时多少。 但找齐每一列后 current_state(1,39) 中每一个值的意思就变成了 这天得到预测值j的概率是多大。(我们把最大的那个,选择相信他。)
列最大值所在行是哪一行。 这个就是位置了。 第j个位置的数字表明 昨天取预测值track【j】时, 今天得到预测值j的概率最大。 也就是统计一个路径。
更新状态。也就是把今天概率看成上一天的概率,看下一天。
track 是一个 长451551 宽39的矩阵。 有45万行 表示45万天 然后有39 列 第j表示 昨天取预测值track【j】时, 今天得到预测值j的概率最大。
我们选择最后一天的那个数字 带入。 这个数字 就是最后一天的发射值。比如这个值是38(正常大家得到的值应该是25) 我们就要去找 38位的值 发现这一位上还是38 那么意思就是 昨天取38时 今天取38的概率最大。 所以预测值里就要加入38 但这里我们是倒序加入,最后要反过来。
到这里 发现38位上写的 7 说明上天是7 今天取38概率最大。然后找到上天的7 继续这个步骤 。
也就是说 按照track这条路去走 是最有可能的 。 所以就取这条路提交。 得到最后的结果。hmm后会比正常提交提高两个百分点左右。
而hmm那个晴天阴天的例子 用第一天的转移用 上面的 代码大概就是 下面这样
import numpy as np a = np.array([0.06,0.24]) b = np.array([[0.7,0.3],[0.4,0.6]]) c = np.array([0.4,0.3]) print(a.reshape(2,1)*b*c)