中文语音识别

转载:http://f.dataguru.cn/thread-857009-1-1.html

          https://blog.csdn.net/u014365862/article/details/53869701

使用的数据集

THCHS30是Dong Wang, Xuewei Zhang, Zhiyong Zhang这几位大神发布的开放语音数据集,可用于开发中文语音识别系统。
为了感谢这几位大神,我是跪在电脑前写的本帖代码。
下载中文语音数据集(5G+):

[python] view plain copy



    在开始之前,先好好检视一下数据集。

[python]  view plain  copy
  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 = 'data/wav/train'    
  11. label_file = 'data/doc/trans/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 % 1 == 0:   #之前是5  
  238.                 saver.save(sess, r'D:\\tensorflow\\Speech_Recognition\\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.     decoded = sess.run(decoded, feed_dict={X: mfcc})  
  258.     # predict = tf.sparse_to_dense(decoded[0].indices, decoded[0].shape, decoded[0].values) + 1  
  259.     print (decoded)  
  260.     predict = tf.sparse_to_dense(decoded[0].indices,decoded[0].dense_shape,decoded[0].values) + 1  
  261.     # predict = decode_sparse_tensor(decoded[0])  
  262.     predict = sess.run(predict)  
  263.     print(predict)  
  264.     
  265.     
  266. if __name__ == "__main__":    
  267.     wav_files = get_wav_files()    
  268.     wav_files, labels = get_wav_label()    
  269.     print(u"样本数 :", len(wav_files))    
  270.     
  271.     all_words = []    
  272.     for label in labels:    
  273.         # 字符分解    
  274.         all_words += [word for word in label]    
  275.     
  276.     counter = Counter(all_words)    
  277.     count_pairs = sorted(counter.items(), key=lambda x: -x[1])    
  278.     
  279.     words, _ = zip(*count_pairs)    
  280.     words_size = len(words)    
  281.     print(u"词汇表大小:", words_size)    
  282.     
  283.     word_num_map = dict(zip(words, range(len(words))))    
  284.     
  285.     # 当字符不在已经收集的words中时,赋予其应当的num,这是一个动态的结果    
  286.     to_num = lambda word: word_num_map.get(word, len(words))    
  287.     
  288.     # 将单个file的标签映射为num 返回对应list,最终all file组成嵌套list    
  289.     labels_vector = [list(map(to_num, label)) for label in labels]    
  290.     
  291.     label_max_len = np.max([len(label) for label in labels_vector])    
  292.     print(u"最长句子的字数:" + str(label_max_len))    
  293.     
  294.     # 下面仅仅计算了语音特征相应的最长的长度。    
  295.     # 如果仅仅是计算长度是否需要施加变换后计算长度?    
  296.     parallel_read = False    
  297.     if parallel_read:    
  298.         wav_max_len = np.max(Parallel(n_jobs=7)(delayed(get_wav_length)(wav) for wav in wav_files))    
  299.     else:    
  300.         wav_max_len = 673    
  301.     print("最长的语音", wav_max_len)    
  302.     
  303.     batch_size = 8    
  304.     n_batch = len(wav_files) // batch_size    
  305.     
  306.     X = tf.placeholder(dtype=tf.float32, shape=[batch_size, None20])    
  307.     
  308.     # 实际mfcc中的元素并非同号,不严格的情况下如此得到序列长度也是可行的    
  309.     sequence_len = tf.reduce_sum(tf.cast(tf.not_equal(tf.reduce_sum(X, reduction_indices=2), 0.), tf.int32), reduction_indices=1)    
  310.     
  311.     Y = tf.placeholder(dtype=tf.int32, shape=[batch_size, None])    
  312.     
  313.     train_speech_to_text_network(wav_max_len)    


后续:从麦克风获得语音输入,使用上面的模型进行识别。

然后预测可以用下边这个:

[python]  view plain  copy
  1. if __name__ == "__main__":  
  2.       
  3.     wav_files = get_wav_files()    
  4.     wav_files, labels = get_wav_label()    
  5.     print(u"样本数 :", len(wav_files))    
  6.     
  7.     all_words = []    
  8.     for label in labels:    
  9.         # 字符分解    
  10.         all_words += [word for word in label]    
  11.     
  12.     counter = Counter(all_words)    
  13.     count_pairs = sorted(counter.items(), key=lambda x: -x[1])    
  14.     
  15.     words, _ = zip(*count_pairs)    
  16.     words_size = len(words)    
  17.     print(u"词汇表大小:", words_size)    
  18.     
  19.     word_num_map = dict(zip(words, range(len(words))))    
  20.     
  21.     # 当字符不在已经收集的words中时,赋予其应当的num,这是一个动态的结果    
  22.     to_num = lambda word: word_num_map.get(word, len(words))    
  23.     
  24.     # 将单个file的标签映射为num 返回对应list,最终all file组成嵌套list    
  25.     labels_vector = [list(map(to_num, label)) for label in labels]    
  26.     
  27.     label_max_len = np.max([len(label) for label in labels_vector])    
  28.     print(u"最长句子的字数:" + str(label_max_len))    
  29.     
  30.     # 下面仅仅计算了语音特征相应的最长的长度。    
  31.     # 如果仅仅是计算长度是否需要施加变换后计算长度?    
  32.     parallel_read = False    
  33.     if parallel_read:    
  34.         wav_max_len = np.max(Parallel(n_jobs=7)(delayed(get_wav_length)(wav) for wav in wav_files))    
  35.     else:    
  36.         wav_max_len = 673    
  37.     print("最长的语音", wav_max_len)    
  38.     
  39.     batch_size = 1   
  40.     n_batch = len(wav_files) // batch_size  
  41.     
  42.     X = tf.placeholder(dtype=tf.float32, shape=[batch_size, None20])  
  43.     
  44.     # 实际mfcc中的元素并非同号,不严格的情况下如此得到序列长度也是可行的    
  45.     sequence_len = tf.reduce_sum(tf.cast(tf.not_equal(tf.reduce_sum(X, reduction_indices=2), 0.), tf.int32), reduction_indices=1)    
  46.     
  47.     Y = tf.placeholder(dtype=tf.int32, shape=[batch_size, None])  
  48.     
  49.     #train_speech_to_text_network(wav_max_len)  #训练  
  50.       
  51.     wav_file = "./D4_750.wav"  
  52.     print (wav_file)  
  53.     speech_to_text(wav_file)  

猜你喜欢

转载自blog.csdn.net/yaningli/article/details/80223036