├── LICENSE
├── README.md
├── conf
├── __init__.py
├── __init__.pyc
├── hyparam.py
└── hyparam.pyc
├── data
└── aishell
│ ├── aishell.py
│ ├── manifest.dev
│ ├── manifest.test
│ ├── manifest.train
│ ├── mean_std.npz
│ └── vocab.txt
├── data_utils
├── __init__.py
├── __init__.pyc
├── audio.py
├── audio.pyc
├── audio_featurizer.py
├── audio_featurizer.pyc
├── build_vocab.py
├── compute_mean_std.py
├── normalizer.py
├── normalizer.pyc
├── process_manifest.py
├── process_manifest.pyc
├── speech.py
├── speech.pyc
├── utility.py
├── utility.pyc
├── utils.py
└── utils.pyc
├── demo_cache
└── __init__.py
├── demo_client.sh
├── demo_server.sh
├── deploy_demo
├── _init_paths.py
├── _init_paths.pyc
├── assert_zero.py
├── assert_zero.pyc
├── demo_client.py
└── demo_server.py
├── example
└── aishell
│ └── run_data.sh
├── img
└── arc.png
├── model_utils
├── __init__.py
├── __init__.pyc
├── init_model.py
├── init_model.pyc
├── network.py
└── network.pyc
├── models
└── lm
│ └── __init__.py
├── test.py
├── test_build.py
├── train.py
└── utils
├── __init__.py
├── __init__.pyc
├── decoder
├── __init__.py
├── __init__.pyc
├── model.py
├── model.pyc
├── swig_wrapper.py
└── swig_wrapper.pyc
├── utility.py
└── utility.pyc
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 基于tensorflow的语音识别系统
2 | ## 简介
3 | 基于 tensorflow 的中文语音识别框架, 模型结构参考 百度[Deepspeech2](http://proceedings.mlr.press/v48/amodei16.pdf) 的论文,训练语料采用Aishell 170 小时数据. 模型结构如下图所示:
4 |
5 |
6 |
7 |
百度Deepspeech2 语音识别模型结构
8 |
9 |
10 | **目前模型训练存在不收敛情况,正在调参研究中**
11 |
12 | ## 安装
13 | ### Prerequisites
14 | * 本程序基于 Python2.7
15 | * Tensorflow 版本应大于1.3,否则tf.nn.softmax等函数可能报错
16 |
17 | ### Setup
18 |
19 | * 安装以下依赖库 pkg-config, flac, ogg, vorbis, boost and swig,在Ubuntu 环境下可以通过apt-get 进行安装
20 | '''
21 | sudo apt-get install -y pkg-config libflac-dev libogg-dev libvorbis-dev libboost-dev swig
22 | '''
23 |
24 | ## 运行
25 |
26 | * 进入conf文件夹,修改 hyparam.py 中的模型参数
27 | * 进入example/aishell 修改 run_data.sh 内相关存储路径后,运行该脚本生成 manfest.{train,dev,test} 文件、vocab.txt以及 mean_std.npz
28 | * 运行 train.py 训练模型
29 | * 运行test.py 进行测试
30 |
31 | ## server/client 运行
32 |
33 | * 打开 ./demo_client.sh or ./demo_server.sh 文件配置 IP、端口等信息
34 | * 执行 ./demo_server.sh 启动服务器
35 | * 执行 ./demo_client.sh 启动客户端
36 | * 在客户端内,持续按空格进行录音,松开空格后发送音频到服务器端进行语音识别
37 |
38 | ## 语言模型
39 | 语言模型采用的是百度提供的中文语言模型,由KenLM工具生成并剪枝得到。详情请查看[Mandarin LM](https://github.com/PaddlePaddle/DeepSpeech#mandarin-lm)
40 |
41 | ### 语言模型参数
42 | 语言模型用于测试和使用阶段的解码。因此当声学模型训练时,语言模型的参数也需要进行改变。hyparam里的参数只是随手写的...
43 |
44 | ## TODO
45 | * 对模型进行调参或结构调整使其能够使用。
46 |
47 | ## Ref
48 | 以 [xxbb1234021/speech_recognition](https://github.com/xxbb1234021/speech_recognition) 和 [PaddlePaddle/Deepspeech2](https://github.com/PaddlePaddle/DeepSpeech)为基础进行修改
49 |
--------------------------------------------------------------------------------
/conf/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/conf/__init__.py
--------------------------------------------------------------------------------
/conf/__init__.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/conf/__init__.pyc
--------------------------------------------------------------------------------
/conf/hyparam.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding=utf-8
3 |
4 |
5 | class Config():
6 | '''
7 | Class to save all config in traing and decoding
8 | :param: None
9 | '''
10 | def __init__(self):
11 |
12 | self.batch_size = 8
13 |
14 | # Network hyparam
15 | self.n_brnn_layers = 3
16 | self.n_cell_brnn = 512
17 | self.learning_rate = 0.001
18 | self.keep_dropout_rate = 0.95
19 | self.b_stddev = 0.046875
20 | self.h_stddev = 0.046875
21 |
22 | # Feature
23 | self.n_input = 39 # 计算MFCC的个数
24 | self.n_context = 2 # n gram around current frame
25 | self.specgram_type = 'linear' # if 'linear' use specgram. 'mfcc' use mfcc with mfcc + delta1 + delta2
26 | self.use_bn = True # Batch normalization
27 |
28 | # Decoder
29 | self.use_lm_decoder = True # Wether use lm decoder. If False, use tf.ctc_beam_search_decoder
30 | self.alpha = 1.2
31 | self.beta = 2.5
32 | self.cutoff_prob = 0.99
33 | self.cutoff_top_n = 10
34 | self.num_proc_bsearch = 8
35 | self.beam_size = 400
36 | self.lang_model_path = './models/lm/zh_giga.no_cna_cmn.prune01244.klm' # you can download it in https://github.com/PaddlePaddle/DeepSpeech
37 |
38 | # Config path
39 | self.vocab_path = u'data/aishell/vocab.txt'
40 | self.wav_path = u'/media/nlp/23ACE59C56A55BF3/wav_file/thchs30/thchs30_tensorflow/wav/'
41 | self.lable_file = u'/media/nlp/23ACE59C56A55BF3/wav_file/thchs30/thchs30_tensorflow/doc/trans/test.word.txt'
42 | self.savedir = u'/media/nlp/23ACE59C56A55BF3/wav_file/thchs30/thchs30_tensorflow/'
43 | self.savefile = u'speech.cpkt'
44 | self.tensorboardfile = u'/media/nlp/23ACE59C56A55BF3/wav_file/thchs30/thchs30_tensorflow/wav/log'
45 |
--------------------------------------------------------------------------------
/conf/hyparam.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/conf/hyparam.pyc
--------------------------------------------------------------------------------
/data/aishell/aishell.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding=utf-8
3 |
4 | # author@baidu deepspeech
5 | # modified by Pelhans
6 |
7 | """
8 | Prepare Aishell mandarin dataset
9 | Create manifest files.
10 | Manifest file is a json-format file with each line containing the
11 | meta data (i.e. audio filepath, transcript and audio duration)
12 | of each audio file in the data set.
13 | """
14 | from __future__ import absolute_import
15 | from __future__ import division
16 | from __future__ import print_function
17 |
18 | import os, sys
19 | import codecs
20 | import soundfile
21 | import json
22 | import argparse
23 |
24 | sys.path.append(r'../../')
25 | from data_utils.utility import download, unpack
26 |
27 |
28 | DATA_HOME = "/media/nlp/23ACE59C56A55BF3/wav_file/"
29 |
30 | URL_ROOT = 'http://www.openslr.org/resources/33'
31 | DATA_URL = URL_ROOT + '/data_aishell.tgz'
32 | MD5_DATA = '2f494334227864a8a8fec932999db9d8'
33 |
34 | parser = argparse.ArgumentParser(description=__doc__)
35 | parser.add_argument(
36 | "--target_dir",
37 | default=DATA_HOME + "aishell",
38 | type=str,
39 | help="Directory to save the dataset. (default: %(default)s)")
40 | parser.add_argument(
41 | "--manifest_prefix",
42 | default="manifest",
43 | type=str,
44 | help="Filepath prefix for output manifests. (default: %(default)s)")
45 | args = parser.parse_args()
46 |
47 |
48 | def create_manifest(data_dir, manifest_path_prefix):
49 | print("Creating manifest %s ..." % manifest_path_prefix)
50 | json_lines = []
51 | transcript_path = os.path.join(data_dir, 'transcript',
52 | 'aishell_transcript_v0.8.txt')
53 | transcript_dict = {}
54 | for line in codecs.open(transcript_path, 'r', 'utf-8'):
55 | line = line.strip()
56 | if line == '': continue
57 | audio_id, text = line.split(' ', 1)
58 | # remove withespace
59 | text = ''.join(text.split())
60 | transcript_dict[audio_id] = text
61 |
62 | data_types = ['train', 'dev', 'test']
63 | for type in data_types:
64 | del json_lines[:]
65 | audio_dir = os.path.join(data_dir, 'wav', type)
66 | for subfolder, _, filelist in sorted(os.walk(audio_dir)):
67 | for fname in filelist:
68 | audio_path = os.path.join(subfolder, fname)
69 | audio_id = fname[:-4]
70 | # if no transcription for audio then skipped
71 | if audio_id not in transcript_dict:
72 | continue
73 | audio_data, samplerate = soundfile.read(audio_path)
74 | duration = float(len(audio_data) / samplerate)
75 | text = transcript_dict[audio_id]
76 | json_lines.append(
77 | json.dumps(
78 | {
79 | 'audio_filepath': audio_path,
80 | 'duration': duration,
81 | 'text': text
82 | },
83 | ensure_ascii=False))
84 | manifest_path = manifest_path_prefix + '.' + type
85 | with codecs.open(manifest_path, 'w', 'utf-8') as fout:
86 | for line in json_lines:
87 | fout.write(line + '\n')
88 |
89 |
90 | def prepare_dataset(url, md5sum, target_dir, manifest_path):
91 | """Download, unpack and create manifest file."""
92 | data_dir = os.path.join(target_dir, 'data_aishell')
93 | if not os.path.exists(data_dir):
94 | filepath = download(url, md5sum, target_dir)
95 | unpack(filepath, target_dir)
96 | # unpack all audio tar files
97 | audio_dir = os.path.join(data_dir, 'wav')
98 | for subfolder, _, filelist in sorted(os.walk(audio_dir)):
99 | for ftar in filelist:
100 | unpack(os.path.join(subfolder, ftar), subfolder, True)
101 | else:
102 | print("Skip downloading and unpacking. Data already exists in %s." %
103 | target_dir)
104 | create_manifest(data_dir, manifest_path)
105 |
106 |
107 | def main():
108 | if args.target_dir.startswith('~'):
109 | args.target_dir = os.path.expanduser(args.target_dir)
110 |
111 | prepare_dataset(
112 | url=DATA_URL,
113 | md5sum=MD5_DATA,
114 | target_dir=args.target_dir,
115 | manifest_path=args.manifest_prefix)
116 |
117 |
118 | if __name__ == '__main__':
119 | main()
120 |
--------------------------------------------------------------------------------
/data/aishell/mean_std.npz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/data/aishell/mean_std.npz
--------------------------------------------------------------------------------
/data/aishell/vocab.txt:
--------------------------------------------------------------------------------
1 | 的
2 | 一
3 | 在
4 | 是
5 | 中
6 | 十
7 | 人
8 | 有
9 | 二
10 | 上
11 | 了
12 | 不
13 | 国
14 | 市
15 | 大
16 | 业
17 | 为
18 | 年
19 | 三
20 | 发
21 | 个
22 | 出
23 | 分
24 | 行
25 | 会
26 | 地
27 | 公
28 | 成
29 | 这
30 | 和
31 | 到
32 | 五
33 | 对
34 | 产
35 | 时
36 | 能
37 | 场
38 | 房
39 | 来
40 | 以
41 | 百
42 | 新
43 | 日
44 | 之
45 | 者
46 | 将
47 | 现
48 | 要
49 | 家
50 | 四
51 | 多
52 | 资
53 | 月
54 | 也
55 | 后
56 | 零
57 | 方
58 | 下
59 | 机
60 | 前
61 | 于
62 | 生
63 | 点
64 | 比
65 | 开
66 | 高
67 | 动
68 | 经
69 | 进
70 | 报
71 | 赛
72 | 体
73 | 用
74 | 价
75 | 金
76 | 车
77 | 可
78 | 万
79 | 子
80 | 司
81 | 过
82 | 被
83 | 自
84 | 手
85 | 本
86 | 全
87 | 作
88 | 目
89 | 八
90 | 最
91 | 电
92 | 六
93 | 部
94 | 我
95 | 交
96 | 七
97 | 面
98 | 力
99 | 九
100 | 企
101 | 度
102 | 实
103 | 加
104 | 元
105 | 小
106 | 其
107 | 定
108 | 已
109 | 同
110 | 还
111 | 城
112 | 而
113 | 工
114 | 内
115 | 与
116 | 关
117 | 合
118 | 得
119 | 他
120 | 法
121 | 网
122 | 品
123 | 就
124 | 入
125 | 记
126 | 理
127 | 名
128 | 长
129 | 事
130 | 两
131 | 商
132 | 女
133 | 们
134 | 京
135 | 都
136 | 并
137 | 但
138 | 制
139 | 平
140 | 化
141 | 主
142 | 期
143 | 重
144 | 次
145 | 据
146 | 表
147 | 保
148 | 通
149 | 相
150 | 利
151 | 政
152 | 道
153 | 务
154 | 天
155 | 量
156 | 间
157 | 展
158 | 北
159 | 第
160 | 员
161 | 所
162 | 提
163 | 因
164 | 海
165 | 好
166 | 数
167 | 投
168 | 示
169 | 管
170 | 建
171 | 外
172 | 更
173 | 区
174 | 从
175 | 等
176 | 项
177 | 应
178 | 运
179 | 性
180 | 计
181 | 增
182 | 收
183 | 当
184 | 信
185 | 明
186 | 位
187 | 着
188 | 民
189 | 起
190 | 学
191 | 台
192 | 规
193 | 调
194 | 持
195 | 设
196 | 很
197 | 今
198 | 没
199 | 格
200 | 正
201 | 股
202 | 心
203 | 然
204 | 去
205 | 此
206 | 安
207 | 无
208 | 如
209 | 受
210 | 科
211 | 美
212 | 果
213 | 线
214 | 身
215 | 队
216 | 基
217 | 达
218 | 世
219 | 东
220 | 证
221 | 需
222 | 费
223 | 近
224 | 情
225 | 消
226 | 布
227 | 未
228 | 标
229 | 些
230 | 求
231 | 步
232 | 男
233 | 看
234 | 里
235 | 向
236 | 千
237 | 说
238 | 息
239 | 回
240 | 式
241 | 及
242 | 米
243 | 门
244 | 意
245 | 接
246 | 改
247 | 续
248 | 监
249 | 联
250 | 总
251 | 打
252 | 亿
253 | 讯
254 | 至
255 | 销
256 | 获
257 | 件
258 | 住
259 | 水
260 | 整
261 | 老
262 | 张
263 | 院
264 | 技
265 | 环
266 | 该
267 | 局
268 | 路
269 | 特
270 | 售
271 | 强
272 | 问
273 | 购
274 | 楼
275 | 由
276 | 统
277 | 处
278 | 涨
279 | 让
280 | 乐
281 | 题
282 | 决
283 | 系
284 | 称
285 | 影
286 | 推
287 | 银
288 | 少
289 | 广
290 | 只
291 | 显
292 | 战
293 | 己
294 | 降
295 | 常
296 | 创
297 | 户
298 | 首
299 | 完
300 | 查
301 | 案
302 | 选
303 | 种
304 | 策
305 | 易
306 | 牌
307 | 参
308 | 立
309 | 营
310 | 跑
311 | 结
312 | 势
313 | 备
314 | 认
315 | 程
316 | 造
317 | 球
318 | 准
319 | 低
320 | 各
321 | 超
322 | 友
323 | 代
324 | 存
325 | 再
326 | 级
327 | 放
328 | 做
329 | 原
330 | 文
331 | 险
332 | 物
333 | 传
334 | 款
335 | 样
336 | 单
337 | 较
338 | 告
339 | 转
340 | 界
341 | 供
342 | 警
343 | 解
344 | 给
345 | 客
346 | 风
347 | 华
348 | 州
349 | 预
350 | 周
351 | 取
352 | 她
353 | 率
354 | 指
355 | 则
356 | 走
357 | 搜
358 | 每
359 | 导
360 | 视
361 | 片
362 | 变
363 | 集
364 | 升
365 | 排
366 | 口
367 | 型
368 | 头
369 | 任
370 | 源
371 | 术
372 | 积
373 | 服
374 | 直
375 | 非
376 | 研
377 | 别
378 | 约
379 | 军
380 | 快
381 | 组
382 | 速
383 | 斯
384 | 社
385 | 专
386 | 医
387 | 活
388 | 领
389 | 使
390 | 王
391 | 器
392 | 想
393 | 马
394 | 构
395 | 团
396 | 份
397 | 模
398 | 难
399 | 智
400 | 或
401 | 先
402 | 星
403 | 施
404 | 带
405 | 么
406 | 拉
407 | 引
408 | 岁
409 | 照
410 | 微
411 | 融
412 | 支
413 | 南
414 | 狐
415 | 儿
416 | 游
417 | 办
418 | 始
419 | 权
420 | 绩
421 | 士
422 | 媒
423 | 确
424 | 半
425 | 仅
426 | 奥
427 | 控
428 | 况
429 | 深
430 | 限
431 | 委
432 | 随
433 | 税
434 | 类
435 | 越
436 | 注
437 | 流
438 | 望
439 | 幅
440 | 均
441 | 争
442 | 亚
443 | 财
444 | 节
445 | 包
446 | 划
447 | 众
448 | 额
449 | 空
450 | 态
451 | 西
452 | 终
453 | 土
454 | 连
455 | 致
456 | 娱
457 | 某
458 | 伤
459 | 济
460 | 育
461 | 值
462 | 际
463 | 仍
464 | 责
465 | 充
466 | 知
467 | 买
468 | 具
469 | 师
470 | 汽
471 | 质
472 | 几
473 | 响
474 | 反
475 | 究
476 | 条
477 | 李
478 | 居
479 | 共
480 | 感
481 | 站
482 | 露
483 | 观
484 | 优
485 | 宅
486 | 继
487 | 季
488 | 冠
489 | 教
490 | 光
491 | 负
492 | 采
493 | 博
494 | 见
495 | 互
496 | 域
497 | 范
498 | 山
499 | 段
500 | 依
501 | 极
502 | 气
503 | 图
504 | 境
505 | 举
506 | 套
507 | 何
508 | 尔
509 | 失
510 | 形
511 | 落
512 | 府
513 | 锦
514 | 健
515 | 复
516 | 益
517 | 贷
518 | 许
519 | 林
520 | 票
521 | 把
522 | 又
523 | 审
524 | 断
525 | 效
526 | 竞
527 | 停
528 | 击
529 | 容
530 | 色
531 | 双
532 | 拿
533 | 却
534 | 足
535 | 热
536 | 松
537 | 那
538 | 清
539 | 诉
540 | 曾
541 | 议
542 | 减
543 | 孩
544 | 考
545 | 功
546 | 助
547 | 板
548 | 除
549 | 太
550 | 试
551 | 港
552 | 疑
553 | 例
554 | 配
555 | 你
556 | 刘
557 | 占
558 | 根
559 | 装
560 | 才
561 | 置
562 | 突
563 | 即
564 | 且
565 | 离
566 | 论
567 | 盘
568 | 涉
569 | 破
570 | 爱
571 | 真
572 | 晚
573 | 演
574 | 练
575 | 纪
576 | 券
577 | 货
578 | 农
579 | 职
580 | 付
581 | 压
582 | 死
583 | 龙
584 | 库
585 | 言
586 | 火
587 | 严
588 | 号
589 | 护
590 | 稳
591 | 话
592 | 协
593 | 昨
594 | 善
595 | 判
596 | 算
597 | 救
598 | 满
599 | 克
600 | 亲
601 | 评
602 | 遭
603 | 红
604 | 卖
605 | 江
606 | 软
607 | 苹
608 | 田
609 | 药
610 | 希
611 | 普
612 | 略
613 | 官
614 | 验
615 | 闻
616 | 按
617 | 飞
618 | 边
619 | 补
620 | 担
621 | 索
622 | 检
623 | 底
624 | 厂
625 | 故
626 | 革
627 | 钱
628 | 频
629 | 象
630 | 必
631 | 租
632 | 湾
633 | 执
634 | 校
635 | 虽
636 | 托
637 | 债
638 | 拍
639 | 录
640 | 够
641 | 远
642 | 园
643 | 像
644 | 阳
645 | 馀
646 | 历
647 | 润
648 | 料
649 | 早
650 | 征
651 | 兴
652 | 康
653 | 店
654 | 状
655 | 端
656 | 否
657 | 障
658 | 病
659 | 便
660 | 围
661 | 往
662 | 层
663 | 批
664 | 测
665 | 尽
666 | 省
667 | 精
668 | 核
669 | 德
670 | 香
671 | 移
672 | 承
673 | 群
674 | 列
675 | 临
676 | 食
677 | 介
678 | 留
679 | 云
680 | 遇
681 | 请
682 | 跌
683 | 奖
684 | 宝
685 | 轻
686 | 激
687 | 属
688 | 夫
689 | 它
690 | 景
691 | 什
692 | 维
693 | 假
694 | 村
695 | 英
696 | 宣
697 | 治
698 | 花
699 | 夺
700 | 白
701 | 初
702 | 胜
703 | 透
704 | 神
705 | 福
706 | 修
707 | 访
708 | 铁
709 | 养
710 | 副
711 | 跳
712 | 辆
713 | 登
714 | 秒
715 | 卡
716 | 违
717 | 婚
718 | 伟
719 | 幕
720 | 短
721 | 届
722 | 杨
723 | 角
724 | 差
725 | 午
726 | 纷
727 | 律
728 | 逐
729 | 左
730 | 训
731 | 董
732 | 刚
733 | 波
734 | 青
735 | 爆
736 | 陈
737 | 候
738 | 宁
739 | 酒
740 | 适
741 | 觉
742 | 字
743 | 书
744 | 似
745 | 黄
746 | 括
747 | 嫌
748 | 块
749 | 防
750 | 径
751 | 待
752 | 申
753 | 甚
754 | 独
755 | 退
756 | 庭
757 | 航
758 | 识
759 | 巴
760 | 右
761 | 述
762 | 止
763 | 亡
764 | 送
765 | 冲
766 | 眼
767 | 乘
768 | 络
769 | 罪
770 | 母
771 | 席
772 | 石
773 | 找
774 | 义
775 | 尼
776 | 令
777 | 志
778 | 换
779 | 析
780 | 损
781 | 卫
782 | 另
783 | 央
784 | 轮
785 | 扩
786 | 绿
787 | 滑
788 | 念
789 | 镇
790 | 刑
791 | 毒
792 | 史
793 | 紧
794 | 吴
795 | 免
796 | 抢
797 | 豪
798 | 乎
799 | 谈
800 | 纳
801 | 妈
802 | 罗
803 | 河
804 | 童
805 | 油
806 | 泳
807 | 洲
808 | 倒
809 | 吸
810 | 素
811 | 密
812 | 孙
813 | 富
814 | 县
815 | 穿
816 | 声
817 | 币
818 | 街
819 | 择
820 | 巨
821 | 犯
822 | 害
823 | 苏
824 | 思
825 | 愿
826 | 庆
827 | 促
828 | 追
829 | 跟
830 | 借
831 | 妻
832 | 措
833 | 赔
834 | 杀
835 | 旅
836 | 晨
837 | 摄
838 | 骗
839 | 温
840 | 汉
841 | 帮
842 | 链
843 | 迎
844 | 习
845 | 趋
846 | 贴
847 | 阶
848 | 疗
849 | 驾
850 | 黑
851 | 圳
852 | 版
853 | 罚
854 | 吃
855 | 亮
856 | 挥
857 | 背
858 | 虑
859 | 阿
860 | 私
861 | 细
862 | 绝
863 | 脑
864 | 础
865 | 切
866 | 命
867 | 裁
868 | 韩
869 | 写
870 | 伙
871 | 抓
872 | 须
873 | 秀
874 | 良
875 | 班
876 | 父
877 | 派
878 | 缺
879 | 享
880 | 脸
881 | 启
882 | 尚
883 | 戏
884 | 池
885 | 陆
886 | 撞
887 | 剧
888 | 危
889 | 招
890 | 签
891 | 戴
892 | 材
893 | 喜
894 | 夜
895 | 延
896 | 渐
897 | 偿
898 | 披
899 | 宗
900 | 针
901 | 操
902 | 募
903 | 拳
904 | 顺
905 | 艺
906 | 释
907 | 衣
908 | 拥
909 | 味
910 | 察
911 | 兰
912 | 迷
913 | 困
914 | 曝
915 | 竟
916 | 春
917 | 励
918 | 靠
919 | 室
920 | 欧
921 | 干
922 | 佳
923 | 估
924 | 坚
925 | 朋
926 | 净
927 | 盖
928 | 圈
929 | 歌
930 | 截
931 | 急
932 | 订
933 | 徽
934 | 束
935 | 患
936 | 顶
937 | 驶
938 | 距
939 | 序
940 | 累
941 | 晒
942 | 悉
943 | 丰
944 | 烈
945 | 姐
946 | 惠
947 | 硬
948 | 织
949 | 顾
950 | 挑
951 | 桥
952 | 培
953 | 旬
954 | 永
955 | 讨
956 | 暴
957 | 玩
958 | 伴
959 | 污
960 | 键
961 | 误
962 | 湖
963 | 怀
964 | 峰
965 | 欢
966 | 彩
967 | 归
968 | 冰
969 | 惊
970 | 探
971 | 古
972 | 败
973 | 异
974 | 抗
975 | 附
976 | 听
977 | 旧
978 | 馆
979 | 怎
980 | 缓
981 | 吗
982 | 暂
983 | 折
984 | 武
985 | 笑
986 | 刺
987 | 输
988 | 血
989 | 杰
990 | 熟
991 | 播
992 | 哪
993 | 简
994 | 休
995 | 阵
996 | 劳
997 | 拟
998 | 雪
999 | 坐
1000 | 账
1001 | 予
1002 | 昆
1003 | 丽
1004 | 刻
1005 | 避
1006 | 架
1007 | 凌
1008 | 谷
1009 | 钟
1010 | 绍
1011 | 音
1012 | 丈
1013 | 寻
1014 | 若
1015 | 综
1016 | 暖
1017 | 禁
1018 | 印
1019 | 威
1020 | 礼
1021 | 屋
1022 | 奇
1023 | 嘉
1024 | 语
1025 | 筹
1026 | 龄
1027 | 汇
1028 | 迅
1029 | 错
1030 | 徐
1031 | 雨
1032 | 座
1033 | 夏
1034 | 宽
1035 | 笔
1036 | 迪
1037 | 尤
1038 | 伦
1039 | 泽
1040 | 筑
1041 | 哥
1042 | 炒
1043 | 乡
1044 | 般
1045 | 粉
1046 | 谢
1047 | 倍
1048 | 攻
1049 | 野
1050 | 概
1051 | 肉
1052 | 朱
1053 | 杯
1054 | 虚
1055 | 鼓
1056 | 朝
1057 | 梦
1058 | 掉
1059 | 缩
1060 | 屏
1061 | 召
1062 | 震
1063 | 呼
1064 | 津
1065 | 冬
1066 | 码
1067 | 弟
1068 | 编
1069 | 幸
1070 | 郑
1071 | 潮
1072 | 锁
1073 | 拘
1074 | 梯
1075 | 渠
1076 | 储
1077 | 授
1078 | 晓
1079 | 诈
1080 | 秘
1081 | 涛
1082 | 川
1083 | 脚
1084 | 映
1085 | 染
1086 | 盛
1087 | 遍
1088 | 肥
1089 | 枪
1090 | 聚
1091 | 蓝
1092 | 洗
1093 | 斗
1094 | 讲
1095 | 画
1096 | 亏
1097 | 符
1098 | 刀
1099 | 吉
1100 | 翻
1101 | 扣
1102 | 守
1103 | 遗
1104 | 洋
1105 | 赞
1106 | 珠
1107 | 久
1108 | 呈
1109 | 宇
1110 | 丹
1111 | 侵
1112 | 苦
1113 | 挂
1114 | 毛
1115 | 森
1116 | 慢
1117 | 盗
1118 | 脱
1119 | 肯
1120 | 摩
1121 | 兵
1122 | 读
1123 | 枚
1124 | 添
1125 | 贵
1126 | 哈
1127 | 丝
1128 | 跨
1129 | 跃
1130 | 皮
1131 | 询
1132 | 榜
1133 | 顿
1134 | 逃
1135 | 胎
1136 | 诺
1137 | 沙
1138 | 触
1139 | 饭
1140 | 妹
1141 | 载
1142 | 俄
1143 | 揭
1144 | 刷
1145 | 隐
1146 | 封
1147 | 拆
1148 | 郭
1149 | 草
1150 | 妇
1151 | 赶
1152 | 册
1153 | 督
1154 | 芯
1155 | 孕
1156 | 既
1157 | 袭
1158 | 档
1159 | 舞
1160 | 贸
1161 | 慧
1162 | 陷
1163 | 爸
1164 | 餐
1165 | 木
1166 | 宏
1167 | 闭
1168 | 奶
1169 | 谁
1170 | 丁
1171 | 荣
1172 | 铜
1173 | 盈
1174 | 扬
1175 | 典
1176 | 桩
1177 | 拒
1178 | 毕
1179 | 宫
1180 | 捐
1181 | 返
1182 | 浪
1183 | 扶
1184 | 撑
1185 | 摘
1186 | 焦
1187 | 莞
1188 | 旗
1189 | 燃
1190 | 弃
1191 | 偷
1192 | 援
1193 | 途
1194 | 含
1195 | 坛
1196 | 末
1197 | 睡
1198 | 骨
1199 | 叫
1200 | 厅
1201 | 雷
1202 | 抱
1203 | 努
1204 | 吕
1205 | 镜
1206 | 玲
1207 | 玉
1208 | 郎
1209 | 弹
1210 | 抵
1211 | 床
1212 | 迹
1213 | 掌
1214 | 散
1215 | 坏
1216 | 煤
1217 | 盟
1218 | 冷
1219 | 胡
1220 | 虹
1221 | 瑞
1222 | 振
1223 | 祖
1224 | 恩
1225 | 潜
1226 | 菜
1227 | 仪
1228 | 牙
1229 | 伏
1230 | 牛
1231 | 痛
1232 | 雅
1233 | 固
1234 | 爷
1235 | 呢
1236 | 芝
1237 | 赵
1238 | 鲁
1239 | 梁
1240 | 淡
1241 | 狂
1242 | 握
1243 | 静
1244 | 纯
1245 | 勇
1246 | 沟
1247 | 纠
1248 | 赢
1249 | 杂
1250 | 砸
1251 | 婆
1252 | 藏
1253 | 慎
1254 | 搭
1255 | 塞
1256 | 蔡
1257 | 献
1258 | 齐
1259 | 奋
1260 | 章
1261 | 恶
1262 | 树
1263 | 晋
1264 | 秋
1265 | 冒
1266 | 剩
1267 | 祝
1268 | 课
1269 | 烟
1270 | 宜
1271 | 拼
1272 | 喝
1273 | 泰
1274 | 偏
1275 | 钢
1276 | 狗
1277 | 鲜
1278 | 寿
1279 | 隔
1280 | 浙
1281 | 坦
1282 | 籍
1283 | 鸟
1284 | 敏
1285 | 弱
1286 | 替
1287 | 趣
1288 | 剂
1289 | 叶
1290 | 杭
1291 | 答
1292 | 恢
1293 | 混
1294 | 耗
1295 | 炸
1296 | 乱
1297 | 杆
1298 | 族
1299 | 堂
1300 | 窃
1301 | 腿
1302 | 赚
1303 | 骑
1304 | 鱼
1305 | 疾
1306 | 诚
1307 | 恋
1308 | 缴
1309 | 棒
1310 | 岛
1311 | 恐
1312 | 捕
1313 | 巢
1314 | 侧
1315 | 迫
1316 | 萌
1317 | 船
1318 | 欲
1319 | 徒
1320 | 奔
1321 | 烧
1322 | 瓦
1323 | 尝
1324 | 递
1325 | 厚
1326 | 灵
1327 | 辉
1328 | 佛
1329 | 醒
1330 | 吧
1331 | 薪
1332 | 拓
1333 | 摆
1334 | 乏
1335 | 残
1336 | 莫
1337 | 矿
1338 | 琪
1339 | 迁
1340 | 阻
1341 | 雄
1342 | 扮
1343 | 碍
1344 | 毫
1345 | 曲
1346 | 梅
1347 | 辑
1348 | 衡
1349 | 射
1350 | 姓
1351 | 吨
1352 | 唯
1353 | 乒
1354 | 炳
1355 | 踪
1356 | 汪
1357 | 逆
1358 | 症
1359 | 繁
1360 | 滴
1361 | 翔
1362 | 卷
1363 | 卓
1364 | 谓
1365 | 迟
1366 | 拖
1367 | 灾
1368 | 碳
1369 | 扎
1370 | 亦
1371 | 沈
1372 | 陪
1373 | 娘
1374 | 洛
1375 | 忧
1376 | 唐
1377 | 轨
1378 | 尾
1379 | 赴
1380 | 誉
1381 | 窗
1382 | 诊
1383 | 怕
1384 | 凭
1385 | 党
1386 | 佐
1387 | 劵
1388 | 玮
1389 | 洁
1390 | 奏
1391 | 垄
1392 | 署
1393 | 恒
1394 | 泛
1395 | 斤
1396 | 赌
1397 | 菲
1398 | 莱
1399 | 撤
1400 | 缘
1401 | 伍
1402 | 旦
1403 | 蒙
1404 | 闹
1405 | 幼
1406 | 敢
1407 | 庄
1408 | 沿
1409 | 搏
1410 | 旺
1411 | 豆
1412 | 惯
1413 | 晶
1414 | 忙
1415 | 溢
1416 | 槛
1417 | 旁
1418 | 绑
1419 | 诸
1420 | 辞
1421 | 液
1422 | 纸
1423 | 氧
1424 | 鉴
1425 | 坡
1426 | 寸
1427 | 箱
1428 | 劲
1429 | 欠
1430 | 哲
1431 | 淘
1432 | 逼
1433 | 墨
1434 | 楚
1435 | 昌
1436 | 蛋
1437 | 猛
1438 | 岗
1439 | 岸
1440 | 唱
1441 | 坠
1442 | 劫
1443 | 饮
1444 | 咨
1445 | 摔
1446 | 搞
1447 | 伯
1448 | 墅
1449 | 墙
1450 | 殊
1451 | 宾
1452 | 洪
1453 | 井
1454 | 仓
1455 | 堵
1456 | 伊
1457 | 兼
1458 | 霸
1459 | 赖
1460 | 琳
1461 | 殴
1462 | 诗
1463 | 砍
1464 | 轿
1465 | 慈
1466 | 燕
1467 | 携
1468 | 允
1469 | 庞
1470 | 铺
1471 | 彻
1472 | 邀
1473 | 沉
1474 | 涵
1475 | 堪
1476 | 抛
1477 | 姆
1478 | 喊
1479 | 牵
1480 | 柯
1481 | 耳
1482 | 倾
1483 | 浦
1484 | 绕
1485 | 挖
1486 | 圾
1487 | 鸡
1488 | 贩
1489 | 垃
1490 | 腐
1491 | 漏
1492 | 阅
1493 | 览
1494 | 滨
1495 | 挺
1496 | 抽
1497 | 拨
1498 | 癌
1499 | 窄
1500 | 逊
1501 | 偶
1502 | 婷
1503 | 词
1504 | 横
1505 | 颁
1506 | 贡
1507 | 抄
1508 | 羊
1509 | 聘
1510 | 扰
1511 | 吐
1512 | 冕
1513 | 疯
1514 | 虎
1515 | 沪
1516 | 腾
1517 | 糖
1518 | 娃
1519 | 栏
1520 | 炼
1521 | 淀
1522 | 贿
1523 | 婴
1524 | 怪
1525 | 澳
1526 | 泄
1527 | 捷
1528 | 灯
1529 | 植
1530 | 篮
1531 | 欣
1532 | 忍
1533 | 帅
1534 | 忽
1535 | 朗
1536 | 冻
1537 | 圆
1538 | 废
1539 | 凯
1540 | 押
1541 | 壁
1542 | 霞
1543 | 尸
1544 | 辛
1545 | 祥
1546 | 泡
1547 | 迈
1548 | 械
1549 | 淫
1550 | 奸
1551 | 佩
1552 | 拔
1553 | 攀
1554 | 卧
1555 | 毁
1556 | 瓶
1557 | 句
1558 | 裂
1559 | 杜
1560 | 踏
1561 | 默
1562 | 丢
1563 | 绪
1564 | 扫
1565 | 麻
1566 | 莉
1567 | 舍
1568 | 驰
1569 | 颜
1570 | 魔
1571 | 搬
1572 | 鬼
1573 | 乔
1574 | 邮
1575 | 疆
1576 | 乳
1577 | 鹏
1578 | 塌
1579 | 君
1580 | 艰
1581 | 暗
1582 | 宿
1583 | 贝
1584 | 姿
1585 | 愈
1586 | 脏
1587 | 兄
1588 | 塔
1589 | 眠
1590 | 寓
1591 | 贯
1592 | 聊
1593 | 碰
1594 | 侦
1595 | 酷
1596 | 敦
1597 | 宋
1598 | 仿
1599 | 廉
1600 | 俩
1601 | 劝
1602 | 羽
1603 | 颖
1604 | 忘
1605 | 巩
1606 | 契
1607 | 著
1608 | 敌
1609 | 舒
1610 | 循
1611 | 肖
1612 | 饼
1613 | 荐
1614 | 挤
1615 | 曼
1616 | 熊
1617 | 悬
1618 | 兑
1619 | 厦
1620 | 谨
1621 | 详
1622 | 惨
1623 | 洞
1624 | 湃
1625 | 敬
1626 | 恰
1627 | 番
1628 | 涯
1629 | 巡
1630 | 纵
1631 | 隆
1632 | 澎
1633 | 炉
1634 | 肩
1635 | 酸
1636 | 锋
1637 | 浮
1638 | 摸
1639 | 伐
1640 | 涌
1641 | 糕
1642 | 薄
1643 | 悄
1644 | 麦
1645 | 菌
1646 | 茶
1647 | 哭
1648 | 乌
1649 | 谋
1650 | 稿
1651 | 漫
1652 | 逸
1653 | 樊
1654 | 摇
1655 | 娜
1656 | 猫
1657 | 驱
1658 | 酬
1659 | 姑
1660 | 烯
1661 | 粮
1662 | 凶
1663 | 巧
1664 | 吓
1665 | 纹
1666 | 摊
1667 | 仁
1668 | 伪
1669 | 邻
1670 | 冀
1671 | 讼
1672 | 灭
1673 | 稀
1674 | 吊
1675 | 尖
1676 | 凡
1677 | 驻
1678 | 胞
1679 | 屡
1680 | 厉
1681 | 傅
1682 | 冯
1683 | 桌
1684 | 俊
1685 | 仑
1686 | 汰
1687 | 诞
1688 | 姻
1689 | 惜
1690 | 闪
1691 | 郁
1692 | 尊
1693 | 怒
1694 | 鸿
1695 | 泉
1696 | 帕
1697 | 胖
1698 | 俱
1699 | 歉
1700 | 肇
1701 | 遥
1702 | 闯
1703 | 咬
1704 | 斌
1705 | 蕾
1706 | 甲
1707 | 磨
1708 | 抚
1709 | 邦
1710 | 勒
1711 | 尺
1712 | 赫
1713 | 颇
1714 | 埃
1715 | 鑫
1716 | 骂
1717 | 卢
1718 | 妙
1719 | 饰
1720 | 稍
1721 | 晰
1722 | 锻
1723 | 肌
1724 | 熙
1725 | 赠
1726 | 闲
1727 | 郊
1728 | 艾
1729 | 扭
1730 | 圣
1731 | 腰
1732 | 浓
1733 | 柳
1734 | 黎
1735 | 伸
1736 | 泥
1737 | 尿
1738 | 暑
1739 | 掀
1740 | 匹
1741 | 悲
1742 | 甜
1743 | 猪
1744 | 啦
1745 | 敲
1746 | 忆
1747 | 颗
1748 | 抑
1749 | 牢
1750 | 堆
1751 | 乓
1752 | 姜
1753 | 汤
1754 | 芬
1755 | 轴
1756 | 臂
1757 | 甘
1758 | 畅
1759 | 腹
1760 | 崇
1761 | 袁
1762 | 溺
1763 | 紫
1764 | 辅
1765 | 盾
1766 | 厕
1767 | 浩
1768 | 胶
1769 | 蒋
1770 | 旋
1771 | 嘴
1772 | 邱
1773 | 刊
1774 | 矛
1775 | 渡
1776 | 稽
1777 | 珍
1778 | 塑
1779 | 践
1780 | 玻
1781 | 幻
1782 | 履
1783 | 邓
1784 | 碎
1785 | 盐
1786 | 宴
1787 | 割
1788 | 赏
1789 | 姚
1790 | 拦
1791 | 毅
1792 | 泪
1793 | 吁
1794 | 帝
1795 | 欺
1796 | 壮
1797 | 帖
1798 | 苗
1799 | 旭
1800 | 柜
1801 | 槽
1802 | 锂
1803 | 萨
1804 | 悦
1805 | 拐
1806 | 惩
1807 | 遵
1808 | 贾
1809 | 鞋
1810 | 桂
1811 | 璃
1812 | 仔
1813 | 祸
1814 | 篇
1815 | 挡
1816 | 曹
1817 | 锡
1818 | 憾
1819 | 裤
1820 | 诱
1821 | 肃
1822 | 陶
1823 | 硕
1824 | 赁
1825 | 衔
1826 | 裕
1827 | 杠
1828 | 厘
1829 | 氮
1830 | 潘
1831 | 夹
1832 | 潭
1833 | 艳
1834 | 疼
1835 | 揽
1836 | 猜
1837 | 馈
1838 | 逾
1839 | 疏
1840 | 秩
1841 | 劣
1842 | 凤
1843 | 烦
1844 | 漂
1845 | 忠
1846 | 屈
1847 | 廷
1848 | 谣
1849 | 弯
1850 | 虾
1851 | 绮
1852 | 倡
1853 | 舆
1854 | 剑
1855 | 辽
1856 | 蝶
1857 | 兆
1858 | 棋
1859 | 栋
1860 | 雇
1861 | 魅
1862 | 擦
1863 | 疲
1864 | 删
1865 | 魏
1866 | 妥
1867 | 催
1868 | 垫
1869 | 啊
1870 | 氏
1871 | 皇
1872 | 彭
1873 | 弗
1874 | 擅
1875 | 氛
1876 | 沃
1877 | 膜
1878 | 钻
1879 | 懂
1880 | 瑄
1881 | 裸
1882 | 貌
1883 | 勤
1884 | 帽
1885 | 碑
1886 | 颠
1887 | 澄
1888 | 址
1889 | 奎
1890 | 蜜
1891 | 孤
1892 | 汗
1893 | 勾
1894 | 锅
1895 | 闫
1896 | 捧
1897 | 颈
1898 | 笼
1899 | 胁
1900 | 框
1901 | 虫
1902 | 荷
1903 | 葛
1904 | 寺
1905 | 捞
1906 | 厨
1907 | 爬
1908 | 辩
1909 | 贪
1910 | 丑
1911 | 削
1912 | 湘
1913 | 鼻
1914 | 乃
1915 | 柏
1916 | 拜
1917 | 描
1918 | 狱
1919 | 吵
1920 | 佣
1921 | 您
1922 | 飙
1923 | 吹
1924 | 轰
1925 | 宠
1926 | 岳
1927 | 怡
1928 | 咖
1929 | 贼
1930 | 磊
1931 | 耐
1932 | 灰
1933 | 贤
1934 | 逝
1935 | 侠
1936 | 肠
1937 | 抬
1938 | 昂
1939 | 俗
1940 | 姣
1941 | 辖
1942 | 瘦
1943 | 奈
1944 | 填
1945 | 昕
1946 | 虐
1947 | 萧
1948 | 蓄
1949 | 猥
1950 | 醉
1951 | 陕
1952 | 贫
1953 | 坑
1954 | 娇
1955 | 饱
1956 | 捡
1957 | 轩
1958 | 峻
1959 | 盲
1960 | 帆
1961 | 瓜
1962 | 雯
1963 | 滞
1964 | 串
1965 | 狼
1966 | 役
1967 | 沫
1968 | 尴
1969 | 戒
1970 | 鼠
1971 | 屯
1972 | 尬
1973 | 瑜
1974 | 睛
1975 | 茂
1976 | 彦
1977 | 喷
1978 | 掘
1979 | 弥
1980 | 棚
1981 | 亨
1982 | 媳
1983 | 插
1984 | 琴
1985 | 凉
1986 | 灿
1987 | 罕
1988 | 纽
1989 | 彼
1990 | 凸
1991 | 肚
1992 | 逻
1993 | 侯
1994 | 峡
1995 | 孔
1996 | 炮
1997 | 荡
1998 | 跪
1999 | 壳
2000 | 荒
2001 | 馨
2002 | 叹
2003 | 踢
2004 | 鸣
2005 | 钧
2006 | 谭
2007 | 酿
2008 | 瞬
2009 | 孟
2010 | 砖
2011 | 旨
2012 | 玛
2013 | 棍
2014 | 盆
2015 | 茨
2016 | 胀
2017 | 蔚
2018 | 躲
2019 | 蒂
2020 | 滚
2021 | 柱
2022 | 涂
2023 | 肢
2024 | 胸
2025 | 崛
2026 | 肤
2027 | 尘
2028 | 衷
2029 | 辰
2030 | 阔
2031 | 鼎
2032 | 剪
2033 | 斜
2034 | 滋
2035 | 页
2036 | 斩
2037 | 柔
2038 | 璇
2039 | 僵
2040 | 萄
2041 | 伞
2042 | 扇
2043 | 丙
2044 | 昏
2045 | 阴
2046 | 烂
2047 | 谐
2048 | 葡
2049 | 挣
2050 | 桶
2051 | 贺
2052 | 寄
2053 | 秦
2054 | 妆
2055 | 碗
2056 | 吞
2057 | 萎
2058 | 桑
2059 | 媛
2060 | 喂
2061 | 驳
2062 | 捉
2063 | 弄
2064 | 谎
2065 | 楠
2066 | 晕
2067 | 怨
2068 | 逢
2069 | 煌
2070 | 赋
2071 | 雾
2072 | 吻
2073 | 戈
2074 | 窝
2075 | 溪
2076 | 愤
2077 | 逮
2078 | 聪
2079 | 衰
2080 | 夕
2081 | 埋
2082 | 痕
2083 | 睐
2084 | 芳
2085 | 滩
2086 | 咚
2087 | 粗
2088 | 孵
2089 | 芸
2090 | 渣
2091 | 嫁
2092 | 肿
2093 | 硅
2094 | 厢
2095 | 寒
2096 | 脂
2097 | 辈
2098 | 钓
2099 | 肝
2100 | 趁
2101 | 桃
2102 | 卿
2103 | 椅
2104 | 耍
2105 | 硫
2106 | 喀
2107 | 亵
2108 | 躺
2109 | 炎
2110 | 翼
2111 | 杉
2112 | 韦
2113 | 竹
2114 | 译
2115 | 渝
2116 | 袋
2117 | 侣
2118 | 郝
2119 | 扑
2120 | 呆
2121 | 绘
2122 | 侃
2123 | 寨
2124 | 琐
2125 | 钩
2126 | 膝
2127 | 瞩
2128 | 殖
2129 | 墓
2130 | 盒
2131 | 炭
2132 | 慌
2133 | 璨
2134 | 缝
2135 | 踩
2136 | 陵
2137 | 囊
2138 | 扔
2139 | 塘
2140 | 谌
2141 | 辟
2142 | 狠
2143 | 趴
2144 | 梳
2145 | 啡
2146 | 粒
2147 | 匪
2148 | 盼
2149 | 夸
2150 | 缠
2151 | 烫
2152 | 歧
2153 | 铅
2154 | 靖
2155 | 叠
2156 | 挽
2157 | 腕
2158 | 罩
2159 | 闸
2160 | 垒
2161 | 弊
2162 | 斥
2163 | 刹
2164 | 锐
2165 | 勘
2166 | 坊
2167 | 慰
2168 | 衍
2169 | 掩
2170 | 翁
2171 | 皆
2172 | 撒
2173 | 拾
2174 | 耀
2175 | 臭
2176 | 顽
2177 | 兹
2178 | 辱
2179 | 仰
2180 | 掷
2181 | 舱
2182 | 蛇
2183 | 脉
2184 | 贬
2185 | 蟹
2186 | 疫
2187 | 穷
2188 | 彰
2189 | 猴
2190 | 裹
2191 | 钥
2192 | 胃
2193 | 宪
2194 | 晖
2195 | 蹈
2196 | 炫
2197 | 犬
2198 | 湿
2199 | 啥
2200 | 掏
2201 | 凝
2202 | 畴
2203 | 挪
2204 | 妮
2205 | 咏
2206 | 坎
2207 | 睹
2208 | 霍
2209 | 倪
2210 | 惑
2211 | 扳
2212 | 酝
2213 | 渴
2214 | 蜂
2215 | 捅
2216 | 碾
2217 | 蚁
2218 | 冤
2219 | 擂
2220 | 奢
2221 | 浅
2222 | 靓
2223 | 帷
2224 | 匿
2225 | 娟
2226 | 惹
2227 | 辨
2228 | 瘫
2229 | 铬
2230 | 刮
2231 | 纱
2232 | 辐
2233 | 狮
2234 | 牲
2235 | 陌
2236 | 撕
2237 | 咸
2238 | 剥
2239 | 瓷
2240 | 脆
2241 | 胆
2242 | 妍
2243 | 皓
2244 | 舰
2245 | 瞄
2246 | 盯
2247 | 遂
2248 | 匙
2249 | 锈
2250 | 傲
2251 | 坝
2252 | 耕
2253 | 悔
2254 | 濠
2255 | 膀
2256 | 柄
2257 | 禽
2258 | 禾
2259 | 牺
2260 | 翘
2261 | 卸
2262 | 晴
2263 | 纤
2264 | 朵
2265 | 堡
2266 | 铭
2267 | 渗
2268 | 喻
2269 | 叔
2270 | 羞
2271 | 逛
2272 | 猝
2273 | 沸
2274 | 浸
2275 | 氢
2276 | 嫖
2277 | 慨
2278 | 僧
2279 | 岩
2280 | 辣
2281 | 怖
2282 | 浏
2283 | 犹
2284 | 淇
2285 | 奠
2286 | 函
2287 | 咕
2288 | 亭
2289 | 御
2290 | 羡
2291 | 糟
2292 | 亩
2293 | 垂
2294 | 肺
2295 | 滥
2296 | 慕
2297 | 淑
2298 | 眉
2299 | 瑟
2300 | 斑
2301 | 魄
2302 | 扯
2303 | 骚
2304 | 跻
2305 | 崔
2306 | 纺
2307 | 撰
2308 | 裙
2309 | 鲍
2310 | 擎
2311 | 洽
2312 | 恨
2313 | 肾
2314 | 谦
2315 | 岭
2316 | 贞
2317 | 乞
2318 | 甩
2319 | 莲
2320 | 袖
2321 | 瘾
2322 | 筋
2323 | 仗
2324 | 骤
2325 | 琦
2326 | 邹
2327 | 悍
2328 | 糊
2329 | 穆
2330 | 盔
2331 | 牧
2332 | 纲
2333 | 勃
2334 | 莎
2335 | 昔
2336 | 箭
2337 | 嫂
2338 | 楷
2339 | 坞
2340 | 叉
2341 | 莓
2342 | 祈
2343 | 霏
2344 | 簿
2345 | 锤
2346 | 妨
2347 | 迄
2348 | 磷
2349 | 娶
2350 | 瞒
2351 | 汁
2352 | 孝
2353 | 宰
2354 | 丧
2355 | 沦
2356 | 萍
2357 | 咋
2358 | 蔓
2359 | 巅
2360 | 霾
2361 | 苛
2362 | 唇
2363 | 脖
2364 | 崩
2365 | 砂
2366 | 蛙
2367 | 啤
2368 | 浆
2369 | 谱
2370 | 艘
2371 | 烤
2372 | 蔬
2373 | 鹤
2374 | 雕
2375 | 爽
2376 | 兽
2377 | 豫
2378 | 绵
2379 | 奉
2380 | 泼
2381 | 抹
2382 | 俏
2383 | 惧
2384 | 恼
2385 | 兜
2386 | 赤
2387 | 撼
2388 | 廊
2389 | 铸
2390 | 甸
2391 | 挫
2392 | 坍
2393 | 姨
2394 | 闷
2395 | 痴
2396 | 饿
2397 | 艇
2398 | 淮
2399 | 朴
2400 | 柴
2401 | 仙
2402 | 剔
2403 | 荧
2404 | 捣
2405 | 钦
2406 | 倩
2407 | 兔
2408 | 肋
2409 | 捍
2410 | 萤
2411 | 绳
2412 | 剖
2413 | 秉
2414 | 哀
2415 | 侈
2416 | 遮
2417 | 霖
2418 | 碟
2419 | 佑
2420 | 韵
2421 | 钉
2422 | 鳄
2423 | 瘤
2424 | 渊
2425 | 渔
2426 | 缔
2427 | 灌
2428 | 罢
2429 | 茅
2430 | 帐
2431 | 浇
2432 | 葩
2433 | 赂
2434 | 竣
2435 | 壤
2436 | 躁
2437 | 嘲
2438 | 凑
2439 | 弈
2440 | 鸭
2441 | 芽
2442 | 钞
2443 | 薇
2444 | 苑
2445 | 漠
2446 | 磅
2447 | 铲
2448 | 廖
2449 | 溜
2450 | 戚
2451 | 竖
2452 | 遏
2453 | 衫
2454 | 彤
2455 | 幺
2456 | 屠
2457 | 旱
2458 | 忌
2459 | 耶
2460 | 钮
2461 | 侨
2462 | 筛
2463 | 磁
2464 | 魂
2465 | 寂
2466 | 焰
2467 | 酵
2468 | 庙
2469 | 卵
2470 | 婿
2471 | 澡
2472 | 嘛
2473 | 邵
2474 | 捂
2475 | 筒
2476 | 秽
2477 | 蝙
2478 | 蹲
2479 | 爹
2480 | 蝠
2481 | 蕴
2482 | 溯
2483 | 尹
2484 | 余
2485 | 焚
2486 | 珊
2487 | 蹭
2488 | 巷
2489 | 蒸
2490 | 龟
2491 | 缉
2492 | 逗
2493 | 妖
2494 | 硝
2495 | 呀
2496 | 歪
2497 | 浴
2498 | 靡
2499 | 翰
2500 | 噪
2501 | 鹅
2502 | 挨
2503 | 愧
2504 | 攒
2505 | 捆
2506 | 谍
2507 | 潼
2508 | 巾
2509 | 燥
2510 | 峥
2511 | 脊
2512 | 蛛
2513 | 悠
2514 | 螺
2515 | 臣
2516 | 熬
2517 | 泣
2518 | 讶
2519 | 悼
2520 | 崖
2521 | 孚
2522 | 牟
2523 | 阱
2524 | 锰
2525 | 擒
2526 | 詹
2527 | 枯
2528 | 嚣
2529 | 稻
2530 | 傍
2531 | 蜘
2532 | 洒
2533 | 墩
2534 | 仲
2535 | 讳
2536 | 傻
2537 | 蕉
2538 | 昊
2539 | 蚊
2540 | 迭
2541 | 碧
2542 | 嵌
2543 | 衅
2544 | 舌
2545 | 佬
2546 | 窜
2547 | 赎
2548 | 唤
2549 | 莹
2550 | 泊
2551 | 罄
2552 | 匆
2553 | 诠
2554 | 饥
2555 | 娼
2556 | 堰
2557 | 畸
2558 | 螃
2559 | 邢
2560 | 棉
2561 | 猎
2562 | 呛
2563 | 坪
2564 | 蓉
2565 | 肆
2566 | 碌
2567 | 氯
2568 | 愉
2569 | 罐
2570 | 骏
2571 | 撇
2572 | 惟
2573 | 铃
2574 | 饶
2575 | 甄
2576 | 徊
2577 | 茫
2578 | 扒
2579 | 竭
2580 | 闵
2581 | 徘
2582 | 丸
2583 | 膨
2584 | 铝
2585 | 榆
2586 | 蛮
2587 | 煎
2588 | 遣
2589 | 嫩
2590 | 僻
2591 | 菇
2592 | 俯
2593 | 衬
2594 | 菱
2595 | 骄
2596 | 咪
2597 | 舟
2598 | 茵
2599 | 薛
2600 | 祭
2601 | 瞻
2602 | 隙
2603 | 宛
2604 | 榨
2605 | 炯
2606 | 哗
2607 | 渭
2608 | 雁
2609 | 婉
2610 | 辄
2611 | 龚
2612 | 玥
2613 | 臻
2614 | 凰
2615 | 掐
2616 | 儒
2617 | 飘
2618 | 淋
2619 | 荆
2620 | 屁
2621 | 滢
2622 | 蔽
2623 | 蘑
2624 | 肪
2625 | 愁
2626 | 蝉
2627 | 麟
2628 | 歇
2629 | 媚
2630 | 趟
2631 | 畏
2632 | 仇
2633 | 汛
2634 | 舅
2635 | 澜
2636 | 丛
2637 | 韶
2638 | 鞠
2639 | 芮
2640 | 溅
2641 | 氨
2642 | 灼
2643 | 缸
2644 | 谅
2645 | 饽
2646 | 呕
2647 | 枝
2648 | 勿
2649 | 哑
2650 | 呦
2651 | 堤
2652 | 焕
2653 | 蒲
2654 | 桐
2655 | 俞
2656 | 狭
2657 | 藤
2658 | 宵
2659 | 耻
2660 | 驴
2661 | 誓
2662 | 茹
2663 | 膏
2664 | 沽
2665 | 恺
2666 | 阁
2667 | 坟
2668 | 姗
2669 | 涤
2670 | 芦
2671 | 淤
2672 | 椎
2673 | 瑰
2674 | 痪
2675 | 鹿
2676 | 殿
2677 | 禅
2678 | 溶
2679 | 庸
2680 | 坤
2681 | 曙
2682 | 臀
2683 | 抖
2684 | 弧
2685 | 淄
2686 | 阚
2687 | 湛
2688 | 瑕
2689 | 弓
2690 | 赃
2691 | 矶
2692 | 埔
2693 | 溃
2694 | 丘
2695 | 寡
2696 | 乙
2697 | 阐
2698 | 腊
2699 | 哦
2700 | 咽
2701 | 仕
2702 | 鄂
2703 | 挠
2704 | 阮
2705 | 煮
2706 | 梨
2707 | 锯
2708 | 刃
2709 | 睁
2710 | 瀚
2711 | 缅
2712 | 焱
2713 | 慑
2714 | 岔
2715 | 豹
2716 | 讹
2717 | 崭
2718 | 厌
2719 | 齿
2720 | 渎
2721 | 闺
2722 | 栈
2723 | 潇
2724 | 髓
2725 | 葬
2726 | 奕
2727 | 绎
2728 | 拇
2729 | 敞
2730 | 钾
2731 | 睿
2732 | 羹
2733 | 扛
2734 | 碘
2735 | 篡
2736 | 蹬
2737 | 畜
2738 | 挟
2739 | 敛
2740 | 岌
2741 | 猩
2742 | 馒
2743 | 咒
2744 | 骆
2745 | 阙
2746 | 绞
2747 | 俨
2748 | 枢
2749 | 酱
2750 | 叙
2751 | 绰
2752 | 株
2753 | 芒
2754 | 翠
2755 | 冉
2756 | 钰
2757 | 揪
2758 | 焊
2759 | 耿
2760 | 歹
2761 | 雏
2762 | 冶
2763 | 芭
2764 | 锣
2765 | 弘
2766 | 搅
2767 | 恭
2768 | 颓
2769 | 竿
2770 | 诟
2771 | 幽
2772 | 蚀
2773 | 庐
2774 | 撬
2775 | 蓬
2776 | 榴
2777 | 隶
2778 | 崎
2779 | 毯
2780 | 蝴
2781 | 搂
2782 | 梗
2783 | 畔
2784 | 夷
2785 | 呐
2786 | 懈
2787 | 橘
2788 | 翡
2789 | 霉
2790 | 哒
2791 | 橙
2792 | 讽
2793 | 隅
2794 | 沾
2795 | 拢
2796 | 窑
2797 | 哄
2798 | 泻
2799 | 浑
2800 | 泸
2801 | 榕
2802 | 沧
2803 | 陀
2804 | 熄
2805 | 絮
2806 | 淹
2807 | 脐
2808 | 拽
2809 | 汹
2810 | 疵
2811 | 魁
2812 | 钠
2813 | 淳
2814 | 昧
2815 | 瑛
2816 | 霜
2817 | 幂
2818 | 彬
2819 | 凳
2820 | 娅
2821 | 霆
2822 | 矩
2823 | 劈
2824 | 颅
2825 | 惕
2826 | 腔
2827 | 滤
2828 | 婧
2829 | 醋
2830 | 袱
2831 | 棕
2832 | 聂
2833 | 锏
2834 | 疤
2835 | 粪
2836 | 鞍
2837 | 沛
2838 | 氰
2839 | 螂
2840 | 聋
2841 | 勺
2842 | 漆
2843 | 裴
2844 | 磕
2845 | 汝
2846 | 茜
2847 | 禹
2848 | 篷
2849 | 屹
2850 | 剽
2851 | 剿
2852 | 幢
2853 | 韧
2854 | 烨
2855 | 鳌
2856 | 邪
2857 | 涩
2858 | 芷
2859 | 翅
2860 | 嘘
2861 | 饲
2862 | 倘
2863 | 彝
2864 | 玄
2865 | 蜡
2866 | 矫
2867 | 拎
2868 | 蜕
2869 | 诡
2870 | 炜
2871 | 窖
2872 | 辜
2873 | 耽
2874 | 呵
2875 | 锆
2876 | 乖
2877 | 脾
2878 | 冈
2879 | 斐
2880 | 蟑
2881 | 摧
2882 | 咱
2883 | 驼
2884 | 蹊
2885 | 佟
2886 | 勋
2887 | 彪
2888 | 渤
2889 | 踞
2890 | 肘
2891 | 贱
2892 | 玺
2893 | 茄
2894 | 醛
2895 | 昭
2896 | 驿
2897 | 杖
2898 | 熏
2899 | 枫
2900 | 晟
2901 | 倦
2902 | 瑾
2903 | 瀑
2904 | 诬
2905 | 笋
2906 | 诀
2907 | 葵
2908 | 祷
2909 | 橄
2910 | 铀
2911 | 幌
2912 | 恳
2913 | 辗
2914 | 眨
2915 | 萱
2916 | 悟
2917 | 琼
2918 | 菡
2919 | 抉
2920 | 榄
2921 | 亥
2922 | 毽
2923 | 杏
2924 | 椒
2925 | 漩
2926 | 玫
2927 | 舶
2928 | 娴
2929 | 坂
2930 | 伽
2931 | 甫
2932 | 黛
2933 | 拣
2934 | 恤
2935 | 剃
2936 | 揣
2937 | 旷
2938 | 敷
2939 | 绯
2940 | 谴
2941 | 祁
2942 | 穗
2943 | 遛
2944 | 朔
2945 | 殷
2946 | 峙
2947 | 柿
2948 | 懒
2949 | 醇
2950 | 袍
2951 | 颂
2952 | 钊
2953 | 涡
2954 | 痱
2955 | 跷
2956 | 窘
2957 | 勉
2958 | 曦
2959 | 缪
2960 | 惫
2961 | 涞
2962 | 蚂
2963 | 晃
2964 | 梭
2965 | 阎
2966 | 拱
2967 | 矢
2968 | 葫
2969 | 砾
2970 | 烹
2971 | 坷
2972 | 谜
2973 | 忱
2974 | 芙
2975 | 琢
2976 | 笨
2977 | 堕
2978 | 芜
2979 | 胰
2980 | 粹
2981 | 壶
2982 | 怜
2983 | 侮
2984 | 绸
2985 | 匝
2986 | 囚
2987 | 洼
2988 | 袂
2989 | 烽
2990 | 躬
2991 | 汀
2992 | 绷
2993 | 匕
2994 | 窥
2995 | 毙
2996 | 戳
2997 | 痒
2998 | 萝
2999 | 晤
3000 | 霄
3001 | 坯
3002 | 泾
3003 | 窒
3004 | 黯
3005 | 垮
3006 | 剁
3007 | 羁
3008 | 栖
3009 | 炙
3010 | 哨
3011 | 珉
3012 | 捏
3013 | 俪
3014 | 腺
3015 | 厮
3016 | 雀
3017 | 嫉
3018 | 粘
3019 | 庚
3020 | 赣
3021 | 腻
3022 | 镶
3023 | 蠢
3024 | 暧
3025 | 纬
3026 | 谤
3027 | 荔
3028 | 泷
3029 | 钜
3030 | 卉
3031 | 岂
3032 | 囤
3033 | 匾
3034 | 鸽
3035 | 瞎
3036 | 妒
3037 | 诽
3038 | 谊
3039 | 庾
3040 | 荫
3041 | 耘
3042 | 丐
3043 | 淆
3044 | 滔
3045 | 雍
3046 | 搁
3047 | 桔
3048 | 涝
3049 | 踹
3050 | 饪
3051 | 璞
3052 | 蛟
3053 | 灶
3054 | 沮
3055 | 栗
3056 | 枞
3057 | 喔
3058 | 獗
3059 | 寥
3060 | 猖
3061 | 棵
3062 | 爪
3063 | 蜇
3064 | 娥
3065 | 掴
3066 | 秸
3067 | 蒜
3068 | 禺
3069 | 晏
3070 | 碱
3071 | 桦
3072 | 绊
3073 | 嗅
3074 | 豁
3075 | 猿
3076 | 耷
3077 | 喆
3078 | 慷
3079 | 梓
3080 | 噬
3081 | 诿
3082 | 嬛
3083 | 韬
3084 | 缆
3085 | 鹰
3086 | 裔
3087 | 吼
3088 | 俘
3089 | 喉
3090 | 伺
3091 | 莽
3092 | 穴
3093 | 荼
3094 | 驭
3095 | 毋
3096 | 橡
3097 | 辍
3098 | 侄
3099 | 巫
3100 | 藻
3101 | 筵
3102 | 畊
3103 | 鹭
3104 | 遴
3105 | 珮
3106 | 匈
3107 | 皱
3108 | 懿
3109 | 秆
3110 | 亟
3111 | 疹
3112 | 峨
3113 | 胫
3114 | 殒
3115 | 昙
3116 | 憬
3117 | 樱
3118 | 鸦
3119 | 宕
3120 | 耒
3121 | 绽
3122 | 眷
3123 | 陋
3124 | 蔗
3125 | 陡
3126 | 躯
3127 | 磋
3128 | 蹿
3129 | 犀
3130 | 窍
3131 | 吾
3132 | 糙
3133 | 蕊
3134 | 剐
3135 | 眈
3136 | 窨
3137 | 囧
3138 | 褒
3139 | 菊
3140 | 镑
3141 | 壹
3142 | 蝇
3143 | 麋
3144 | 褚
3145 | 巍
3146 | 垦
3147 | 蛰
3148 | 喧
3149 | 襄
3150 | 哽
3151 | 悚
3152 | 邯
3153 | 觑
3154 | 翟
3155 | 炖
3156 | 瓯
3157 | 枣
3158 | 掠
3159 | 珀
3160 | 酗
3161 | 帜
3162 | 鞭
3163 | 蹼
3164 | 璀
3165 | 羲
3166 | 寇
3167 | 璧
3168 | 殡
3169 | 皂
3170 | 煊
3171 | 婵
3172 | 膺
3173 | 沼
3174 | 寞
3175 | 癫
3176 | 叮
3177 | 饵
3178 | 戎
3179 | 奴
3180 | 铉
3181 | 缚
3182 | 咳
3183 | 镉
3184 | 棠
3185 | 卜
3186 | 苍
3187 | 郸
3188 | 蒿
3189 | 苯
3190 | 暨
3191 | 沥
3192 | 憧
3193 | 钵
3194 | 岚
3195 | 捻
3196 | 娄
3197 | 缭
3198 | 赡
3199 | 宙
3200 | 斧
3201 | 峭
3202 | 禄
3203 | 夯
3204 | 飚
3205 | 噱
3206 | 瞅
3207 | 馅
3208 | 蹴
3209 | 颐
3210 | 淞
3211 | 汞
3212 | 咎
3213 | 茗
3214 | 踝
3215 | 踵
3216 | 呜
3217 | 怂
3218 | 矣
3219 | 扁
3220 | 挚
3221 | 厥
3222 | 拯
3223 | 凹
3224 | 晗
3225 | 煦
3226 | 隋
3227 | 淝
3228 | 镍
3229 | 跤
3230 | 炬
3231 | 肛
3232 | 骷
3233 | 遐
3234 | 襁
3235 | 赘
3236 | 辙
3237 | 嘀
3238 | 莆
3239 | 倚
3240 | 顷
3241 | 豚
3242 | 杳
3243 | 暇
3244 | 祠
3245 | 粟
3246 | 嚼
3247 | 诫
3248 | 瞧
3249 | 舵
3250 | 廓
3251 | 竺
3252 | 觅
3253 | 祺
3254 | 膊
3255 | 丫
3256 | 骸
3257 | 殃
3258 | 辫
3259 | 昱
3260 | 甥
3261 | 藜
3262 | 仨
3263 | 怠
3264 | 揍
3265 | 拷
3266 | 陨
3267 | 渍
3268 | 梧
3269 | 攥
3270 | 泔
3271 | 崴
3272 | 涿
3273 | 刁
3274 | 漓
3275 | 嘟
3276 | 栽
3277 | 窟
3278 | 咫
3279 | 鲸
3280 | 栓
3281 | 嗯
3282 | 矗
3283 | 褓
3284 | 阀
3285 | 褪
3286 | 嫣
3287 | 蜀
3288 | 癖
3289 | 榔
3290 | 蔷
3291 | 惺
3292 | 枕
3293 | 晔
3294 | 礁
3295 | 奂
3296 | 逍
3297 | 槌
3298 | 釜
3299 | 靳
3300 | 煞
3301 | 籁
3302 | 徙
3303 | 妃
3304 | 髅
3305 | 嗒
3306 | 泌
3307 | 喇
3308 | 嘱
3309 | 痹
3310 | 熠
3311 | 厄
3312 | 羿
3313 | 棱
3314 | 萃
3315 | 酌
3316 | 歆
3317 | 甯
3318 | 砒
3319 | 泵
3320 | 漳
3321 | 牡
3322 | 峪
3323 | 搀
3324 | 煜
3325 | 诵
3326 | 噩
3327 | 墟
3328 | 蹦
3329 | 屑
3330 | 瘠
3331 | 弦
3332 | 踊
3333 | 胯
3334 | 簧
3335 | 虏
3336 | 拙
3337 | 汲
3338 | 拮
3339 | 籽
3340 | 孜
3341 | 蹄
3342 | 腆
3343 | 獒
3344 | 铨
3345 | 羚
3346 | 聆
3347 | 屎
3348 | 譬
3349 | 谙
3350 | 狸
3351 | 筷
3352 | 叼
3353 | 枉
3354 | 骋
3355 | 麾
3356 | 戛
3357 | 粤
3358 | 粥
3359 | 毓
3360 | 壕
3361 | 铐
3362 | 撂
3363 | 莘
3364 | 闽
3365 | 砺
3366 | 凿
3367 | 宸
3368 | 胺
3369 | 邬
3370 | 惋
3371 | 趾
3372 | 拌
3373 | 琨
3374 | 尧
3375 | 憋
3376 | 珲
3377 | 懋
3378 | 诧
3379 | 媲
3380 | 亢
3381 | 芋
3382 | 蔺
3383 | 咄
3384 | 抠
3385 | 憨
3386 | 矮
3387 | 筱
3388 | 匀
3389 | 薯
3390 | 叭
3391 | 琅
3392 | 袒
3393 | 笛
3394 | 闰
3395 | 恍
3396 | 汕
3397 | 熹
3398 | 濒
3399 | 麓
3400 | 缜
3401 | 滕
3402 | 赐
3403 | 唏
3404 | 轧
3405 | 骁
3406 | 翱
3407 | 嬉
3408 | 馊
3409 | 渚
3410 | 腥
3411 | 掣
3412 | 髦
3413 | 焯
3414 | 睫
3415 | 绚
3416 | 镳
3417 | 伎
3418 | 帘
3419 | 缀
3420 | 缮
3421 | 煲
3422 | 炅
3423 | 夭
3424 | 榷
3425 | 荟
3426 | 腼
3427 | 覆
3428 | 姬
3429 | 涅
3430 | 钛
3431 | 罂
3432 | 寅
3433 | 潢
3434 | 焉
3435 | 蔑
3436 | 稚
3437 | 汶
3438 | 岖
3439 | 涠
3440 | 痰
3441 | 崂
3442 | 伶
3443 | 奚
3444 | 卞
3445 | 愕
3446 | 蛐
3447 | 硚
3448 | 啧
3449 | 吝
3450 | 瞰
3451 | 犷
3452 | 瓣
3453 | 皋
3454 | 睬
3455 | 磐
3456 | 柚
3457 | 郡
3458 | 垤
3459 | 撮
3460 | 裆
3461 | 町
3462 | 菁
3463 | 翩
3464 | 饺
3465 | 霹
3466 | 滁
3467 | 灞
3468 | 缨
3469 | 噎
3470 | 缕
3471 | 窦
3472 | 嗤
3473 | 橱
3474 | 矸
3475 | 瘀
3476 | 嚷
3477 | 匮
3478 | 飓
3479 | 敖
3480 | 愚
3481 | 拄
3482 | 琬
3483 | 蕙
3484 | 卤
3485 | 瑶
3486 | 摁
3487 | 绒
3488 | 蝗
3489 | 柬
3490 | 惮
3491 | 昀
3492 | 殉
3493 | 垡
3494 | 苣
3495 | 忑
3496 | 锌
3497 | 庵
3498 | 槟
3499 | 匣
3500 | 忐
3501 | 畿
3502 | 箍
3503 | 圪
3504 | 鹜
3505 | 唾
3506 | 痣
3507 | 瞪
3508 | 檬
3509 | 腱
3510 | 黏
3511 | 馋
3512 | 邑
3513 | 膛
3514 | 嗓
3515 | 喘
3516 | 诅
3517 | 釉
3518 | 褂
3519 | 砌
3520 | 苟
3521 | 迂
3522 | 杞
3523 | 绣
3524 | 卦
3525 | 檀
3526 | 胳
3527 | 炽
3528 | 琛
3529 | 掰
3530 | 戟
3531 | 痫
3532 | 隧
3533 | 紊
3534 | 嗑
3535 | 璐
3536 | 膳
3537 | 葱
3538 | 谬
3539 | 姥
3540 | 懵
3541 | 跆
3542 | 颤
3543 | 懊
3544 | 骥
3545 | 禀
3546 | 哼
3547 | 栅
3548 | 熔
3549 | 悴
3550 | 沓
3551 | 寝
3552 | 呃
3553 | 贮
3554 | 讧
3555 | 鹊
3556 | 苇
3557 | 谩
3558 | 啃
3559 | 痘
3560 | 摹
3561 | 锄
3562 | 嘎
3563 | 禧
3564 | 抡
3565 | 瑚
3566 | 孰
3567 | 俐
3568 | 腌
3569 | 庇
3570 | 渀
3571 | 烃
3572 | 沐
3573 | 鄙
3574 | 讪
3575 | 掺
3576 | 狄
3577 | 斋
3578 | 搡
3579 | 塾
3580 | 缄
3581 | 诩
3582 | 睦
3583 | 棺
3584 | 袄
3585 | 涧
3586 | 茸
3587 | 鳝
3588 | 渺
3589 | 皖
3590 | 媞
3591 | 铂
3592 | 僚
3593 | 柠
3594 | 毗
3595 | 沣
3596 | 拧
3597 | 扼
3598 | 蚕
3599 | 溥
3600 | 匠
3601 | 哉
3602 | 婶
3603 | 靴
3604 | 寮
3605 | 滇
3606 | 诙
3607 | 糯
3608 | 叱
3609 | 莴
3610 | 雳
3611 | 钴
3612 | 鹃
3613 | 跺
3614 | 搪
3615 | 瞳
3616 | 叛
3617 | 嗨
3618 | 蜓
3619 | 妞
3620 | 垢
3621 | 迸
3622 | 拗
3623 | 鄞
3624 | 洱
3625 | 昼
3626 | 啼
3627 | 悖
3628 | 铆
3629 | 矜
3630 | 筏
3631 | 恿
3632 | 酪
3633 | 憔
3634 | 蜚
3635 | 黝
3636 | 蚯
3637 | 舛
3638 | 嚏
3639 | 掂
3640 | 罹
3641 | 鲨
3642 | 锹
3643 | 痊
3644 | 锵
3645 | 椰
3646 | 濮
3647 | 皙
3648 | 舀
3649 | 貅
3650 | 鄢
3651 | 琊
3652 | 浊
3653 | 兢
3654 | 汴
3655 | 殆
3656 | 伉
3657 | 袜
3658 | 咤
3659 | 酶
3660 | 屿
3661 | 垣
3662 | 秧
3663 | 躏
3664 | 氓
3665 | 盹
3666 | 嚎
3667 | 暮
3668 | 飒
3669 | 妩
3670 | 抒
3671 | 帼
3672 | 楞
3673 | 嗡
3674 | 灸
3675 | 袈
3676 | 樟
3677 | 綦
3678 | 貔
3679 | 晾
3680 | 窕
3681 | 琶
3682 | 臃
3683 | 婪
3684 | 榈
3685 | 箔
3686 | 辘
3687 | 蔫
3688 | 婕
3689 | 恙
3690 | 酣
3691 | 袆
3692 | 裟
3693 | 挎
3694 | 烘
3695 | 妄
3696 | 掮
3697 | 觊
3698 | 戮
3699 | 粽
3700 | 氾
3701 | 烁
3702 | 邺
3703 | 蟀
3704 | 俸
3705 | 惚
3706 | 瓢
3707 | 挝
3708 | 姊
3709 | 啸
3710 | 饕
3711 | 雌
3712 | 瞿
3713 | 胱
3714 | 犒
3715 | 鸥
3716 | 逡
3717 | 斛
3718 | 溧
3719 | 铿
3720 | 圩
3721 | 砷
3722 | 卑
3723 | 铎
3724 | 柞
3725 | 瓮
3726 | 酋
3727 | 隼
3728 | 锚
3729 | 嗷
3730 | 淖
3731 | 棘
3732 | 忻
3733 | 嗦
3734 | 弑
3735 | 沁
3736 | 覃
3737 | 蚝
3738 | 隽
3739 | 蹂
3740 | 熨
3741 | 侬
3742 | 鳖
3743 | 彿
3744 | 蝎
3745 | 彷
3746 | 鸠
3747 | 吆
3748 | 锷
3749 | 揉
3750 | 屌
3751 | 泗
3752 | 稣
3753 | 茁
3754 | 胚
3755 | 掖
3756 | 砥
3757 | 扉
3758 | 叨
3759 | 虱
3760 | 弩
3761 | 磺
3762 | 痼
3763 | 砰
3764 | 殭
3765 | 猬
3766 | 榻
3767 | 簸
3768 | 祉
3769 | 瑙
3770 | 祛
3771 | 鳞
3772 | 骜
3773 | 涕
3774 | 鲟
3775 | 溉
3776 | 鲶
3777 | 姝
3778 | 檐
3779 | 玖
3780 | 疚
3781 | 哆
3782 | 丞
3783 | 俾
3784 | 鹞
3785 | 藩
3786 | 圃
3787 | 瀛
3788 | 菠
3789 | 筐
3790 | 镯
3791 | 邃
3792 | 捺
3793 | 萋
3794 | 悸
3795 | 镁
3796 | 腑
3797 | 髋
3798 | 俚
3799 | 栾
3800 | 陂
3801 | 蜷
3802 | 卯
3803 | 凄
3804 | 舸
3805 | 捎
3806 | 餮
3807 | 窈
3808 | 锭
3809 | 佶
3810 | 嗽
3811 | 笈
3812 | 殓
3813 | 郫
3814 | 甬
3815 | 蟋
3816 | 狙
3817 | 槿
3818 | 馥
3819 | 蠕
3820 | 椿
3821 | 侥
3822 | 嘻
3823 | 箕
3824 | 怦
3825 | 绅
3826 | 闳
3827 | 蜿
3828 | 珜
3829 | 惦
3830 | 镖
3831 | 蚓
3832 | 漯
3833 | 郜
3834 | 狰
3835 | 狒
3836 | 啵
3837 | 鳅
3838 | 葆
3839 | 澈
3840 | 蜒
3841 | 伢
3842 | 抿
3843 | 佼
3844 | 瘟
3845 | 霁
3846 | 朽
3847 | 陇
3848 | 觎
3849 | 燎
3850 | 迢
3851 | 腩
3852 | 驯
3853 | 铰
3854 | 槐
3855 | 逞
3856 | 萦
3857 | 秃
3858 | 爵
3859 | 乍
3860 | 珑
3861 | 烊
3862 | 淌
3863 | 钝
3864 | 渲
3865 | 摒
3866 | 颚
3867 | 荤
3868 | 狞
3869 | 浚
3870 | 邋
3871 | 馑
3872 | 咣
3873 | 诲
3874 | 暄
3875 | 骼
3876 | 琉
3877 | 黔
3878 | 擘
3879 | 嵩
3880 | 忪
3881 | 茬
3882 | 浈
3883 | 凋
3884 | 垌
3885 | 壑
3886 | t
3887 | 谑
3888 | 嗣
3889 | 拭
3890 | 稼
3891 | 竽
3892 | 羔
3893 | 褛
3894 | 惆
3895 | 掬
3896 | 吏
3897 | 哎
3898 | 湍
3899 | 泞
3900 | 霎
3901 | 亳
3902 | 炷
3903 | 蜈
3904 | 瘸
3905 | 鼾
3906 | 戬
3907 | 潞
3908 | 恬
3909 | 陬
3910 | 烷
3911 | 琏
3912 | 骐
3913 | 氟
3914 | 匡
3915 | 锥
3916 | 宦
3917 | 薙
3918 | 癣
3919 | 惬
3920 | 粕
3921 | 妧
3922 | 鸾
3923 | 狡
3924 | 遢
3925 | 巿
3926 | 琥
3927 | 盎
3928 | 寐
3929 | 莅
3930 | 榉
3931 | 璋
3932 | 嵘
3933 | 佘
3934 | 枭
3935 | 窿
3936 | 侑
3937 | 孪
3938 | 芪
3939 | 腮
3940 | 裳
3941 | 啶
3942 | 叵
3943 | 岐
3944 | 札
3945 | 玟
3946 | 嫔
3947 | 铠
3948 | 篪
3949 | 卒
3950 | 隍
3951 | 唠
3952 | 兀
3953 | 沱
3954 | 蓁
3955 | 珏
3956 | 跛
3957 | 铡
3958 | 锟
3959 | 泱
3960 | 瞌
3961 | 麒
3962 | 肮
3963 | 揄
3964 | 桉
3965 | 胧
3966 | 濑
3967 | 耄
3968 | 锢
3969 | 冥
3970 | 眶
3971 | 霈
3972 | 靶
3973 | 怯
3974 | 漱
3975 | 蛀
3976 | 赝
3977 | 宓
3978 | 傥
3979 | 梵
3980 | 褴
3981 | 妊
3982 | 诶
3983 | 娩
3984 | 脯
3985 | 荃
3986 | 襟
3987 | 蜊
3988 | 娌
3989 | 舜
3990 | 侍
3991 | 胛
3992 | 孢
3993 | 洙
3994 | 涮
3995 | 仄
3996 | 臆
3997 | 凇
3998 | 缤
3999 | 瘪
4000 | 撸
4001 | 蹚
4002 | 磡
4003 | 悯
4004 | 嚓
4005 | 醐
4006 | 吩
4007 | 昵
4008 | 嬷
4009 | 荇
4010 | 擞
4011 | 眺
4012 | 茆
4013 | 娠
4014 | 纣
4015 | 榭
4016 | 楂
4017 | 蓟
4018 | 泯
4019 | 睾
4020 | 俭
4021 | 咔
4022 | 嘶
4023 | 吿
4024 | 颍
4025 | 啕
4026 | 沅
4027 | 唬
4028 | 谚
4029 | 斟
4030 | 羣
4031 | 螳
4032 | 撵
4033 | 虞
4034 | 嫡
4035 | 咐
4036 | 嫦
4037 | 挛
4038 | 濡
4039 | 佃
4040 | 惶
4041 | 塍
4042 | 琵
4043 | 谀
4044 | 芊
4045 | 醍
4046 | 遨
4047 | 碚
4048 | 嗲
4049 | 孺
4050 | 噼
4051 | 殚
4052 | 漭
4053 | 绌
4054 | 拴
4055 | 瘁
4056 | 貉
4057 | 怅
4058 | 揩
4059 | 镐
4060 | 曰
4061 | 嵋
4062 | 潦
4063 | 衙
4064 | 绢
4065 | 崧
4066 | 刨
4067 | 岷
4068 | 燊
4069 | 喽
4070 | 猾
4071 | 粱
4072 | 叩
4073 | 蕲
4074 | 跄
4075 | 獾
4076 | 侗
4077 | 肴
4078 | 拈
4079 | 敝
4080 | 罡
4081 | 炕
4082 | 疝
4083 | 掳
4084 | 埠
4085 | 悌
4086 | 狩
4087 | 牾
4088 | 沂
4089 | 珺
4090 | 妤
4091 | 怵
4092 | 纶
4093 | 蛆
4094 | 黍
4095 | k
4096 | 蜗
4097 | 秤
4098 | 垅
4099 | 骇
4100 | 焖
4101 | 洵
4102 | 秣
4103 | 泓
4104 | 兖
4105 | 莺
4106 | 耋
4107 | 漕
4108 | 蜥
4109 | 艋
4110 | 疃
4111 | 鏖
4112 | 涓
4113 | 咙
4114 | 槎
4115 | 汾
4116 | 湄
4117 | 孱
4118 | 眯
4119 | 鸵
4120 | 遁
4121 | 魇
4122 | 腋
4123 | 觐
4124 | 铮
4125 | 竲
4126 | 徉
4127 | 蚣
4128 | 薰
4129 | 咯
4130 | 漾
4131 | 噘
4132 | 庶
4133 | 脍
4134 | 隘
4135 | 镊
4136 | 鸳
4137 | 涟
4138 | 厩
4139 | 翌
4140 | 揶
4141 | 犁
4142 | 埜
4143 | 冗
4144 | 氪
4145 | 砲
4146 | 憷
4147 | 苡
4148 | 邂
4149 | 谕
4150 | 鞘
4151 | 砝
4152 | 寰
4153 | 斡
4154 | 耸
4155 | 恸
4156 | 蚌
4157 | 毂
4158 | 圭
4159 | 髌
4160 | 桓
4161 | 恣
4162 | 乾
4163 | 阂
4164 | 徇
4165 | 碉
4166 | 焘
4167 | 氦
4168 | 眬
4169 | 岱
4170 | 踉
4171 | 枷
4172 | 镀
4173 | 鲷
4174 | 烙
4175 | 皎
4176 | 缇
4177 | 骊
4178 | 嘭
4179 | 瑁
4180 | 莠
4181 | 嵛
4182 | 僮
4183 | 嶝
4184 | 荞
4185 | 簇
4186 | 纰
4187 | 碴
4188 | 呗
4189 | 胤
4190 | 磴
4191 | 瘩
4192 | 缰
4193 | 咧
4194 | 蜴
4195 | 诓
4196 | 楔
4197 | 啬
4198 | 逅
4199 | 颊
4200 | 弛
4201 | 吭
4202 | 哺
4203 | 嗬
4204 | 酯
4205 | 淼
4206 | 膑
4207 | 邛
4208 | 褶
4209 | 幄
4210 | 痉
4211 | 烛
4212 | 迥
4213 | 卲
4214 | 唉
4215 | 涎
4216 | 鸯
4217 | 锜
4218 | 俺
4219 | 斓
4220 | 帚
4221 | 瞟
4222 | 撩
4223 | 崃
4224 | 椋
4225 | 渥
4226 | 嘈
4227 | 沏
4228 | 倜
4229 | 荚
4230 | 婀
4231 | 哟
4232 | 赦
4233 | 缙
4234 | 吟
4235 | 砚
4236 | c
4237 | 唁
4238 | 馗
4239 | 邝
4240 | 犄
4241 | 孀
4242 | 咀
4243 | 箫
4244 | 阜
4245 | 憩
4246 | 喱
4247 | 琰
4248 | 靛
4249 | 茎
4250 | 趸
4251 | 恪
4252 | 夙
4253 | 呲
4254 | 稠
4255 | 蟒
4256 | 泠
4257 | 骅
4258 | 靑
4259 | 喵
4260 | 峁
4261 | 桎
4262 | 奘
4263 | 啰
4264 | 钒
4265 | 仡
4266 | 犊
4267 | 腓
4268 | 嫚
4269 | 楣
4270 | 铣
4271 | 朦
4272 | 哇
4273 | 祢
4274 | 糗
4275 | 觥
4276 | 菩
4277 | 搽
4278 | 轶
4279 | 惰
4280 | 啪
4281 | 塬
4282 | 笙
4283 | 抨
4284 | 岬
4285 | 鲤
4286 | a
4287 | 狈
4288 | 朐
4289 | 垛
4290 | 妯
4291 | 玳
4292 | 晦
4293 | 蹶
4294 | 笃
4295 | 炊
4296 | 逵
4297 | 蜻
4298 | 祯
4299 |
--------------------------------------------------------------------------------
/data_utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/data_utils/__init__.py
--------------------------------------------------------------------------------
/data_utils/__init__.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/data_utils/__init__.pyc
--------------------------------------------------------------------------------
/data_utils/audio.py:
--------------------------------------------------------------------------------
1 | """Contains the audio segment class."""
2 | from __future__ import absolute_import
3 | from __future__ import division
4 | from __future__ import print_function
5 |
6 | import numpy as np
7 | import io
8 | import struct
9 | import re
10 | import soundfile
11 | import resampy
12 | from scipy import signal
13 | import random
14 | import copy
15 |
16 |
17 | class AudioSegment(object):
18 | """Monaural audio segment abstraction.
19 |
20 | :param samples: Audio samples [num_samples x num_channels].
21 | :type samples: ndarray.float32
22 | :param sample_rate: Audio sample rate.
23 | :type sample_rate: int
24 | :raises TypeError: If the sample data type is not float or int.
25 | """
26 |
27 | def __init__(self, samples, sample_rate):
28 | """Create audio segment from samples.
29 |
30 | Samples are convert float32 internally, with int scaled to [-1, 1].
31 | """
32 | self._samples = self._convert_samples_to_float32(samples)
33 | self._sample_rate = sample_rate
34 | if self._samples.ndim >= 2:
35 | self._samples = np.mean(self._samples, 1)
36 |
37 | def __eq__(self, other):
38 | """Return whether two objects are equal."""
39 | if type(other) is not type(self):
40 | return False
41 | if self._sample_rate != other._sample_rate:
42 | return False
43 | if self._samples.shape != other._samples.shape:
44 | return False
45 | if np.any(self.samples != other._samples):
46 | return False
47 | return True
48 |
49 | def __ne__(self, other):
50 | """Return whether two objects are unequal."""
51 | return not self.__eq__(other)
52 |
53 | def __str__(self):
54 | """Return human-readable representation of segment."""
55 | return ("%s: num_samples=%d, sample_rate=%d, duration=%.2fsec, "
56 | "rms=%.2fdB" % (type(self), self.num_samples, self.sample_rate,
57 | self.duration, self.rms_db))
58 |
59 | @classmethod
60 | def from_file(cls, file):
61 | """Create audio segment from audio file.
62 |
63 | :param filepath: Filepath or file object to audio file.
64 | :type filepath: basestring|file
65 | :return: Audio segment instance.
66 | :rtype: AudioSegment
67 | """
68 | if isinstance(file, basestring) and re.findall(r".seqbin_\d+$", file):
69 | return cls.from_sequence_file(file)
70 | else:
71 | samples, sample_rate = soundfile.read(file, dtype='float32')
72 | return cls(samples, sample_rate)
73 |
74 | @classmethod
75 | def slice_from_file(cls, file, start=None, end=None):
76 | """Loads a small section of an audio without having to load
77 | the entire file into the memory which can be incredibly wasteful.
78 |
79 | :param file: Input audio filepath or file object.
80 | :type file: basestring|file
81 | :param start: Start time in seconds. If start is negative, it wraps
82 | around from the end. If not provided, this function
83 | reads from the very beginning.
84 | :type start: float
85 | :param end: End time in seconds. If end is negative, it wraps around
86 | from the end. If not provided, the default behvaior is
87 | to read to the end of the file.
88 | :type end: float
89 | :return: AudioSegment instance of the specified slice of the input
90 | audio file.
91 | :rtype: AudioSegment
92 | :raise ValueError: If start or end is incorrectly set, e.g. out of
93 | bounds in time.
94 | """
95 | sndfile = soundfile.SoundFile(file)
96 | sample_rate = sndfile.samplerate
97 | duration = float(len(sndfile)) / sample_rate
98 | start = 0. if start is None else start
99 | end = 0. if end is None else end
100 | if start < 0.0:
101 | start += duration
102 | if end < 0.0:
103 | end += duration
104 | if start < 0.0:
105 | raise ValueError("The slice start position (%f s) is out of "
106 | "bounds." % start)
107 | if end < 0.0:
108 | raise ValueError("The slice end position (%f s) is out of bounds." %
109 | end)
110 | if start > end:
111 | raise ValueError("The slice start position (%f s) is later than "
112 | "the slice end position (%f s)." % (start, end))
113 | if end > duration:
114 | raise ValueError("The slice end position (%f s) is out of bounds "
115 | "(> %f s)" % (end, duration))
116 | start_frame = int(start * sample_rate)
117 | end_frame = int(end * sample_rate)
118 | sndfile.seek(start_frame)
119 | data = sndfile.read(frames=end_frame - start_frame, dtype='float32')
120 | return cls(data, sample_rate)
121 |
122 | @classmethod
123 | def from_sequence_file(cls, filepath):
124 | """Create audio segment from sequence file. Sequence file is a binary
125 | file containing a collection of multiple audio files, with several
126 | header bytes in the head indicating the offsets of each audio byte data
127 | chunk.
128 |
129 | The format is:
130 |
131 | 4 bytes (int, version),
132 | 4 bytes (int, num of utterance),
133 | 4 bytes (int, bytes per header),
134 | [bytes_per_header*(num_utterance+1)] bytes (offsets for each audio),
135 | audio_bytes_data_of_1st_utterance,
136 | audio_bytes_data_of_2nd_utterance,
137 | ......
138 |
139 | Sequence file name must end with ".seqbin". And the filename of the 5th
140 | utterance's audio file in sequence file "xxx.seqbin" must be
141 | "xxx.seqbin_5", with "5" indicating the utterance index within this
142 | sequence file (starting from 1).
143 |
144 | :param filepath: Filepath of sequence file.
145 | :type filepath: basestring
146 | :return: Audio segment instance.
147 | :rtype: AudioSegment
148 | """
149 | # parse filepath
150 | matches = re.match(r"(.+\.seqbin)_(\d+)", filepath)
151 | if matches is None:
152 | raise IOError("File type of %s is not supported" % filepath)
153 | filename = matches.group(1)
154 | fileno = int(matches.group(2))
155 |
156 | # read headers
157 | f = open(filename, 'rb')
158 | version = f.read(4)
159 | num_utterances = struct.unpack("i", f.read(4))[0]
160 | bytes_per_header = struct.unpack("i", f.read(4))[0]
161 | header_bytes = f.read(bytes_per_header * (num_utterances + 1))
162 | header = [
163 | struct.unpack("i", header_bytes[bytes_per_header * i:
164 | bytes_per_header * (i + 1)])[0]
165 | for i in range(num_utterances + 1)
166 | ]
167 |
168 | # read audio bytes
169 | f.seek(header[fileno - 1])
170 | audio_bytes = f.read(header[fileno] - header[fileno - 1])
171 | f.close()
172 |
173 | # create audio segment
174 | try:
175 | return cls.from_bytes(audio_bytes)
176 | except Exception as e:
177 | samples = np.frombuffer(audio_bytes, dtype='int16')
178 | return cls(samples=samples, sample_rate=8000)
179 |
180 | @classmethod
181 | def from_bytes(cls, bytes):
182 | """Create audio segment from a byte string containing audio samples.
183 |
184 | :param bytes: Byte string containing audio samples.
185 | :type bytes: str
186 | :return: Audio segment instance.
187 | :rtype: AudioSegment
188 | """
189 | samples, sample_rate = soundfile.read(
190 | io.BytesIO(bytes), dtype='float32')
191 | return cls(samples, sample_rate)
192 |
193 | @classmethod
194 | def concatenate(cls, *segments):
195 | """Concatenate an arbitrary number of audio segments together.
196 |
197 | :param *segments: Input audio segments to be concatenated.
198 | :type *segments: tuple of AudioSegment
199 | :return: Audio segment instance as concatenating results.
200 | :rtype: AudioSegment
201 | :raises ValueError: If the number of segments is zero, or if the
202 | sample_rate of any segments does not match.
203 | :raises TypeError: If any segment is not AudioSegment instance.
204 | """
205 | # Perform basic sanity-checks.
206 | if len(segments) == 0:
207 | raise ValueError("No audio segments are given to concatenate.")
208 | sample_rate = segments[0]._sample_rate
209 | for seg in segments:
210 | if sample_rate != seg._sample_rate:
211 | raise ValueError("Can't concatenate segments with "
212 | "different sample rates")
213 | if type(seg) is not cls:
214 | raise TypeError("Only audio segments of the same type "
215 | "can be concatenated.")
216 | samples = np.concatenate([seg.samples for seg in segments])
217 | return cls(samples, sample_rate)
218 |
219 | @classmethod
220 | def make_silence(cls, duration, sample_rate):
221 | """Creates a silent audio segment of the given duration and sample rate.
222 |
223 | :param duration: Length of silence in seconds.
224 | :type duration: float
225 | :param sample_rate: Sample rate.
226 | :type sample_rate: float
227 | :return: Silent AudioSegment instance of the given duration.
228 | :rtype: AudioSegment
229 | """
230 | samples = np.zeros(int(duration * sample_rate))
231 | return cls(samples, sample_rate)
232 |
233 | def to_wav_file(self, filepath, dtype='float32'):
234 | """Save audio segment to disk as wav file.
235 |
236 | :param filepath: WAV filepath or file object to save the
237 | audio segment.
238 | :type filepath: basestring|file
239 | :param dtype: Subtype for audio file. Options: 'int16', 'int32',
240 | 'float32', 'float64'. Default is 'float32'.
241 | :type dtype: str
242 | :raises TypeError: If dtype is not supported.
243 | """
244 | samples = self._convert_samples_from_float32(self._samples, dtype)
245 | subtype_map = {
246 | 'int16': 'PCM_16',
247 | 'int32': 'PCM_32',
248 | 'float32': 'FLOAT',
249 | 'float64': 'DOUBLE'
250 | }
251 | soundfile.write(
252 | filepath,
253 | samples,
254 | self._sample_rate,
255 | format='WAV',
256 | subtype=subtype_map[dtype])
257 |
258 | def superimpose(self, other):
259 | """Add samples from another segment to those of this segment
260 | (sample-wise addition, not segment concatenation).
261 |
262 | Note that this is an in-place transformation.
263 |
264 | :param other: Segment containing samples to be added in.
265 | :type other: AudioSegments
266 | :raise TypeError: If type of two segments don't match.
267 | :raise ValueError: If the sample rates of the two segments are not
268 | equal, or if the lengths of segments don't match.
269 | """
270 | if isinstance(other, type(self)):
271 | raise TypeError("Cannot add segments of different types: %s "
272 | "and %s." % (type(self), type(other)))
273 | if self._sample_rate != other._sample_rate:
274 | raise ValueError("Sample rates must match to add segments.")
275 | if len(self._samples) != len(other._samples):
276 | raise ValueError("Segment lengths must match to add segments.")
277 | self._samples += other._samples
278 |
279 | def to_bytes(self, dtype='float32'):
280 | """Create a byte string containing the audio content.
281 |
282 | :param dtype: Data type for export samples. Options: 'int16', 'int32',
283 | 'float32', 'float64'. Default is 'float32'.
284 | :type dtype: str
285 | :return: Byte string containing audio content.
286 | :rtype: str
287 | """
288 | samples = self._convert_samples_from_float32(self._samples, dtype)
289 | return samples.tostring()
290 |
291 | def gain_db(self, gain):
292 | """Apply gain in decibels to samples.
293 |
294 | Note that this is an in-place transformation.
295 |
296 | :param gain: Gain in decibels to apply to samples.
297 | :type gain: float|1darray
298 | """
299 | self._samples *= 10.**(gain / 20.)
300 |
301 | def change_speed(self, speed_rate):
302 | """Change the audio speed by linear interpolation.
303 |
304 | Note that this is an in-place transformation.
305 |
306 | :param speed_rate: Rate of speed change:
307 | speed_rate > 1.0, speed up the audio;
308 | speed_rate = 1.0, unchanged;
309 | speed_rate < 1.0, slow down the audio;
310 | speed_rate <= 0.0, not allowed, raise ValueError.
311 | :type speed_rate: float
312 | :raises ValueError: If speed_rate <= 0.0.
313 | """
314 | if speed_rate <= 0:
315 | raise ValueError("speed_rate should be greater than zero.")
316 | old_length = self._samples.shape[0]
317 | new_length = int(old_length / speed_rate)
318 | old_indices = np.arange(old_length)
319 | new_indices = np.linspace(start=0, stop=old_length, num=new_length)
320 | self._samples = np.interp(new_indices, old_indices, self._samples)
321 |
322 | def normalize(self, target_db=-20, max_gain_db=300.0):
323 | """Normalize audio to be of the desired RMS value in decibels.
324 |
325 | Note that this is an in-place transformation.
326 |
327 | :param target_db: Target RMS value in decibels. This value should be
328 | less than 0.0 as 0.0 is full-scale audio.
329 | :type target_db: float
330 | :param max_gain_db: Max amount of gain in dB that can be applied for
331 | normalization. This is to prevent nans when
332 | attempting to normalize a signal consisting of
333 | all zeros.
334 | :type max_gain_db: float
335 | :raises ValueError: If the required gain to normalize the segment to
336 | the target_db value exceeds max_gain_db.
337 | """
338 | gain = target_db - self.rms_db
339 | if gain > max_gain_db:
340 | raise ValueError(
341 | "Unable to normalize segment to %f dB because the "
342 | "the probable gain have exceeds max_gain_db (%f dB)" %
343 | (target_db, max_gain_db))
344 | self.gain_db(min(max_gain_db, target_db - self.rms_db))
345 |
346 | def normalize_online_bayesian(self,
347 | target_db,
348 | prior_db,
349 | prior_samples,
350 | startup_delay=0.0):
351 | """Normalize audio using a production-compatible online/causal
352 | algorithm. This uses an exponential likelihood and gamma prior to
353 | make online estimates of the RMS even when there are very few samples.
354 |
355 | Note that this is an in-place transformation.
356 |
357 | :param target_db: Target RMS value in decibels.
358 | :type target_bd: float
359 | :param prior_db: Prior RMS estimate in decibels.
360 | :type prior_db: float
361 | :param prior_samples: Prior strength in number of samples.
362 | :type prior_samples: float
363 | :param startup_delay: Default 0.0s. If provided, this function will
364 | accrue statistics for the first startup_delay
365 | seconds before applying online normalization.
366 | :type startup_delay: float
367 | """
368 | # Estimate total RMS online.
369 | startup_sample_idx = min(self.num_samples - 1,
370 | int(self.sample_rate * startup_delay))
371 | prior_mean_squared = 10.**(prior_db / 10.)
372 | prior_sum_of_squares = prior_mean_squared * prior_samples
373 | cumsum_of_squares = np.cumsum(self.samples**2)
374 | sample_count = np.arange(self.num_samples) + 1
375 | if startup_sample_idx > 0:
376 | cumsum_of_squares[:startup_sample_idx] = \
377 | cumsum_of_squares[startup_sample_idx]
378 | sample_count[:startup_sample_idx] = \
379 | sample_count[startup_sample_idx]
380 | mean_squared_estimate = ((cumsum_of_squares + prior_sum_of_squares) /
381 | (sample_count + prior_samples))
382 | rms_estimate_db = 10 * np.log10(mean_squared_estimate)
383 | # Compute required time-varying gain.
384 | gain_db = target_db - rms_estimate_db
385 | self.gain_db(gain_db)
386 |
387 | def resample(self, target_sample_rate, filter='kaiser_best'):
388 | """Resample the audio to a target sample rate.
389 |
390 | Note that this is an in-place transformation.
391 |
392 | :param target_sample_rate: Target sample rate.
393 | :type target_sample_rate: int
394 | :param filter: The resampling filter to use one of {'kaiser_best',
395 | 'kaiser_fast'}.
396 | :type filter: str
397 | """
398 | self._samples = resampy.resample(
399 | self.samples, self.sample_rate, target_sample_rate, filter=filter)
400 | self._sample_rate = target_sample_rate
401 |
402 | def pad_silence(self, duration, sides='both'):
403 | """Pad this audio sample with a period of silence.
404 |
405 | Note that this is an in-place transformation.
406 |
407 | :param duration: Length of silence in seconds to pad.
408 | :type duration: float
409 | :param sides: Position for padding:
410 | 'beginning' - adds silence in the beginning;
411 | 'end' - adds silence in the end;
412 | 'both' - adds silence in both the beginning and the end.
413 | :type sides: str
414 | :raises ValueError: If sides is not supported.
415 | """
416 | if duration == 0.0:
417 | return self
418 | cls = type(self)
419 | silence = self.make_silence(duration, self._sample_rate)
420 | if sides == "beginning":
421 | padded = cls.concatenate(silence, self)
422 | elif sides == "end":
423 | padded = cls.concatenate(self, silence)
424 | elif sides == "both":
425 | padded = cls.concatenate(silence, self, silence)
426 | else:
427 | raise ValueError("Unknown value for the sides %s" % sides)
428 | self._samples = padded._samples
429 |
430 | def shift(self, shift_ms):
431 | """Shift the audio in time. If `shift_ms` is positive, shift with time
432 | advance; if negative, shift with time delay. Silence are padded to
433 | keep the duration unchanged.
434 |
435 | Note that this is an in-place transformation.
436 |
437 | :param shift_ms: Shift time in millseconds. If positive, shift with
438 | time advance; if negative; shift with time delay.
439 | :type shift_ms: float
440 | :raises ValueError: If shift_ms is longer than audio duration.
441 | """
442 | if abs(shift_ms) / 1000.0 > self.duration:
443 | raise ValueError("Absolute value of shift_ms should be smaller "
444 | "than audio duration.")
445 | shift_samples = int(shift_ms * self._sample_rate / 1000)
446 | if shift_samples > 0:
447 | # time advance
448 | self._samples[:-shift_samples] = self._samples[shift_samples:]
449 | self._samples[-shift_samples:] = 0
450 | elif shift_samples < 0:
451 | # time delay
452 | self._samples[-shift_samples:] = self._samples[:shift_samples]
453 | self._samples[:-shift_samples] = 0
454 |
455 | def subsegment(self, start_sec=None, end_sec=None):
456 | """Cut the AudioSegment between given boundaries.
457 |
458 | Note that this is an in-place transformation.
459 |
460 | :param start_sec: Beginning of subsegment in seconds.
461 | :type start_sec: float
462 | :param end_sec: End of subsegment in seconds.
463 | :type end_sec: float
464 | :raise ValueError: If start_sec or end_sec is incorrectly set, e.g. out
465 | of bounds in time.
466 | """
467 | start_sec = 0.0 if start_sec is None else start_sec
468 | end_sec = self.duration if end_sec is None else end_sec
469 | if start_sec < 0.0:
470 | start_sec = self.duration + start_sec
471 | if end_sec < 0.0:
472 | end_sec = self.duration + end_sec
473 | if start_sec < 0.0:
474 | raise ValueError("The slice start position (%f s) is out of "
475 | "bounds." % start_sec)
476 | if end_sec < 0.0:
477 | raise ValueError("The slice end position (%f s) is out of bounds." %
478 | end_sec)
479 | if start_sec > end_sec:
480 | raise ValueError("The slice start position (%f s) is later than "
481 | "the end position (%f s)." % (start_sec, end_sec))
482 | if end_sec > self.duration:
483 | raise ValueError("The slice end position (%f s) is out of bounds "
484 | "(> %f s)" % (end_sec, self.duration))
485 | start_sample = int(round(start_sec * self._sample_rate))
486 | end_sample = int(round(end_sec * self._sample_rate))
487 | self._samples = self._samples[start_sample:end_sample]
488 |
489 | def random_subsegment(self, subsegment_length, rng=None):
490 | """Cut the specified length of the audiosegment randomly.
491 |
492 | Note that this is an in-place transformation.
493 |
494 | :param subsegment_length: Subsegment length in seconds.
495 | :type subsegment_length: float
496 | :param rng: Random number generator state.
497 | :type rng: random.Random
498 | :raises ValueError: If the length of subsegment is greater than
499 | the origineal segemnt.
500 | """
501 | rng = random.Random() if rng is None else rng
502 | if subsegment_length > self.duration:
503 | raise ValueError("Length of subsegment must not be greater "
504 | "than original segment.")
505 | start_time = rng.uniform(0.0, self.duration - subsegment_length)
506 | self.subsegment(start_time, start_time + subsegment_length)
507 |
508 | def convolve(self, impulse_segment, allow_resample=False):
509 | """Convolve this audio segment with the given impulse segment.
510 |
511 | Note that this is an in-place transformation.
512 |
513 | :param impulse_segment: Impulse response segments.
514 | :type impulse_segment: AudioSegment
515 | :param allow_resample: Indicates whether resampling is allowed when
516 | the impulse_segment has a different sample
517 | rate from this signal.
518 | :type allow_resample: bool
519 | :raises ValueError: If the sample rate is not match between two
520 | audio segments when resample is not allowed.
521 | """
522 | if allow_resample and self.sample_rate != impulse_segment.sample_rate:
523 | impulse_segment.resample(self.sample_rate)
524 | if self.sample_rate != impulse_segment.sample_rate:
525 | raise ValueError("Impulse segment's sample rate (%d Hz) is not "
526 | "equal to base signal sample rate (%d Hz)." %
527 | (impulse_segment.sample_rate, self.sample_rate))
528 | samples = signal.fftconvolve(self.samples, impulse_segment.samples,
529 | "full")
530 | self._samples = samples
531 |
532 | def convolve_and_normalize(self, impulse_segment, allow_resample=False):
533 | """Convolve and normalize the resulting audio segment so that it
534 | has the same average power as the input signal.
535 |
536 | Note that this is an in-place transformation.
537 |
538 | :param impulse_segment: Impulse response segments.
539 | :type impulse_segment: AudioSegment
540 | :param allow_resample: Indicates whether resampling is allowed when
541 | the impulse_segment has a different sample
542 | rate from this signal.
543 | :type allow_resample: bool
544 | """
545 | target_db = self.rms_db
546 | self.convolve(impulse_segment, allow_resample=allow_resample)
547 | self.normalize(target_db)
548 |
549 | def add_noise(self,
550 | noise,
551 | snr_dB,
552 | allow_downsampling=False,
553 | max_gain_db=300.0,
554 | rng=None):
555 | """Add the given noise segment at a specific signal-to-noise ratio.
556 | If the noise segment is longer than this segment, a random subsegment
557 | of matching length is sampled from it and used instead.
558 |
559 | Note that this is an in-place transformation.
560 |
561 | :param noise: Noise signal to add.
562 | :type noise: AudioSegment
563 | :param snr_dB: Signal-to-Noise Ratio, in decibels.
564 | :type snr_dB: float
565 | :param allow_downsampling: Whether to allow the noise signal to be
566 | downsampled to match the base signal sample
567 | rate.
568 | :type allow_downsampling: bool
569 | :param max_gain_db: Maximum amount of gain to apply to noise signal
570 | before adding it in. This is to prevent attempting
571 | to apply infinite gain to a zero signal.
572 | :type max_gain_db: float
573 | :param rng: Random number generator state.
574 | :type rng: None|random.Random
575 | :raises ValueError: If the sample rate does not match between the two
576 | audio segments when downsampling is not allowed, or
577 | if the duration of noise segments is shorter than
578 | original audio segments.
579 | """
580 | rng = random.Random() if rng is None else rng
581 | if allow_downsampling and noise.sample_rate > self.sample_rate:
582 | noise = noise.resample(self.sample_rate)
583 | if noise.sample_rate != self.sample_rate:
584 | raise ValueError("Noise sample rate (%d Hz) is not equal to base "
585 | "signal sample rate (%d Hz)." % (noise.sample_rate,
586 | self.sample_rate))
587 | if noise.duration < self.duration:
588 | raise ValueError("Noise signal (%f sec) must be at least as long as"
589 | " base signal (%f sec)." %
590 | (noise.duration, self.duration))
591 | noise_gain_db = min(self.rms_db - noise.rms_db - snr_dB, max_gain_db)
592 | noise_new = copy.deepcopy(noise)
593 | noise_new.random_subsegment(self.duration, rng=rng)
594 | noise_new.gain_db(noise_gain_db)
595 | self.superimpose(noise_new)
596 |
597 | @property
598 | def samples(self):
599 | """Return audio samples.
600 |
601 | :return: Audio samples.
602 | :rtype: ndarray
603 | """
604 | return self._samples.copy()
605 |
606 | @property
607 | def sample_rate(self):
608 | """Return audio sample rate.
609 |
610 | :return: Audio sample rate.
611 | :rtype: int
612 | """
613 | return self._sample_rate
614 |
615 | @property
616 | def num_samples(self):
617 | """Return number of samples.
618 |
619 | :return: Number of samples.
620 | :rtype: int
621 | """
622 | return self._samples.shape[0]
623 |
624 | @property
625 | def duration(self):
626 | """Return audio duration.
627 |
628 | :return: Audio duration in seconds.
629 | :rtype: float
630 | """
631 | return self._samples.shape[0] / float(self._sample_rate)
632 |
633 | @property
634 | def rms_db(self):
635 | """Return root mean square energy of the audio in decibels.
636 |
637 | :return: Root mean square energy in decibels.
638 | :rtype: float
639 | """
640 | # square root => multiply by 10 instead of 20 for dBs
641 | mean_square = np.mean(self._samples**2)
642 | return 10 * np.log10(mean_square)
643 |
644 | def _convert_samples_to_float32(self, samples):
645 | """Convert sample type to float32.
646 |
647 | Audio sample type is usually integer or float-point.
648 | Integers will be scaled to [-1, 1] in float32.
649 | """
650 | float32_samples = samples.astype('float32')
651 | if samples.dtype in np.sctypes['int']:
652 | bits = np.iinfo(samples.dtype).bits
653 | float32_samples *= (1. / 2**(bits - 1))
654 | elif samples.dtype in np.sctypes['float']:
655 | pass
656 | else:
657 | raise TypeError("Unsupported sample type: %s." % samples.dtype)
658 | return float32_samples
659 |
660 | def _convert_samples_from_float32(self, samples, dtype):
661 | """Convert sample type from float32 to dtype.
662 |
663 | Audio sample type is usually integer or float-point. For integer
664 | type, float32 will be rescaled from [-1, 1] to the maximum range
665 | supported by the integer type.
666 |
667 | This is for writing a audio file.
668 | """
669 | dtype = np.dtype(dtype)
670 | output_samples = samples.copy()
671 | if dtype in np.sctypes['int']:
672 | bits = np.iinfo(dtype).bits
673 | output_samples *= (2**(bits - 1) / 1.)
674 | min_val = np.iinfo(dtype).min
675 | max_val = np.iinfo(dtype).max
676 | output_samples[output_samples > max_val] = max_val
677 | output_samples[output_samples < min_val] = min_val
678 | elif samples.dtype in np.sctypes['float']:
679 | min_val = np.finfo(dtype).min
680 | max_val = np.finfo(dtype).max
681 | output_samples[output_samples > max_val] = max_val
682 | output_samples[output_samples < min_val] = min_val
683 | else:
684 | raise TypeError("Unsupported sample type: %s." % samples.dtype)
685 | return output_samples.astype(dtype)
686 |
--------------------------------------------------------------------------------
/data_utils/audio.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/data_utils/audio.pyc
--------------------------------------------------------------------------------
/data_utils/audio_featurizer.py:
--------------------------------------------------------------------------------
1 | """Contains the audio featurizer class."""
2 | from __future__ import absolute_import
3 | from __future__ import division
4 | from __future__ import print_function
5 |
6 | import numpy as np
7 | from python_speech_features import mfcc
8 | from python_speech_features import delta
9 |
10 |
11 | class AudioFeaturizer(object):
12 | """Audio featurizer, for extracting features from audio contents of
13 | AudioSegment or SpeechSegment.
14 |
15 | Currently, it supports feature types of linear spectrogram and mfcc.
16 |
17 | :param specgram_type: Specgram feature type. Options: 'linear'.
18 | :type specgram_type: str
19 | :param stride_ms: Striding size (in milliseconds) for generating frames.
20 | :type stride_ms: float
21 | :param window_ms: Window size (in milliseconds) for generating frames.
22 | :type window_ms: float
23 | :param max_freq: When specgram_type is 'linear', only FFT bins
24 | corresponding to frequencies between [0, max_freq] are
25 | returned; when specgram_type is 'mfcc', max_feq is the
26 | highest band edge of mel filters.
27 | :types max_freq: None|float
28 | :param target_sample_rate: Audio are resampled (if upsampling or
29 | downsampling is allowed) to this before
30 | extracting spectrogram features.
31 | :type target_sample_rate: float
32 | :param use_dB_normalization: Whether to normalize the audio to a certain
33 | decibels before extracting the features.
34 | :type use_dB_normalization: bool
35 | :param target_dB: Target audio decibels for normalization.
36 | :type target_dB: float
37 | """
38 |
39 | def __init__(self,
40 | specgram_type='linear',
41 | stride_ms=10.0,
42 | window_ms=20.0,
43 | max_freq=None,
44 | target_sample_rate=16000,
45 | use_dB_normalization=True,
46 | target_dB=-20):
47 | self._specgram_type = specgram_type
48 | self._stride_ms = stride_ms
49 | self._window_ms = window_ms
50 | self._max_freq = max_freq
51 | self._target_sample_rate = target_sample_rate
52 | self._use_dB_normalization = use_dB_normalization
53 | self._target_dB = target_dB
54 |
55 | def featurize(self,
56 | audio_segment,
57 | allow_downsampling=True,
58 | allow_upsampling=True):
59 | """Extract audio features from AudioSegment or SpeechSegment.
60 |
61 | :param audio_segment: Audio/speech segment to extract features from.
62 | :type audio_segment: AudioSegment|SpeechSegment
63 | :param allow_downsampling: Whether to allow audio downsampling before
64 | featurizing.
65 | :type allow_downsampling: bool
66 | :param allow_upsampling: Whether to allow audio upsampling before
67 | featurizing.
68 | :type allow_upsampling: bool
69 | :return: Spectrogram audio feature in 2darray.
70 | :rtype: ndarray
71 | :raises ValueError: If audio sample rate is not supported.
72 | """
73 | # upsampling or downsampling
74 | if ((audio_segment.sample_rate > self._target_sample_rate and
75 | allow_downsampling) or
76 | (audio_segment.sample_rate < self._target_sample_rate and
77 | allow_upsampling)):
78 | audio_segment.resample(self._target_sample_rate)
79 | if audio_segment.sample_rate != self._target_sample_rate:
80 | raise ValueError("Audio sample rate is not supported. "
81 | "Turn allow_downsampling or allow up_sampling on.")
82 | # decibel normalization
83 | if self._use_dB_normalization:
84 | audio_segment.normalize(target_db=self._target_dB)
85 | # extract spectrogram
86 | return self._compute_specgram(audio_segment.samples,
87 | audio_segment.sample_rate)
88 |
89 | def _compute_specgram(self, samples, sample_rate):
90 | """Extract various audio features."""
91 | if self._specgram_type == 'linear':
92 | return self._compute_linear_specgram(
93 | samples, sample_rate, self._stride_ms, self._window_ms,
94 | self._max_freq)
95 | elif self._specgram_type == 'mfcc':
96 | return self._compute_mfcc(samples, sample_rate, self._stride_ms,
97 | self._window_ms, self._max_freq)
98 | else:
99 | raise ValueError("Unknown specgram_type %s. "
100 | "Supported values: linear." % self._specgram_type)
101 |
102 | def _compute_linear_specgram(self,
103 | samples,
104 | sample_rate,
105 | stride_ms=10.0,
106 | window_ms=20.0,
107 | max_freq=None,
108 | eps=1e-14):
109 | """Compute the linear spectrogram from FFT energy."""
110 | if max_freq is None:
111 | max_freq = sample_rate / 2
112 | if max_freq > sample_rate / 2:
113 | raise ValueError("max_freq must not be greater than half of "
114 | "sample rate.")
115 | if stride_ms > window_ms:
116 | raise ValueError("Stride size must not be greater than "
117 | "window size.")
118 | stride_size = int(0.001 * sample_rate * stride_ms)
119 | window_size = int(0.001 * sample_rate * window_ms)
120 | specgram, freqs = self._specgram_real(
121 | samples,
122 | window_size=window_size,
123 | stride_size=stride_size,
124 | sample_rate=sample_rate)
125 | ind = np.where(freqs <= max_freq)[0][-1] + 1
126 | return np.log(specgram[:ind, :] + eps)
127 |
128 | def _specgram_real(self, samples, window_size, stride_size, sample_rate=16000):
129 | """Compute the spectrogram for samples from a real signal."""
130 | # extract strided windows
131 | truncate_size = (len(samples) - window_size) % stride_size
132 | samples = samples[:len(samples) - truncate_size]
133 | nshape = (window_size, (len(samples) - window_size) // stride_size + 1)
134 | nstrides = (samples.strides[0], samples.strides[0] * stride_size)
135 | windows = np.lib.stride_tricks.as_strided(
136 | samples, shape=nshape, strides=nstrides)
137 | assert np.all(
138 | windows[:, 1] == samples[stride_size:(stride_size + window_size)])
139 | # window weighting, squared Fast Fourier Transform (fft), scaling
140 | weighting = np.hanning(window_size)[:, None]
141 | fft = np.fft.rfft(windows * weighting, axis=0)
142 | fft = np.absolute(fft)
143 | fft = fft**2
144 | scale = np.sum(weighting**2) * sample_rate
145 | fft[1:-1, :] *= (2.0 / scale)
146 | fft[(0, -1), :] /= scale
147 | # prepare fft frequency list
148 | freqs = float(sample_rate) / window_size * np.arange(fft.shape[0])
149 | return fft, freqs
150 |
151 | def _compute_mfcc(self,
152 | samples,
153 | sample_rate,
154 | stride_ms=10.0,
155 | window_ms=20.0,
156 | max_freq=None):
157 | """Compute mfcc from samples."""
158 | if max_freq is None:
159 | max_freq = sample_rate / 2
160 | if max_freq > sample_rate / 2:
161 | raise ValueError("max_freq must not be greater than half of "
162 | "sample rate.")
163 | if stride_ms > window_ms:
164 | raise ValueError("Stride size must not be greater than "
165 | "window size.")
166 | # compute the 13 cepstral coefficients, and the first one is replaced
167 | # by log(frame energy)
168 | mfcc_feat = mfcc(
169 | signal=samples,
170 | samplerate=sample_rate,
171 | winlen=0.001 * window_ms,
172 | winstep=0.001 * stride_ms,
173 | highfreq=max_freq)
174 | # Deltas
175 | d_mfcc_feat = delta(mfcc_feat, 2)
176 | # Deltas-Deltas
177 | dd_mfcc_feat = delta(d_mfcc_feat, 2)
178 | # transpose
179 | mfcc_feat = np.transpose(mfcc_feat)
180 | d_mfcc_feat = np.transpose(d_mfcc_feat)
181 | dd_mfcc_feat = np.transpose(dd_mfcc_feat)
182 | # concat above three features
183 | concat_mfcc_feat = np.concatenate(
184 | (mfcc_feat, d_mfcc_feat, dd_mfcc_feat))
185 | return concat_mfcc_feat
186 |
--------------------------------------------------------------------------------
/data_utils/audio_featurizer.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/data_utils/audio_featurizer.pyc
--------------------------------------------------------------------------------
/data_utils/build_vocab.py:
--------------------------------------------------------------------------------
1 | """Build vocabulary from manifest files.
2 |
3 | Each item in vocabulary file is a character.
4 | """
5 |
6 | from __future__ import absolute_import
7 | from __future__ import division
8 |
9 | import argparse
10 | import functools
11 | import codecs
12 | import json
13 | from collections import Counter
14 | import os.path
15 | import sys
16 |
17 | sys.path.append(os.path.dirname(__file__) + "/../")
18 | from data_utils.utility import read_manifest
19 | from utils.utility import add_arguments, print_arguments
20 |
21 | parser = argparse.ArgumentParser(description=__doc__)
22 | add_arg = functools.partial(add_arguments, argparser=parser)
23 | # yapf: disable
24 | add_arg('count_threshold', int, 0, "Truncation threshold for char counts.")
25 | add_arg('vocab_path', str,
26 | 'data/aishell/vocab.txt',
27 | "Filepath to write the vocabulary.")
28 | add_arg('manifest_paths', str,
29 | None,
30 | "Filepaths of manifests for building vocabulary. "
31 | "You can provide multiple manifest files.",
32 | nargs='+',
33 | required=True)
34 | # yapf: disable
35 | args = parser.parse_args()
36 |
37 |
38 | def count_manifest(counter, manifest_path):
39 | manifest_jsons = read_manifest(manifest_path)
40 | for line_json in manifest_jsons:
41 | for char in line_json['text']:
42 | counter.update(char)
43 |
44 |
45 | def main():
46 | print_arguments(args)
47 |
48 | counter = Counter()
49 | for manifest_path in args.manifest_paths:
50 | count_manifest(counter, manifest_path)
51 |
52 | count_sorted = sorted(counter.items(), key=lambda x: x[1], reverse=True)
53 | with codecs.open(args.vocab_path, 'w', 'utf-8') as fout:
54 | for char, count in count_sorted:
55 | if count < args.count_threshold: break
56 | fout.write(char + '\n')
57 |
58 |
59 | if __name__ == '__main__':
60 | main()
61 |
--------------------------------------------------------------------------------
/data_utils/compute_mean_std.py:
--------------------------------------------------------------------------------
1 | """Compute mean and std for feature normalizer, and save to file."""
2 | from __future__ import absolute_import
3 | from __future__ import division
4 | from __future__ import print_function
5 |
6 | import sys, os
7 | import argparse
8 | import functools
9 |
10 | sys.path.append(os.path.dirname(__file__) + "/../")
11 | from data_utils.normalizer import FeatureNormalizer
12 | from data_utils.audio_featurizer import AudioFeaturizer
13 | from utils.utility import add_arguments, print_arguments
14 |
15 | parser = argparse.ArgumentParser(description=__doc__)
16 | add_arg = functools.partial(add_arguments, argparser=parser)
17 | # yapf: disable
18 | add_arg('num_samples', int, 2000, "# of samples to for statistics.")
19 | add_arg('specgram_type', str,
20 | 'linear',
21 | "Audio feature type. Options: linear, mfcc.",
22 | choices=['linear', 'mfcc'])
23 | add_arg('manifest_path', str,
24 | 'data/aishell/manifest.train',
25 | "Filepath of manifest to compute normalizer's mean and stddev.")
26 | add_arg('output_path', str,
27 | 'data/aishell/mean_std.npz',
28 | "Filepath of write mean and stddev to (.npz).")
29 | # yapf: disable
30 | args = parser.parse_args()
31 |
32 |
33 | def main():
34 | print_arguments(args)
35 |
36 | audio_featurizer = AudioFeaturizer(specgram_type=args.specgram_type)
37 |
38 | def augment_and_featurize(audio_segment):
39 | return audio_featurizer.featurize(audio_segment)
40 |
41 | normalizer = FeatureNormalizer(
42 | mean_std_filepath=None,
43 | manifest_path=args.manifest_path,
44 | featurize_func=augment_and_featurize,
45 | num_samples=args.num_samples)
46 | normalizer.write_to_file(args.output_path)
47 |
48 |
49 | if __name__ == '__main__':
50 | main()
51 |
--------------------------------------------------------------------------------
/data_utils/normalizer.py:
--------------------------------------------------------------------------------
1 | """Contains feature normalizers."""
2 | from __future__ import absolute_import
3 | from __future__ import division
4 | from __future__ import print_function
5 |
6 | import numpy as np
7 | import random
8 | from data_utils.utility import read_manifest
9 | from data_utils.audio import AudioSegment
10 |
11 |
12 | class FeatureNormalizer(object):
13 | """Feature normalizer. Normalize features to be of zero mean and unit
14 | stddev.
15 |
16 | if mean_std_filepath is provided (not None), the normalizer will directly
17 | initilize from the file. Otherwise, both manifest_path and featurize_func
18 | should be given for on-the-fly mean and stddev computing.
19 |
20 | :param mean_std_filepath: File containing the pre-computed mean and stddev.
21 | :type mean_std_filepath: None|basestring
22 | :param manifest_path: Manifest of instances for computing mean and stddev.
23 | :type meanifest_path: None|basestring
24 | :param featurize_func: Function to extract features. It should be callable
25 | with ``featurize_func(audio_segment)``.
26 | :type featurize_func: None|callable
27 | :param num_samples: Number of random samples for computing mean and stddev.
28 | :type num_samples: int
29 | :param random_seed: Random seed for sampling instances.
30 | :type random_seed: int
31 | :raises ValueError: If both mean_std_filepath and manifest_path
32 | (or both mean_std_filepath and featurize_func) are None.
33 | """
34 |
35 | def __init__(self,
36 | mean_std_filepath,
37 | manifest_path=None,
38 | featurize_func=None,
39 | num_samples=500,
40 | random_seed=0):
41 | if not mean_std_filepath:
42 | if not (manifest_path and featurize_func):
43 | raise ValueError("If mean_std_filepath is None, meanifest_path "
44 | "and featurize_func should not be None.")
45 | self._rng = random.Random(random_seed)
46 | self._compute_mean_std(manifest_path, featurize_func, num_samples)
47 | else:
48 | self._read_mean_std_from_file(mean_std_filepath)
49 |
50 | def apply(self, features, eps=1e-14):
51 | """Normalize features to be of zero mean and unit stddev.
52 |
53 | :param features: Input features to be normalized.
54 | :type features: ndarray
55 | :param eps: added to stddev to provide numerical stablibity.
56 | :type eps: float
57 | :return: Normalized features.
58 | :rtype: ndarray
59 | """
60 | return (features - self._mean) / (self._std + eps)
61 |
62 | def write_to_file(self, filepath):
63 | """Write the mean and stddev to the file.
64 |
65 | :param filepath: File to write mean and stddev.
66 | :type filepath: basestring
67 | """
68 | np.savez(filepath, mean=self._mean, std=self._std)
69 |
70 | def _read_mean_std_from_file(self, filepath):
71 | """Load mean and std from file."""
72 | npzfile = np.load(filepath)
73 | self._mean = npzfile["mean"]
74 | self._std = npzfile["std"]
75 |
76 | def _compute_mean_std(self, manifest_path, featurize_func, num_samples):
77 | """Compute mean and std from randomly sampled instances."""
78 | manifest = read_manifest(manifest_path)
79 | print("num_samples: ", num_samples)
80 | sampled_manifest = self._rng.sample(manifest, num_samples)
81 | features = []
82 | for instance in sampled_manifest:
83 | features.append(
84 | featurize_func(
85 | AudioSegment.from_file(instance["audio_filepath"])))
86 | features = np.hstack(features)
87 | self._mean = np.mean(features, axis=1).reshape([-1, 1])
88 | self._std = np.std(features, axis=1).reshape([-1, 1])
89 |
--------------------------------------------------------------------------------
/data_utils/normalizer.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/data_utils/normalizer.pyc
--------------------------------------------------------------------------------
/data_utils/process_manifest.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding=utf-8
3 |
4 | """ Data pre-process """
5 |
6 | import json
7 | from collections import Counter
8 |
9 | def get_path_trans(manifest_path="data/aishell/manifest.train" ):
10 | '''Get path_to_wav and transcript list from data/manifest.{train,dev,test}
11 |
12 | :param manifest_path: path to manifest file
13 | :type manifest: str
14 | return
15 | '''
16 |
17 | path_to_wav = []
18 | transcript = []
19 | duration = []
20 | lines = open(manifest_path, "r").readlines()
21 | for line in lines:
22 | man_dict = json.loads(line)
23 | path_to_wav.append(man_dict["audio_filepath"])
24 | transcript.append(man_dict["text"])
25 | duration.append(man_dict["duration"])
26 | return path_to_wav, transcript, duration
27 |
28 | def create_dict(vocab):
29 | '''Creat word dict and map from word to num
30 |
31 | :param vocab: path to vocab.txt
32 | :type vocab: str
33 | return
34 | '''
35 |
36 | total_words = open(vocab, 'r').readlines()
37 | total_words = [word.strip() for word in total_words]
38 | counter = Counter(total_words)
39 | words = sorted(counter)
40 | word_size = len(words)
41 | word_num_map = dict(zip(words, range(word_size)))
42 |
43 | print "word_size: ", word_size
44 | return word_size, words, word_num_map
45 |
46 | if __name__ == "__main__":
47 | get_path_trans("../data/aishell/manifest.test")
48 | creat_dict("../data/aishell/vocab.txt")
49 |
--------------------------------------------------------------------------------
/data_utils/process_manifest.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/data_utils/process_manifest.pyc
--------------------------------------------------------------------------------
/data_utils/speech.py:
--------------------------------------------------------------------------------
1 | """Contains the speech segment class."""
2 | from __future__ import absolute_import
3 | from __future__ import division
4 | from __future__ import print_function
5 |
6 | from data_utils.audio import AudioSegment
7 |
8 |
9 | class SpeechSegment(AudioSegment):
10 | """Speech segment abstraction, a subclass of AudioSegment,
11 | with an additional transcript.
12 |
13 | :param samples: Audio samples [num_samples x num_channels].
14 | :type samples: ndarray.float32
15 | :param sample_rate: Audio sample rate.
16 | :type sample_rate: int
17 | :param transcript: Transcript text for the speech.
18 | :type transript: basestring
19 | :raises TypeError: If the sample data type is not float or int.
20 | """
21 |
22 | def __init__(self, samples, sample_rate, transcript):
23 | AudioSegment.__init__(self, samples, sample_rate)
24 | self._transcript = transcript
25 |
26 | def __eq__(self, other):
27 | """Return whether two objects are equal.
28 | """
29 | if not AudioSegment.__eq__(self, other):
30 | return False
31 | if self._transcript != other._transcript:
32 | return False
33 | return True
34 |
35 | def __ne__(self, other):
36 | """Return whether two objects are unequal."""
37 | return not self.__eq__(other)
38 |
39 | @classmethod
40 | def from_file(cls, filepath, transcript):
41 | """Create speech segment from audio file and corresponding transcript.
42 |
43 | :param filepath: Filepath or file object to audio file.
44 | :type filepath: basestring|file
45 | :param transcript: Transcript text for the speech.
46 | :type transript: basestring
47 | :return: Speech segment instance.
48 | :rtype: SpeechSegment
49 | """
50 | audio = AudioSegment.from_file(filepath)
51 | return cls(audio.samples, audio.sample_rate, transcript)
52 |
53 | @classmethod
54 | def from_bytes(cls, bytes, transcript):
55 | """Create speech segment from a byte string and corresponding
56 | transcript.
57 |
58 | :param bytes: Byte string containing audio samples.
59 | :type bytes: str
60 | :param transcript: Transcript text for the speech.
61 | :type transript: basestring
62 | :return: Speech segment instance.
63 | :rtype: Speech Segment
64 | """
65 | audio = AudioSegment.from_bytes(bytes)
66 | return cls(audio.samples, audio.sample_rate, transcript)
67 |
68 | @classmethod
69 | def concatenate(cls, *segments):
70 | """Concatenate an arbitrary number of speech segments together, both
71 | audio and transcript will be concatenated.
72 |
73 | :param *segments: Input speech segments to be concatenated.
74 | :type *segments: tuple of SpeechSegment
75 | :return: Speech segment instance.
76 | :rtype: SpeechSegment
77 | :raises ValueError: If the number of segments is zero, or if the
78 | sample_rate of any two segments does not match.
79 | :raises TypeError: If any segment is not SpeechSegment instance.
80 | """
81 | if len(segments) == 0:
82 | raise ValueError("No speech segments are given to concatenate.")
83 | sample_rate = segments[0]._sample_rate
84 | transcripts = ""
85 | for seg in segments:
86 | if sample_rate != seg._sample_rate:
87 | raise ValueError("Can't concatenate segments with "
88 | "different sample rates")
89 | if type(seg) is not cls:
90 | raise TypeError("Only speech segments of the same type "
91 | "instance can be concatenated.")
92 | transcripts += seg._transcript
93 | samples = np.concatenate([seg.samples for seg in segments])
94 | return cls(samples, sample_rate, transcripts)
95 |
96 | @classmethod
97 | def slice_from_file(cls, filepath, transcript, start=None, end=None):
98 | """Loads a small section of an speech without having to load
99 | the entire file into the memory which can be incredibly wasteful.
100 |
101 | :param filepath: Filepath or file object to audio file.
102 | :type filepath: basestring|file
103 | :param start: Start time in seconds. If start is negative, it wraps
104 | around from the end. If not provided, this function
105 | reads from the very beginning.
106 | :type start: float
107 | :param end: End time in seconds. If end is negative, it wraps around
108 | from the end. If not provided, the default behvaior is
109 | to read to the end of the file.
110 | :type end: float
111 | :param transcript: Transcript text for the speech. if not provided,
112 | the defaults is an empty string.
113 | :type transript: basestring
114 | :return: SpeechSegment instance of the specified slice of the input
115 | speech file.
116 | :rtype: SpeechSegment
117 | """
118 | audio = AudioSegment.slice_from_file(filepath, start, end)
119 | return cls(audio.samples, audio.sample_rate, transcript)
120 |
121 | @classmethod
122 | def make_silence(cls, duration, sample_rate):
123 | """Creates a silent speech segment of the given duration and
124 | sample rate, transcript will be an empty string.
125 |
126 | :param duration: Length of silence in seconds.
127 | :type duration: float
128 | :param sample_rate: Sample rate.
129 | :type sample_rate: float
130 | :return: Silence of the given duration.
131 | :rtype: SpeechSegment
132 | """
133 | audio = AudioSegment.make_silence(duration, sample_rate)
134 | return cls(audio.samples, audio.sample_rate, "")
135 |
136 | @property
137 | def transcript(self):
138 | """Return the transcript text.
139 |
140 | :return: Transcript text for the speech.
141 | :rtype: basestring
142 | """
143 | return self._transcript
144 |
--------------------------------------------------------------------------------
/data_utils/speech.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/data_utils/speech.pyc
--------------------------------------------------------------------------------
/data_utils/utility.py:
--------------------------------------------------------------------------------
1 | """Contains data helper functions."""
2 | from __future__ import absolute_import
3 | from __future__ import division
4 | from __future__ import print_function
5 |
6 | import json
7 | import codecs
8 | import os
9 | import tarfile
10 | import time
11 | import md5
12 | from Queue import Queue
13 | from threading import Thread
14 | from multiprocessing import Process, Manager, Value
15 |
16 |
17 | def read_manifest(manifest_path, max_duration=float('inf'), min_duration=0.0):
18 | """Load and parse manifest file.
19 |
20 | Instances with durations outside [min_duration, max_duration] will be
21 | filtered out.
22 |
23 | :param manifest_path: Manifest file to load and parse.
24 | :type manifest_path: basestring
25 | :param max_duration: Maximal duration in seconds for instance filter.
26 | :type max_duration: float
27 | :param min_duration: Minimal duration in seconds for instance filter.
28 | :type min_duration: float
29 | :return: Manifest parsing results. List of dict.
30 | :rtype: list
31 | :raises IOError: If failed to parse the manifest.
32 | """
33 | manifest = []
34 | for json_line in codecs.open(manifest_path, 'r', 'utf-8'):
35 | try:
36 | json_data = json.loads(json_line)
37 | except Exception as e:
38 | raise IOError("Error reading manifest: %s" % str(e))
39 | if (json_data["duration"] <= max_duration and
40 | json_data["duration"] >= min_duration):
41 | manifest.append(json_data)
42 | return manifest
43 |
44 |
45 | def getfile_insensitive(path):
46 | """Get the actual file path when given insensitive filename."""
47 | directory, filename = os.path.split(path)
48 | directory, filename = (directory or '.'), filename.lower()
49 | for f in os.listdir(directory):
50 | newpath = os.path.join(directory, f)
51 | if os.path.isfile(newpath) and f.lower() == filename:
52 | return newpath
53 |
54 |
55 | def download_multi(url, target_dir, extra_args):
56 | """Download multiple files from url to target_dir."""
57 | if not os.path.exists(target_dir): os.makedirs(target_dir)
58 | print("Downloading %s ..." % url)
59 | ret_code = os.system("wget -c " + url + ' ' + extra_args + " -P " +
60 | target_dir)
61 | return ret_code
62 |
63 |
64 | def download(url, md5sum, target_dir):
65 | """Download file from url to target_dir, and check md5sum."""
66 | if not os.path.exists(target_dir): os.makedirs(target_dir)
67 | filepath = os.path.join(target_dir, url.split("/")[-1])
68 | m1 = md5.new()
69 | m1.update(filepath)
70 | print ("adsadas", m1.hexdigest())
71 | if not (os.path.exists(filepath) and m1.hexdigest() == md5sum):
72 | print("Downloading %s ..." % url)
73 | os.system("wget -c " + url + " -P " + target_dir)
74 | print("\nMD5 Chesksum %s ..." % filepath)
75 | if not m1.hexdigest() == md5sum:
76 | raise RuntimeError("MD5 checksum failed.")
77 | else:
78 | print("File exists, skip downloading. (%s)" % filepath)
79 | return filepath
80 |
81 |
82 | def unpack(filepath, target_dir, rm_tar=False):
83 | """Unpack the file to the target_dir."""
84 | print("Unpacking %s ..." % filepath)
85 | tar = tarfile.open(filepath)
86 | tar.extractall(target_dir)
87 | tar.close()
88 | if rm_tar == True:
89 | os.remove(filepath)
90 |
91 |
92 | class XmapEndSignal():
93 | pass
94 |
95 |
96 | def xmap_readers_mp(mapper, reader, process_num, buffer_size, order=False):
97 | """A multiprocessing pipeline wrapper for the data reader.
98 |
99 | :param mapper: Function to map sample.
100 | :type mapper: callable
101 | :param reader: Given data reader.
102 | :type reader: callable
103 | :param process_num: Number of processes in the pipeline
104 | :type process_num: int
105 | :param buffer_size: Maximal buffer size.
106 | :type buffer_size: int
107 | :return: The wrappered reader and cleanup callback
108 | :rtype: tuple
109 | """
110 | end_flag = XmapEndSignal()
111 |
112 | read_workers = []
113 | handle_workers = []
114 | flush_workers = []
115 |
116 | read_exit_flag = Value('i', 0)
117 | handle_exit_flag = Value('i', 0)
118 | flush_exit_flag = Value('i', 0)
119 |
120 | # define a worker to read samples from reader to in_queue with order flag
121 | def order_read_worker(reader, in_queue):
122 | for order_id, sample in enumerate(reader()):
123 | if read_exit_flag.value == 1: break
124 | in_queue.put((order_id, sample))
125 | in_queue.put(end_flag)
126 | # the reading worker should not exit until all handling work exited
127 | while handle_exit_flag.value == 0 or read_exit_flag.value == 0:
128 | time.sleep(0.001)
129 |
130 | # define a worker to handle samples from in_queue by mapper and put results
131 | # to out_queue with order
132 | def order_handle_worker(in_queue, out_queue, mapper, out_order):
133 | ins = in_queue.get()
134 | while not isinstance(ins, XmapEndSignal):
135 | if handle_exit_flag.value == 1: break
136 | order_id, sample = ins
137 | result = mapper(sample)
138 | while order_id != out_order[0]:
139 | time.sleep(0.001)
140 | out_queue.put(result)
141 | out_order[0] += 1
142 | ins = in_queue.get()
143 | in_queue.put(end_flag)
144 | out_queue.put(end_flag)
145 | # wait for exit of flushing worker
146 | while flush_exit_flag.value == 0 or handle_exit_flag.value == 0:
147 | time.sleep(0.001)
148 | read_exit_flag.value = 1
149 | handle_exit_flag.value = 1
150 |
151 | # define a thread worker to flush samples from Manager.Queue to Queue
152 | # for acceleration
153 | def flush_worker(in_queue, out_queue):
154 | finish = 0
155 | while finish < process_num and flush_exit_flag.value == 0:
156 | sample = in_queue.get()
157 | if isinstance(sample, XmapEndSignal):
158 | finish += 1
159 | else:
160 | out_queue.put(sample)
161 | out_queue.put(end_flag)
162 | handle_exit_flag.value = 1
163 | flush_exit_flag.value = 1
164 |
165 | def cleanup():
166 | # first exit flushing workers
167 | flush_exit_flag.value = 1
168 | for w in flush_workers:
169 | w.join()
170 | # next exit handling workers
171 | handle_exit_flag.value = 1
172 | for w in handle_workers:
173 | w.join()
174 | # last exit reading workers
175 | read_exit_flag.value = 1
176 | for w in read_workers:
177 | w.join()
178 |
179 | def xreader():
180 | # prepare shared memory
181 | manager = Manager()
182 | in_queue = manager.Queue(buffer_size)
183 | out_queue = manager.Queue(buffer_size)
184 | out_order = manager.list([0])
185 |
186 | # start a read worker in a process
187 | target = order_read_worker
188 | p = Process(target=target, args=(reader, in_queue))
189 | p.daemon = True
190 | p.start()
191 | read_workers.append(p)
192 |
193 | # start handle_workers with multiple processes
194 | target = order_handle_worker
195 | args = (in_queue, out_queue, mapper, out_order)
196 | workers = [
197 | Process(target=target, args=args) for _ in xrange(process_num)
198 | ]
199 | for w in workers:
200 | w.daemon = True
201 | w.start()
202 | handle_workers.append(w)
203 |
204 | # start a thread to read data from slow Manager.Queue
205 | flush_queue = Queue(buffer_size)
206 | t = Thread(target=flush_worker, args=(out_queue, flush_queue))
207 | t.daemon = True
208 | t.start()
209 | flush_workers.append(t)
210 |
211 | # get results
212 | sample = flush_queue.get()
213 | while not isinstance(sample, XmapEndSignal):
214 | yield sample
215 | sample = flush_queue.get()
216 |
217 | return xreader, cleanup
218 |
--------------------------------------------------------------------------------
/data_utils/utility.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/data_utils/utility.pyc
--------------------------------------------------------------------------------
/data_utils/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import absolute_import
3 | from __future__ import division
4 |
5 | import os
6 | from collections import Counter
7 |
8 | import numpy as np
9 | import scipy.io.wavfile as wav
10 | from python_speech_features import mfcc
11 | from data_utils.audio_featurizer import AudioFeaturizer
12 | from data_utils.speech import SpeechSegment
13 | from data_utils.normalizer import FeatureNormalizer
14 | from conf.hyparam import Config
15 |
16 | '''
17 | To help creat train set and get batch from data
18 | '''
19 |
20 | def next_batch(start_idx=0,
21 | batch_size=1,
22 | n_input=None,
23 | n_context=None,
24 | labels=None,
25 | wav_files=None,
26 | word_num_map=None,
27 | specgram_type='mfcc'):
28 | """ Get data batch for training
29 |
30 | :param start_idx:
31 | :param batch_size:
32 | :param n_input:
33 | :param n_context:
34 | :param labels:
35 | :param wav_files:
36 | :param word_num_map:
37 | :param specgram_type
38 | :return:
39 | """
40 | filesize = len(labels)
41 | end_idx = min(filesize, start_idx + batch_size)
42 | idx_list = range(start_idx, end_idx)
43 | txt_labels = [labels[i] for i in idx_list]
44 | wav_files = [wav_files[i] for i in idx_list]
45 | audio_features, audio_features_len, text_vector, text_vector_len = get_audio_mfcc_features(None,
46 | wav_files,
47 | n_input,
48 | n_context,
49 | word_num_map,
50 | txt_labels,
51 | specgram_type)
52 |
53 | start_idx += batch_size
54 | # confirm start_idx
55 | if start_idx >= filesize:
56 | start_idx = -1
57 |
58 | # use 0 padding when serveral inputs
59 | audio_features, audio_features_len = pad_sequences(audio_features)
60 | sparse_labels = sparse_tuple_from(text_vector)
61 |
62 | return start_idx, audio_features, audio_features_len, sparse_labels, wav_files
63 |
64 |
65 | def get_audio_mfcc_features(txt_files, wav_files, n_input,
66 | n_context, word_num_map, txt_labels=None,
67 | specgram_type='mfcc', mean_std_filepath='data/aishell/mean_std.npz'):
68 | """ Get MFCC/linear specgram features. The dim of MFCC is 39, contains 13 mfcc + 13 delta1 + 13 delta2.
69 | Linear specgram contains 161 features in different frequency section.
70 |
71 | :param txt_files:
72 | :param wav_files:
73 | :param n_input:
74 | :param n_context:
75 | :param word_num_map:
76 | :param txt_labels:
77 | :return:
78 | """
79 | audio_features = []
80 | audio_features_len = []
81 | text_vector = []
82 | text_vector_len = []
83 | if txt_files != None:
84 | txt_labels = txt_files
85 | get_feature = AudioFeaturizer(specgram_type)
86 | normalizer = FeatureNormalizer(mean_std_filepath)
87 | for txt_obj, wav_file in zip(txt_labels, wav_files):
88 | # Turn inputs into features
89 | if specgram_type == 'mfcc':
90 | audio_data = audiofile_to_input_vector(wav_file, n_input, n_context) # get mfcc feature ( ???, 741 )
91 | elif specgram_type == 'linear':
92 | speech_segment = SpeechSegment.from_file(wav_file, "")
93 | specgram = get_feature.featurize(speech_segment)
94 | audio_data = normalizer.apply(specgram)
95 | audio_data = np.transpose(audio_data) # get linear specgram feature, (?, 161)
96 | audio_data = audio_data.astype('float32')
97 |
98 | audio_features.append(audio_data)
99 | audio_features_len.append(np.int32(len(audio_data)))
100 |
101 | target = []
102 | if txt_files != None: # txt_obj是文件
103 | target = trans_text_ch_to_vector(txt_obj, word_num_map)
104 | else:
105 | target = trans_text_ch_to_vector(None, word_num_map, txt_obj) # txt_obj是labels
106 | text_vector.append(target)
107 | text_vector_len.append(len(target))
108 |
109 | audio_features = np.asarray(audio_features)
110 | audio_features_len = np.asarray(audio_features_len)
111 | text_vector = np.asarray(text_vector)
112 | text_vector_len = np.asarray(text_vector_len)
113 | return audio_features, audio_features_len, text_vector, text_vector_len
114 |
115 |
116 | def sparse_tuple_from(sequences, dtype=np.int32):
117 | """ Turn dense matrix to sparse matrix
118 |
119 | :param sequences:
120 | :param dtype:
121 | :return:
122 | """
123 | indices = []
124 | values = []
125 |
126 | for n, seq in enumerate(sequences):
127 | indices.extend(zip([n] * len(seq), range(len(seq))))
128 | values.extend(seq)
129 |
130 | indices = np.asarray(indices, dtype=np.int64)
131 | values = np.asarray(values, dtype=dtype)
132 | shape = np.asarray([len(sequences), indices.max(0)[1] + 1], dtype=np.int64)
133 |
134 | return indices, values, shape
135 |
136 |
137 | def trans_text_ch_to_vector(txt_file, word_num_map, txt_label=None):
138 | """ Trans chinese chars to vector
139 |
140 | :param txt_file:
141 | :param word_num_map:
142 | :param txt_label:
143 | :return:
144 | """
145 | words_size = len(word_num_map)
146 |
147 | to_num = lambda word: word_num_map.get(word.encode('utf-8'), words_size)
148 |
149 | if txt_file != None:
150 | txt_label = get_ch_lable(txt_file)
151 |
152 | labels_vector = list(map(to_num, txt_label))
153 | return labels_vector
154 |
155 |
156 | def get_ch_lable(txt_file):
157 | labels = ""
158 | with open(txt_file, 'rb') as f:
159 | for label in f:
160 | labels = labels + label.decode('gb2312')
161 | return labels
162 |
163 |
164 | def trans_tuple_to_texts_ch(tuple, words):
165 | """ Trans vector to chars
166 |
167 | :param tuple:
168 | :param words:
169 | :return:
170 | """
171 | indices = tuple[0]
172 | values = tuple[1]
173 | results = [''] * tuple[2][0]
174 | for i in range(len(indices)):
175 | index = indices[i][0]
176 | c = values[i]
177 | c = ' ' if c == 0 else words[c] # chr(c + FIRST_INDEX)
178 | results[index] = results[index] + c
179 |
180 | return results
181 |
182 |
183 | def trans_array_to_text_ch(value, words):
184 | results = ''
185 | for i in range(len(value)):
186 | results += words[value[i]] # chr(value[i] + FIRST_INDEX)
187 | return results.replace('`', ' ')
188 |
189 |
190 | def audiofile_to_input_vector(audio_filename, n_input, n_context):
191 | """ Compute MFCC features with n_context
192 |
193 | :param audio_filename:
194 | :param n_input:
195 | :param n_context:
196 | :return:
197 | """
198 | fs, audio = wav.read(audio_filename)
199 |
200 | # get mfcc features with dim 39
201 | get_feature = AudioFeaturizer("mfcc")
202 | speech_segment = SpeechSegment.from_file(audio_filename, "")
203 | orig_inputs = get_feature.featurize(speech_segment) # (39, ?)
204 | orig_inputs = np.transpose(orig_inputs) # trans to time major (?, 39)
205 |
206 |
207 | train_inputs = np.zeros((orig_inputs.shape[0], n_input + 2 * n_input * n_context)) #(***/2, 195)
208 | empty_mfcc = np.zeros((n_input))
209 |
210 | # Prepare input data, consist of three parts,
211 | # output is (past hyparam.n_context * 39 + current + future hyparam.n_context * 39)
212 | time_slices = range(train_inputs.shape[0])
213 | context_past_min = time_slices[0] + n_context
214 | context_future_max = time_slices[-1] - n_context
215 | for time_slice in time_slices:
216 | # padding with 0 for the first of 9,mfcc features
217 | need_empty_past = max(0, (context_past_min - time_slice))
218 | empty_source_past = list(empty_mfcc for empty_slots in range(need_empty_past))
219 | data_source_past = orig_inputs[ max(0, time_slice - n_context):time_slice]
220 |
221 | # padding with 0 for the last of 9,mfcc features
222 | need_empty_future = max(0, (time_slice - context_future_max))
223 | empty_source_future = list(empty_mfcc for empty_slots in range(need_empty_future))
224 | data_source_future = orig_inputs[time_slice + 1:time_slice + n_context + 1]
225 |
226 | if need_empty_past:
227 | past = np.concatenate((empty_source_past, data_source_past))
228 | else:
229 | past = data_source_past
230 |
231 | if need_empty_future:
232 | future = np.concatenate((data_source_future, empty_source_future))
233 | else:
234 | future = data_source_future
235 |
236 | past = np.reshape(past, n_context * 39)
237 | now = orig_inputs[time_slice]
238 | future = np.reshape(future, n_context * n_input)
239 | train_inputs[time_slice] = np.concatenate((past, now, future))
240 |
241 | # Tran data to Norm distribution, minus mean value then over the varr
242 | train_inputs = (train_inputs - np.mean(train_inputs)) / np.std(train_inputs)
243 |
244 | # shape of train_inputs: (shape(orig_inputs)/2, n_context * 2 * 39 + 39)
245 | return train_inputs
246 |
247 |
248 | def pad_sequences(sequences, maxlen=None, dtype=np.float32,
249 | padding='post', truncating='post', value=0.):
250 | """ Padding data with 0
251 |
252 | :param sequences:
253 | :param maxlen:
254 | :param dtype:
255 | :param padding:
256 | :param truncating:
257 | :param value:
258 | :return:
259 | """
260 | sequences_each_len = np.asarray([len(s) for s in sequences], dtype=np.int64)
261 |
262 | nb_samples = len(sequences)
263 | if maxlen is None:
264 | maxlen = np.max(sequences_each_len)
265 |
266 | sample_shape = tuple()
267 | for s in sequences:
268 | if len(s) > 0:
269 | sample_shape = np.asarray(s).shape[1:]
270 | break
271 |
272 | x = (np.ones((nb_samples, maxlen) + sample_shape) * value).astype(dtype)
273 | for idx, s in enumerate(sequences):
274 | if len(s) == 0:
275 | continue
276 | if truncating == 'pre':
277 | trunc = s[-maxlen:]
278 | elif truncating == 'post':
279 | trunc = s[:maxlen]
280 | else:
281 | raise ValueError('Truncating type "%s" not understood' % truncating)
282 |
283 | # check `trunc` has expected shape
284 | trunc = np.asarray(trunc, dtype=dtype)
285 | if trunc.shape[1:] != sample_shape:
286 | raise ValueError('Shape of sample %s of sequence at position %s is different from expected shape %s' %
287 | (trunc.shape[1:], idx, sample_shape))
288 |
289 | if padding == 'post':
290 | x[idx, :len(trunc)] = trunc
291 | elif padding == 'pre':
292 | x[idx, -len(trunc):] = trunc
293 | else:
294 | raise ValueError('Padding type "%s" not understood' % padding)
295 | return x, sequences_each_len
296 |
297 |
298 | if __name__ == "__main__":
299 |
300 | print("")
301 |
--------------------------------------------------------------------------------
/data_utils/utils.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/data_utils/utils.pyc
--------------------------------------------------------------------------------
/demo_cache/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/demo_cache/__init__.py
--------------------------------------------------------------------------------
/demo_client.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | CUDA_VISIBLE_DEVICES=0 python -u deploy_demo/demo_client.py --host_ip '10.3.27.97' --host_port 8086
4 |
--------------------------------------------------------------------------------
/demo_server.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | CUDA_VISIBLE_DEVICES=0 \
4 | python deploy_demo/demo_server.py \
5 | --host_ip 10.3.27.97 \
6 | --host_port 8086
7 |
--------------------------------------------------------------------------------
/deploy_demo/_init_paths.py:
--------------------------------------------------------------------------------
1 | """Set up paths for DS2"""
2 | from __future__ import absolute_import
3 | from __future__ import division
4 | from __future__ import print_function
5 |
6 | import os.path
7 | import sys
8 |
9 |
10 | def add_path(path):
11 | if path not in sys.path:
12 | sys.path.insert(0, path)
13 |
14 |
15 | this_dir = os.path.dirname(__file__)
16 |
17 | # Add project path to PYTHONPATH
18 | proj_path = os.path.join(this_dir, '..')
19 | add_path(proj_path)
20 |
--------------------------------------------------------------------------------
/deploy_demo/_init_paths.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/deploy_demo/_init_paths.pyc
--------------------------------------------------------------------------------
/deploy_demo/assert_zero.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding=utf-8
3 |
4 | """ Check zero inputs for wav_files to avoid core dumped error """
5 |
6 | import os
7 | import wave
8 | from time import sleep
9 | import numpy as np
10 |
11 | SUCCESS = 0
12 | FAIL = 1
13 |
14 | def ZCR(curFrame):
15 | # Zero crossing rate
16 | tmp1 = curFrame[:-1]
17 | tmp2 = curFrame[1:]
18 | sings = (tmp1 * tmp2 <= 0)
19 | diffs = (tmp1 - tmp2) > 0.02
20 | zcr = np.sum(sings * diffs)
21 | return zcr
22 |
23 |
24 | def STE(curFrame):
25 | # short time energy
26 | amp = np.sum(np.abs(curFrame))
27 | return amp
28 |
29 |
30 | class Vad(object):
31 | def __init__(self):
32 | # 初始短时能量高门限
33 | self.amp1 = 140
34 | # 初始短时能量低门限
35 | self.amp2 = 120
36 | # 初始短时过零率高门限
37 | self.zcr1 = 10
38 | # 初始短时过零率低门限
39 | self.zcr2 = 5
40 | # 允许最大静音长度
41 | self.maxsilence = 100
42 | # 语音的最短长度
43 | self.minlen = 40
44 | # 偏移值
45 | self.offsets = 40
46 | self.offsete = 40
47 | # 能量最大值
48 | self.max_en = 20000
49 | # 初始状态为静音
50 | self.status = 0
51 | self.count = 0
52 | self.silence = 0
53 | self.frame_len = 256
54 | self.frame_inc = 128
55 | self.cur_status = 0
56 | self.frames = []
57 | # 数据开始偏移
58 | self.frames_start = []
59 | self.frames_start_num = 0
60 | # 数据结束偏移
61 | self.frames_end = []
62 | self.frames_end_num = 0
63 | # 缓存数据
64 | self.cache_frames = []
65 | self.cache = ""
66 | # 最大缓存长度
67 | self.cache_frames_num = 0
68 | self.end_flag = False
69 | self.wait_flag = False
70 | self.on = True
71 | self.callback = None
72 | self.callback_res = []
73 | self.callback_kwargs = {}
74 |
75 | def clean(self):
76 | self.frames = []
77 | # 数据开始偏移
78 | self.frames_start = []
79 | self.frames_start_num = 0
80 | # 数据结束偏移
81 | self.frames_end = []
82 | self.frames_end_num = 0
83 | # 缓存数据
84 | self.cache_frames = []
85 | # 最大缓存长度
86 | self.cache_frames_num = 0
87 | self.end_flag = False
88 | self.wait_flag = False
89 |
90 | def go(self):
91 | self.wait_flag = False
92 |
93 | def wait(self):
94 | self.wait_flag = True
95 |
96 | def stop(self):
97 | self.on = False
98 |
99 | def add(self, frame, wait=True):
100 | if wait:
101 | print 'wait'
102 | frame = self.cache + frame
103 |
104 | while len(frame) > self.frame_len:
105 | frame_block = frame[:self.frame_len]
106 | self.cache_frames.append(frame_block)
107 | frame = frame[self.frame_len:]
108 | if wait:
109 | self.cache = frame
110 | else:
111 | self.cache = ""
112 | self.cache_frames.append(-1)
113 |
114 | def run(self,hasNum):
115 | print "开始执行音频端点检测"
116 | is_zero = True
117 | step = self.frame_len - self.frame_inc
118 | num = 0
119 | while 1:
120 | # 开始端点
121 | # 获得音频文件数字信号
122 | if self.wait_flag:
123 | sleep(1)
124 | continue
125 | if len(self.cache_frames) < 2:
126 | sleep(0.05)
127 | continue
128 |
129 | if self.cache_frames[1] == -1:
130 | print '----------------没有声音--------------'
131 | break
132 | # 从缓存中读取音频数据
133 | record_stream = "".join(self.cache_frames[:2])
134 | wave_data = np.fromstring(record_stream, dtype=np.int16)
135 | wave_data = wave_data * 1.0 / self.max_en
136 | data = wave_data[np.arange(0, self.frame_len)]
137 | speech_data = self.cache_frames.pop(0)
138 | # 获得音频过零率
139 | zcr = ZCR(data)
140 | # 获得音频的短时能量, 平方放大
141 | amp = STE(data) ** 2
142 | # 返回当前音频数据状态
143 | res = self.speech_status(amp, zcr)
144 |
145 | if res == 2:
146 | hasNum += 1
147 |
148 | if hasNum > 10:
149 | is_zero = False
150 | print '+++++++++++++++++++++++++有声音++++++++++++++++++++++++'
151 | break
152 | num = num + 1
153 | # 一段一段进行检测
154 | self.frames_start.append(speech_data)
155 | self.frames_start_num += 1
156 | if self.frames_start_num == self.offsets:
157 | # 开始音频开始的缓存部分
158 | self.frames_start.pop(0)
159 | self.frames_start_num -= 1
160 | if self.end_flag:
161 | # 当音频结束后进行后部缓存
162 | self.frames_end_num += 1
163 | # 下一段语音开始,或达到缓存阀值
164 | if res == 2 or self.frames_end_num == self.offsete:
165 | speech_stream = b"".join(self.frames + self.frames_end)
166 | self.callback_res.append(self.callback(speech_stream, **self.callback_kwargs))
167 |
168 | # 数据环境初始化
169 | # self.clean()
170 | self.end_flag = False
171 |
172 | self.frames = []
173 | self.frames_end_num = 0
174 | self.frames_end = []
175 |
176 | self.frames_end.append(speech_data)
177 | if res == 2:
178 | if self.cur_status in [0, 1]:
179 | # 添加开始偏移数据到数据缓存
180 | self.frames.append(b"".join(self.frames_start))
181 | # 添加当前的语音数据
182 | self.frames.append(speech_data)
183 | if res == 3:
184 | print '检测音频结束'
185 | self.frames.append(speech_data)
186 | # 开启音频结束标志
187 | self.end_flag = True
188 |
189 | self.cur_status = res
190 | return is_zero
191 | # return self.callback_res
192 |
193 | def speech_status(self, amp, zcr):
194 | status = 0
195 | # 0= 静音, 1= 可能开始, 2=确定进入语音段
196 | if self.cur_status in [0, 1]:
197 | # 确定进入语音段
198 | if amp > self.amp1:
199 | status = 2
200 | self.silence = 0
201 | self.count += 1
202 | # 可能处于语音段
203 | elif amp > self.amp2 or zcr > self.zcr2:
204 | status = 1
205 | self.count += 1
206 | # 静音状态
207 | else:
208 | status = 0
209 | self.count = 0
210 | self.count = 0
211 | # 2 = 语音段
212 | elif self.cur_status == 2:
213 | # 保持在语音段
214 | if amp > self.amp2 or zcr > self.zcr2:
215 | self.count += 1
216 | status = 2
217 | # 语音将结束
218 | else:
219 | # 静音还不够长,尚未结束
220 | self.silence += 1
221 | if self.silence < self.maxsilence:
222 | self.count += 1
223 | status = 2
224 | # 语音长度太短认为是噪声
225 | elif self.count < self.minlen:
226 | status = 0
227 | self.silence = 0
228 | self.count = 0
229 | # 语音结束
230 | else:
231 | status = 3
232 | self.silence = 0
233 | self.count = 0
234 | return status
235 |
236 |
237 | def read_file_data(filename):
238 | """
239 | 输入:需要读取的文件名
240 | 返回:(声道,量化位数,采样率,数据)
241 | """
242 | read_file = wave.open(filename, "r")
243 | params = read_file.getparams()
244 | nchannels, sampwidth, framerate, nframes = params[:4]
245 | data = read_file.readframes(nframes)
246 | return nchannels, sampwidth, framerate, data
247 |
248 | class FileParser(Vad):
249 | def __init__(self):
250 | self.block_size = 256
251 | Vad.__init__(self)
252 | def read_file(self, filename):
253 | if not os.path.isfile(filename):
254 | print "文件%s不存在" % filename
255 | return FAIL
256 | datas = read_file_data(filename)[-1]
257 | self.add(datas, False)
258 |
259 | if __name__ == "__main__":
260 | stream_test = FileParser()
261 |
262 | filename = '20180723021835_10.3.10.194.wav'
263 | result = stream_test.read_file(filename)
264 | if result != FAIL:
265 | print stream_test.run(0)
266 | if not stream_test.run(0):
267 | print "有声音"
268 |
--------------------------------------------------------------------------------
/deploy_demo/assert_zero.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/deploy_demo/assert_zero.pyc
--------------------------------------------------------------------------------
/deploy_demo/demo_client.py:
--------------------------------------------------------------------------------
1 | """Client-end for the ASR demo."""
2 | from pynput import keyboard
3 | import struct
4 | import socket
5 | import sys
6 | import argparse
7 | import pyaudio
8 |
9 | parser = argparse.ArgumentParser(description=__doc__)
10 | parser.add_argument(
11 | "--host_ip",
12 | default="localhost",
13 | type=str,
14 | help="Server IP address. (default: %(default)s)")
15 | parser.add_argument(
16 | "--host_port",
17 | default=8086,
18 | type=int,
19 | help="Server Port. (default: %(default)s)")
20 | args = parser.parse_args()
21 |
22 | is_recording = False
23 | enable_trigger_record = True
24 |
25 |
26 | def on_press(key):
27 | """On-press keyboard callback function."""
28 | global is_recording, enable_trigger_record
29 | if key == keyboard.Key.space:
30 | if (not is_recording) and enable_trigger_record:
31 | sys.stdout.write("Start Recording ... ")
32 | sys.stdout.flush()
33 | is_recording = True
34 |
35 |
36 | def on_release(key):
37 | """On-release keyboard callback function."""
38 | global is_recording, enable_trigger_record
39 | if key == keyboard.Key.esc:
40 | return False
41 | elif key == keyboard.Key.space:
42 | if is_recording == True:
43 | is_recording = False
44 |
45 |
46 | data_list = []
47 |
48 |
49 | def callback(in_data, frame_count, time_info, status):
50 | """Audio recorder's stream callback function."""
51 | global data_list, is_recording, enable_trigger_record
52 | if is_recording:
53 | data_list.append(in_data)
54 | enable_trigger_record = False
55 | elif len(data_list) > 0:
56 | # Connect to server and send data
57 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
58 | sock.connect((args.host_ip, args.host_port))
59 | sent = ''.join(data_list)
60 | sock.sendall(struct.pack('>i', len(sent)) + sent)
61 | print('Speech[length=%d] Sent.' % len(sent))
62 | # Receive data from the server and shut down
63 | received = sock.recv(1024)
64 | print "Recognition Results: {}".format(received)
65 | sock.close()
66 | data_list = []
67 | enable_trigger_record = True
68 | return (in_data, pyaudio.paContinue)
69 |
70 |
71 | def main():
72 | # prepare audio recorder
73 | p = pyaudio.PyAudio()
74 | stream = p.open(
75 | format=pyaudio.paInt16,
76 | channels=1,
77 | rate=16000,
78 | input=True,
79 | stream_callback=callback)
80 | stream.start_stream()
81 |
82 | # prepare keyboard listener
83 | with keyboard.Listener(
84 | on_press=on_press, on_release=on_release) as listener:
85 | listener.join()
86 |
87 | # close up
88 | stream.stop_stream()
89 | stream.close()
90 | p.terminate()
91 |
92 |
93 | if __name__ == "__main__":
94 | main()
95 |
--------------------------------------------------------------------------------
/deploy_demo/demo_server.py:
--------------------------------------------------------------------------------
1 | """Server-end for the ASR demo."""
2 | import os
3 | import time
4 | import random
5 | import re
6 | import argparse
7 | import functools
8 | from time import gmtime, strftime
9 | import SocketServer
10 | import struct
11 | import wave
12 |
13 | import _init_paths
14 | import assert_zero
15 | from data_utils import process_manifest
16 | from model_utils import init_model
17 | from conf.hyparam import Config
18 | from utils.utility import add_arguments, print_arguments
19 |
20 | parser = argparse.ArgumentParser(description=__doc__)
21 | add_arg = functools.partial(add_arguments, argparser=parser)
22 | conf = Config()
23 | # yapf: disable
24 | add_arg('host_port', int, 8086, "Server's IP port.")
25 | add_arg('beam_size', int, conf.beam_size, "Beam search width.")
26 | add_arg('num_conv_layers', int, 2, "# of convolution layers.")
27 | add_arg('num_brnn_layers', int, conf.n_brnn_layers, "# of recurrent layers.")
28 | add_arg('rnn_layer_size', int, conf.n_cell_brnn, "# of recurrent cells per layer.")
29 | add_arg('alpha', float, conf.alpha, "Coef of LM for beam search.")
30 | add_arg('beta', float, conf.beta, "Coef of WC for beam search.")
31 | add_arg('cutoff_prob', float, conf.cutoff_prob, "Cutoff probability for pruning.")
32 | add_arg('cutoff_top_n', int, conf.cutoff_top_n, "Cutoff number for pruning.")
33 | add_arg('use_gpu', bool, True, "Use GPU or not.")
34 | add_arg('host_ip', str,
35 | 'localhost',
36 | "Server's IP address.")
37 | add_arg('speech_save_dir', str,
38 | 'demo_cache',
39 | "Directory to save demo audios.")
40 | add_arg('warmup_manifest', str,
41 | 'data/aishell/manifest.dev',
42 | "Filepath of manifest to warm up.")
43 | add_arg('mean_std_path', str,
44 | 'data/aishell/mean_std.npz',
45 | "Filepath of normalizer's mean & std.")
46 | add_arg('vocab_path', str,
47 | 'data/aishell/vocab.txt',
48 | "Filepath of vocabulary.")
49 | add_arg('model_path', str,
50 | conf.savedir + conf.savefile,
51 | "If None, the training starts from scratch, "
52 | "otherwise, it resumes from the pre-trained model.")
53 | add_arg('lang_model_path', str,
54 | conf.lang_model_path,
55 | "Filepath for language model.")
56 | add_arg('use lm decoder', bool,
57 | conf.use_lm_decoder,
58 | "Decoding method. Options: ctc_beam_search, ctc_greedy",
59 | choices = ['ctc_beam_search', 'ctc_greedy'])
60 | add_arg('specgram_type', str,
61 | conf.specgram_type,
62 | "Audio feature type. Options: linear, mfcc.",
63 | choices=['linear', 'mfcc'])
64 | # yapf: disable
65 | args = parser.parse_args()
66 |
67 |
68 | class AsrTCPServer(SocketServer.TCPServer):
69 | """The ASR TCP Server."""
70 |
71 | def __init__(self,
72 | server_address,
73 | RequestHandlerClass,
74 | speech_save_dir,
75 | audio_process_handler,
76 | bind_and_activate=True):
77 | self.speech_save_dir = speech_save_dir
78 | self.audio_process_handler = audio_process_handler
79 | SocketServer.TCPServer.__init__(
80 | self, server_address, RequestHandlerClass, bind_and_activate=True)
81 |
82 |
83 | class AsrRequestHandler(SocketServer.BaseRequestHandler):
84 | """The ASR request handler."""
85 |
86 | def handle(self):
87 | # receive data through TCP socket
88 | chunk = self.request.recv(1024)
89 | target_len = struct.unpack('>i', chunk[:4])[0]
90 | data = chunk[4:]
91 | while len(data) < target_len:
92 | chunk = self.request.recv(1024)
93 | data += chunk
94 | # write to file
95 | filename = self._write_to_file(data)
96 |
97 | print("Received utterance[length=%d] from %s, saved to %s." %
98 | (len(data), self.client_address[0], filename))
99 | start_time = time.time()
100 | transcript = self.server.audio_process_handler(filename)
101 | finish_time = time.time()
102 | print("Response Time: %f, Transcript: %s" %
103 | (finish_time - start_time, transcript))
104 | if transcript == None:
105 | transcript = ""
106 | self.request.sendall(transcript)
107 |
108 | def _write_to_file(self, data):
109 | # prepare save dir and filename
110 | if not os.path.exists(self.server.speech_save_dir):
111 | os.mkdir(self.server.speech_save_dir)
112 | timestamp = strftime("%Y%m%d%H%M%S", gmtime())
113 | out_filename = os.path.join(
114 | self.server.speech_save_dir,
115 | timestamp + "_" + self.client_address[0] + ".wav")
116 | # write to wav file
117 | file = wave.open(out_filename, 'wb')
118 | file.setnchannels(1)
119 | file.setsampwidth(2)
120 | file.setframerate(16000)
121 | file.writeframes(data)
122 | file.close()
123 | return out_filename
124 |
125 |
126 | def warm_up_test(audio_process_handler,
127 | manifest_path,
128 | num_test_cases,
129 | random_seed=0):
130 | """Warming-up test."""
131 | manifest = read_manifest(manifest_path)
132 | rng = random.Random(random_seed)
133 | samples = rng.sample(manifest, num_test_cases)
134 | for idx, sample in enumerate(samples):
135 | print("Warm-up Test Case %d: %s", idx, sample['audio_filepath'])
136 | start_time = time.time()
137 | transcript = audio_process_handler(sample['audio_filepath'])
138 | finish_time = time.time()
139 | print("Response Time: %f, Transcript: %s" %
140 | (finish_time - start_time, transcript))
141 |
142 |
143 | def start_server():
144 | """Start the ASR server"""
145 | # prepare data generator
146 | wav_files, text_labels, _ = process_manifest.get_path_trans()
147 | words_size, words, word_num_map = process_manifest.create_dict("data/aishell/vocab.txt")
148 | deepspeech2 = init_model.DeepSpeech2(wav_files, text_labels, words_size, words, word_num_map)
149 | online_model = deepspeech2.init_online_model()
150 | # prepare ASR inference handler
151 | def file_to_transcript(filename):
152 | stream_test = assert_zero.FileParser()
153 | read_file = stream_test.read_file(filename)
154 | if read_file == 1 or stream_test.run(0):
155 | print "recive a empty wav file"
156 | return ""
157 | else:
158 | result_transcript = deepspeech2.predict(re.split('',filename), ["deepspeech2"])
159 | return result_transcript
160 |
161 | # warming up with utterrances sampled from Librispeech
162 | print('-----------------------------------------------------------')
163 | print('Warming up ...')
164 | deepspeech2.test()
165 | print('-----------------------------------------------------------')
166 |
167 | # start the server
168 | server = AsrTCPServer(
169 | server_address=(args.host_ip, args.host_port),
170 | RequestHandlerClass=AsrRequestHandler,
171 | speech_save_dir=args.speech_save_dir,
172 | audio_process_handler=file_to_transcript)
173 | print("ASR Server Started.")
174 | server.serve_forever()
175 |
176 |
177 | def main():
178 | print_arguments(args)
179 | start_server()
180 |
181 |
182 | if __name__ == "__main__":
183 | main()
184 |
--------------------------------------------------------------------------------
/example/aishell/run_data.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # shell script to generate manifests.{train,dev,test} mean_std.npz vocab.txt
4 |
5 | cd ../.. > /dev/null
6 |
7 | # download data, generate manifests
8 | PYTHONPATH=.:$PYTHONPATH python data/aishell/aishell.py \
9 | --manifest_prefix='data/aishell/manifest' \
10 | --target_dir='/media/nlp/23ACE59C56A55BF3/wav_file/aishell/'
11 |
12 | if [ $? -ne 0 ]; then
13 | echo "Prepare Aishell failed. Terminated."
14 | exit 1
15 | fi
16 |
17 | # build vocabulary
18 | python data_utils/build_vocab.py \
19 | --count_threshold=0 \
20 | --vocab_path='data/aishell/vocab.txt' \
21 | --manifest_paths 'data/aishell/manifest.train' 'data/aishell/manifest.dev'
22 |
23 | if [ $? -ne 0 ]; then
24 | echo "Build vocabulary failed. Terminated."
25 | exit 1
26 | fi
27 |
28 | # compute mean and stddev for normalizer
29 | python data_utils/compute_mean_std.py \
30 | --manifest_path='data/aishell/manifest.train' \
31 | --num_samples=2000 \
32 | --specgram_type='linear' \
33 | --output_path='data/aishell/mean_std.npz'
34 |
35 | if [ $? -ne 0 ]; then
36 | echo "Compute mean and stddev failed. Terminated."
37 | exit 1
38 | fi
39 |
40 | echo "Aishell data preparation done."
41 | exit 0
42 |
--------------------------------------------------------------------------------
/img/arc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/img/arc.png
--------------------------------------------------------------------------------
/model_utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/model_utils/__init__.py
--------------------------------------------------------------------------------
/model_utils/__init__.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/model_utils/__init__.pyc
--------------------------------------------------------------------------------
/model_utils/init_model.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding=utf-8
3 | from __future__ import absolute_import
4 | from __future__ import division
5 |
6 | import time
7 | import math
8 | import numpy as np
9 | import tensorflow as tf
10 | from tensorflow.python.ops import ctc_ops
11 |
12 | from data_utils import utils
13 | from conf.hyparam import Config
14 | from model_utils import network
15 | from utils.decoder.model import LM_decoder
16 |
17 | class DeepSpeech2(object):
18 | ''' Class to init model
19 |
20 | :param wav_files: path to wav files
21 | :type wav_files: str
22 | :param text_labels: transcript for wav files
23 | :type text_labels: list
24 | :param words_size: the size of vocab
25 | :type words_size: int
26 | :param words : a list for vocab
27 | :type words: list
28 | :param word_num_map: a map dict from word to num
29 | :type word_num_map: dict
30 | return
31 | '''
32 | def __init__(self, wav_files, text_labels, words_size, words, word_num_map):
33 | self.hyparam = Config()
34 | self.wav_files = wav_files
35 | self.text_labels = text_labels
36 | self.words_size = words_size
37 | self.words = words
38 | self.word_num_map = word_num_map
39 | # mfcc features contains 39 * 2 * 2 + 39 = 195 dims , linear specgram 161 dim which 161 = (8000-0)/50 + 1
40 | self.n_dim = self.hyparam.n_input + 2 * self.hyparam.n_input * self.hyparam.n_context if self.hyparam.specgram_type == 'mfcc' else 161
41 |
42 | def add_placeholders(self):
43 | # input tensor for log filter or MFCC features
44 | self.input_tensor = tf.placeholder( tf.float32,
45 | [None, None, self.n_dim],
46 | name='input')
47 | self.text = tf.sparse_placeholder(tf.int32, name='text')
48 | self.seq_length = tf.placeholder(tf.int32, [None], name='seq_length')
49 | self.keep_dropout = tf.placeholder(tf.float32)
50 |
51 | def deepspeech2(self):
52 | '''
53 | BUild a network with CNN-BRNN-Lookahead CNN -FC.
54 | '''
55 | batch_x = self.input_tensor
56 | seq_length = self.seq_length
57 | n_character = self.words_size + 1
58 | keep_dropout = self.keep_dropout
59 | n_input = self.hyparam.n_input
60 | n_context = self.hyparam.n_context
61 |
62 | batch_x_shape = tf.shape(batch_x)
63 | batch_x = tf.transpose(batch_x, [1, 0, 2])
64 | batch_x = tf.expand_dims(batch_x, -1)
65 | batch_x = tf.reshape(batch_x,
66 | [batch_x_shape[0], -1, self.n_dim, 1] ) # shape (batch_size, ?, n_dim, 1)
67 |
68 | with tf.variable_scope('conv_1'):
69 | # usage: conv2d(batch_x, filter_shape, strides, pool_size, hyparam, use_dropout=False)
70 | # Output is [batch_size, height, width. out_channel]
71 | conv_1 = network.conv2d(batch_x,
72 | [1, n_input / 3, 1, 1], # filter: [height, width, in_channel, out_channel]
73 | [1, 1, n_input/5 , 1], # strides: [1, height, width, 1]
74 | 2, self.hyparam, use_dropout=False) # shape (8, ?, 19, 1)
75 | conv_1 = tf.squeeze(conv_1, [-1])
76 | conv_1 = tf.transpose(conv_1, [1, 0, 2])
77 |
78 | with tf.variable_scope('birnn_1'):
79 | birnn_1 = network.BiRNN(conv_1, seq_length, batch_x_shape, self.hyparam )
80 | with tf.variable_scope('birnn_2'):
81 | birnn_2 = network.BiRNN(birnn_1, seq_length, batch_x_shape, self.hyparam )
82 | with tf.variable_scope('birnn_3'):
83 | birnn_3 = network.BiRNN(birnn_2, seq_length, batch_x_shape, self.hyparam, use_dropout=True)
84 | birnn_3 = tf.reshape(birnn_3, [batch_x_shape[0], -1, 2*self.hyparam.n_cell_brnn])
85 | birnn_3 = tf.expand_dims(birnn_3, -1)
86 | with tf.variable_scope('lcnn_1'):
87 | # Lookahead CNN combines n time-steps in furture
88 | # lcnn_1 = network.lookahead_cnn(birnn_3, [2, 2*self.hyparam.n_cell_brnn, 1, 2*self.hyparam.n_cell_brnn], 2, seq_length, self.hyparam, use_dropout=True)
89 | lcnn_1 = network.conv2d(birnn_3,
90 | [1, n_input, 1, 1],
91 | [1, 1, n_input/5, 1],
92 | 2, self.hyparam, use_dropout=True)
93 | lcnn_1 = tf.squeeze(lcnn_1,[-1])
94 | width_lcnn1 = 14 # use to compute lcnn_1[-1], computed by pool_size * n_input / 5
95 | lcnn_1 = tf.reshape(lcnn_1, [-1, int(math.ceil(2*self.hyparam.n_cell_brnn/width_lcnn1))])
96 |
97 | with tf.variable_scope('fc'):
98 | b_fc = self.variable_on_device('b_fc', [n_character], tf.random_normal_initializer(stddev=self.hyparam.b_stddev))
99 | h_fc = self.variable_on_device('h_fc',
100 | [int(math.ceil(2*self.hyparam.n_cell_brnn/width_lcnn1)), n_character],
101 | tf.random_normal_initializer(stddev=self.hyparam.h_stddev))
102 | layer_fc = tf.add(tf.matmul(lcnn_1, h_fc), b_fc)
103 | # turn it to 3 dim, [n_steps, hyparam.batch_size, n_character]
104 | layer_fc = tf.reshape(layer_fc, [-1, batch_x_shape[0], n_character])
105 |
106 | self.logits = layer_fc
107 |
108 | def loss(self):
109 | """ Define loss
110 | return
111 | """
112 | # ctc loss
113 | with tf.name_scope('loss'):
114 | self.avg_loss = tf.reduce_mean(ctc_ops.ctc_loss(self.text, self.logits, self.seq_length))
115 | tf.summary.scalar('loss',self.avg_loss)
116 | # [optimizer]
117 | with tf.name_scope('train'):
118 | self.optimizer = tf.train.AdamOptimizer(learning_rate=self.hyparam.learning_rate).minimize(self.avg_loss)
119 |
120 | with tf.name_scope("decode"):
121 | self.decoded, log_prob = ctc_ops.ctc_beam_search_decoder(self.logits, self.seq_length, merge_repeated=False)
122 |
123 | with tf.name_scope("ctc_beam_search_decode"):
124 | self.prob = tf.nn.softmax(self.logits, dim=0)
125 | self.prob = tf.transpose(self.prob, [1, 0, 2]) # keep the same dim with decoder {batch_size, time_step, n_character}
126 | self.decoder = LM_decoder(self.hyparam.alpha, self.hyparam.beta, self.hyparam.lang_model_path, self.words)
127 |
128 | with tf.name_scope("accuracy"):
129 | self.distance = tf.edit_distance(tf.cast(self.decoded[0], tf.int32), self.text)
130 | # compute label error rate (accuracy)
131 | self.label_err = tf.reduce_mean(self.distance, name='label_error_rate')
132 | tf.summary.scalar('accuracy', self.label_err)
133 |
134 |
135 | def get_feed_dict(self, dropout=None):
136 | """ Define feed dict
137 |
138 | :param dropout:
139 | :return:
140 | """
141 | feed_dict = {self.input_tensor: self.audio_features,
142 | self.text: self.sparse_labels,
143 | self.seq_length: self.audio_features_len}
144 |
145 | if dropout != None:
146 | feed_dict[self.keep_dropout] = dropout
147 | else:
148 | feed_dict[self.keep_dropout] = self.hyparam.keep_dropout_rate
149 |
150 | return feed_dict
151 |
152 | def init_session(self):
153 | self.savedir = self.hyparam.savedir
154 | self.saver = tf.train.Saver(max_to_keep=1)
155 | gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.7)
156 | self.sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options))
157 | # if no models , init it
158 | self.sess.run(tf.global_variables_initializer())
159 |
160 | ckpt = tf.train.latest_checkpoint(self.savedir)
161 | print "ckpt:", ckpt
162 | self.startepo = 0
163 | if ckpt != None:
164 | self.saver.restore(self.sess, ckpt)
165 | ind = ckpt.rfind("-")
166 | self.startepo = int(ckpt[ind + 1:])
167 | print(self.startepo)
168 | print()
169 |
170 | def add_summary(self):
171 | self.merged = tf.summary.merge_all()
172 | self.writer = tf.summary.FileWriter(self.hyparam.tensorboardfile, self.sess.graph)
173 |
174 | def init_decode(self):
175 | self.prob = tf.nn.softmax(self.logits, dim=0)
176 | self.prob = tf.transpose(self.prob, [1, 0, 2]) # keep the same dim with decoder {batch_size, time_step, n_character}
177 | self.decoder = LM_decoder(self.hyparam.alpha, self.hyparam.beta, self.hyparam.lang_model_path, self.words)
178 |
179 | def lm_decode(self, probality):
180 | result_transcripts = self.decoder.decode_batch_beam_search(
181 | probs_split=probality,
182 | beam_alpha=self.hyparam.alpha,
183 | beam_beta=self.hyparam.beta,
184 | beam_size=self.hyparam.beam_size,
185 | cutoff_prob=self.hyparam.cutoff_prob,
186 | cutoff_top_n=self.hyparam.cutoff_top_n,
187 | vocab_list=self.words,
188 | num_processes=self.hyparam.num_proc_bsearch)
189 | results = "" if result_transcripts == None else result_transcripts
190 | return results[0].encode('utf-8')
191 |
192 | def train(self):
193 | epochs = 120
194 | section = '\n{0:=^40}\n'
195 | print section.format('Start training...')
196 |
197 | train_start = time.time()
198 | for epoch in range(epochs):
199 | epoch_start = time.time()
200 | if epoch < self.startepo:
201 | continue
202 |
203 | print "Current epoch :", epoch, " the total epochs is ", epochs
204 | n_batches_epoch = int(np.ceil(len(self.text_labels) / self.hyparam.batch_size))
205 | print "CUrrent epoch contains batchs: ", n_batches_epoch, " the batch size is :", self.hyparam.batch_size
206 |
207 | train_cost = 0
208 | train_err = 0
209 | next_idx = 0
210 |
211 | for batch in range(n_batches_epoch):
212 | next_idx, self.audio_features, self.audio_features_len, self.sparse_labels, wav_files = utils.next_batch(
213 | next_idx,
214 | self.hyparam.batch_size,
215 | self.hyparam.n_input,
216 | self.hyparam.n_context,
217 | self.text_labels,
218 | self.wav_files,
219 | self.word_num_map,
220 | specgram_type=self.hyparam.specgram_type)
221 |
222 | batch_cost, _ = self.sess.run([self.avg_loss, self.optimizer], feed_dict=self.get_feed_dict())
223 | train_cost += batch_cost
224 |
225 | if (batch + 1) % 70 == 0:
226 | rs = self.sess.run(self.merged, feed_dict=self.get_feed_dict())
227 | self.writer.add_summary(rs, batch)
228 |
229 | print 'Current batch :', batch, ' Loss: ', train_cost / (batch + 1)
230 |
231 | d, train_err = self.sess.run([self.decoded[0], self.label_err], feed_dict=self.get_feed_dict(dropout=1.0))
232 | dense_decoded = tf.sparse_tensor_to_dense(d, default_value=-1).eval(session=self.sess)
233 | dense_labels = utils.trans_tuple_to_texts_ch(self.sparse_labels, self.words)
234 |
235 | print 'error rate: ', train_err
236 | for orig, decoded_array in zip(dense_labels, dense_decoded):
237 | # convert to strings
238 | decoded_str = utils.trans_array_to_text_ch(decoded_array, self.words)
239 | print 'Orinal inputs: ', orig
240 | print 'Transcript: ', decoded_str
241 | break
242 |
243 | epoch_duration = time.time() - epoch_start
244 | log = 'Epoch {}/{}, Loss: {:.3f}, error rate: {:.3f}, time: {:.2f} sec'
245 | print(log.format(epoch, epochs, train_cost, train_err, epoch_duration))
246 | self.saver.save(self.sess, self.savedir + self.hyparam.savefile, global_step=epoch)
247 |
248 | train_duration = time.time() - train_start
249 | print('Training complete, total duration: {:.2f} min'.format(train_duration / 60))
250 | self.sess.close()
251 |
252 | def test(self):
253 | index = 0
254 | next_idx = 20
255 |
256 | for index in range(10):
257 | next_idx, self.audio_features, self.audio_features_len, self.sparse_labels, wav_files = utils.next_batch(
258 | next_idx,
259 | 1,
260 | self.hyparam.n_input,
261 | self.hyparam.n_context,
262 | self.text_labels,
263 | self.wav_files,
264 | self.word_num_map,
265 | specgram_type=self.hyparam.specgram_type)
266 |
267 | print 'Load wav file: ', wav_files[0]
268 | print 'Recognizing......'
269 |
270 | prob, d, train_ler = self.sess.run([self.prob, self.decoded[0], self.label_err], feed_dict=self.get_feed_dict(dropout=1.0))
271 | dense_labels = utils.trans_tuple_to_texts_ch(self.sparse_labels, self.words)
272 |
273 | if self.hyparam.use_lm_decoder:
274 | result_transcripts = self.lm_decode(prob)
275 | print "Orinal text: ", dense_labels[0]
276 | print "Transcript: ", result_transcripts
277 | else:
278 | dense_decoded = tf.sparse_tensor_to_dense(d, default_value=-1).eval(session=self.sess)
279 | print "dense_decoded", np.shape(dense_decoded), dense_decoded
280 | for orig, decoded_array in zip(dense_labels, dense_decoded):
281 | # turn to string
282 | decoded_str = utils.trans_array_to_text_ch(decoded_array, self.words)
283 | print "Orinal text:", orig
284 | print "Transcript: ", decoded_str
285 | break
286 | # self.sess.close()
287 |
288 | def recon_wav_file(self, wav_files, txt_labels):
289 | self.audio_features, self.audio_features_len, text_vector, text_vector_len = utils.get_audio_mfcc_features(
290 | None,
291 | wav_files,
292 | self.hyparam.n_input,
293 | self.hyparam.n_context,
294 | self.word_num_map,
295 | txt_labels,
296 | specgram_type=self.hyparam.specgram_type)
297 | self.sparse_labels = utils.sparse_tuple_from(text_vector)
298 | prob, d, train_ler = self.sess.run([self.prob, self.decoded[0], self.label_err], feed_dict=self.get_feed_dict(dropout=1.0))
299 | if self.hyparam.use_lm_decoder:
300 | result_transcripts = self.lm_decode(prob)
301 | else:
302 | dense_decoded = tf.sparse_tensor_to_dense(d, default_value=-1).eval(session=self.sess)
303 | result_transcripts = utils.trans_array_to_text_ch(dense_decoded[0], self.words).encode('utf-8')
304 | # print "Transcript: ", result_transcripts
305 | return result_transcripts
306 |
307 | # self.sess.close()
308 |
309 | def build_train(self):
310 | self.add_placeholders()
311 | self.deepspeech2()
312 | self.loss()
313 | self.init_session()
314 | self.add_summary()
315 | self.train()
316 |
317 | def build_test(self):
318 | self.add_placeholders()
319 | self.deepspeech2()
320 | self.loss()
321 | self.init_session()
322 | self.init_decode()
323 | self.test()
324 |
325 | def init_online_model(self):
326 | self.add_placeholders()
327 | self.deepspeech2()
328 | self.loss()
329 | self.init_session()
330 |
331 | def predict(self, wav_files, txt_labels):
332 | transcript = self.recon_wav_file(wav_files, txt_labels)
333 | return transcript
334 |
335 | def close_onlie(self):
336 | self.sess.close()
337 |
338 | def variable_on_device(self, name, shape, initializer):
339 | # with tf.device('/gpu:0'):
340 | var = tf.get_variable(name=name, shape=shape, initializer=initializer)
341 | return var
342 |
343 |
--------------------------------------------------------------------------------
/model_utils/init_model.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/model_utils/init_model.pyc
--------------------------------------------------------------------------------
/model_utils/network.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding=utf-8
3 |
4 | """ Deep Network wraper for BRNN CNN Lookahead CNN """
5 | import tensorflow as tf
6 | import numpy as np
7 |
8 | scale = tf.Variable(tf.ones([1]))
9 | offset = tf.Variable(tf.zeros([1]))
10 | variance_epsilon = 0.001
11 |
12 | def conv2d(batch_x, filter_shape, strides, pool_size, hyparam, use_dropout=False):
13 | ''' Convolution Network wraper for tf.conv2d, contains conv relu act and pooling
14 |
15 | :param batch_x: input tensor with shape [batch_size, time_steps, features_dim, in_channel]
16 | :type batch_x: tensorflow tensor
17 | :param filter_shape: a list to control filtr shape, [height, width, in_channel, out_channel]
18 | :type filter_shape: list
19 | :param strides: a list to control conv strides, [1, height, width, 1]
20 | :type strides: list
21 | :param pool_size: pooling size, default value is 2
22 | :type pool_size: int
23 | :param hyparam: hyparam config class
24 | :type hyparam: class
25 | :param use_dropout: decide wether use dropout
26 | :type use_dropout: bool
27 | return a tensor with shape [batch_size, height, width. out_channel]
28 | '''
29 | if hyparam.use_bn:
30 | batch_mean, batch_var = tf.nn.moments(batch_x, [0, 1, 2])
31 | batch_x = tf.nn.batch_normalization(batch_x, batch_mean, batch_var, offset, scale, variance_epsilon)
32 |
33 | filter = tf.get_variable("filter",
34 | shape=filter_shape,
35 | regularizer=tf.contrib.layers.l2_regularizer(0.0001),
36 | initializer=tf.truncated_normal_initializer(stddev=0.01),
37 | dtype=tf.float32)
38 | conv = tf.nn.conv2d(batch_x, filter, strides, padding='SAME' )
39 | conv = tf.nn.relu(conv)
40 |
41 | conv = tf.nn.max_pool(conv,
42 | ksize=[1, 1, pool_size, 1],
43 | strides=[1, 1, pool_size, 1],
44 | padding='SAME')
45 | if use_dropout:
46 | conv = tf.nn.dropout(conv, 0.5)
47 |
48 | return conv
49 |
50 | # Ongoing...
51 | def lookahead_cnn(inputs, filter_shape, pool_size, seq_length, hyparam, use_dropout=True):
52 | ''' Lookahead CNN combines 2 future inputs.
53 |
54 | :param inputs: input tensor with shape [batch_size, time_steps, features_dim, in_channel]
55 | :type inputs: tensorflow tensor
56 | :param filter_shape: a list to control filtr shape, [height, width, in_channel, out_channel]
57 | :type filter_shape: list
58 | :param strides: a list to control conv strides, [1, height, width, 1]
59 | :type strides: list
60 | :param pool_size: pooling size, default value is 2
61 | :type pool_size: int
62 | :param hyparam: hyparam config class
63 | :type hyparam: class
64 | :param use_dropout: decide wether use dropout
65 | :type use_dropout: bool
66 | return a tensor with shape [batch_size, height, width. out_channel]
67 | '''
68 | # combine 2 ahead inputs
69 |
70 | lcnn_inputs = []
71 | h = tf.get_variable('h', shape=[3, hyparam.n_cell_dim],
72 | initializer=tf.random_normal_initializer(stddev=hyparam.h_stddev))
73 | b = tf.get_variable('b', shape=[hyparam.n_cell_dim],
74 | initializer=tf.random_normal_initializer(stddev=hyparam.b_stddev))
75 | if np.shape(inputs)[1] < 3:
76 | print "Too short to use lookahead_cnn, the inputs should larger than 2"
77 | return inputs
78 | else:
79 | # range only receive a interger, so I don't know how to iter it to add the outputs of time step t, t+1,t+2
80 | for j in range(hyparam.batch_size):
81 | lcnn_inputs = [[inputs[j][i], inputs[j][i+1], inputs[j][i+2]] for i in range(np.shape(inputs)[1]-2) ]
82 | lcnn_inputs.append([inputs[j][-2], inputs[j][-1], np.zeros(np.shape(inputs[j][-1])).tolist()])
83 | lcnn_inputs.append([inputs[j][-1]. np.zeros(np.shape(inputs[j][-1])).tolist(), np.zeros(np.shape(inputs[j][-1])).tolist()])
84 |
85 | lcnn_inputs = tf.add( tf.matmul(lcnn_inputs, h), b)
86 |
87 | # need reshape inputs with [batch_size, height, withdth, 1]
88 |
89 | lcnn_layer = conv2d(lcnn_inputs, filter_shape, pool_size, use_dropout)
90 |
91 | return lcnn_layer
92 |
93 | def BiRNN(inputs, seq_length, batch_x_shape, hyparam, use_dropout=False):
94 | '''BiRNN wraper with time major
95 |
96 | :param inputs: input tensor with time_major, [time_steps, batch_size, features_dim]
97 | :type inputs: tensor
98 | :param seq_length: length of input audio
99 | :type seq_length: tensor
100 | :param batch_x_shape: shape of inputs in dim 0
101 | :type batch_x_shape: tensor
102 | :param hyparam: model config in class hyparam
103 | :type hyparam: class
104 | :param use_dropout: wether use dropout
105 | :type use_dropout: bool
106 | return a tensor with [time_steps, batch_size, features_dim]
107 | '''
108 |
109 | if hyparam.use_bn:
110 | batch_mean, batch_var = tf.nn.moments(inputs, [0, 1, 2])
111 | batch_x = tf.nn.batch_normalization(inputs, batch_mean, batch_var, offset, scale, variance_epsilon)
112 |
113 | # forward
114 | lstm_fw_cell = tf.contrib.rnn.BasicLSTMCell(hyparam.n_cell_brnn, forget_bias=1.0, state_is_tuple=True)
115 | lstm_fw_cell = tf.contrib.rnn.DropoutWrapper(lstm_fw_cell, input_keep_prob=hyparam.keep_dropout_rate)
116 |
117 | # backward
118 | lstm_bw_cell = tf.contrib.rnn.BasicLSTMCell(hyparam.n_cell_brnn, forget_bias=1.0, state_is_tuple=True)
119 | lstm_bw_cell = tf.contrib.rnn.DropoutWrapper(lstm_bw_cell, input_keep_prob=hyparam.keep_dropout_rate)
120 |
121 | outputs, output_states = tf.nn.bidirectional_dynamic_rnn(cell_fw=lstm_fw_cell,
122 | cell_bw=lstm_bw_cell,
123 | inputs=inputs,
124 | dtype=tf.float32,
125 | time_major=True, # if time_major is True, the input shape should be [time_steps, batch_size, ...]
126 | sequence_length=seq_length)
127 |
128 |
129 |
130 | outputs = tf.concat(outputs, 2)
131 | outputs = tf.reshape(outputs, [-1,batch_x_shape[0] , 2 * hyparam.n_cell_brnn])
132 |
133 | if use_dropout :
134 | outputs = tf.nn.dropout(outputs, 0.5)
135 |
136 | return outputs
137 |
--------------------------------------------------------------------------------
/model_utils/network.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/model_utils/network.pyc
--------------------------------------------------------------------------------
/models/lm/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/models/lm/__init__.py
--------------------------------------------------------------------------------
/test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding=utf-8
3 |
4 | import os
5 |
6 | from data_utils import process_manifest
7 | from model_utils import init_model
8 | from conf.hyparam import Config
9 |
10 | conf = Config()
11 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
12 |
13 | wav_files, text_labels, _ = process_manifest.get_path_trans()
14 |
15 | words_size, words, word_num_map = process_manifest.create_dict(conf.vocab_path)
16 |
17 | deepspeech2 = init_model.DeepSpeech2(wav_files, text_labels, words_size, words, word_num_map)
18 |
19 | deepspeech2.build_test()
20 |
--------------------------------------------------------------------------------
/test_build.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding=utf-8
3 |
4 | import os
5 | import re
6 | from data_utils import process_manifest
7 | from model_utils import init_model
8 | from conf.hyparam import Config
9 |
10 | conf = Config()
11 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
12 |
13 | wav_files, text_labels, _ = process_manifest.get_path_trans()
14 |
15 | words_size, words, word_num_map = process_manifest.create_dict(conf.vocab_path)
16 |
17 | deepspeech2 = init_model.DeepSpeech2(wav_files, text_labels, words_size, words, word_num_map)
18 | filename = "demo_cache/20180730080730_10.3.27.97.wav"
19 |
20 | deepspeech2.recon_wav_file_test(re.split("", filename),["你好"])
21 |
--------------------------------------------------------------------------------
/train.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding=utf-8
3 |
4 | """Trainer for DeepSpeech2 model."""
5 | from __future__ import absolute_import
6 | from __future__ import division
7 | from __future__ import print_function
8 |
9 | from data_utils import process_manifest
10 | from model_utils import init_model
11 | from conf.hyparam import Config
12 |
13 | conf = Config()
14 | wav_files, text_labels, _ = process_manifest.get_path_trans()
15 |
16 | words_size, words, word_num_map = process_manifest.create_dict(conf.vocab_path)
17 |
18 |
19 | deepspeech2 = init_model.DeepSpeech2(wav_files, text_labels, words_size, words, word_num_map)
20 |
21 | deepspeech2.build_train()
22 |
--------------------------------------------------------------------------------
/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/utils/__init__.py
--------------------------------------------------------------------------------
/utils/__init__.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/utils/__init__.pyc
--------------------------------------------------------------------------------
/utils/decoder/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/utils/decoder/__init__.py
--------------------------------------------------------------------------------
/utils/decoder/__init__.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/utils/decoder/__init__.pyc
--------------------------------------------------------------------------------
/utils/decoder/model.py:
--------------------------------------------------------------------------------
1 | """Contains DeepSpeech2 model."""
2 | from __future__ import absolute_import
3 | from __future__ import division
4 | from __future__ import print_function
5 |
6 | import sys
7 | import os
8 | import time
9 | import logging
10 | import gzip
11 | import copy
12 | import numpy as np
13 | import inspect
14 | from utils.decoder.swig_wrapper import Scorer
15 | from utils.decoder.swig_wrapper import ctc_greedy_decoder
16 | from utils.decoder.swig_wrapper import ctc_beam_search_decoder_batch
17 |
18 |
19 | class LM_decoder(object):
20 |
21 | def __init__(self, beam_alpha, beam_beta, language_model_path,
22 | vocab_list):
23 | """Initialize the external scorer.
24 |
25 | :param beam_alpha: Parameter associated with language model.
26 | :type beam_alpha: float
27 | :param beam_beta: Parameter associated with word count.
28 | :type beam_beta: float
29 | :param language_model_path: Filepath for language model. If it is
30 | empty, the external scorer will be set to
31 | None, and the decoding method will be pure
32 | beam search without scorer.
33 | :type language_model_path: basestring|None
34 | :param vocab_list: List of tokens in the vocabulary, for decoding.
35 | :type vocab_list: list
36 | """
37 | if language_model_path != '':
38 | print("begin to initialize the external scorer "
39 | "for decoding")
40 | self._ext_scorer = Scorer(beam_alpha, beam_beta,
41 | language_model_path, vocab_list)
42 | lm_char_based = self._ext_scorer.is_character_based()
43 | lm_max_order = self._ext_scorer.get_max_order()
44 | lm_dict_size = self._ext_scorer.get_dict_size()
45 | print("language model: "
46 | "is_character_based = %d," % lm_char_based +
47 | " max_order = %d," % lm_max_order +
48 | " dict_size = %d" % lm_dict_size)
49 | print("end initializing scorer")
50 | else:
51 | self._ext_scorer = None
52 | print("no language model provided, "
53 | "decoding by pure beam search without scorer.")
54 |
55 | def decode_batch_beam_search(self, probs_split, beam_alpha, beam_beta,
56 | beam_size, cutoff_prob, cutoff_top_n,
57 | vocab_list, num_processes):
58 | """Decode by beam search for a batch of probs matrix input.
59 |
60 | :param probs_split: List of 2-D probability matrix, and each consists
61 | of prob vectors for one speech utterancce.
62 | :param probs_split: List of matrix
63 | :param beam_alpha: Parameter associated with language model.
64 | :type beam_alpha: float
65 | :param beam_beta: Parameter associated with word count.
66 | :type beam_beta: float
67 | :param beam_size: Width for Beam search.
68 | :type beam_size: int
69 | :param cutoff_prob: Cutoff probability in pruning,
70 | default 1.0, no pruning.
71 | :type cutoff_prob: float
72 | :param cutoff_top_n: Cutoff number in pruning, only top cutoff_top_n
73 | characters with highest probs in vocabulary will be
74 | used in beam search, default 40.
75 | :type cutoff_top_n: int
76 | :param vocab_list: List of tokens in the vocabulary, for decoding.
77 | :type vocab_list: list
78 | :param num_processes: Number of processes (CPU) for decoder.
79 | :type num_processes: int
80 | :return: List of transcription texts.
81 | :rtype: List of basestring
82 | """
83 | if self._ext_scorer != None:
84 | self._ext_scorer.reset_params(beam_alpha, beam_beta)
85 | # beam search decode
86 | num_processes = min(num_processes, np.shape(probs_split)[0])
87 | beam_search_results = ctc_beam_search_decoder_batch(
88 | probs_split=probs_split,
89 | vocabulary=vocab_list,
90 | beam_size=beam_size,
91 | num_processes=num_processes,
92 | ext_scoring_func=self._ext_scorer,
93 | cutoff_prob=cutoff_prob,
94 | cutoff_top_n=cutoff_top_n)
95 |
96 | results = [result[0][1] for result in beam_search_results]
97 | return results
98 |
99 | def _adapt_feeding_dict(self, feeding_dict):
100 | """Adapt feeding dict according to network struct.
101 |
102 | To remove impacts from padding part, we add scale_sub_region layer and
103 | sub_seq layer. For sub_seq layer, 'sequence_offset' and
104 | 'sequence_length' fields are appended. For each scale_sub_region layer
105 | 'convN_index_range' field is appended.
106 |
107 | :param feeding_dict: Feeding is a map of field name and tuple index
108 | of the data that reader returns.
109 | :type feeding_dict: dict|list
110 | :return: Adapted feeding dict.
111 | :rtype: dict|list
112 | """
113 | adapted_feeding_dict = copy.deepcopy(feeding_dict)
114 | if isinstance(feeding_dict, dict):
115 | adapted_feeding_dict["sequence_offset"] = len(adapted_feeding_dict)
116 | adapted_feeding_dict["sequence_length"] = len(adapted_feeding_dict)
117 | for i in xrange(self._num_conv_layers):
118 | adapted_feeding_dict["conv%d_index_range" %i] = \
119 | len(adapted_feeding_dict)
120 | elif isinstance(feeding_dict, list):
121 | adapted_feeding_dict.append("sequence_offset")
122 | adapted_feeding_dict.append("sequence_length")
123 | for i in xrange(self._num_conv_layers):
124 | adapted_feeding_dict.append("conv%d_index_range" % i)
125 | else:
126 | raise ValueError("Type of feeding_dict is %s, not supported." %
127 | type(feeding_dict))
128 |
129 | return adapted_feeding_dict
130 |
131 | def _adapt_data(self, data):
132 | """Adapt data according to network struct.
133 |
134 | For each convolution layer in the conv_group, to remove impacts from
135 | padding data, we can multiply zero to the padding part of the outputs
136 | of each batch normalization layer. We add a scale_sub_region layer after
137 | each batch normalization layer to reset the padding data.
138 | For rnn layers, to remove impacts from padding data, we can truncate the
139 | padding part before output data feeded into the first rnn layer. We use
140 | sub_seq layer to achieve this.
141 |
142 | :param data: Data from data_provider.
143 | :type data: list|function
144 | :return: Adapted data.
145 | :rtype: list|function
146 | """
147 |
148 | def adapt_instance(instance):
149 | if len(instance) < 2 or len(instance) > 3:
150 | raise ValueError("Size of instance should be 2 or 3.")
151 | padded_audio = instance[0]
152 | text = instance[1]
153 | # no padding part
154 | if len(instance) == 2:
155 | audio_len = padded_audio.shape[1]
156 | else:
157 | audio_len = instance[2]
158 | adapted_instance = [padded_audio, text]
159 | # Stride size for conv0 is (3, 2)
160 | # Stride size for conv1 to convN is (1, 2)
161 | # Same as the network, hard-coded here
162 | padded_conv0_h = (padded_audio.shape[0] - 1) // 2 + 1
163 | padded_conv0_w = (padded_audio.shape[1] - 1) // 3 + 1
164 | valid_w = (audio_len - 1) // 3 + 1
165 | adapted_instance += [
166 | [0], # sequence offset, always 0
167 | [valid_w], # valid sequence length
168 | # Index ranges for channel, height and width
169 | # Please refer scale_sub_region layer to see details
170 | [1, 32, 1, padded_conv0_h, valid_w + 1, padded_conv0_w]
171 | ]
172 | pre_padded_h = padded_conv0_h
173 | for i in xrange(self._num_conv_layers - 1):
174 | padded_h = (pre_padded_h - 1) // 2 + 1
175 | pre_padded_h = padded_h
176 | adapted_instance += [
177 | [1, 32, 1, padded_h, valid_w + 1, padded_conv0_w]
178 | ]
179 | return adapted_instance
180 |
181 | if isinstance(data, list):
182 | return map(adapt_instance, data)
183 | elif inspect.isgeneratorfunction(data):
184 |
185 | def adapted_reader():
186 | for instance in data():
187 | yield map(adapt_instance, instance)
188 |
189 | return adapted_reader
190 | else:
191 | raise ValueError("Type of data is %s, not supported." % type(data))
192 |
193 | def _create_parameters(self, model_path=None):
194 | """Load or create model parameters."""
195 | if model_path is None:
196 | self._parameters = paddle.parameters.create(self._loss)
197 | else:
198 | self._parameters = paddle.parameters.Parameters.from_tar(
199 | gzip.open(model_path))
200 |
201 | def _create_network(self, vocab_size, num_conv_layers, num_rnn_layers,
202 | rnn_layer_size, use_gru, share_rnn_weights):
203 | """Create data layers and model network."""
204 | # paddle.data_type.dense_array is used for variable batch input.
205 | # The size 161 * 161 is only an placeholder value and the real shape
206 | # of input batch data will be induced during training.
207 | audio_data = paddle.layer.data(
208 | name="audio_spectrogram",
209 | type=paddle.data_type.dense_array(161 * 161))
210 | text_data = paddle.layer.data(
211 | name="transcript_text",
212 | type=paddle.data_type.integer_value_sequence(vocab_size))
213 | seq_offset_data = paddle.layer.data(
214 | name='sequence_offset',
215 | type=paddle.data_type.integer_value_sequence(1))
216 | seq_len_data = paddle.layer.data(
217 | name='sequence_length',
218 | type=paddle.data_type.integer_value_sequence(1))
219 | index_range_datas = []
220 | for i in xrange(num_rnn_layers):
221 | index_range_datas.append(
222 | paddle.layer.data(
223 | name='conv%d_index_range' % i,
224 | type=paddle.data_type.dense_vector(6)))
225 |
226 | self._log_probs, self._loss = deep_speech_v2_network(
227 | audio_data=audio_data,
228 | text_data=text_data,
229 | seq_offset_data=seq_offset_data,
230 | seq_len_data=seq_len_data,
231 | index_range_datas=index_range_datas,
232 | dict_size=vocab_size,
233 | num_conv_layers=num_conv_layers,
234 | num_rnn_layers=num_rnn_layers,
235 | rnn_size=rnn_layer_size,
236 | use_gru=use_gru,
237 | share_rnn_weights=share_rnn_weights)
238 |
--------------------------------------------------------------------------------
/utils/decoder/model.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/utils/decoder/model.pyc
--------------------------------------------------------------------------------
/utils/decoder/swig_wrapper.py:
--------------------------------------------------------------------------------
1 | """Wrapper for various CTC decoders in SWIG."""
2 | from __future__ import absolute_import
3 | from __future__ import division
4 | from __future__ import print_function
5 |
6 | import swig_decoders
7 |
8 |
9 | class Scorer(swig_decoders.Scorer):
10 | """Wrapper for Scorer.
11 |
12 | :param alpha: Parameter associated with language model. Don't use
13 | language model when alpha = 0.
14 | :type alpha: float
15 | :param beta: Parameter associated with word count. Don't use word
16 | count when beta = 0.
17 | :type beta: float
18 | :model_path: Path to load language model.
19 | :type model_path: basestring
20 | """
21 |
22 | def __init__(self, alpha, beta, model_path, vocabulary):
23 | swig_decoders.Scorer.__init__(self, alpha, beta, model_path, vocabulary)
24 |
25 |
26 | def ctc_greedy_decoder(probs_seq, vocabulary):
27 | """Wrapper for ctc best path decoder in swig.
28 |
29 | :param probs_seq: 2-D list of probability distributions over each time
30 | step, with each element being a list of normalized
31 | probabilities over vocabulary and blank.
32 | :type probs_seq: 2-D list
33 | :param vocabulary: Vocabulary list.
34 | :type vocabulary: list
35 | :return: Decoding result string.
36 | :rtype: basestring
37 | """
38 | result = swig_decoders.ctc_greedy_decoder(probs_seq.tolist(), vocabulary)
39 | return result.decode('utf-8')
40 |
41 |
42 | def ctc_beam_search_decoder(probs_seq,
43 | vocabulary,
44 | beam_size,
45 | cutoff_prob=1.0,
46 | cutoff_top_n=40,
47 | ext_scoring_func=None):
48 | """Wrapper for the CTC Beam Search Decoder.
49 |
50 | :param probs_seq: 2-D list of probability distributions over each time
51 | step, with each element being a list of normalized
52 | probabilities over vocabulary and blank.
53 | :type probs_seq: 2-D list
54 | :param vocabulary: Vocabulary list.
55 | :type vocabulary: list
56 | :param beam_size: Width for beam search.
57 | :type beam_size: int
58 | :param cutoff_prob: Cutoff probability in pruning,
59 | default 1.0, no pruning.
60 | :type cutoff_prob: float
61 | :param cutoff_top_n: Cutoff number in pruning, only top cutoff_top_n
62 | characters with highest probs in vocabulary will be
63 | used in beam search, default 40.
64 | :type cutoff_top_n: int
65 | :param ext_scoring_func: External scoring function for
66 | partially decoded sentence, e.g. word count
67 | or language model.
68 | :type external_scoring_func: callable
69 | :return: List of tuples of log probability and sentence as decoding
70 | results, in descending order of the probability.
71 | :rtype: list
72 | """
73 | beam_results = swig_decoders.ctc_beam_search_decoder(
74 | probs_seq.tolist(), vocabulary, beam_size, cutoff_prob, cutoff_top_n,
75 | ext_scoring_func)
76 | beam_results = [(res[0], res[1].decode('utf-8')) for res in beam_results]
77 | return beam_results
78 |
79 |
80 | def ctc_beam_search_decoder_batch(probs_split,
81 | vocabulary,
82 | beam_size,
83 | num_processes,
84 | cutoff_prob=1.0,
85 | cutoff_top_n=40,
86 | ext_scoring_func=None):
87 | """Wrapper for the batched CTC beam search decoder.
88 |
89 | :param probs_seq: 3-D list with each element as an instance of 2-D list
90 | of probabilities used by ctc_beam_search_decoder().
91 | :type probs_seq: 3-D list
92 | :param vocabulary: Vocabulary list.
93 | :type vocabulary: list
94 | :param beam_size: Width for beam search.
95 | :type beam_size: int
96 | :param num_processes: Number of parallel processes.
97 | :type num_processes: int
98 | :param cutoff_prob: Cutoff probability in vocabulary pruning,
99 | default 1.0, no pruning.
100 | :type cutoff_prob: float
101 | :param cutoff_top_n: Cutoff number in pruning, only top cutoff_top_n
102 | characters with highest probs in vocabulary will be
103 | used in beam search, default 40.
104 | :type cutoff_top_n: int
105 | :param num_processes: Number of parallel processes.
106 | :type num_processes: int
107 | :param ext_scoring_func: External scoring function for
108 | partially decoded sentence, e.g. word count
109 | or language model.
110 | :type external_scoring_function: callable
111 | :return: List of tuples of log probability and sentence as decoding
112 | results, in descending order of the probability.
113 | :rtype: list
114 | """
115 | probs_split = [probs_seq.tolist() for probs_seq in probs_split]
116 |
117 | batch_beam_results = swig_decoders.ctc_beam_search_decoder_batch(
118 | probs_split, vocabulary, beam_size, num_processes, cutoff_prob,
119 | cutoff_top_n, ext_scoring_func)
120 | batch_beam_results = [
121 | [(res[0], res[1].decode("utf-8")) for res in beam_results]
122 | for beam_results in batch_beam_results
123 | ]
124 | return batch_beam_results
125 |
--------------------------------------------------------------------------------
/utils/decoder/swig_wrapper.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/utils/decoder/swig_wrapper.pyc
--------------------------------------------------------------------------------
/utils/utility.py:
--------------------------------------------------------------------------------
1 | """Contains common utility functions."""
2 | from __future__ import absolute_import
3 | from __future__ import division
4 | from __future__ import print_function
5 |
6 | ''' Help to show args '''
7 | import distutils.util
8 |
9 | def print_arguments(args):
10 | """Print argparse's arguments.
11 |
12 | Usage:
13 |
14 | .. code-block:: python
15 |
16 | parser = argparse.ArgumentParser()
17 | parser.add_argument("name", default="Jonh", type=str, help="User name.")
18 | args = parser.parse_args()
19 | print_arguments(args)
20 |
21 | :param args: Input argparse.Namespace for printing.
22 | :type args: argparse.Namespace
23 | """
24 | print("----------- Configuration Arguments -----------")
25 | for arg, value in sorted(vars(args).iteritems()):
26 | print("%s: %s" % (arg, value))
27 | print("------------------------------------------------")
28 |
29 |
30 | def add_arguments(argname, type, default, help, argparser, **kwargs):
31 | """Add argparse's argument.
32 |
33 | Usage:
34 |
35 | .. code-block:: python
36 |
37 | parser = argparse.ArgumentParser()
38 | add_argument("name", str, "Jonh", "User name.", parser)
39 | args = parser.parse_args()
40 | """
41 | type = distutils.util.strtobool if type == bool else type
42 | argparser.add_argument(
43 | "--" + argname,
44 | default=default,
45 | type=type,
46 | help=help + ' Default: %(default)s.',
47 | **kwargs)
48 |
--------------------------------------------------------------------------------
/utils/utility.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pelhans/ZASR_tensorflow/f7851a9ecab10a75dad22f5c013c7716c0407497/utils/utility.pyc
--------------------------------------------------------------------------------