class image_loader() 类中的三个主要函数

image_loader() 该类中, 主要实现了三个函数;

1. def __init__():

def __init__(self, data_dir, folds_file, test_fold, train_flag, params_json, input_transform=None, stetho_id = -1, aug_scale=None):

该初始化函数的作用,

1.1 声明变量,

以及初始化变量, 方便该类中的方法 后续实现;

主要包括,音频参数的变量和语谱图参数的变量;

1. self.file_to_device:   该文件所对应的 听诊器设备;
2. slef.filenames:  样本的文件名;
3. self.audio_data:   用于存放, 将每个样本音频根据标注文本,切片出来后,每个呼吸音周期的标签, 文件名, 在样本中对应第几个cycle,  增强方式;
4. self.labels:  该呼吸音周期的标签;
5. self.train_flag: 是否训练; 
6. self.data_dir:   数据集路径
7. self.input_transform:   输入进行标准化, 减去均值,除以方差;

# 用于 语谱图的属性参数
1. self.sample_rate :
2. self.desired_length: 每个呼吸音周期统一的长度;
3. self.n_mels = 64 ? 待定, 滤波器个数?
4. self.nfft = 256 窗口函数的大小;
5. self.hop = self.nfft //2 :  两个窗口之间的重叠度大小;
6. self.f_max = 2000 ?  待定,最大截止频率?



# 用于 呼吸音的属性参数;
1. self.cycle_list : 存放每个呼吸音属于样本音频中的第几个周期;
2. self.classwise_cycle_list:  分四种呼吸音类别, 存放各个类别下,所对应的样本中的第几个呼吸音周期;
3. self.new_augment:   进行样本之间拼接, 生成新的样本,用于扩充数据集;
4. self.audio_data:  更新self.audio_data 将新生成的样本数据加入到其中;


#  统计各个属性的参数
1. self.device_wise:  用于统计该设备下,所对应的呼吸音的个数;
2. self.class_probs:  统计每类呼吸音的数目, 占总的四类呼吸音的比例;
3. self.identifiers:  用于定位呼吸音的信息, 包括文件名,位于该音频样本中的第几个呼吸音周期, 以及它所对应的标签;  

1. 2. 对整体数据集进行划分, 按照 5折划分;

其中训练集 选取其中的四折, 测试集为其中的一折;

这里,尤其需要注意到, 每一折中的病人不会交叉, 即一个病人的音频只会出现在某一折中, 而不会出现在其他折中。

所以,在训练集中, 后续所有的音频操作,都是对这4折中的数据进行操作,
而这些数据都不会在测试集中出现, 即某一个病人的数据 始终不会出现在,测试集中。

1.3 提取每个音频样本:

根据标注文本, 将其中的每个呼吸音周期提取出来,
通过调用 utils.py中的 get_sound_samples() 实现;
将所有音频(指训练集中的所有音频)根据标注信息进行划分,
提取出各个 标注段的呼吸音 作为样本。

1.4 根据条件判断, 是否使用数据扩充,

如果扩充,调用拼接函数new_augment, 进行数据扩充 (**创新点1 **);

1.5 统一所有呼吸音的周期长度,

将每个呼吸音通过智能补全的方法, (创新点2),
通过调用 utils.py中的 split_and_pad() 实现;

2. new_augment():

new_augment(self, scale):

该函数的作用:

1.扩充数据集, scale 参数代表扩充的倍数;
将每个类别的音频样本进行扩充;

以normal 类别的样本数目为基准,其他三个类别扩充到和其相同的样本数目下。

具体实现是: 通过在该类型下,将两个样本进行拼接,生成一个新的样本;

3. __getitem__():

__getitem__(self, index):

3.1. 呼吸音进行数据增强,

使用 50% 的概率, 对训练集中的 样本音频,进行数据增强;
方式将呼吸音周期随机拉伸或压缩,即加速和减速, vtlp;
调用utils.py中的 gen_augmented() 实现;

