python
1def ComputeFBANK(self, waveform):2 '''メルフィルタバンク特徴(FBANK)を計算する 3 出力1: fbank_features: メルフィルタバンク特徴 4 出力2: log_power: 対数パワー値(MFCC抽出時に使用) 5 '''6 # 波形データの総サンプル数7 num_samples = np.size(waveform)8 # 特徴量の総フレーム数を計算する9 num_frames = (num_samples - self.frame_size) // self.frame_shift + 110 # メルフィルタバンク特徴11 fbank_features = np.zeros((num_frames, self.num_mel_bins))12 # 対数パワー(MFCC特徴を求める際に使用する)13 log_power = np.zeros(num_frames)14 15 # 1フレームずつ特徴量を計算する16 for frame in range(num_frames):17 # 分析の開始位置は,フレーム番号(0始まり)*フレームシフト18 start_index = frame * self.frame_shift 19 # 1フレーム分の波形を抽出し,前処理を実施する.20 # また対数パワーの値も得る21 window, log_pow = self.ExtractWindow(waveform, start_index, num_samples)22 23 # 高速フーリエ変換(FFT)を実行24 spectrum = np.fft.fft(window, n=self.fft_size)25 # FFT結果の右半分(負の周波数成分)を取り除く26 # ※Kaldiの実装ではナイキスト周波数成分(最後の+1)は捨てているが,27 # 本実装では捨てずに用いている28 spectrum = spectrum[:int(self.fft_size/2) + 1]29 30 # パワースペクトルを計算する31 spectrum = np.abs(spectrum) ** 232 33 # メルフィルタバンクを畳み込む34 fbank = np.dot(spectrum, self.mel_filter_bank.T)35 36 # 対数計算時に-infが出力されないよう,フロアリング処理を行う37 fbank[fbank<0.1] = 0.138 39 # 対数をとってfbank_featuresに加える40 fbank_features[frame] = np.log(fbank)41 42 # 対数パワーの値をlog_powerに加える43 log_power[frame] = log_pow 44 45 return fbank_features, log_power 46 47 48 def MakeDCTMatrix(self):49 ''' 離散コサイン変換(DCT)の基底行列を作成する 50 '''51 N = self.num_mel_bins 52 # DCT基底行列 (基底数(=MFCCの次元数) x FBANKの次元数)53 dct_matrix = np.zeros((self.num_ceps,self.num_mel_bins))54 for k in range(self.num_ceps):55 if k == 0:56 dct_matrix[k] = np.ones(self.num_mel_bins) * 1.0 / np.sqrt(N)57 else:58 dct_matrix[k] = np.sqrt(2/N) \ 59 * np.cos(((2.0*np.arange(N)+1)*k*np.pi) / (2*N))60 61 return dct_matrix 62 63 64 def MakeLifter(self):65 ''' リフタを計算する 66 '''67 Q = self.lifter_coef 68 I = np.arange(self.num_ceps)69 lifter = 1.0 + 0.5 * Q * np.sin(np.pi * I / Q)70 return lifter 71 72 73 def ComputeMFCC(self, waveform):74 ''' MFCCを計算する 75 '''76 # FBANKおよび対数パワーを計算する77 fbank, log_power = self.ComputeFBANK(waveform)78 79 # DCTの基底行列との内積により,DCTを実施する80 mfcc = np.dot(fbank, self.dct_matrix.T)81 82 # リフタリングを行う83 mfcc *= self.lifter 84 85 # MFCCの0次元目を,前処理をする前の波形の対数パワーに置き換える86 mfcc[:,0] = log_power 87 88 return mfcc 89 90#91# メイン関数92#93if __name__ == "__main__":94 95 #96 # 設定ここから97 #98 99 # 各wavファイルのリストと特徴量の出力先100 train_small_wav_scp = '../data/label/train_small/wav.scp'101 train_small_out_dir = './fbank/train_small'102 train_large_wav_scp = '../data/label/train_large/wav.scp'103 train_large_out_dir = './fbank/train_large'104 dev_wav_scp = '../data/label/dev/wav.scp'105 dev_out_dir = './fbank/dev'106 test_wav_scp = '../data/label/test/wav.scp'107 test_out_dir = './fbank/test'108 109 # サンプリング周波数 [Hz]110 sample_frequency = 16000111 # フレーム長 [ミリ秒]112 frame_length = 25113 # フレームシフト [ミリ秒]114 frame_shift = 10115 # 低周波数帯域除去のカットオフ周波数 [Hz]116 low_frequency = 20117 # 高周波数帯域除去のカットオフ周波数 [Hz]118 high_frequency = sample_frequency / 2119 # メルフィルタバンク特徴の次元数120 num_mel_bins = 40121 # ディザリングの係数122 dither=1.0123 124 # 乱数シードの設定(ディザリング処理結果の再現性を担保)125 np.random.seed(seed=0)126 127 # 特徴量抽出クラスを呼び出す128 feat_extractor = FeatureExtractor(129 sample_frequency=sample_frequency, 130 frame_length=frame_length, 131 frame_shift=frame_shift, 132 num_mel_bins=num_mel_bins, 133 low_frequency=low_frequency, 134 high_frequency=high_frequency, 135 dither=dither)136 137 # wavファイルリストと出力先をリストにする138 wav_scp_list = [train_small_wav_scp, 139 train_large_wav_scp, 140 dev_wav_scp, 141 test_wav_scp]142 out_dir_list = [train_small_out_dir, 143 train_large_out_dir, 144 dev_out_dir, 145 test_out_dir]146 147 # 各セットについて処理を実行する148 for (wav_scp, out_dir) in zip(wav_scp_list, out_dir_list):149 print('Input wav_scp: %s' % (wav_scp))150 print('Output directory: %s' % (out_dir))151 152 # 特徴量ファイルのパス,フレーム数,153 # 次元数を記したリスト154 feat_scp = os.path.join(out_dir, 'feats.scp')155 156 # 出力ディレクトリが存在しない場合は作成する157 os.makedirs(out_dir, exist_ok=True)158 159 # wavリストを読み込みモード、160 # 特徴量リストを書き込みモードで開く161 with open(wav_scp, mode='r') as file_wav, \ 162 open(feat_scp, mode='w') as file_feat:163 # wavリストを1行ずつ読み込む164 for line in file_wav:165 # 各行には,発話IDとwavファイルのパスが166 # スペース区切りで記載されているので,167 # split関数を使ってスペース区切りの行を168 # リスト型の変数に変換する169 parts = line.split()170 # 0番目が発話ID171 utterance_id = parts[0]172 # 1番目がwavファイルのパス173 wav_path = parts[1]174 175 # wavファイルを読み込み,特徴量を計算する176 with wave.open(wav_path) as wav:177 # サンプリング周波数のチェック178 if wav.getframerate() != sample_frequency:179 sys.stderr.write('The expected \ 180 sampling rate is 16000.\n')181 exit(1)182 # wavファイルが1チャネル(モノラル)183 # データであることをチェック184 if wav.getnchannels() != 1:185 sys.stderr.write('This program \ 186 supports monaural wav file only.\n')187 exit(1)188 189 # wavデータのサンプル数190 num_samples = wav.getnframes()191 192 # wavデータを読み込む193 waveform = wav.readframes(num_samples)194 195 # 読み込んだデータはバイナリ値196 # (16bit integer)なので,数値(整数)に変換する197 waveform = np.frombuffer(waveform, dtype=np.int16)198 199 # FBANKを計算する(log_power:対数パワー情報も200 # 出力されるが,ここでは使用しない)201 fbank, log_power = feat_extractor.ComputeFBANK(waveform)202 203 # 特徴量のフレーム数と次元数を取得204 (num_frames, num_dims) = np.shape(fbank)205 206 # 特徴量ファイルの名前(splitextで拡張子を取り除いている)207 out_file = os.path.splitext(os.path.basename(wav_path))[0]208 out_file = os.path.join(os.path.abspath(out_dir), 209 out_file + '.bin')210 211 # データをfloat32形式に変換212 fbank = fbank.astype(np.float32)213 214 # データをファイルに出力215 fbank.tofile(out_file)216 # 発話ID,特徴量ファイルのパス,フレーム数,217 # 次元数を特徴量リストに書き込む218 file_feat.write("%s %s %d %d\n" %219 (utterance_id, out_file, num_frames, num_dims))220
0 コメント