【项目实战】WaveNet 代码解析 —— ops.py 【更新中】

WaveNet 代码解析 —— ops.py

  简介

       本项目一个基于 WaveNet 生成神经网络体系结构的语音合成项目,它是使用 TensorFlow 实现的(项目地址)。
       
        WaveNet 神经网络体系结构能直接生成原始音频波形,在文本到语音和一般音频生成方面显示了出色的结果(详情请参阅 WaveNet 的详细介绍)。
       
       由于 WaveNet 项目较大,代码较多。为了方便学习与整理,将按照工程文件的结构依次介绍。
       
       本文将介绍项目中的 ops.py 文件:基础操作函数集。
       

  代码解析

    变量解析

       以下变量为 ops.py 脚本的全局变量:

		# optimizer_factory 保存了优化器的三种方案:adam, sgd, rmsporp
		# 分别对应了 tensorflow 中 optimizer 的几种设置方法
		optimizer_factory = {'adam': create_adam_optimizer,
		                     'sgd': create_sgd_optimizer,
		                     'rmsprop': create_rmsprop_optimizer}

       

    函数解析

      create_adam_optimizer

        下面这段代码的主要任务是:创建 adam 优化器

	# learning_rate : 学习速率
	# epsilon : 数值稳定性的小常数,作为精度
	def create_adam_optimizer(learning_rate, momentum):
	    # 实现 Adam 算法的优化器
	    return tf.train.AdamOptimizer(learning_rate=learning_rate,
	                                  epsilon=1e-4)

       

      create_sgd_optimizer

        下面这段代码的主要任务是:创建 sgd 优化器

	# learning_rate : 学习速率
	# momentum : 动量
	def create_sgd_optimizer(learning_rate, momentum):
	    # 实现动量算法的优化器
	    return tf.train.MomentumOptimizer(learning_rate=learning_rate,
	                                      momentum=momentum)

       

      create_rmsprop_optimizer

        下面这段代码的主要任务是:创建 RMSProp 优化器

	# learning_rate : 学习速率
	# momentum : 动量
	# epsilon : 数值稳定性的小常数,作为精度
	def create_rmsprop_optimizer(learning_rate, momentum):
	    # 实现RMSProp算法的优化器
	    return tf.train.RMSPropOptimizer(learning_rate=learning_rate,
	                                     momentum=momentum,
	                                     epsilon=1e-5)

       

      time_to_batch

        下面这段代码的主要任务是:时序数据划分成 dilation 批,便于膨胀卷积运算

	def time_to_batch(value, dilation, name=None):
	    # 创建 time_to_batch 变量命名空间
	    with tf.name_scope('time_to_batch'):
	        # 获取 value 的形状
	        shape = tf.shape(value)
	        # 为了让 value 的数据量恰好为 dilation 的整数倍,计算需要填补的元素个数
	        pad_elements = dilation - 1 - (shape[1] + dilation - 1) % dilation
	        # 在 value 的数据维度上填补 pad_elements 个0
	        padded = tf.pad(value, [[0, 0], [0, pad_elements], [0, 0]])
	        # 将输入的数据转换格式,使每 dilation 个数据一组
	        reshaped = tf.reshape(padded, [-1, dilation, shape[2]])
	        # 交换维度,使数据转换成易于卷积的格式
	        transposed = tf.transpose(reshaped, perm=[1, 0, 2])
	        # 返回数据,确保数据的格式与需要的个数相符
	        return tf.reshape(transposed, [shape[0] * dilation, -1, shape[2]])

       

      batch_to_time

        下面这段代码的主要任务是:将 dilation 批数据还原为时序数据,为后续的网络层做准备

	def batch_to_time(value, dilation, name=None):
	    # 创建 batch_to_time 变量命名空间
	    with tf.name_scope('batch_to_time'):
	        # 获取 value 的形状
	        shape = tf.shape(value)
	        # 确保 value 的形状是所需的形状
	        prepared = tf.reshape(value, [dilation, -1, shape[2]])
	        # 交换维度,将数据还原到每组 dilation 个
	        transposed = tf.transpose(prepared, perm=[1, 0, 2])
	        # 还原数据,将数据平铺,并返回
	        return tf.reshape(transposed,
	                          [tf.div(shape[0], dilation), -1, shape[2]])

       

      causal_conv

        下面这段代码的主要任务是:对当前层根据膨胀系数的大小分情况进行卷积,并将卷积的结果返回

	def causal_conv(value, filter_, dilation, name='causal_conv'):
	    with tf.name_scope(name):
	        # 取过滤器宽度
	        filter_width = tf.shape(filter_)[0]
	        # 若膨胀系数大于1
	        if dilation > 1:
	            # 将时序数据转换为便于直接卷积的 dilation 批数据
	            transformed = time_to_batch(value, dilation)
	            # 开始卷积
	            conv = tf.nn.conv1d(transformed, filter_, stride=1,
	                                padding='VALID')
	            # 将卷积后的数据还原成时序数据
	            restored = batch_to_time(conv, dilation)
	        # 若膨胀系数为1
	        else:
	            # 直接进行卷积
	            restored = tf.nn.conv1d(value, filter_, stride=1, padding='VALID')
	        # 计算数据应有的输出宽度
	        out_width = tf.shape(value)[1] - (filter_width - 1) * dilation
	        # 删除多余的元素,并返回
	        result = tf.slice(restored,
	                          [0, 0, 0],
	                          [-1, out_width, -1])
	        return result

       

      mu_law_encode

        下面这段代码的主要任务是:使用数字转换波形振幅

	def mu_law_encode(audio, quantization_channels):
	    # 创建 encode 变量命名空间
	    with tf.name_scope('encode'):
	        # 量化振幅值的数量
	        mu = tf.to_float(quantization_channels - 1)
	        
	        # 限制最大值,避免大振幅的出现
	        safe_audio_abs = tf.minimum(tf.abs(audio), 1.0)
	        # 执行 mu-law 扩展变换
	        magnitude = tf.log1p(mu * safe_audio_abs) / tf.log1p(mu)
	        signal = tf.sign(audio) * magnitude
	        # 将信号量化到指定的数值
	        return tf.to_int32((signal + 1) / 2 * mu + 0.5)

       

      mu_law_decode

        下面这段代码的主要任务是:从量化值恢复波形

	def mu_law_decode(output, quantization_channels):
	    # 创建 decode 变量命名空间
	    with tf.name_scope('decode'):
	        # 量化振幅值的数量
	        mu = quantization_channels - 1
	        # 将值映射回[- 1,1]
	        signal = 2 * (tf.to_float(output) / mu) - 1
	        # 进行 mu-law 逆变换,并返回
	        magnitude = (1 / mu) * ((1 + mu)**abs(signal) - 1)
	        return tf.sign(signal) * magnitude

       

       
       
       本文还在持续更新中!
       欢迎各位大佬交流讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值