并且对增强后的音频, 重新使用对齐功能, 对齐到统一的 长度;
通过调用 utils.py中的 split_and_pad() 实现;;

3.2. 确保保证音频是一维数组个数,roll_audio():

沿着给定轴滚动数组元素。超出最后位置的元素将会滚动到第一个位置;

3.3. 将音频信号转换为语谱图,

并将语谱图变为3倍大小,

原始的语谱图大小, 是通过 [ n_mels, n_frames] 确定生成的;
根据原始的配置, n_mels = 64, n_frames = 250 , 计算得来;
n_frames = audio_len / hop_len;

注意到,原始的语谱图是一个单通道的 图片, 这里调用了
utils.py中的 create_mel_raw() 实现,
该函数中实现如下功能:

  1. 在fmin , fmax 之间 , 生成MEL 语谱图, (64, 250)

  2. 功率值转换成对数值, power_to_db

  3. 将对数值,进行归一化;

  4. 将单通道的数值, 映射成三通道的数值;

  5. 调整语谱图的大小, 行数, 和列数 同时扩大 3倍; (64, 250)---> (192, 750 )

  6. 将语谱图水平翻转, 原始的语谱图,低频出现在矩阵的第一行中;
    翻转之后, 从而低频在矩阵中最后一行, 符合人类从下往上, 低频到高频的特性;

3.4. 统计行数中的占0 比例,

智能裁剪, (创新点3
同样调用 create_mel_raw() 实现, 生成三通道语谱图

  1. 但是, 此次, 没有进行改变语谱图的大小; 保持 (64, 250) 大小;

  2. 将三通道的重新转换成单通道的语谱图, 灰度语谱图;

  3. 对该灰度语谱图,中所有数值小于10 的置成0;

行数从上到下(注意,翻转过后,最上面是高频, 即截止频率f_max )
开始统计, 统计当前行上, 当前 行中, 占0 的 比例,
当某一行中, 占 0 的比例小于 0.80 时,

则停止往下移动, 记录当前行数数值= row, 等于从 上往下的 行数;

3.5 切割三通道的语谱图

        if (row+1)*3 < audio_image.shape[0]:
            audio_image = audio_image[(row+1)*3:, :, :]

将上述 的行数 row * 3, 没有超出3通道的语谱图的总行数时(这是经过放大的语谱图)

则将 三通道的语谱图, 从 0 到 (row+1) *3 的 行数, 全部去除,
因为,进行三通道的扩充的时候 row *3, 使用的是 线性插值的方式;

3.6 统一语谱图大小 (重要)

        audio_image = cv2.resize(audio_image, (audio_image.shape[1], self.n_mels*3), interpolation=cv2.INTER_LINEAR)

由于之前, 针对不同的音频语谱图进行裁剪,

此时 每个呼吸音的语谱图的行数大小,不同,

为了进行统一, 将裁剪后的语谱图的行数, 重新统一成N_mels * 3 的大小,
中间的数值, 仍然使用线性插值的方式生成;

3.7 判断,是否保存语谱图的 图片

   `self.dump_images: `

3.8 使用 input_transform

个人,此时理解的 self.input_transform的作用是:

消除测试集 , 和 训练集的 数据分布的差异性;

然而, 要起到消除 差异性的作用,
则必须保证,self.input_transform 是在整个数据集上得来的,

而不应该, 只通过 训练集的数据, 得到该数值,
否则, 训练集和 测试集的 差异性 仍然存在;

  生成的是灰度图;
  对灰度图进行裁剪, 裁剪的时候根据每行中0的比例是否大于0.8, 如果大于0.8裁剪;

  1. 再次确认语谱图是统一的三倍大小;

  2. 保存语谱图的 图片,以RGB三通道形式;

  3. 确定标签, 是否对特征语谱图 进行标注化, 减均值, 除方差;

  4. 返回最终的语谱图, 标签;

4 __len__(self):

return len(self.audio_data)

统计所有类型中的音频样本个数;

posted on 2022-05-04 18:35  Hello_zhengXinTang  阅读(47)  评论(0)    收藏  举报