用Tensorflow进行简单音频分类

Tensorflow因支持功能的全面性,序列化的突出优点,以及高性能的部署优点等等俘获了一大批的铁杆粉丝。但是对于小白来说要上手还是需要啃一些实战案例,积累一些实现方法的。

在视觉、语言领域相关的深度学习发展很好,例如:CNN 在图像上表现非常好,具有像素的局部相关性;RNN 或transformers这样的序列模型在语言上也表现得非常好,具有顺序性。

音频看起来用的很少,以至于一些同学也不知道处理音频数据时使用了哪些类型的模型和过程。来啃下面的Tensorflow 代码吧!你会收获到音频分类问题的高效方法!

声明:本案例出于演示目的,使用了“语音命令”数据集。

Waveforms(波形)

通常“ .wav ”格式的音频文件,通常被称为波形,波形是每个特定时间信号幅度的时间序列,当将这些波形样本中一部分进行可视化,会这样显示:

直觉上,大部分人都可能会考虑使用某种RNN模型对这些数据进行建模,就像常规时间序列(例如股票价格预测)一样,用这种方法这是可以做到的。

但是,由于我们使用的是音频信号,因此更合适的选择是将波形样本转换为频谱图。

Spectrograms(频谱图)

频谱图是波形信号的图像表示,它显示了随时间变化的频率强度范围,当要评估信号随时间变化的频率分布时,频谱图非常有用。

下图是上面波形图像的频谱图表示:

语音命令用例

为了让大家能够更容易理解整个操作过程,我们将使用“语音命令”数据集(在文章底部获取链接),该数据集包含一秒钟的音频剪辑,其中包含以下口语:“向下”、“前进”、“左”、“否”、“右”、“停止”、“向上”和“是”。

使用 Tensorflow 处理音频

上面讲解了如何处理音频数据以用于深度学习模型,接下来看如何用代码实现,所用管线将遵循下图所述的简单工作流:

注意以下,在用例中,第一步是直接从“.wav”文件加载数据,第三步是可选的,因为每个音频文件只有一秒钟,在某些情况下,裁剪音频可能是个好的做法,这样可以用于更长的文件,也可以在所有样本中保持固定长度。

加载数据

def load_dataset(filenames):

dataset = tf.data.Dataset.from_tensor_slices(filenames)

return dataset

load_dataset函数负责加载.wav文件并转换为 Tensorflow 数据集

提取波形和标签

commands = np.array(tf.io.gfile.listdir(str(data_dir)))
commands = commands[commands != 'README.md']
def decode_audio(audio_binary):
  audio, _ = tf.audio.decode_wav(audio_binary)
  return tf.squeeze(audio, axis=-1)
def get_label(filename):
  label = tf.strings.split(filename, os.path.sep)[-2]
  label = tf.argmax(label == commands)
  return label
def get_waveform_and_label(filename):
  label = get_label(filename)
  audio_binary = tf.io.read_file(filename)
  waveform = decode_audio(audio_binary)
  return waveform, label

加载.wav文件后,然后对文件进行解码,使用tf.audio.decode_wav函数来完成,将.wav文件转换为浮点张量。

接下来,从文件中提取标签,在这个特定用例中,从每个样本的文件路径中获取标签,之后只需要进行单(独)热编码(one-hot encode the labels)。

看这个例子,首先,我们得到这样一个文件路径:

"data/mini_speech_commands/up/50f55535_nohash_0.wav"

然后我们提取第二个“ / ”之后的文本,在这种情况下,标签是向上的,最后,我们使用commands列表对标签进行单(独)热编码(one-hot encode the labels)。

Commands: ['up' 'down' 'go' 'stop' 'left' 'no' 'yes' 'right']
Label = 'up'
After one-hot encoding:
Label = [1, 0, 0, 0, 0, 0, 0, 0]

将波形转换为频谱图

接着将波形文件转换为频谱图,Tensorflow 有一个功能可以直接做到,tf.signal.stft应用short-time Fourier transform ( STFT ) 将音频转换为时频域,然后我们应用tf.abs算子去除信号相位,只保留幅度。

