Tensorflow 2.0 信號處理

Tensorflow 2 信號處理

官方文檔太簡潔,因此有此文。

Tensorflow 2 Signal Processing API: https://www.tensorflow.org/api_docs/python/tf/signal

參考:https://www.tensorflow.org/versions/r1.10/api_guides/python/contrib.signal

tf.signal是用於信號處理原語的模塊。所有操作都具有GPU支持並且可以微分。儘管該技術在許多領域都非常有用,但該模型對於構建可處理或生成音頻的TensorFlow模型特別有用。

import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import soundfile as sf
import librosa
WAV_FILE = './data/diarizationExample_sr16k_ac2_10s.wav'
# 默認返回單聲道
x, fs = librosa.load(WAV_FILE, dtype=np.float32, sr=16000)
plt.figure()
plt.plot(x)
plt.show()
Tensorflow 2.0 信號處理

構建(Frame)可變長序列

但處理可變長度的信號(比如音頻)時,通常將它們分幀為多個固定長度的窗口(windows)。如果幀的步長小於幀的長度,則這些窗口會重疊。tf.signal.frame就是這麼做的。

# signals = tf.compat.v1.placeholder(tf.float32, [None, 9152]) # 這是TensorFlow 1.x的靜態圖方式
signals = [x]
# frame_length與frame_step的單位為樣本數(samples)
# tf.signal.frame返回:[..., frames, frame_length, ...]
# 本例中返回的是:[1, frames, frame_length]
frames = tf.signal.frame(signals, frame_length=256, frame_step=64)
# 生成幅度譜圖
magnitude_spectrograms = tf.abs(tf.signal.rfft(frames, fft_length=[256]))
image = tf.expand_dims(magnitude_spectrograms, 3)
plt.figure()
plt.imshow(tf.transpose(magnitude_spectrograms[0,:,:].numpy()), origin='lower')
plt.show()
Tensorflow 2.0 信號處理

直接對音頻數據進行stft(短時傅里葉變換)

# 返回的`magnitude_spectrograms`是形狀為[batch_size, ?, 129]張量的頻譜圖
magnitude_spectrograms = tf.abs(tf.signal.stft(
pcm, frame_length=256, frame_step=64, fft_length=256))
plt.figure()
plt.imshow(tf.transpose(magnitude_spectrograms[0,:,:].numpy()), origin='lower')
plt.show()
Tensorflow 2.0 信號處理

# `spectrogram_patches` is a [batch_size, ?, 64, 129] tensor containing a
# variable number of [64, 129] spectrogram patches per batch item.
spectrogram_patches = tf.signal.frame(
magnitude_spectrograms, frame_length=64, frame_step=16, axis=1)

重建幀序列並應用漸縮(tapering)窗口

tf.signal.overlap_and_add可用於從幀序列中重建音頻信號。例如,以下代碼重建了前面示例中產生的信號。

# 從上文中生成的`frames`重建音頻信號`signals`。
# 但是,重建生成的`reconstructed_signals`其振幅比原音頻`signals`高。
reconstructed_signals = tf.signal.overlap_and_add(frames, frame_step=64)
plt.figure()
plt.plot(reconstructed_signals[0])
plt.show()
Tensorflow 2.0 信號處理

請注意,由於上面示例的frame_step是frame_length的25%,最終生成的重建音頻比原始信號具有更大的幅度。為了彌補這一點,我們可以使用漸縮(tapering)窗口函數。如果窗口函數滿足給定幀長的常量重疊相加(Constant Overlap-Add, COLA)屬性,則它將恢復原始信號。

tf.signal.hamming_window與tf.signal.hann_window都滿足COLA屬性,重疊率為75%。

frame_length = 256
frame_step = 64
windowed_frames = frames * tf.signal.hann_window(frame_length)
reconstructed_signals = tf.signal.overlap_and_add(
windowed_frames, frame_step)
plt.figure()
plt.plot(reconstructed_signals[0])
plt.show()
Tensorflow 2.0 信號處理

計算頻譜圖(Spectrogram)

頻譜圖是信號的時頻分解,表示隨時間變化的頻率內容。計算頻譜圖最常見的方法是採用短時傅立葉變換(Short-time Fourier Transform, STFT)的大小,tf.signal.stft使用方式如下:

