博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
TensorFlow 中文语音识别【转】
阅读量:2193 次
发布时间:2019-05-02

本文共 10962 字,大约阅读时间需要 36 分钟。

来自:https://blog.csdn.net/sinat_30665603/article/details/74897891

http://blog.topspeedsnail.com/archives/10696

数据集下载参见该文。

其中下面的代码进行了一些小小的调整。

其中包含缩进、版本方面(作者是python 3.5)、求wav_max_len方面(并行)、tf.nn.ctc_loss的参数顺序。

(具体改变可与原文链接中的代码进行对比)

并在程序中给出了一些小注解。

感谢作者将这么好的资料开源,吾辈只能望洋兴叹。

[python] 
 
  1. #coding: utf-8  
  2. import tensorflow as tf  
  3. import numpy as np  
  4. import os  
  5. from collections import Counter  
  6. import librosa  
  7.   
  8. from joblib import Parallel, delayed  
  9.   
  10. wav_path = 'train'  
  11. label_file = "train.word.txt"  
  12.   
  13. def get_wav_files(wav_path = wav_path):  
  14.     wav_files = []  
  15.     for (dirpath, dirnames, filenames) in os.walk(wav_path):  
  16.         for filename in filenames:  
  17.             if filename.endswith(".wav"or filename.endswith(".WAV"):  
  18.                 filename_path = os.sep.join([dirpath, filename])  
  19.                 if os.stat(filename_path).st_size < 240000:  
  20.                     continue  
  21.                 wav_files.append(filename_path)  
  22.   
  23.     return wav_files  
  24.   
  25. wav_files = get_wav_files()  
  26.   
  27. def get_wav_label(wav_files = wav_files, label_file = label_file):  
  28.     labels_dict = {}  
  29.     with open(label_file, "r", encoding='utf-8') as f:  
  30.         for label in f:  
  31.             label = label.strip("\n")  
  32.             label_id, label_text = label.split(' '1)  
  33.             labels_dict[label_id] = label_text  
  34.   
  35.     labels = []  
  36.     new_wav_files = []  
  37.     for wav_file in wav_files:  
  38.         wav_id = os.path.basename(wav_file).split(".")[0]  
  39.         if wav_id in labels_dict:  
  40.             labels.append(labels_dict[wav_id])  
  41.             new_wav_files.append(wav_file)  
  42.   
  43.     return new_wav_files, labels  
  44.   
  45. def get_wav_length(wav):  
  46.     import numpy as np  
  47.     import librosa  
  48.   
  49.     print(wav)  
  50.   
  51.     wav, sr = librosa.load(wav)  
  52.     mfcc = np.transpose(librosa.feature.mfcc(wav, sr), [10])  
  53.     return len(mfcc)  
  54.   
  55. pointer = 0  
  56. def get_next_batches(batch_size, wav_max_len):  
  57.     global pointer  
  58.     batches_wavs = []  
  59.     batches_labels = []  
  60.     for i in range(batch_size):  
  61.         wav, sr = librosa.load(wav_files[pointer])  
  62.         mfcc = np.transpose(librosa.feature.mfcc(wav, sr), [1,0])  
  63.         batches_wavs.append(mfcc.tolist())  
  64.         batches_labels.append(labels_vector[pointer])  
  65.         pointer += 1  
  66.   
  67.     # 取零补齐  
  68.     # label append 0 , 0 对应的字符  
  69.     # mfcc 默认的计算长度为20(n_mfcc of mfcc) 作为channel length  
  70.     for mfcc in batches_wavs:  
  71.         while len(mfcc) < wav_max_len:  
  72.             mfcc.append([0]*20)  
  73.     for label in batches_labels:  
  74.         while len(label) < label_max_len:  
  75.             label.append(0)  
  76.   
  77.     return batches_wavs, batches_labels  
  78.   
  79. conv1d_index = 0  
  80. def conv1d_layer(input_tensor, size, dim, activation, scale, bias):  
  81.     global conv1d_index  
  82.     with tf.variable_scope("conv1d_" + str(conv1d_index)):  
  83.         W = tf.get_variable('W', (size, input_tensor.get_shape().as_list()[-1], dim), dtype=tf.float32, initializer=tf.random_uniform_initializer(minval=-scale, maxval=scale))  
  84.         if bias:  
  85.             b = tf.get_variable('b', [dim], dtype = tf.float32, initializer=tf.constant_initializer(0))  
  86.         out = tf.nn.conv1d(input_tensor, W, stride=1, padding='SAME') + (b if bias else 0)  
  87.   
  88.         if not bias:  
  89.             beta = tf.get_variable('beta', dim, dtype=tf.float32, initializer=tf.constant_initializer(0))  
  90.             gamma = tf.get_variable('gamma', dim, dtype=tf.float32, initializer=tf.constant_initializer(1))  
  91.             mean_running = tf.get_variable('mean', dim, dtype=tf.float32, initializer=tf.constant_initializer(0))  
  92.             variance_running = tf.get_variable('variance', dim, dtype=tf.float32, initializer=tf.constant_initializer(1))  
  93.             mean, variance = tf.nn.moments(out, axes=list(range(len(out.get_shape()) - 1)))  
  94.   
  95.             def update_running_stat():  
  96.                 decay = 0.99  
  97.   
  98.                 # 定义了均值方差指数衰减 见 http://blog.csdn.net/liyuan123zhouhui/article/details/70698264  
  99.                 update_op = [mean_running.assign(mean_running * decay + mean * (1 - decay)), variance_running.assign(variance_running * decay + variance * (1 - decay))]  
  100.   
  101.                 # 指定先执行均值方差的更新运算 见 http://blog.csdn.net/u012436149/article/details/72084744  
  102.                 with tf.control_dependencies(update_op):  
  103.                     return tf.identity(mean), tf.identity(variance)  
  104.   
  105.             # 条件运算(https://applenob.github.io/tf_9.html) 按照作者这里的指定 是不进行指数衰减的  
  106.             m, v = tf.cond(tf.Variable(False, trainable=False), update_running_stat,lambda: (mean_running, variance_running))  
  107.             out = tf.nn.batch_normalization(out, m, v, beta, gamma, 1e-8)  
  108.   
  109.         if activation == 'tanh':  
  110.             out = tf.nn.tanh(out)  
  111.         elif activation == 'sigmoid':  
  112.             out = tf.nn.sigmoid(out)  
  113.   
  114.         conv1d_index += 1  
  115.         return out  
  116.   
  117. # 极黑卷积层 https://www.zhihu.com/question/57414498  
  118. # 其输入参数中要包含一个大于 1 的rate 输出 channels与输入相同  
  119. aconv1d_index = 0  
  120. def aconv1d_layer(input_tensor, size, rate, activation, scale, bias):  
  121.     global aconv1d_index  
  122.     with tf.variable_scope('aconv1d_' + str(aconv1d_index)):  
  123.         shape = input_tensor.get_shape().as_list()  
  124.   
  125.         # 利用 2 维极黑卷积函数计算相应 1 维卷积,expand_dims squeeze做了相应维度处理  
  126.         # 实际 上一个 tf.nn.conv1d 在之前的tensorflow版本中是没有的,其的一个实现也是经过维度调整后调用 tf.nn.conv2d  
  127.         W = tf.get_variable('W', (1, size, shape[-1], shape[-1]), dtype=tf.float32, initializer=tf.random_uniform_initializer(minval=-scale, maxval=scale))  
  128.         if bias:  
  129.             b = tf.get_variable('b', [shape[-1]], dtype=tf.float32, initializer=tf.constant_initializer(0))  
  130.         out = tf.nn.atrous_conv2d(tf.expand_dims(input_tensor, dim=1), W, rate = rate, padding='SAME')  
  131.         out = tf.squeeze(out, [1])  
  132.   
  133.         if not bias:  
  134.             beta = tf.get_variable('beta', shape[-1], dtype=tf.float32, initializer=tf.constant_initializer(0))  
  135.             gamma = tf.get_variable('gamma', shape[-1], dtype=tf.float32, initializer=tf.constant_initializer(1))  
  136.             mean_running = tf.get_variable('mean', shape[-1], dtype=tf.float32, initializer=tf.constant_initializer(0))  
  137.             variance_running = tf.get_variable('variance', shape[-1], dtype=tf.float32, initializer=tf.constant_initializer(1))  
  138.             mean, variance = tf.nn.moments(out, axes=list(range(len(out.get_shape()) - 1)))  
  139.   
  140.             def update_running_stat():  
  141.                 decay = 0.99  
  142.                 update_op = [mean_running.assign(mean_running * decay + mean * (1 - decay)), variance_running.assign(variance_running * decay + variance * (1 - decay))]  
  143.                 with tf.control_dependencies(update_op):  
  144.                     return tf.identity(mean), tf.identity(variance)  
  145.   
  146.             m, v = tf.cond(tf.Variable(False, trainable=False), update_running_stat,lambda: (mean_running, variance_running))  
  147.             out = tf.nn.batch_normalization(out, m, v, beta, gamma, 1e-8)  
  148.   
  149.         if activation == 'tanh':  
  150.             out = tf.nn.tanh(out)  
  151.         elif activation == 'sigmoid':  
  152.             out = tf.nn.sigmoid(out)  
  153.   
  154.         aconv1d_index += 1  
  155.         return out  
  156.   
  157. def speech_to_text_network(n_dim = 128, n_blocks = 3):  
  158.     out = conv1d_layer(input_tensor=X, size=1, dim = n_dim, activation='tanh', scale=0.14, bias=False)  
  159.   
  160.     def residual_block(input_sensor, size, rate):  
  161.         conv_filter = aconv1d_layer(input_tensor=input_sensor, size=size, rate=rate, activation='tanh', scale=0.03, bias=False)  
  162.         conv_gate = aconv1d_layer(input_tensor=input_sensor, size=size, rate=rate, activation='sigmoid', scale=0.03, bias=False)  
  163.         out = conv_filter * conv_gate  
  164.         out = conv1d_layer(out, size = 1, dim=n_dim, activation='tanh', scale=0.08, bias=False)  
  165.         return out + input_sensor, out  
  166.   
  167.     skip = 0  
  168.     for _ in range(n_blocks):  
  169.         for r in [124816]:  
  170.             out, s = residual_block(out, size = 7, rate = r)  
  171.             skip += s  
  172.   
  173.     logit = conv1d_layer(skip, size = 1, dim = skip.get_shape().as_list()[-1], activation='tanh', scale = 0.08, bias=False)  
  174.   
  175.     # 最后卷积层输出是词汇表大小  
  176.     logit = conv1d_layer(logit, size = 1, dim = words_size, activation = None, scale = 0.04, bias = True)  
  177.   
  178.     return logit  
  179.   
  180. # 作者自己定义了优化器  
  181. class MaxPropOptimizer(tf.train.Optimizer):  
  182.     def __init__(self, learning_rate=0.001, beta2=0.999, use_locking=False, name="MaxProp"):  
  183.         super(MaxPropOptimizer, self).__init__(use_locking, name)  
  184.         self._lr = learning_rate  
  185.         self._beta2 = beta2  
  186.         self._lr_t = None  
  187.         self._beta2_t = None  
  188.     def _prepare(self):  
  189.         self._lr_t = tf.convert_to_tensor(self._lr, name="learning_rate")  
  190.         self._beta2_t = tf.convert_to_tensor(self._beta2, name="beta2")  
  191.     def _create_slots(self, var_list):  
  192.         for v in var_list:  
  193.             self._zeros_slot(v, "m"self._name)  
  194.     def _apply_dense(self, grad, var):  
  195.         lr_t = tf.cast(self._lr_t, var.dtype.base_dtype)  
  196.         beta2_t = tf.cast(self._beta2_t, var.dtype.base_dtype)  
  197.         if var.dtype.base_dtype == tf.float16:  
  198.             eps = 1e-7  
  199.         else:  
  200.             eps = 1e-8  
  201.         m = self.get_slot(var, "m")  
  202.         m_t = m.assign(tf.maximum(beta2_t * m + eps, tf.abs(grad)))  
  203.         g_t = grad / m_t  
  204.         var_update = tf.assign_sub(var, lr_t * g_t)  
  205.         return tf.group(*[var_update, m_t])  
  206.     def _apply_sparse(self, grad, var):  
  207.         return self._apply_dense(grad, var)  
  208.   
  209. def train_speech_to_text_network(wav_max_len):  
  210.     logit = speech_to_text_network()  
  211.   
  212.     # CTC loss  
  213.     indices = tf.where(tf.not_equal(tf.cast(Y, tf.float32), 0.))  
  214.     target = tf.SparseTensor(indices=indices, values=tf.gather_nd(Y, indices) - 1, dense_shape=tf.cast(tf.shape(Y), tf.int64))  
  215.     loss = tf.nn.ctc_loss(target, logit, sequence_len, time_major=False)  
  216.     # optimizer  
  217.     lr = tf.Variable(0.001, dtype=tf.float32, trainable=False)  
  218.     optimizer = MaxPropOptimizer(learning_rate=lr, beta2=0.99)  
  219.     var_list = [t for t in tf.trainable_variables()]  
  220.     gradient = optimizer.compute_gradients(loss, var_list=var_list)  
  221.     optimizer_op = optimizer.apply_gradients(gradient)  
  222.   
  223.     with tf.Session() as sess:  
  224.         sess.run(tf.global_variables_initializer())  
  225.   
  226.         saver = tf.train.Saver(tf.global_variables())  
  227.   
  228.         for epoch in range(16):  
  229.             sess.run(tf.assign(lr, 0.001 * (0.97 ** epoch)))  
  230.   
  231.             global pointer  
  232.             pointer = 0  
  233.             for batch in range(n_batch):  
  234.                 batches_wavs, batches_labels = get_next_batches(batch_size, wav_max_len)  
  235.                 train_loss, _ = sess.run([loss, optimizer_op], feed_dict={X: batches_wavs, Y: batches_labels})  
  236.                 print(epoch, batch, train_loss)  
  237.             if epoch % 5 == 0:  
  238.                 saver.save(sess, r'/speech/module', global_step=epoch)  
  239.   
  240. # 训练  
  241. #train_speech_to_text_network()  
  242.   
  243. # 语音识别  
  244. # 把batch_size改为1  
  245. def speech_to_text(wav_file):  
  246.     wav, sr = librosa.load(wav_file, mono=True)  
  247.     mfcc = np.transpose(np.expand_dims(librosa.feature.mfcc(wav, sr), axis=0), [0,2,1])  
  248.   
  249.     logit = speech_to_text_network()  
  250.   
  251.     saver = tf.train.Saver()  
  252.     with tf.Session() as sess:  
  253.         saver.restore(sess, tf.train.latest_checkpoint('.'))  
  254.   
  255.         decoded = tf.transpose(logit, perm=[102])  
  256.         decoded, _ = tf.nn.ctc_beam_search_decoder(decoded, sequence_len, merge_repeated=False)  
  257.         predict = tf.sparse_to_dense(decoded[0].indices, decoded[0].shape, decoded[0].values) + 1  
  258.         output = sess.run(decoded, feed_dict={X: mfcc})  
  259.         print(output)  
  260.   
  261.   
  262. if __name__ == "__main__":  
  263.     wav_files = get_wav_files()  
  264.     wav_files, labels = get_wav_label()  
  265.     print(u"样本数 :", len(wav_files))  
  266.   
  267.     all_words = []  
  268.     for label in labels:  
  269.         # 字符分解  
  270.         all_words += [word for word in label]  
  271.   
  272.     counter = Counter(all_words)  
  273.     count_pairs = sorted(counter.items(), key=lambda x: -x[1])  
  274.   
  275.     words, _ = zip(*count_pairs)  
  276.     words_size = len(words)  
  277.     print(u"词汇表大小:", words_size)  
  278.   
  279.     word_num_map = dict(zip(words, range(len(words))))  
  280.   
  281.     # 当字符不在已经收集的words中时,赋予其应当的num,这是一个动态的结果  
  282.     to_num = lambda word: word_num_map.get(word, len(words))  
  283.   
  284.     # 将单个file的标签映射为num 返回对应list,最终all file组成嵌套list  
  285.     labels_vector = [list(map(to_num, label)) for label in labels]  
  286.   
  287.     label_max_len = np.max([len(label) for label in labels_vector])  
  288.     print(u"最长句子的字数:" + str(label_max_len))  
  289.   
  290.     # 下面仅仅计算了语音特征相应的最长的长度。  
  291.     # 如果仅仅是计算长度是否需要施加变换后计算长度?  
  292.     parallel_read = False  
  293.     if parallel_read:  
  294.         wav_max_len = np.max(Parallel(n_jobs=7)(delayed(get_wav_length)(wav) for wav in wav_files))  
  295.     else:  
  296.         wav_max_len = 673  
  297.     print("最长的语音", wav_max_len)  
  298.   
  299.     batch_size = 16  
  300.     n_batch = len(wav_files) // batch_size  
  301.   
  302.     X = tf.placeholder(dtype=tf.float32, shape=[batch_size, None20])  
  303.   
  304.     # 实际mfcc中的元素并非同号,不严格的情况下如此得到序列长度也是可行的  
  305.     sequence_len = tf.reduce_sum(tf.cast(tf.not_equal(tf.reduce_sum(X, reduction_indices=2), 0.), tf.int32), reduction_indices=1)  
  306.   
  307.     Y = tf.placeholder(dtype=tf.int32, shape=[batch_size, None])  
  308.   
  309.     train_speech_to_text_network(wav_max_len)  
你可能感兴趣的文章
【雅思】雅思需要购买和准备的学习资料
查看>>
【雅思】雅思写作作业(1)
查看>>
【雅思】【大作文】【审题作业】关于同不同意的审题作业(重点)
查看>>
【Loadrunner】通过loadrunner录制时候有事件但是白页无法出来登录页怎么办?
查看>>
【English】【托业】【四六级】写译高频词汇
查看>>
【托业】【新东方全真模拟】01~02-----P5~6
查看>>
【托业】【新东方全真模拟】03~04-----P5~6
查看>>
【托业】【新东方托业全真模拟】TEST05~06-----P5~6
查看>>
【托业】【新东方托业全真模拟】TEST09~10-----P5~6
查看>>
【托业】【新东方托业全真模拟】TEST07~08-----P5~6
查看>>
solver及其配置
查看>>
JAVA多线程之volatile 与 synchronized 的比较
查看>>
Java集合框架知识梳理
查看>>
笔试题(一)—— java基础
查看>>
Redis学习笔记(三)—— 使用redis客户端连接windows和linux下的redis并解决无法连接redis的问题
查看>>
Intellij IDEA使用(一)—— 安装Intellij IDEA(ideaIU-2017.2.3)并完成Intellij IDEA的简单配置
查看>>
Intellij IDEA使用(二)—— 在Intellij IDEA中配置JDK(SDK)
查看>>
Intellij IDEA使用(三)——在Intellij IDEA中配置Tomcat服务器
查看>>
Intellij IDEA使用(四)—— 使用Intellij IDEA创建静态的web(HTML)项目
查看>>
Intellij IDEA使用(五)—— Intellij IDEA在使用中的一些其他常用功能或常用配置收集
查看>>