这里注意一下,tf.signal.stft函数有一些参数,例如frame_length和frame_step,它们会影响生成的频谱图。

def get_spectrogram(waveform, padding=False, min_padding=48000):
  waveform = tf.cast(waveform, tf.float32)
  spectrogram = tf.signal.stft(waveform, frame_length=2048, frame_step=512, fft_length=2048)
  spectrogram = tf.abs(spectrogram)
  return spectrogram
def get_spectrogram_tf(waveform, label):
  spectrogram = get_spectrogram(waveform)
  spectrogram = tf.expand_dims(spectrogram, axis=-1)
  return spectrogram, label

将频谱图转换为 RGB 图像

最后一步是将频谱图转换为 RGB 图像,这一步是可选的,这里使用在 ImageNet 数据集上预先训练的模型,该模型需要具有 3 个通道的输入图像,除此之外,还可以只保留一个通道的光谱图。

def prepare_sample(spectrogram, label):
  spectrogram = tf.image.resize(spectrogram, [HEIGHT, WIDTH])
  spectrogram = tf.image.grayscale_to_rgb(spectrogram)
  return spectrogram, label

结合在一起

HEIGHT, WIDTH = 128, 128
AUTO = tf.data.AUTOTUNE
def get_dataset(filenames, batch_size=32):
  dataset = load_dataset(filenames)
    
  dataset = files_ds.map(get_waveform_and_label, num_parallel_calls=AUTO)
  dataset = dataset.map(get_spectrogram_tf, num_parallel_calls=AUTO)
  dataset = dataset.map(prepare_sample, num_parallel_calls=AUTO)
  dataset = dataset.shuffle(256)
  dataset = dataset.repeat()
  dataset = dataset.batch(batch_size)
  dataset = dataset.prefetch(AUTO)
  return dataset

总而言之,在完成所有步骤之后,将文件名输入到get_dataset函数中,返回一个带有 RGB 光谱图像及其标签的 Tensorflow 数据集。

该模型

def model_fn(input_shape, N_CLASSES):
  inputs = L.Input(shape=input_shape, name='input_audio')
  base_model = efn.EfficientNetB0(input_tensor=inputs, 
                                  include_top=False, 
                                  weights='imagenet')

  x = L.GlobalAveragePooling2D()(base_model.output)
  x = L.Dropout(.5)(x)
  output = L.Dense(N_CLASSES, activation='softmax',name='output')(x)
    
  model = Model(inputs=inputs, outputs=output)

  return model

我们的模型将有一个EfficientNetB0主干。

在其顶部,我们添加了一个GlobalAveragePooling2D,然后是一个Dropout,最后一个Dense层将进行实际的多类分类。

对于小数据集,EfficientNetB0可能是一个很好的基线,即使是一个快速和轻的模型,它也有相当好的精度。

训练

model = model_fn((None, None, CHANNELS), N_CLASSES)
model.compile(optimizer=tf.optimizers.Adam(), 
              loss=losses.CategoricalCrossentropy(), 
              metrics=[metrics.CategoricalAccuracy()])

model.fit(x=get_dataset(FILENAMES), 
          steps_per_epoch=100, 
          epochs=10)

Keras 模型的训练代码非常标准,你可能不会在这里找到任何新内容。

现在大家应该更清楚地了解了将深度学习应用于音频文件的工作流程,虽然这并不是唯一的解决办法,但它是一种关于易用性和性能权衡的最佳选择。

本文参考文档:

https://pub.towardsai.net/a-gentle-introduction-to-audio-classification-with-tensorflow-c469cb0be6f5

语言命令数据集: https://arxiv.org/abs/1804.03209 tensorflow

官方文档: https://www.tensorflow.org/tutorials/audio/simple_audio

今后【学姐带你玩AI】公众号还会更新更多的

深度学习和机器学习的干货及示例

关注我变大神!

给学姐点个赞吧!这样学姐就有动力肝更多干货出来了!

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值