# `stfts`是一個complex64張量,表示`signals`中每個信號的短時傅立葉變換。
# 其形狀為[batch_size,?,fft_unique_bins]
# 其中fft_unique_bins = fft_length // 2 + 1 = 513。
stfts = tf.signal.stft(signals, frame_length=1024, frame_step = 512, fft_length=1024)

# 功率譜圖是復值STFT的平方幅度。
# 形狀為[batch_size,?,513]的float32張量。
power_spectrograms = tf.math.real(stfts * tf.math.conj(stfts))

# 能量譜/振幅譜圖是復值STFT的大小。
# 形狀為[batch_size,?,513]的float32張量。
magnitude_spectrograms = tf.abs(stfts)
plt.figure()
plt.imshow(tf.transpose(power_spectrograms[0]), origin='lower')
plt.show()
Tensorflow 2.0 信號處理

plt.figure()
plt.imshow(tf.transpose(magnitude_spectrograms[0]), origin='lower')
plt.show()
Tensorflow 2.0 信號處理

我們可以使用功率譜圖或幅度譜圖;每個都有其優點。請注意,如果使用對數壓縮,則功率譜圖和幅度譜圖的相差為2倍。

對數壓縮

通常的做法是將非線性壓縮(例如對數或冪律壓縮)應用於頻譜圖。這有助於在頻譜圖的低能和高能區域中平衡細節的重要性,這與人類的聽覺靈敏度更加接近(對低頻更敏感)。

使用對數壓縮時,最好使用穩定偏移量,以避免由零的奇點引起的高動態範圍。

log_offset = 1e-6
log_magnitude_spectrograms = tf.math.log(magnitude_spectrograms + log_offset)
plt.figure()
plt.imshow(tf.transpose(log_magnitude_spectrograms[0]), origin='lower')
plt.show()
Tensorflow 2.0 信號處理

計算對數梅爾頻譜圖

當使用音頻的頻譜表示法時,梅爾音階(mel scale)是一種常見的頻率維度重新加權法(reweighting ),這樣,音頻的維數較低,並且在聽覺上(perceptually)更相關。

tf.signal.linear_to_mel_weight_matrix生成一個矩陣,可用於將頻譜圖轉換為mel scale。

# 將線性標度、幅度譜圖扭曲為mel標度。
sample_rate = fs
num_spectrogram_bins = magnitude_spectrograms.shape[-1]
lower_edge_hertz, upper_edge_hertz, num_mel_bins = 80.0, 7600.0, 64
linear_to_mel_weight_matrix = tf.signal.linear_to_mel_weight_matrix(
num_mel_bins, num_spectrogram_bins, sample_rate, lower_edge_hertz,
upper_edge_hertz)
mel_spectrograms = tf.tensordot(
magnitude_spectrograms, linear_to_mel_weight_matrix, 1)
mel_spectrograms.set_shape(magnitude_spectrograms.shape[:-1].concatenate(
linear_to_mel_weight_matrix.shape[-1:]))
plt.figure()
plt.imshow(tf.transpose(mel_spectrograms[0]), origin='lower')
plt.show()
Tensorflow 2.0 信號處理

如果需要,請壓縮梅爾頻譜圖幅度。例如,可以使用對數壓縮(如上一節所述)。

順序很重要!重新加權頻率後壓縮頻譜圖幅值與先壓縮頻譜圖幅值再重新加權是不同的。根據梅爾音階的感知(perceptual)合理性,從線性音階進行轉換意味著對相鄰頻帶之間的強度或能量求和,即應在對數壓縮之前應用它。對數壓縮值的加權求和等於取對數前值的乘積,這幾乎是沒有道理的。

log_offset = 1e-6
log_mel_spectrograms = tf.math.log(mel_spectrograms + log_offset)
plt.figure()
plt.imshow(tf.transpose(log_mel_spectrograms[0]), origin='lower')
plt.show()
Tensorflow 2.0 信號處理

計算梅爾頻率倒譜系數(MFCC)

MFCC: Mel-Frequency Cepstral Coefficients. 調用tf.signal.mfccs_from_log_mel_spectrograms以從對數幅度頻譜圖、梅爾標度頻譜圖(如上例中計算)計算MFCC:

num_mfccs = 13
# 只取前 `num_mfccs` 個MFCCs.
mfccs = tf.signal.mfccs_from_log_mel_spectrograms(
log_mel_spectrograms)[..., :num_mfccs]
plt.figure()
plt.imshow(tf.transpose(mfccs[0]), origin='lower')
plt.show()
Tensorflow 2.0 信號處理


分享到:


相關文章: