提交 d05ae8ee 编写于 作者: H Hui Zhang

Merge branch 'develop' into align

此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -272,8 +272,8 @@ class DeepSpeech2Tester(DeepSpeech2Trainer):
infer_model,
input_spec=[
paddle.static.InputSpec(
shape=[None, feat_dim, None],
dtype='float32'), # audio, [B,D,T]
shape=[None, None, feat_dim],
dtype='float32'), # audio, [B,T,D]
paddle.static.InputSpec(shape=[None],
dtype='int64'), # audio_length, [B]
])
......
......@@ -15,7 +15,7 @@ from paddle import nn
from paddle.nn import functional as F
from deepspeech.modules.activation import brelu
from deepspeech.modules.mask import sequence_mask
from deepspeech.modules.mask import make_non_pad_mask
from deepspeech.utils.log import Log
logger = Log(__name__).getlog()
......@@ -111,8 +111,10 @@ class ConvBn(nn.Layer):
) // self.stride[1] + 1
# reset padding part to 0
masks = sequence_mask(x_len) #[B, T]
masks = make_non_pad_mask(x_len) #[B, T]
masks = masks.unsqueeze(1).unsqueeze(1) # [B, 1, 1, T]
# TODO(Hui Zhang): not support bool multiply
masks = masks.type_as(x)
x = x.multiply(masks)
return x, x_len
......
......@@ -18,40 +18,12 @@ from deepspeech.utils.log import Log
logger = Log(__name__).getlog()
__all__ = [
'sequence_mask', "make_pad_mask", "make_non_pad_mask", "subsequent_mask",
"make_pad_mask", "make_non_pad_mask", "subsequent_mask",
"subsequent_chunk_mask", "add_optional_chunk_mask", "mask_finished_scores",
"mask_finished_preds"
]
def sequence_mask(x_len, max_len=None, dtype='float32'):
"""batch sequence mask.
Args:
x_len ([paddle.Tensor]): xs lenght, [B]
max_len ([type], optional): max sequence length. Defaults to None.
dtype (str, optional): mask data type. Defaults to 'float32'.
Returns:
paddle.Tensor: [B, Tmax]
Examples:
>>> sequence_mask([2, 4])
[[1., 1., 0., 0.],
[1., 1., 1., 1.]]
"""
# (TODO: Hui Zhang): jit not support Tenosr.dim() and Tensor.ndim
# assert x_len.dim() == 1, (x_len.dim(), x_len)
max_len = max_len or x_len.max()
x_len = paddle.unsqueeze(x_len, -1)
row_vector = paddle.arange(max_len)
# TODO(Hui Zhang): fix this bug
#mask = row_vector < x_len
mask = row_vector > x_len # a bug, broadcast 的时候出错了
mask = paddle.cast(mask, dtype)
return mask
def make_pad_mask(lengths: paddle.Tensor) -> paddle.Tensor:
"""Make mask tensor containing indices of padded part.
See description of make_non_pad_mask.
......@@ -66,7 +38,8 @@ def make_pad_mask(lengths: paddle.Tensor) -> paddle.Tensor:
[0, 0, 0, 1, 1],
[0, 0, 1, 1, 1]]
"""
assert lengths.dim() == 1
# (TODO: Hui Zhang): jit not support Tenosr.dim() and Tensor.ndim
# assert lengths.dim() == 1
batch_size = int(lengths.shape[0])
max_len = int(lengths.max())
seq_range = paddle.arange(0, max_len, dtype=paddle.int64)
......
......@@ -19,7 +19,7 @@ from paddle.nn import functional as F
from paddle.nn import initializer as I
from deepspeech.modules.activation import brelu
from deepspeech.modules.mask import sequence_mask
from deepspeech.modules.mask import make_non_pad_mask
from deepspeech.utils.log import Log
logger = Log(__name__).getlog()
......@@ -306,7 +306,9 @@ class RNNStack(nn.Layer):
"""
for i, rnn in enumerate(self.rnn_stacks):
x, x_len = rnn(x, x_len)
masks = sequence_mask(x_len) #[B, T]
masks = make_non_pad_mask(x_len) #[B, T]
masks = masks.unsqueeze(-1) # [B, T, 1]
# TODO(Hui Zhang): not support bool multiply
masks = masks.type_as(x)
x = x.multiply(masks)
return x, x_len
# ASR Text Backend
1. [Text Segmentation](text_front_end#text segmentation)
2. Text Corrector
3. Add Punctuation
4. Text Filter
## Text Corrector
* [pycorrector](https://github.com/shibing624/pycorrector)
本项目重点解决其中的谐音、混淆音、形似字错误、中文拼音全拼、语法错误带来的纠错任务。PS:[网友源码解读](https://zhuanlan.zhihu.com/p/138981644)
* DeepCorrection [1](https://praneethbedapudi.medium.com/deepcorrection-1-sentence-segmentation-of-unpunctuated-text-a1dbc0db4e98) [2](https://praneethbedapudi.medium.com/deepcorrection2-automatic-punctuation-restoration-ac4a837d92d9) [3](https://praneethbedapudi.medium.com/deepcorrection-3-spell-correction-and-simple-grammar-correction-d033a52bc11d) [4](https://praneethbedapudi.medium.com/deepsegment-2-0-multilingual-text-segmentation-with-vector-alignment-fd76ce62194f)
### Question
中文文本纠错任务,常见错误类型包括:
- 谐音字词,如 配副眼睛-配副眼镜
- 混淆音字词,如 流浪织女-牛郎织女
- 字词顺序颠倒,如 伍迪艾伦-艾伦伍迪
- 字词补全,如 爱有天意-假如爱有天意
- 形似字错误,如 高梁-高粱
- 中文拼音全拼,如 xingfu-幸福
- 中文拼音缩写,如 sz-深圳
- 语法错误,如 想象难以-难以想象
当然,针对不同业务场景,这些问题并不一定全部存在。
比如输入法中需要处理前四种,搜索引擎需要处理所有类型,语音识别后文本纠错只需要处理前两种, 其中'形似字错误'主要针对五笔或者笔画手写输入等。
### Solution
#### 规则的解决思路
1. 中文纠错分为两步走,第一步是错误检测,第二步是错误纠正;
2. 错误检测部分先通过结巴中文分词器切词,由于句子中含有错别字,所以切词结果往往会有切分错误的情况,这样从字粒度和词粒度两方面检测错误, 整合这两种粒度的疑似错误结果,形成疑似错误位置候选集;
3. 错误纠正部分,是遍历所有的疑似错误位置,并使用音似、形似词典替换错误位置的词,然后通过语言模型计算句子困惑度,对所有候选集结果比较并排序,得到最优纠正词。
#### 深度模型的解决思路
1. 端到端的深度模型可以避免人工提取特征,减少人工工作量,RNN序列模型对文本任务拟合能力强,rnn_attention在英文文本纠错比赛中取得第一名成绩,证明应用效果不错;
2. CRF会计算全局最优输出节点的条件概率,对句子中特定错误类型的检测,会根据整句话判定该错误,阿里参赛2016中文语法纠错任务并取得第一名,证明应用效果不错;
3. Seq2Seq模型是使用Encoder-Decoder结构解决序列转换问题,目前在序列转换任务中(如机器翻译、对话生成、文本摘要、图像描述)使用最广泛、效果最好的模型之一;
4. BERT/ELECTRA/ERNIE/MacBERT等预训练模型强大的语言表征能力,对NLP界带来翻天覆地的改变,海量的训练数据拟合的语言模型效果无与伦比,基于其MASK掩码的特征,可以简单改造预训练模型用于纠错,加上fine-tune,效果轻松达到最优。
### 规则检测方法
- kenlm:kenlm统计语言模型工具,规则方法,语言模型纠错,利用混淆集,扩展性强
#### 错误检测
- 字粒度:语言模型困惑度(ppl)检测某字的似然概率值低于句子文本平均值,则判定该字是疑似错别字的概率大。
- 词粒度:切词后不在词典中的词是疑似错词的概率大。
#### 错误纠正
- 通过错误检测定位所有疑似错误后,取所有疑似错字的音似、形似候选词,
- 使用候选词替换,基于语言模型得到类似翻译模型的候选排序结果,得到最优纠正词。
#### 思考
1. 现在的处理手段,在词粒度的错误召回还不错,但错误纠正的准确率还有待提高,更多优质的纠错集及纠错词库会有提升。
2. 另外,现在的文本错误不再局限于字词粒度上的拼写错误,需要提高中文语法错误检测(CGED, Chinese Grammar Error Diagnosis)及纠正能力。
### Reference
* https://github.com/shibing624/pycorrector
* [基于文法模型的中文纠错系统](https://blog.csdn.net/mingzai624/article/details/82390382)
* [Norvig’s spelling corrector](http://norvig.com/spell-correct.html)
* [Chinese Spelling Error Detection and Correction Based on Language Model, Pronunciation, and Shape[Yu, 2013]](http://www.aclweb.org/anthology/W/W14/W14-6835.pdf)
* [Chinese Spelling Checker Based on Statistical Machine Translation[Chiu, 2013]](http://www.aclweb.org/anthology/O/O13/O13-1005.pdf)
* [Chinese Word Spelling Correction Based on Rule Induction[yeh, 2014]](http://aclweb.org/anthology/W14-6822)
* [Neural Language Correction with Character-Based Attention[Ziang Xie, 2016]](https://arxiv.org/pdf/1603.09727.pdf)
* [Chinese Spelling Check System Based on Tri-gram Model[Qiang Huang, 2014]](http://www.anthology.aclweb.org/W/W14/W14-6827.pdf)
* [Neural Abstractive Text Summarization with Sequence-to-Sequence Models[Tian Shi, 2018]](https://arxiv.org/abs/1812.02303)
* [基于深度学习的中文文本自动校对研究与实现[杨宗霖, 2019]](https://github.com/shibing624/pycorrector/blob/master/docs/基于深度学习的中文文本自动校对研究与实现.pdf)
* [A Sequence to Sequence Learning for Chinese Grammatical Error Correction[Hongkai Ren, 2018]](https://link.springer.com/chapter/10.1007/978-3-319-99501-4_36)
* [ELECTRA: Pre-training Text Encoders as Discriminators Rather Than Generators](https://openreview.net/pdf?id=r1xMH1BtvB)
* [Revisiting Pre-trained Models for Chinese Natural Language Processing](https://arxiv.org/abs/2004.13922)
## Add Punctuation
* DeepCorrection [1](https://praneethbedapudi.medium.com/deepcorrection-1-sentence-segmentation-of-unpunctuated-text-a1dbc0db4e98) [2](https://praneethbedapudi.medium.com/deepcorrection2-automatic-punctuation-restoration-ac4a837d92d9) [3](https://praneethbedapudi.medium.com/deepcorrection-3-spell-correction-and-simple-grammar-correction-d033a52bc11d) [4](https://praneethbedapudi.medium.com/deepsegment-2-0-multilingual-text-segmentation-with-vector-alignment-fd76ce62194f)
## Text Filter
* 敏感词(黄暴、涉政、违法违禁等)
# Speech Synthesis
* [爱丁堡大学公开课](http://speech.zone/courses/speech-synthesis)
* ### 推荐书籍
1. Daniel Jurafsky and James H. Martin, Speech and language processing: An introduction to natural language processing, computational linguistics, and speech recognition. 这本书之前在学习语音识别的时候也经常翻阅。 推荐阅读章节: Ch 7 & Ch 8 (都读过啦~)
2. Xuedong Huang, Alex Aceoro, Hsiao-Wuen Hon, Spoken Language Processing: A guide to theory, algorithm, and system development, Prentice Hall, 2011 这本书的三位作者都是大佬,本书推荐阅读 Ch2, Ch5, Ch6, Part IV: Text-to-Speech Systems. 学习一下基础知识点,如信号处理等
3. Paul Taylor, Text-to-Speech Synthesis, Cambridege University Press, 2009. 比较系统地讲述了神经网络之前的语音合成系统。
### 语音合成
现代语音合成主要包含文本分析和语音合成
#### 文本分析
文本分析主要分为
- **断句** : 怎么判断一句句子结束了,单纯用句号来切分并不靠谱,比如 ‘B.C.’, ‘Dr.J.M.’,’。。。’
- **文本归一化** : 根据上下文消除一些词的读法,常见有数字的读法,”In 1950, he went to” -> “nineteen fifty”, “There are 1950 sheep.” => “one thousand and fifty”, “The code number is 1950” -> “one nine five zero”.
- **分词** : 将句子分成一个个的词,对于中文这种没有空格作为天然分隔符的语言是需要分词单元的。
- **词性分析** : 将分好的词中的每个词进行标注,”动词,名词,形容词,…”
- **注音** : 有些词的读音在不同上下文中发音是不一样的,比如 ‘live’ -> /l ih v/ or /l ay v/ 中文中也有多音字的现象,所以需要进行标注。
- **韵律分析** : 声调,重读,韵律边界
#### 语音合成方法
**波形拼接** : 将各种语音单元拼接起来,需要考虑目标代价(目标语音单元和候选的语音单元匹配度)和连接代价(相邻语音单元之间的流畅度)
**基于轨迹指导的拼接合成**
**统计参数合成** : 帧级建模包括时长模型(音素序列->帧级文本特征)和声学模型(帧级文本特征->帧级语音输出)。主要方法是基于HMM 的 SPSS (Statistical Parametric Speech Synthesis), 可以用的工具包 HTS。
**神经网络合成方法** : 目前许多商用场景下已经部署了基于神经网络的语音合成模型。目前基于神经网络的方法还不是纯端到端的,分为两个部分,输入文本类信息(音素,时长等)经过神经网络得到输出特征(LF0, UV, 谱特征, bap), 接着将这些特征放到声码器(vocoder) 中得到对应的语音波形。主流方法是 Tactron, Tactron2, 注意力机制,Transformer。正在朝着基于序列到序列的语音合成,纯端到端的语音合成方向发展。
**声码器**的总结如下:
| **模型类型** | **模型** | **合成语音质量** | **效率** |
| ------------ | ----------------- | ---------------- | ---------- |
| AR | WaveNet | 非常好 | 非常差 |
| AR | WaveRNN | 非常好 | 中等 |
| AR | Multiband WaveRNN | 非常好 | 中等 |
| AR | LPCNET | 非常好 | 挺好的 |
| Non-AR | Parallel WaveNet | 非常好 | 还不错 |
| Non-AR | WaveGlow | 非常好 | 还不错 |
| Non-AR | FlowWaveNet | 非常好 | 还不错 |
| GAN | ParallelWaveGAN | 非常好 | 挺好的 |
| GAN | MelGAN | 挺好的 | 非常好 |
| GAN | MB-MelGAN | 非常好 | 非常非常好 |
从上面表格中可以看到基于神经网络的声码器效果都挺好的,主要需要优化的就是生成的速度。出现了利用GAN的声码器之后,推理速度也极大的提高了。
### 高阶话题
* 基于注意力机制的序列要序列的模型框架稳定性问题: 长句、连读、丢字、漏字、重复
* 小样本学习(few shots & one shot)
* 情感/表现力/可控性(句子内部细粒度控制,风格建模)
* 纯端到端
* 抗噪
* 语音转换
* 歌唱合成
### 语音合成评估
文本分析模块可以有比较客观的指标:precision, recall, fscore 之类的。
生成的语音质量评估方法有:和参考样例之间的距离度量(DTW), 谱包络(MCD), F0轮廓,V/UV Error, 时长 (Duration RMSE)。
主观指标包括 MOS,CMOS, AB Best, MUSHRA。
### 语音合成数据集
数据质量非常重要
中文: 标贝DB-1,女性说话,1万句,10.3小时
英文: VCTK, LJSpeech, LibriSpeech, LibriTTS
### 非端到端的语音合
目前非端到端的语音合成算法有两种,
1)**参数语音合成方法**,其中*声学模型*包括基于隐马尔可夫(HMM)的统计参数语音合成和基于神经网络(NN)的统计参数语音合成,而*声码器*包括基于源-滤波器的声码器和基于NN的声码器
2) **单元拼接语音合成方法** 简单地理解是有一个很大的语音库包含了许多词/音素的发音,用一些方法将各个单元拼接起来。
#### 声学特征
传统声学模型这里的声学特征主要包括 MGC-梅尔生成倒谱, MCEP-梅尔倒谱, LSP-线谱对,这些普参数加上激励参数如基频F0,就是需要拟合的声学特征。而我们的音频通常都是一个个的采样点,谱参数+激励参数是可以还原到音频采样点的。
常用的工具:Straight, World, SPTK, [HTS](http://hts.sp.nitech.ac.jp/), [Pysptk](https://github.com/r9y9/pysptk)
#### 基于HMM的统计参数语音合成
HMM 应用到 TTS 这里和 ASR 还是有些区别的。主要参考的论文是 [An Introduction to HMM-Based Speech Synthesis](https://www.researchgate.net/publication/265398553_An_Introduction_to_HMM-Based_Speech_Synthesis):
#### 基于 NN 的参数语音合成
基于 NN 的参数语音合成主要依赖时长模型和声学模型。
### 风格化和个性化语音合成
风格化和个性化语音合成,难点有三个方面:
- 风格化: 需要合成丰富且可控的语音,包括语速、停顿、重音、情感等。
- 个性化: 要求我们利用多说话人建模技术及说话人自适应技术,在少量录音室或非录音室数据的条件下,为某一新说话人定制语音合成模型。
- 迁移学习: 在只有一种语言的训练数据集下让说话人说另一种语言或者让说话人学习另一说话人的风格。迁移学习使我们能够利用额外的数据进行知识迁移,进而完成一些特定任务。
建模和评估比较困难、数据集标注成本高,标注人员对风格问题容易产生分歧、模型缺乏控制合成语音风格的能力。
## Reference
* https://slyne.github.io/%E5%85%AC%E5%BC%80%E8%AF%BE/2020/09/26/TTS/
* https://slyne.github.io/%E5%85%AC%E5%BC%80%E8%AF%BE/2020/10/25/TTS2/
* https://slyne.github.io/%E5%85%AC%E5%BC%80%E8%AF%BE/2020/12/04/TTS6/
# Aishell-1
## Deepspeech2
| Model | release | Config | Test set | CER |
| --- | --- | --- | --- | --- |
| DeepSpeech2 | 2.1 | conf/deepspeech2.yaml | test | 0.078671 |
| DeepSpeech2 | 2.0 | conf/deepspeech2.yaml | test | 0.078977 |
| DeepSpeech2 | 1.8.5 | - | test | 0.080447 |
| Model | release | Config | Test set | Loss | CER |
| --- | --- | --- | --- | --- | --- |
| DeepSpeech2 | 2.1.0 | conf/deepspeech2.yaml | test | 7.299022197723389 | 0.078671 |
| DeepSpeech2 | 2.0.0 | conf/deepspeech2.yaml | test | - | 0.078977 |
| DeepSpeech2 | 1.8.5 | - | test | - | 0.080447 |
#! /usr/bin/env bash
if [ $# != 2 ];then
echo "usage: ${0} ckpt_dir avg_num"
exit -1
fi
ckpt_dir=${1}
average_num=${2}
decode_checkpoint=${ckpt_dir}/avg_${average_num}.pdparams
python3 -u ${MAIN_ROOT}/utils/avg_model.py \
--dst_model ${decode_checkpoint} \
--ckpt_dir ${ckpt_dir} \
--num ${average_num} \
--val_best
if [ $? -ne 0 ]; then
echo "Failed in avg ckpt!"
exit 1
fi
exit 0
\ No newline at end of file
......@@ -24,7 +24,7 @@ data:
n_fft: None
stride_ms: 10.0
window_ms: 25.0
use_dB_normalization: False
use_dB_normalization: True
target_dB: -20
random_seed: 0
keep_transcription_text: False
......@@ -76,7 +76,7 @@ model:
training:
n_epoch: 240
accum_grad: 2
global_grad_clip: 5.0
global_grad_clip: 3.0
optim: adam
optim_conf:
lr: 0.002
......
......@@ -15,6 +15,10 @@ fi
config_path=$1
ckpt_prefix=$2
ckpt_name=$(basename ${ckpt_prefxi})
mkdir -p exp
# download language model
#bash local/download_lm_ch.sh
#if [ $? -ne 0 ]; then
......@@ -25,11 +29,13 @@ ckpt_prefix=$2
for type in attention ctc_greedy_search; do
echo "decoding ${type}"
batch_size=64
output_dir=${ckpt_prefix}
mkdir -p ${output_dir}
python3 -u ${BIN_DIR}/test.py \
--device ${device} \
--nproc 1 \
--config ${config_path} \
--result_file ${ckpt_prefix}.${type}.rsl \
--result_file ${output_dir}/${type}.rsl \
--checkpoint_path ${ckpt_prefix} \
--opts decoding.decoding_method ${type} decoding.batch_size ${batch_size}
......@@ -42,11 +48,13 @@ done
for type in ctc_prefix_beam_search attention_rescoring; do
echo "decoding ${type}"
batch_size=1
output_dir=${ckpt_prefix}
mkdir -p ${output_dir}
python3 -u ${BIN_DIR}/test.py \
--device ${device} \
--nproc 1 \
--config ${config_path} \
--result_file ${ckpt_prefix}.${type}.rsl \
--result_file ${output_dir}/${type}.rsl \
--checkpoint_path ${ckpt_prefix} \
--opts decoding.decoding_method ${type} decoding.batch_size ${batch_size}
......
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# https://github.com/rubber-duck-dragon/rubber-duck-dragon.github.io/blob/master/cc-cedict_parser/parser.py
#A parser for the CC-Cedict. Convert the Chinese-English dictionary into a list of python dictionaries with "traditional","simplified", "pinyin", and "english" keys.
#Make sure that the cedict_ts.u8 file is in the same folder as this file, and that the name matches the file name on line 13.
#Before starting, open the CEDICT text file and delete the copyright information at the top. Otherwise the program will try to parse it and you will get an error message.
#Characters that are commonly used as surnames have two entries in CC-CEDICT. This program will remove the surname entry if there is another entry for the character. If you want to include the surnames, simply delete lines 59 and 60.
#This code was written by Franki Allegra in February 2020.
import json
import sys
# usage: bin ccedict dump.json
with open(sys.argv[1], 'rt') as file:
text = file.read()
lines = text.split('\n')
dict_lines = list(lines)
def parse_line(line):
parsed = {}
if line == '':
dict_lines.remove(line)
return 0
if line.startswith('#'):
return 0
if line.startswith('%'):
return 0
line = line.rstrip('/')
line = line.split('/')
if len(line) <= 1:
return 0
english = line[1]
char_and_pinyin = line[0].split('[')
characters = char_and_pinyin[0]
characters = characters.split()
traditional = characters[0]
simplified = characters[1]
pinyin = char_and_pinyin[1]
pinyin = pinyin.rstrip()
pinyin = pinyin.rstrip("]")
parsed['traditional'] = traditional
parsed['simplified'] = simplified
parsed['pinyin'] = pinyin
parsed['english'] = english
list_of_dicts.append(parsed)
def remove_surnames():
for x in range(len(list_of_dicts) - 1, -1, -1):
if "surname " in list_of_dicts[x]['english']:
if list_of_dicts[x]['traditional'] == list_of_dicts[x + 1][
'traditional']:
list_of_dicts.pop(x)
def main():
#make each line into a dictionary
print("Parsing dictionary . . .")
for line in dict_lines:
parse_line(line)
#remove entries for surnames from the data (optional):
print("Removing Surnames . . .")
remove_surnames()
print("Saving to database (this may take a few minutes) . . .")
with open(sys.argv[2], 'wt') as fout:
for one_dict in list_of_dicts:
json_str = json.dumps(one_dict)
fout.write(json_str + "\n")
print('Done!')
list_of_dicts = []
parsed_dict = main()
export MAIN_ROOT=${PWD}/../../
export PATH=${MAIN_ROOT}:${MAIN_ROOT}/utils:${PATH}
export LC_ALL=C
# Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C
export PYTHONIOENCODING=UTF-8
export PYTHONPATH=${MAIN_ROOT}:${PYTHONPATH}
export LD_LIBRARY_PATH=/usr/local/lib/:${LD_LIBRARY_PATH}
\ No newline at end of file
#!/bin/bash
# CC-CEDICT download: https://www.mdbg.net/chinese/dictionary?page=cc-cedict
# The word dictionary of this website is based on CC-CEDICT.
# CC-CEDICT is a continuation of the CEDICT project started by Paul Denisowski in 1997 with the
# aim to provide a complete downloadable Chinese to English dictionary with pronunciation in pinyin for the Chinese characters.
# This website allows you to easily add new entries or correct existing entries in CC-CEDICT.
# Submitted entries will be checked and processed frequently and released for download in CEDICT format on this page.
set -e
source path.sh
stage=-1
stop_stage=100
source ${MAIN_ROOT}/utils/parse_options.sh || exit -1
cedict_url=https://www.mdbg.net/chinese/export/cedict/cedict_1_0_ts_utf-8_mdbg.zip
cedict=cedict_1_0_ts_utf-8_mdbg.zip
mkdir -p data
if [ $stage -le -1 ] && [ $stop_stage -ge -1 ];then
test -f data/${cedict} || wget -O data/${cedict} ${cedict_url}
pushd data
unzip ${cedict}
popd
fi
mkdir -p exp
if [ $stage -le 0 ] && [ $stop_stage -ge 0 ];then
cp data/cedict_ts.u8 exp/cedict
python3 local/parser.py exp/cedict exp/cedict.json
fi
# Download Baker dataset
Baker dataset has to be downloaded mannually and moved to 'data/', because you will have to pass the CATTCHA from a browswe to download the dataset.
Download URL https://test.data-baker.com/#/data/index/source.
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import re
import jieba
from pypinyin import lazy_pinyin
from pypinyin import Style
def extract_pinyin(source, target, use_jieba=False):
with open(source, 'rt', encoding='utf-8') as fin:
with open(target, 'wt', encoding='utf-8') as fout:
for i, line in enumerate(fin):
if i % 2 == 0:
sentence_id, raw_text = line.strip().split()
raw_text = re.sub(r'#\d', '', raw_text)
if use_jieba:
raw_text = jieba.lcut(raw_text)
syllables = lazy_pinyin(
raw_text,
errors='ignore',
style=Style.TONE3,
neutral_tone_with_five=True)
transcription = ' '.join(syllables)
fout.write(f'{sentence_id} {transcription}\n')
else:
continue
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="extract baker pinyin labels")
parser.add_argument(
"input", type=str, help="source file of baker's prosody label file")
parser.add_argument(
"output", type=str, help="target file to write pinyin lables")
parser.add_argument(
"--use-jieba",
action='store_true',
help="use jieba for word segmentation.")
args = parser.parse_args()
extract_pinyin(args.input, args.output, use_jieba=args.use_jieba)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
def extract_pinyin_lables(source, target):
"""Extract pinyin labels from Baker's prosody labeling."""
with open(source, 'rt', encoding='utf-8') as fin:
with open(target, 'wt', encoding='utf-8') as fout:
for i, line in enumerate(fin):
if i % 2 == 0:
sentence_id, raw_text = line.strip().split()
fout.write(f'{sentence_id} ')
else:
transcription = line.strip()
fout.write(f'{transcription}\n')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="extract baker pinyin labels")
parser.add_argument(
"input", type=str, help="source file of baker's prosody label file")
parser.add_argument(
"output", type=str, help="target file to write pinyin lables")
args = parser.parse_args()
extract_pinyin_lables(args.input, args.output)
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
from typing import List, Union
from pathlib import Path
def erized(syllable: str) -> bool:
"""Whether the syllable contains erhua effect.
Example
--------
huar -> True
guanr -> True
er -> False
"""
# note: for pinyin, len(syllable) >=2 is always true
# if not: there is something wrong in the data
assert len(syllable) >= 2, f"inavlid syllable {syllable}"
return syllable[:2] != "er" and syllable[-2] == 'r'
def ignore_sandhi(reference: List[str], generated: List[str]) -> List[str]:
"""
Given a sequence of syllables from human annotation(reference),
which makes sandhi explici and a sequence of syllables from some
simple g2p program(generated), which does not consider sandhi,
return a the reference sequence while ignore sandhi.
Example
--------
['lao2', 'hu3'], ['lao3', 'hu3'] -> ['lao3', 'hu3']
"""
i = 0
j = 0
# sandhi ignored in the result while other errors are not included
result = []
while i < len(reference):
if erized(reference[i]):
result.append(reference[i])
i += 1
j += 2
elif reference[i][:-1] == generated[i][:-1] and reference[i][
-1] == '2' and generated[i][-1] == '3':
result.append(generated[i])
i += 1
j += 1
else:
result.append(reference[i])
i += 1
j += 1
assert j == len(
generated
), "length of transcriptions mismatch, There may be some characters that are ignored in the generated transcription."
return result
def convert_transcriptions(reference: Union[str, Path], generated: Union[str, Path], output: Union[str, Path]):
with open(reference, 'rt') as f_ref:
with open(generated, 'rt') as f_gen:
with open(output, 'wt') as f_out:
for i, (ref, gen) in enumerate(zip(f_ref, f_gen)):
sentence_id, ref_transcription = ref.strip().split(' ', 1)
_, gen_transcription = gen.strip().split(' ', 1)
try:
result = ignore_sandhi(ref_transcription.split(),
gen_transcription.split())
result = ' '.join(result)
except Exception:
print(
f"sentence_id: {sentence_id} There is some annotation error in the reference or generated transcription. Use the reference."
)
result = ref_transcription
f_out.write(f"{sentence_id} {result}\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="reference transcription but ignore sandhi.")
parser.add_argument(
"--reference",
type=str,
help="path to the reference transcription of baker dataset.")
parser.add_argument(
"--generated", type=str, help="path to the generated transcription.")
parser.add_argument("--output", type=str, help="path to save result.")
args = parser.parse_args()
convert_transcriptions(args.reference, args.generated, args.output)
#!/bin/bash
exp_dir="exp"
data_dir="data"
source ${MAIN_ROOT}/utils/parse_options.sh || exit -1
archive=${data_dir}/"BZNSYP.rar"
if [ ! -f ${archive} ]; then
echo "Baker Dataset not found! Download it first to the data_dir."
exit -1
fi
MD5='c4350563bf7dc298f7dd364b2607be83'
md5_result=$(md5sum ${archive} | awk -F[' '] '{print $1}')
if [ ${md5_result} != ${MD5} ]; then
echo "MD5 mismatch! The Archive has been changed."
exit -1
fi
label_file='ProsodyLabeling/000001-010000.txt'
filename='000001-010000.txt'
unrar e ${archive} ${label_file}
cp ${filename} ${exp_dir}
rm -f ${filename}
if [ ! -f ${exp_dir}/${filename} ];then
echo "File extraction failed!"
exit
fi
exit 0
export MAIN_ROOT=${PWD}/../../
export PATH=${MAIN_ROOT}:${MAIN_ROOT}/utils:${PATH}
export LC_ALL=C
# Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C
export PYTHONIOENCODING=UTF-8
export PYTHONPATH=${MAIN_ROOT}:${PYTHONPATH}
#!/usr/bin/env bash
source path.sh
stage=-1
stop_stage=100
exp_dir=exp
data_dir=data
source ${MAIN_ROOT}/utils/parse_options.sh || exit -1
mkdir -p ${exp_dir}
if [ $stage -le 0 ] && [ $stop_stage -ge 0 ];then
echo "stage 0: Extracting Prosody Labeling"
bash local/prepare_dataset.sh --exp-dir ${exp_dir} --data-dir ${data_dir}
fi
# convert transcription in chinese into pinyin with pypinyin or jieba+pypinyin
filename="000001-010000.txt"
if [ $stage -le 1 ] && [ $stop_stage -ge 1 ]; then
echo "stage 1: Processing transcriptions..."
python3 local/extract_pinyin_label.py ${exp_dir}/${filename} ${exp_dir}/ref.pinyin
python3 local/convert_transcription.py ${exp_dir}/${filename} ${exp_dir}/trans.pinyin
python3 local/convert_transcription.py --use-jieba ${exp_dir}/${filename} ${exp_dir}/trans.jieba.pinyin
fi
echo "done"
exit 0
......@@ -2,7 +2,8 @@
## Deepspeech2
| Model | Config | Test set | WER |
| --- | --- | --- | --- |
| DeepSpeech2 | conf/deepspeech2.yaml | test-clean | 0.073973 |
| DeepSpeech2 | release 1.8.5 | test-clean | 0.074939 |
| Model | release | Config | Test set | Loss | WER |
| --- | --- | --- | --- | --- | --- |
| DeepSpeech2 | 2.1.0 | conf/deepspeech2.yaml | 15.184467315673828 | test-clean | 0.072154 |
| DeepSpeech2 | 2.0.0 | conf/deepspeech2.yaml | - | test-clean | 0.073973 |
| DeepSpeech2 | 1.8.5 | - | test-clean | - | 0.074939 |
......@@ -41,7 +41,7 @@ training:
lr: 1e-3
lr_decay: 0.83
weight_decay: 1e-06
global_grad_clip: 3.0
global_grad_clip: 5.0
log_interval: 100
decoding:
......
#! /usr/bin/env bash
if [ $# != 2 ];then
echo "usage: ${0} ckpt_dir avg_num"
exit -1
fi
ckpt_dir=${1}
average_num=${2}
decode_checkpoint=${ckpt_dir}/avg_${average_num}.pdparams
python3 -u ${MAIN_ROOT}/utils/avg_model.py \
--dst_model ${decode_checkpoint} \
--ckpt_dir ${ckpt_dir} \
--num ${average_num} \
--val_best
if [ $? -ne 0 ]; then
echo "Failed in avg ckpt!"
exit 1
fi
exit 0
\ No newline at end of file
......@@ -4,7 +4,7 @@ source path.sh
stage=0
stop_stage=100
conf_path=conf/transformer.yaml
conf_path=conf/deepspeech2.yaml
avg_num=30
source ${MAIN_ROOT}/utils/parse_options.sh || exit 1;
......
......@@ -14,7 +14,7 @@ data:
min_output_len: 0.0 # tokens
max_output_len: 400.0 # tokens
min_output_input_ratio: 0.05
max_output_input_ratio: 10.0
max_output_input_ratio: 10.0
raw_wav: True # use raw_wav or kaldi feature
specgram_type: fbank #linear, mfcc, fbank
feat_dim: 80
......@@ -77,7 +77,7 @@ model:
training:
n_epoch: 120
accum_grad: 8
global_grad_clip: 5.0
global_grad_clip: 3.0
optim: adam
optim_conf:
lr: 0.004
......
#! /usr/bin/env bash
if [ $# != 2 ]; then
echo "usage: ${0} ckpt_dir avg_num"
exit -1
fi
ckpt_dir=${1}
average_num=${2}
decode_checkpoint=${ckpt_dir}/avg_${average_num}.pdparams
python3 -u ${MAIN_ROOT}/utils/avg_model.py \
--dst_model ${decode_checkpoint} \
--ckpt_dir ${ckpt_dir} \
--num ${average_num} \
--val_best
if [ $? -ne 0 ]; then
echo "Failed in avg ckpt!"
exit 1
fi
exit 0
#! /usr/bin/env bash
if [ $# != 2 ];then
echo "usage: ${0} ckpt_dir avg_num"
exit -1
fi
ckpt_dir=${1}
average_num=${2}
decode_checkpoint=${ckpt_dir}/avg_${average_num}.pdparams
python3 -u ${MAIN_ROOT}/utils/avg_model.py \
--dst_model ${decode_checkpoint} \
--ckpt_dir ${ckpt_dir} \
--num ${average_num} \
--val_best
if [ $? -ne 0 ]; then
echo "Failed in avg ckpt!"
exit 1
fi
exit 0
\ No newline at end of file
#! /usr/bin/env bash
if [ $# != 2 ];then
echo "usage: ${0} ckpt_dir avg_num"
exit -1
fi
ckpt_dir=${1}
average_num=${2}
decode_checkpoint=${ckpt_dir}/avg_${average_num}.pdparams
python3 -u ${MAIN_ROOT}/utils/avg_model.py \
--dst_model ${decode_checkpoint} \
--ckpt_dir ${ckpt_dir} \
--num ${average_num} \
--val_best
if [ $? -ne 0 ]; then
echo "Failed in avg ckpt!"
exit 1
fi
exit 0
\ No newline at end of file
......@@ -18,7 +18,6 @@ import paddle
from deepspeech.modules.mask import make_non_pad_mask
from deepspeech.modules.mask import make_pad_mask
from deepspeech.modules.mask import sequence_mask
class TestU2Model(unittest.TestCase):
......@@ -36,16 +35,10 @@ class TestU2Model(unittest.TestCase):
[False, False, True, True, True],
])
def test_sequence_mask(self):
res = sequence_mask(self.lengths, dtype='bool')
self.assertSequenceEqual(res.numpy().tolist(), self.masks.tolist())
def test_make_non_pad_mask(self):
res = make_non_pad_mask(self.lengths)
res1 = sequence_mask(self.lengths, dtype='bool')
res2 = make_pad_mask(self.lengths).logical_not()
self.assertSequenceEqual(res.numpy().tolist(), self.masks.tolist())
self.assertSequenceEqual(res.numpy().tolist(), res1.numpy().tolist())
self.assertSequenceEqual(res.numpy().tolist(), res2.numpy().tolist())
def test_make_pad_mask(self):
......
......@@ -18,3 +18,7 @@ licence: MIT
* [chinese_text_normalization](https://github.com/speechio/chinese_text_normalization.git)
commit: 9e92c7bf2d6b5a7974305406d8e240045beac51c
licence: MIT
* [phkit](https://github.com/KuangDD/phkit.git)
commit: b2100293c1e36da531d7f30bd52c9b955a649522
licence: None
![phkit](phkit.png "phkit")
## phkit
phoneme toolkit: 拼音相关的文本处理工具箱,中文和英文的语音合成前端文本解决方案。
#### 安装
```
pip install -U phkit
```
#### 版本
v0.2.8
### pinyinkit
文本转拼音的模块,依赖python-pinyin,jieba,phrase-pinyin-data模块。
### chinese
适用于中文、英文和中英混合的音素,其中汉字拼音采用清华大学的音素,英文字符分字母和英文。
- 中文音素简介:
```
声母:
aa b c ch d ee f g h ii j k l m n oo p q r s sh t uu vv x z zh
韵母:
a ai an ang ao e ei en eng er i ia ian iang iao ie in ing iong iu ix iy iz o ong ou u ua uai uan uang ueng ui un uo v van ve vn ng uong
声调:
1 2 3 4 5
字母:
Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz
英文:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
标点:
! ? . , ; : " # ( )
注:!=!!|?=??|.=.。|,=,,、|;=;;|:=::|"="“|#=#   |(=(([[{{【<《|)=))]]}}】>》
预留:
w y 0 6 7 8 9
注:w=%|y=$|0=0|6=6|7=7|8=8|9=9
其他:
_ ~ - *
```
#### symbol
音素标记。
中文音素,简单英文音素,简单中文音素。
#### sequence
转为序列的方法,文本转为音素列表,文本转为ID列表。
拼音变调,拼音转音素。
#### pinyin
转为拼音的方法,汉字转拼音,分离声调。
拼音为字母+数字形式,例如pin1。
#### phoneme
音素映射表。
不带声调拼音转为音素,声调转音素,英文字母转音素,标点转音素。
#### number
数字读法。
按数值大小读,一个一个数字读。
#### convert
文本转换。
全角半角转换,简体繁体转换。
#### style
拼音格式转换。
国标样式的拼音和字母数字的样式的拼音相互转换。
### english
from https://github.com/keithito/tacotron "
Cleaners are transformations that run over the input text at both training and eval time.
Cleaners can be selected by passing a comma-delimited list of cleaner names as the "cleaners"
hyperparameter. Some cleaners are English-specific. You'll typically want to use:
1. "english_cleaners" for English text
2. "transliteration_cleaners" for non-English text that can be transliterated to ASCII using
the Unidecode library (https://pypi.python.org/pypi/Unidecode)
3. "basic_cleaners" if you do not want to transliterate (in this case, you should also update
the symbols in symbols.py to match your data).
### 历史版本
#### v0.2.8
- 文本转拼音轻声用5表示音调。
- 文本转拼音确保文本和拼音一一对应,文本长度和拼音列表长度相同。
- 增加拼音格式转换,国标格式和字母数字格式相互转换。
#### v0.2.7
- 所有中文音素都能被映射到。
#### v0.2.5
- 修正拼音转音素的潜在bug。
#### v0.2.4
- 修正几个默认拼音。
#### v0.2.3
- 汉字转拼音轻量化。
- 词语拼音词典去除全都是默认拼音的词语。
#### v0.2.2
- 修正安装依赖报错问题。
#### v0.2.1
- 增加中文的text_to_sequence方法,可替换英文版本应对中文环境。
- 兼容v0.1.0(含)之前版本需要在python3.7(含)版本以上,否则请改为从phkit.chinese导入模块。
#### v0.2.0
- 增加文本转拼音的模块,依赖python-pinyin,jieba,phrase-pinyin-data模块。
- 中文的音素方案移动到chinese模块。
#### v0.1.0
- 增加英文版本的音素方案,包括英文字母和英文音素。
- 增加简单的数字转中文的方法。
#### todo
```
文本正则化处理
数字读法
字符读法
常见规则读法
文本转拼音
pypinyin
国标和alnum转换
anything转音素
字符
英文
汉字
OOV
进阶:
分词
命名实体识别
依存句法分析
```
#!usr/bin/env python
# -*- coding: utf-8 -*-
# author: kuangdd
# date: 2020/2/17
"""
![phkit](phkit.png "phkit")
## phkit
phoneme toolkit: 拼音相关的文本处理工具箱,中文和英文的语音合成前端文本解决方案。
#### 安装
```
pip install -U phkit
```
"""
__version__ = "0.2.8"
version_doc = """
#### 版本
v{}
""".format(__version__)
history_doc = """
### 历史版本
#### v0.2.8
- 文本转拼音轻声用5表示音调。
- 文本转拼音确保文本和拼音一一对应,文本长度和拼音列表长度相同。
- 增加拼音格式转换,国标格式和字母数字格式相互转换。
#### v0.2.7
- 所有中文音素都能被映射到。
#### v0.2.5
- 修正拼音转音素的潜在bug。
#### v0.2.4
- 修正几个默认拼音。
#### v0.2.3
- 汉字转拼音轻量化。
- 词语拼音词典去除全都是默认拼音的词语。
#### v0.2.2
- 修正安装依赖报错问题。
#### v0.2.1
- 增加中文的text_to_sequence方法,可替换英文版本应对中文环境。
- 兼容v0.1.0(含)之前版本需要在python3.7(含)版本以上,否则请改为从phkit.chinese导入模块。
#### v0.2.0
- 增加文本转拼音的模块,依赖python-pinyin,jieba,phrase-pinyin-data模块。
- 中文的音素方案移动到chinese模块。
#### v0.1.0
- 增加英文版本的音素方案,包括英文字母和英文音素。
- 增加简单的数字转中文的方法。
#### todo
```
文本正则化处理
数字读法
字符读法
常见规则读法
文本转拼音
pypinyin
国标和alnum转换
anything转音素
字符
英文
汉字
OOV
进阶:
分词
命名实体识别
依存句法分析
```
"""
from phkit.chinese import __doc__ as doc_chinese
from phkit.chinese.symbol import __doc__ as doc_symbol
from phkit.chinese.sequence import __doc__ as doc_sequence
from phkit.chinese.pinyin import __doc__ as doc_pinyin
from phkit.chinese.phoneme import __doc__ as doc_phoneme
from phkit.chinese.number import __doc__ as doc_number
from phkit.chinese.convert import __doc__ as doc_convert
from phkit.chinese.style import __doc__ as doc_style
from .english import __doc__ as doc_english
from .pinyinkit import __doc__ as doc_pinyinkit
readme_docs = [__doc__, version_doc,
doc_pinyinkit,
doc_chinese, doc_symbol, doc_sequence, doc_pinyin, doc_phoneme, doc_number, doc_convert, doc_style,
doc_english,
history_doc]
from .chinese import text_to_sequence as chinese_text_to_sequence, sequence_to_text as chinese_sequence_to_text
from .english import text_to_sequence as english_text_to_sequence, sequence_to_text as english_sequence_to_text
from .pinyinkit import lazy_pinyin
# 兼容0.1.0之前的版本,python3.7以上版本支持。
from .chinese import convert, number, phoneme, sequence, symbol, style
from .chinese.style import guobiao2shengyundiao, shengyundiao2guobiao
from .chinese.convert import fan2jian, jian2fan, quan2ban, ban2quan
from .chinese.number import say_digit, say_decimal, say_number
from .chinese.pinyin import text2pinyin, split_pinyin
from .chinese.sequence import text2sequence, text2phoneme, pinyin2phoneme, phoneme2sequence, sequence2phoneme
from .chinese.sequence import symbol_chinese, ph2id_dict, id2ph_dict
if __name__ == "__main__":
print(__file__)
"""
### chinese
适用于中文、英文和中英混合的音素,其中汉字拼音采用清华大学的音素,英文字符分字母和英文。
- 中文音素简介:
```
声母:
aa b c ch d ee f g h ii j k l m n oo p q r s sh t uu vv x z zh
韵母:
a ai an ang ao e ei en eng er i ia ian iang iao ie in ing iong iu ix iy iz o ong ou u ua uai uan uang ueng ui un uo v van ve vn ng uong
声调:
1 2 3 4 5
字母:
Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz
英文:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
标点:
! ? . , ; : " # ( )
注:!=!!|?=??|.=.。|,=,,、|;=;;|:=::|"="“|#=#  \t|(=(([[{{【<《|)=))]]}}】>》
预留:
w y 0 6 7 8 9
注:w=%|y=$|0=0|6=6|7=7|8=8|9=9
其他:
_ ~ - *
```
"""
from .convert import fan2jian, jian2fan, quan2ban, ban2quan
from .number import say_digit, say_decimal, say_number
from .pinyin import text2pinyin, split_pinyin
from .sequence import text2sequence, text2phoneme, pinyin2phoneme, phoneme2sequence, sequence2phoneme, change_diao
from .sequence import symbol_chinese, ph2id_dict, id2ph_dict
from .symbol import symbol_chinese as symbols
from .phoneme import shengyun2ph_dict
def text_to_sequence(src, cleaner_names=None, **kwargs):
"""
文本样例:卡尔普陪外孙玩滑梯。
拼音样例:ka3 er3 pu3 pei2 wai4 sun1 wan2 hua2 ti1 .
:param src: str,拼音或文本字符串
:param cleaner_names: 文本处理方法选择,暂时提供拼音和文本两种方法。
:return: list,ID列表
"""
if cleaner_names == "pinyin":
pys = []
for py in src.split():
if py.isalnum():
pys.append(py)
else:
pys.append((py,))
phs = pinyin2phoneme(pys)
phs = change_diao(phs)
seq = phoneme2sequence(phs)
return seq
else:
return text2sequence(src)
def sequence_to_text(src):
out = sequence2phoneme(src)
return " ".join(out)
if __name__ == "__main__":
print(__file__)
text = "ka3 er3 pu3 pei2 wai4 sun1 wan2 hua2 ti1 . "
out = text_to_sequence(text)
print(out)
out = sequence_to_text(out)
print(out)
#!usr/bin/env python
# -*- coding: utf-8 -*-
# author: kuangdd
# date: 2020/2/17
"""
#### convert
文本转换。
全角半角转换,简体繁体转换。
"""
from .hanziconv import HanziConv
hc = HanziConv()
# 繁体转简体
fan2jian = hc.toSimplified
# 简体转繁体
jian2fan = hc.toTraditional
# 半角转全角映射表
ban2quan_dict = {i: i + 65248 for i in range(33, 127)}
ban2quan_dict.update({32: 12288})
# 全角转半角映射表
quan2ban_dict = {v: k for k, v in ban2quan_dict.items()}
def ban2quan(text: str):
"""
半角转全角
:param text:
:return:
"""
return text.translate(ban2quan_dict)
def quan2ban(text: str):
"""
全角转半角
:param text:
:return:
"""
return text.translate(quan2ban_dict)
if __name__ == "__main__":
assert ban2quan("aA1 ,:$。、") == "aA1 ,:$。、"
assert quan2ban("aA1 ,:$。、") == "aA1 ,:$。、"
assert jian2fan("中国语言") == "中國語言"
assert fan2jian("中國語言") == "中国语言"
# Copyright 2014 Bernard Yue
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
__doc__ = """
Hanzi Converter 繁簡轉換器 | 繁简转换器
This module provides functions converting chinese text between simplified and
traditional characters. It returns unicode represnetation of the text.
Class HanziConv is the main entry point of the module, you can import the
class by doing:
>>> from hanziconv import HanziConv
"""
import os
from zhon import cedict
class HanziConv():
"""This class supports hanzi (漢字) convention between simplified and
traditional format"""
__traditional_charmap = cedict.traditional
__simplified_charmap = cedict.simplified
@classmethod
def __convert(cls, text, toTraditional=True):
"""Convert `text` to Traditional characters if `toTraditional` is
True, else convert to simplified characters
:param text: data to convert
:param toTraditional: True -- convert to traditional text
False -- covert to simplified text
:returns: converted 'text`
"""
if isinstance(text, bytes):
text = text.decode('utf-8')
fromMap = cls.__simplified_charmap
toMap = cls.__traditional_charmap
if not toTraditional:
fromMap = cls.__traditional_charmap
toMap = cls.__simplified_charmap
final = []
for c in text:
index = fromMap.find(c)
if index != -1:
final.append(toMap[index])
else:
final.append(c)
return ''.join(final)
@classmethod
def toSimplified(cls, text):
"""Convert `text` to simplified character string. Assuming text is
traditional character string
:param text: text to convert
:returns: converted UTF-8 characters
>>> from hanziconv import HanziConv
>>> print(HanziConv.toSimplified('繁簡轉換器'))
繁简转换器
"""
return cls.__convert(text, toTraditional=False)
@classmethod
def toTraditional(cls, text):
"""Convert `text` to traditional character string. Assuming text is
simplified character string
:param text: text to convert
:returns: converted UTF-8 characters
>>> from hanziconv import HanziConv
>>> print(HanziConv.toTraditional('繁简转换器'))
繁簡轉換器
"""
return cls.__convert(text, toTraditional=True)
@classmethod
def same(cls, text1, text2):
"""Return True if text1 and text2 meant literally the same, False
otherwise
:param text1: string to compare to ``text2``
:param text2: string to compare to ``text1``
:returns: **True** -- ``text1`` and ``text2`` are the same in meaning,
**False** -- otherwise
>>> from hanziconv import HanziConv
>>> print(HanziConv.same('繁简转换器', '繁簡轉換器'))
True
"""
t1 = cls.toSimplified(text1)
t2 = cls.toSimplified(text2)
return t1 == t2
\ No newline at end of file
#!usr/bin/env python
# -*- coding: utf-8 -*-
# author: kuangdd
# date: 2020/2/16
"""
#### number
数字读法。
按数值大小读,一个一个数字读。
"""
import re
_number_cn = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
_number_level = ['千', '百', '十', '万', '千', '百', '十', '亿', '千', '百', '十', '万', '千', '百', '十', '个']
_zero = _number_cn[0]
_ten_re = re.compile(r'^一十')
_grade_level = {'万', '亿', '个'}
_number_group_re = re.compile(r"([0-9]+)")
def say_digit(num: str) -> str:
"""123 -> 一二三
Args:
num (str): digit
Returns:
str: hanzi number
"""
outs = []
for zi in num:
outs.append(_number_cn[int(zi)])
return ''.join(outs)
def say_number(num: str):
x = str(int(num))
if x == '0':
return _number_cn[0]
elif len(x) > 16:
return num
length = len(x)
outs = []
for num, zi in enumerate(x):
a = _number_cn[int(zi)]
b = _number_level[len(_number_level) - length + num]
if a != _zero:
outs.append(a)
outs.append(b)
else:
if b in _grade_level:
if outs[-1] != _zero:
outs.append(b)
else:
outs[-1] = b
else:
if outs[-1] != _zero:
outs.append(a)
out = ''.join(outs[:-1])
out = _ten_re.sub(r'十', out)
return out
def say_decimal(num: str):
z, x = num.split('.')
z_cn = say_number(z)
x_cn = say_digit(x)
return z_cn + '点' + x_cn
def convert_number(text):
parts = _number_group_re.split(text)
outs = []
for elem in parts:
if elem.isdigit():
if len(elem) <= 9:
outs.append(say_number(elem))
else:
outs.append(say_digit(elem))
else:
outs.append(elem)
return ''.join(outs)
if __name__ == "__main__":
print(__file__)
assert say_number("1234567890123456") == "一千二百三十四万五千六百七十八亿九千零一十二万三千四百五十六"
assert say_digit("123456") == "一二三四五六"
assert say_decimal("3.14") == "三点一四"
assert convert_number("hello314.1592and2718281828") == "hello三百一十四.一千五百九十二and二七一八二八一八二八"
#!usr/bin/env python
# -*- coding: utf-8 -*-
# author: kuangdd
# date: 2020/2/16
"""
#### phoneme
音素映射表。
不带声调拼音转为音素,声调转音素,英文字母转音素,标点转音素。
"""
# 拼音转音素映射表:420
shengyun2ph_dict = {
'a': 'aa a',
'ai': 'aa ai',
'an': 'aa an',
'ang': 'aa ang',
'ao': 'aa ao',
'ba': 'b a',
'bai': 'b ai',
'ban': 'b an',
'bang': 'b ang',
'bao': 'b ao',
'bei': 'b ei',
'ben': 'b en',
'beng': 'b eng',
'bi': 'b i',
'bian': 'b ian',
'biao': 'b iao',
'bie': 'b ie',
'bin': 'b in',
'bing': 'b ing',
'bo': 'b o',
'bu': 'b u',
'ca': 'c a',
'cai': 'c ai',
'can': 'c an',
'cang': 'c ang',
'cao': 'c ao',
'ce': 'c e',
'cen': 'c en',
'ceng': 'c eng',
'ci': 'c iy',
'cong': 'c ong',
'cou': 'c ou',
'cu': 'c u',
'cuan': 'c uan',
'cui': 'c ui',
'cun': 'c un',
'cuo': 'c uo',
'cha': 'ch a',
'chai': 'ch ai',
'chan': 'ch an',
'chang': 'ch ang',
'chao': 'ch ao',
'che': 'ch e',
'chen': 'ch en',
'cheng': 'ch eng',
'chi': 'ch ix',
'chong': 'ch ong',
'chou': 'ch ou',
'chu': 'ch u',
'chuai': 'ch uai',
'chuan': 'ch uan',
'chuang': 'ch uang',
'chui': 'ch ui',
'chun': 'ch un',
'chuo': 'ch uo',
'da': 'd a',
'dai': 'd ai',
'dan': 'd an',
'dang': 'd ang',
'dao': 'd ao',
'de': 'd e',
'dei': 'd ei',
'deng': 'd eng',
'di': 'd i',
'dia': 'd ia',
'dian': 'd ian',
'diao': 'd iao',
'die': 'd ie',
'ding': 'd ing',
'diu': 'd iu',
'dong': 'd ong',
'dou': 'd ou',
'du': 'd u',
'duan': 'd uan',
'dui': 'd ui',
'dun': 'd un',
'duo': 'd uo',
'e': 'ee e',
'ei': 'ee ei',
'en': 'ee en',
'er': 'ee er',
'fa': 'f a',
'fan': 'f an',
'fang': 'f ang',
'fei': 'f ei',
'fen': 'f en',
'feng': 'f eng',
'fo': 'f o',
'fou': 'f ou',
'fu': 'f u',
'ga': 'g a',
'gai': 'g ai',
'gan': 'g an',
'gang': 'g ang',
'gao': 'g ao',
'ge': 'g e',
'gei': 'g ei',
'gen': 'g en',
'geng': 'g eng',
'gong': 'g ong',
'gou': 'g ou',
'gu': 'g u',
'gua': 'g ua',
'guai': 'g uai',
'guan': 'g uan',
'guang': 'g uang',
'gui': 'g ui',
'gun': 'g un',
'guo': 'g uo',
'ha': 'h a',
'hai': 'h ai',
'han': 'h an',
'hang': 'h ang',
'hao': 'h ao',
'he': 'h e',
'hei': 'h ei',
'hen': 'h en',
'heng': 'h eng',
'hong': 'h ong',
'hou': 'h ou',
'hu': 'h u',
'hua': 'h ua',
'huai': 'h uai',
'huan': 'h uan',
'huang': 'h uang',
'hui': 'h ui',
'hun': 'h un',
'huo': 'h uo',
'yi': 'ii i',
'ya': 'ii ia',
'yan': 'ii ian',
'yang': 'ii iang',
'yao': 'ii iao',
'ye': 'ii ie',
'yin': 'ii in',
'ying': 'ii ing',
'yong': 'ii iong',
'you': 'ii iu',
'ji': 'j i',
'jia': 'j ia',
'jian': 'j ian',
'jiang': 'j iang',
'jiao': 'j iao',
'jie': 'j ie',
'jin': 'j in',
'jing': 'j ing',
'jiong': 'j iong',
'jiu': 'j iu',
'ju': 'j v',
'juan': 'j van',
'jue': 'j ve',
'jun': 'j vn',
'ka': 'k a',
'kai': 'k ai',
'kan': 'k an',
'kang': 'k ang',
'kao': 'k ao',
'ke': 'k e',
'ken': 'k en',
'keng': 'k eng',
'kong': 'k ong',
'kou': 'k ou',
'ku': 'k u',
'kua': 'k ua',
'kuai': 'k uai',
'kuan': 'k uan',
'kuang': 'k uang',
'kui': 'k ui',
'kun': 'k un',
'kuo': 'k uo',
'la': 'l a',
'lai': 'l ai',
'lan': 'l an',
'lang': 'l ang',
'lao': 'l ao',
'le': 'l e',
'lei': 'l ei',
'leng': 'l eng',
'li': 'l i',
'lia': 'l ia',
'lian': 'l ian',
'liang': 'l iang',
'liao': 'l iao',
'lie': 'l ie',
'lin': 'l in',
'ling': 'l ing',
'liu': 'l iu',
'lo': 'l o',
'long': 'l ong',
'lou': 'l ou',
'lu': 'l u',
'luan': 'l uan',
'lun': 'l un',
'luo': 'l uo',
'lv': 'l v',
'lve': 'l ve',
'ma': 'm a',
'mai': 'm ai',
'man': 'm an',
'mang': 'm ang',
'mao': 'm ao',
'me': 'm e',
'mei': 'm ei',
'men': 'm en',
'meng': 'm eng',
'mi': 'm i',
'mian': 'm ian',
'miao': 'm iao',
'mie': 'm ie',
'min': 'm in',
'ming': 'm ing',
'miu': 'm iu',
'mo': 'm o',
'mou': 'm ou',
'mu': 'm u',
'na': 'n a',
'nai': 'n ai',
'nan': 'n an',
'nang': 'n ang',
'nao': 'n ao',
'ne': 'n e',
'nei': 'n ei',
'nen': 'n en',
'neng': 'n eng',
'ni': 'n i',
'nian': 'n ian',
'niang': 'n iang',
'niao': 'n iao',
'nie': 'n ie',
'nin': 'n in',
'ning': 'n ing',
'niu': 'n iu',
'nong': 'n ong',
'nu': 'n u',
'nuan': 'n uan',
'nuo': 'n uo',
'nv': 'n v',
'nve': 'n ve',
'o': 'oo o',
'ou': 'oo ou',
'pa': 'p a',
'pai': 'p ai',
'pan': 'p an',
'pang': 'p ang',
'pao': 'p ao',
'pei': 'p ei',
'pen': 'p en',
'peng': 'p eng',
'pi': 'p i',
'pian': 'p ian',
'piao': 'p iao',
'pie': 'p ie',
'pin': 'p in',
'ping': 'p ing',
'po': 'p o',
'pou': 'p ou',
'pu': 'p u',
'qi': 'q i',
'qia': 'q ia',
'qian': 'q ian',
'qiang': 'q iang',
'qiao': 'q iao',
'qie': 'q ie',
'qin': 'q in',
'qing': 'q ing',
'qiong': 'q iong',
'qiu': 'q iu',
'qu': 'q v',
'quan': 'q van',
'que': 'q ve',
'qun': 'q vn',
'ran': 'r an',
'rang': 'r ang',
'rao': 'r ao',
're': 'r e',
'ren': 'r en',
'reng': 'r eng',
'ri': 'r iz',
'rong': 'r ong',
'rou': 'r ou',
'ru': 'r u',
'ruan': 'r uan',
'rui': 'r ui',
'run': 'r un',
'ruo': 'r uo',
'sa': 's a',
'sai': 's ai',
'san': 's an',
'sang': 's ang',
'sao': 's ao',
'se': 's e',
'sen': 's en',
'seng': 's eng',
'si': 's iy',
'song': 's ong',
'sou': 's ou',
'su': 's u',
'suan': 's uan',
'sui': 's ui',
'sun': 's un',
'suo': 's uo',
'sha': 'sh a',
'shai': 'sh ai',
'shan': 'sh an',
'shang': 'sh ang',
'shao': 'sh ao',
'she': 'sh e',
'shei': 'sh ei',
'shen': 'sh en',
'sheng': 'sh eng',
'shi': 'sh ix',
'shou': 'sh ou',
'shu': 'sh u',
'shua': 'sh ua',
'shuai': 'sh uai',
'shuan': 'sh uan',
'shuang': 'sh uang',
'shui': 'sh ui',
'shun': 'sh un',
'shuo': 'sh uo',
'ta': 't a',
'tai': 't ai',
'tan': 't an',
'tang': 't ang',
'tao': 't ao',
'te': 't e',
'teng': 't eng',
'ti': 't i',
'tian': 't ian',
'tiao': 't iao',
'tie': 't ie',
'ting': 't ing',
'tong': 't ong',
'tou': 't ou',
'tu': 't u',
'tuan': 't uan',
'tui': 't ui',
'tun': 't un',
'tuo': 't uo',
'wu': 'uu u',
'wa': 'uu ua',
'wai': 'uu uai',
'wan': 'uu uan',
'wang': 'uu uang',
'weng': 'uu ueng',
'wei': 'uu ui',
'wen': 'uu un',
'wo': 'uu uo',
'yu': 'vv v',
'yuan': 'vv van',
'yue': 'vv ve',
'yun': 'vv vn',
'xi': 'x i',
'xia': 'x ia',
'xian': 'x ian',
'xiang': 'x iang',
'xiao': 'x iao',
'xie': 'x ie',
'xin': 'x in',
'xing': 'x ing',
'xiong': 'x iong',
'xiu': 'x iu',
'xu': 'x v',
'xuan': 'x van',
'xue': 'x ve',
'xun': 'x vn',
'za': 'z a',
'zai': 'z ai',
'zan': 'z an',
'zang': 'z ang',
'zao': 'z ao',
'ze': 'z e',
'zei': 'z ei',
'zen': 'z en',
'zeng': 'z eng',
'zi': 'z iy',
'zong': 'z ong',
'zou': 'z ou',
'zu': 'z u',
'zuan': 'z uan',
'zui': 'z ui',
'zun': 'z un',
'zuo': 'z uo',
'zha': 'zh a',
'zhai': 'zh ai',
'zhan': 'zh an',
'zhang': 'zh ang',
'zhao': 'zh ao',
'zhe': 'zh e',
'zhei': 'zh ei',
'zhen': 'zh en',
'zheng': 'zh eng',
'zhi': 'zh ix',
'zhong': 'zh ong',
'zhou': 'zh ou',
'zhu': 'zh u',
'zhua': 'zh ua',
'zhuai': 'zh uai',
'zhuan': 'zh uan',
'zhuang': 'zh uang',
'zhui': 'zh ui',
'zhun': 'zh un',
'zhuo': 'zh uo',
'cei': 'c ei',
'chua': 'ch ua',
'den': 'd en',
'din': 'd in',
'eng': 'ee eng',
'ng': 'ee ng',
'fiao': 'f iao',
'yo': 'ii o',
'kei': 'k ei',
'len': 'l en',
'nia': 'n ia',
'nou': 'n ou',
'nun': 'n un',
'rua': 'r ua',
'tei': 't ei',
'wong': 'uu uong',
'n': 'n ng'
}
diao2ph_dict = {'1': '1', '2': '2', '3': '3', '4': '4', '5': '5'}
# 字母音素:26
_alphabet = 'Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz'.split()
# 字母:26
_upper = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
_lower = list('abcdefghijklmnopqrstuvwxyz')
upper2ph_dict = dict(zip(_upper, _alphabet))
lower2ph_dict = dict(zip(_lower, _upper))
# 标点:9
_biaodian = '! ? . , ; : " # ( )'.split()
# 注:!=!!|?=??|.=.。|,=,,、|;=;;|:=::|"="“”'‘’|#=  \t|(=(([[{{【<《|)=))]]}}】>》
biao2ph_dict = {
'!': '!', '!': '!',
'?': '?', '?': '?',
'.': '.', '。': '.',
',': ',', ',': ',', '、': ',',
';': ';', ';': ';',
':': ':', ':': ':',
'"': '"', '“': '"', '”': '"', "'": '"', '‘': '"', '’': '"',
'#': '#', '#': '#', ' ': '#', ' ': '#', '\t': '#',
'(': '(', '(': '(', '[': '(', '[': '(', '{': '(', '{': '(', '【': '(', '<': '(', '《': '(',
')': ')', ')': ')', ']': ')', ']': ')', '}': ')', '}': ')', '】': ')', '>': ')', '》': ')'
}
# 其他:7
_other = 'w y 0 6 7 8 9'.split()
other2ph_dict = {
'%': 'w',
'$': 'y',
'0': '0',
'6': '6',
'7': '7',
'8': '8',
'9': '9'
}
char2ph_dict = {**upper2ph_dict, **lower2ph_dict, **biao2ph_dict, **other2ph_dict}
if __name__ == "__main__":
print(__file__)
#!usr/bin/env python
# -*- coding: utf-8 -*-
# author: kuangdd
# date: 2020/2/17
"""
#### pinyin
转为拼音的方法,汉字转拼音,分离声调。
拼音为字母+数字形式,例如pin1。
"""
from ..pinyinkit import text2pinyin, split_pinyin
#!usr/bin/env python
# -*- coding: utf-8 -*-
# author: kuangdd
# date: 2020/2/16
"""
#### sequence
转为序列的方法,文本转为音素列表,文本转为ID列表。
拼音变调,拼音转音素。
"""
from .phoneme import shengyun2ph_dict, diao2ph_dict, char2ph_dict
from .pinyin import text2pinyin, split_pinyin
from .symbol import _chain, _eos, _pad, symbol_chinese
from .convert import fan2jian, quan2ban
from .number import convert_number
import re
# 分隔英文字母
_en_re = re.compile(r"([a-zA-Z]+)")
phs = ({w for p in shengyun2ph_dict.values() for w in p.split()}
| set(diao2ph_dict.values()) | set(char2ph_dict.values()))
assert bool(phs - set(symbol_chinese)) is False
ph2id_dict = {p: i for i, p in enumerate(symbol_chinese)}
id2ph_dict = {i: p for i, p in enumerate(symbol_chinese)}
assert len(ph2id_dict) == len(id2ph_dict)
def text2phoneme(text):
"""
文本转为音素,用中文音素方案。
中文转为拼音,按照清华大学方案转为音素,分为辅音、元音、音调。
英文全部大写,转为字母读音。
英文非全部大写,转为英文读音。
标点映射为音素。
:param text: str,正则化后的文本。
:return: list,音素列表
"""
text = normalize_chinese(text)
text = normalize_english(text)
pys = text2pinyin(text, errors=lambda x: (x,))
phs = pinyin2phoneme(pys)
phs = change_diao(phs)
return phs
def text2sequence(text):
"""
文本转为ID序列。
:param text:
:return:
"""
phs = text2phoneme(text)
seq = phoneme2sequence(phs)
return seq
def pinyin2phoneme(src):
"""
拼音或其他字符转音素。
:param src: list,拼音用str格式,其他用tuple格式。
:return: list
"""
out = []
for py in src:
if type(py) is str:
fuyuan, diao = split_pinyin(py)
if fuyuan in shengyun2ph_dict and diao in diao2ph_dict:
phs = shengyun2ph_dict[fuyuan].split()
phs.append(diao2ph_dict[diao])
else:
phs = py_errors(py)
else:
phs = []
for w in py:
ph = py_errors(w)
phs.extend(ph)
if phs:
out.extend(phs)
out.append(_chain)
out.append(_eos)
out.append(_pad)
return out
def change_diao(src):
"""
拼音变声调,连续上声声调的把前一个上声变为阳平。
:param src: list,音素列表
:return: list,变调后的音素列表
"""
flag = -5
out = []
for i, w in enumerate(reversed(src)):
if w == '3':
if i - flag == 4:
out.append('2')
else:
flag = i
out.append(w)
else:
out.append(w)
return list(reversed(out))
def phoneme2sequence(src):
out = []
for w in src:
if w in ph2id_dict:
out.append(ph2id_dict[w])
return out
def sequence2phoneme(src):
out = []
for w in src:
if w in id2ph_dict:
out.append(id2ph_dict[w])
return out
def py_errors(text):
out = []
for p in text:
if p in char2ph_dict:
out.append(char2ph_dict[p])
return out
def normalize_chinese(text):
text = quan2ban(text)
text = fan2jian(text)
text = convert_number(text)
return text
def normalize_english(text):
out = []
parts = _en_re.split(text)
for part in parts:
if not part.isupper():
out.append(part.lower())
else:
out.append(part)
return "".join(out)
if __name__ == "__main__":
print(__file__)
此差异已折叠。
#!usr/bin/env python
# -*- coding: utf-8 -*-
# author: kuangdd
# date: 2020/2/16
"""
#### symbol
音素标记。
中文音素,简单英文音素,简单中文音素。
"""
_pad = '_' # 填充符
_eos = '~' # 结束符
_chain = '-' # 连接符,连接读音单位
_oov = '*'
# 中文音素表
# 声母:27
_shengmu = [
'aa', 'b', 'c', 'ch', 'd', 'ee', 'f', 'g', 'h', 'ii', 'j', 'k', 'l', 'm', 'n', 'oo', 'p', 'q', 'r', 's', 'sh',
't', 'uu', 'vv', 'x', 'z', 'zh'
]
# 韵母:41
_yunmu = [
'a', 'ai', 'an', 'ang', 'ao', 'e', 'ei', 'en', 'eng', 'er', 'i', 'ia', 'ian', 'iang', 'iao', 'ie', 'in', 'ing',
'iong', 'iu', 'ix', 'iy', 'iz', 'o', 'ong', 'ou', 'u', 'ua', 'uai', 'uan', 'uang', 'ueng', 'ui', 'un', 'uo', 'v',
'van', 've', 'vn', 'ng', 'uong'
]
# 声调:5
_shengdiao = ['1', '2', '3', '4', '5']
# 字母:26
_alphabet = 'Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz'.split()
# 英文:26
_english = 'A B C D E F G H I J K L M N O P Q R S T U V W X Y Z'.split()
# 标点:10
_biaodian = '! ? . , ; : " # ( )'.split()
# 注:!=!!|?=??|.=.。|,=,,、|;=;;|:=::|"="“|#= \t|(=(([[{{【<《|)=))]]}}】>》
# 其他:7
_other = 'w y 0 6 7 8 9'.split()
# 大写字母:26
_upper = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
# 小写字母:26
_lower = list('abcdefghijklmnopqrstuvwxyz')
# 标点符号:12
_punctuation = list('!\'"(),-.:;? ')
# 数字:10
_digit = list('0123456789')
# 字母和符号:64
# 用于英文:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!\'"(),-.:;?\s
_character_en = _upper + _lower + _punctuation
# 字母、数字和符号:74
# 用于英文或中文:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!\'"(),-.:;?\s0123456789
_character_cn = _upper + _lower + _punctuation + _digit
# 中文音素:145
# 支持中文环境、英文环境、中英混合环境,中文把文字转为清华大学标准的音素表示
symbol_chinese = [_pad, _eos, _chain] + _shengmu + _yunmu + _shengdiao + _alphabet + _english + _biaodian + _other
# 简单英文音素:66
# 支持英文环境
# ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!\'"(),-.:;?\s
symbol_english_simple = [_pad, _eos] + _upper + _lower + _punctuation
# 简单中文音素:76
# 支持英文、中文环境,中文把文字转为拼音字符串
# ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!\'"(),-.:;?\s0123456789
symbol_chinese_simple = [_pad, _eos] + _upper + _lower + _punctuation + _digit
Copyright (c) 2017 Keith Ito
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
### english
from https://github.com/keithito/tacotron "
Cleaners are transformations that run over the input text at both training and eval time.
Cleaners can be selected by passing a comma-delimited list of cleaner names as the "cleaners"
hyperparameter. Some cleaners are English-specific. You'll typically want to use:
1. "english_cleaners" for English text
2. "transliteration_cleaners" for non-English text that can be transliterated to ASCII using
the Unidecode library (https://pypi.python.org/pypi/Unidecode)
3. "basic_cleaners" if you do not want to transliterate (in this case, you should also update
the symbols in symbols.py to match your data).
"""
import re
import random
from . import cleaners
from .symbols import symbols
# Mappings from symbol to numeric ID and vice versa:
_symbol_to_id = {s: i for i, s in enumerate(symbols)}
_id_to_symbol = {i: s for i, s in enumerate(symbols)}
# Regular expression matching text enclosed in curly braces:
_curly_re = re.compile(r'(.*?)\{(.+?)\}(.*)')
def get_arpabet(word, dictionary):
word_arpabet = dictionary.lookup(word)
if word_arpabet is not None:
return "{" + word_arpabet[0] + "}"
else:
return word
def text_to_sequence(text, cleaner_names, dictionary=None, p_arpabet=1.0):
'''Converts a string of text to a sequence of IDs corresponding to the symbols in the text.
The text can optionally have ARPAbet sequences enclosed in curly braces embedded
in it. For example, "Turn left on {HH AW1 S S T AH0 N} Street."
Args:
text: string to convert to a sequence
cleaner_names: names of the cleaner functions to run the text through
dictionary: arpabet class with arpabet dictionary
Returns:
List of integers corresponding to the symbols in the text
'''
sequence = []
space = _symbols_to_sequence(' ')
# Check for curly braces and treat their contents as ARPAbet:
while len(text):
m = _curly_re.match(text)
if not m:
clean_text = _clean_text(text, cleaner_names)
if dictionary is not None:
clean_text = [get_arpabet(w, dictionary)
if random.random() < p_arpabet else w
for w in clean_text.split(" ")]
for i in range(len(clean_text)):
t = clean_text[i]
if t.startswith("{"):
sequence += _arpabet_to_sequence(t[1:-1])
else:
sequence += _symbols_to_sequence(t)
sequence += space
else:
sequence += _symbols_to_sequence(clean_text)
break
clean_text = _clean_text(text, cleaner_names)
sequence += _symbols_to_sequence(_clean_text(m.group(1), cleaner_names))
sequence += _arpabet_to_sequence(m.group(2))
text = m.group(3)
# remove trailing space
sequence = sequence[:-1] if sequence[-1] == space[0] else sequence
return sequence
def sequence_to_text(sequence):
'''Converts a sequence of IDs back to a string'''
result = []
for symbol_id in sequence:
if symbol_id in _id_to_symbol:
s = _id_to_symbol[symbol_id]
# Enclose ARPAbet back in curly braces:
if len(s) > 1 and s[0] == '@':
s = '{%s}' % s[1:]
result.append(s)
result = ''.join(result)
return result.replace('}{', ' ')
def _clean_text(text, cleaner_names):
for name in cleaner_names:
cleaner = getattr(cleaners, name)
if not cleaner:
raise Exception('Unknown cleaner: %s' % name)
text = cleaner(text)
return text
def _symbols_to_sequence(symbols):
return [_symbol_to_id[s] for s in symbols if _should_keep_symbol(s)]
def _arpabet_to_sequence(text):
return _symbols_to_sequence(['@' + s for s in text.split()])
def _should_keep_symbol(s):
return s in _symbol_to_id and s is not '_' and s is not '~'
'''
### english
from https://github.com/keithito/tacotron "
Cleaners are transformations that run over the input text at both training and eval time.
Cleaners can be selected by passing a comma-delimited list of cleaner names as the "cleaners"
hyperparameter. Some cleaners are English-specific. You'll typically want to use:
1. "english_cleaners" for English text
2. "transliteration_cleaners" for non-English text that can be transliterated to ASCII using
the Unidecode library (https://pypi.python.org/pypi/Unidecode)
3. "basic_cleaners" if you do not want to transliterate (in this case, you should also update
the symbols in symbols.py to match your data).
'''
import re
from unidecode import unidecode
from .numbers import normalize_numbers
# Regular expression matching whitespace:
_whitespace_re = re.compile(r'\s+')
# List of (regular expression, replacement) pairs for abbreviations:
_abbreviations = [(re.compile('\\b%s\\.' % x[0], re.IGNORECASE), x[1]) for x in [
('mrs', 'misess'),
('mr', 'mister'),
('dr', 'doctor'),
('st', 'saint'),
('co', 'company'),
('jr', 'junior'),
('maj', 'major'),
('gen', 'general'),
('drs', 'doctors'),
('rev', 'reverend'),
('lt', 'lieutenant'),
('hon', 'honorable'),
('sgt', 'sergeant'),
('capt', 'captain'),
('esq', 'esquire'),
('ltd', 'limited'),
('col', 'colonel'),
('ft', 'fort'),
]]
def expand_abbreviations(text):
for regex, replacement in _abbreviations:
text = re.sub(regex, replacement, text)
return text
def expand_numbers(text):
return normalize_numbers(text)
def lowercase(text):
return text.lower()
def collapse_whitespace(text):
return re.sub(_whitespace_re, ' ', text)
def convert_to_ascii(text):
return unidecode(text)
def basic_cleaners(text):
'''Basic pipeline that lowercases and collapses whitespace without transliteration.'''
text = lowercase(text)
text = collapse_whitespace(text)
return text
def transliteration_cleaners(text):
'''Pipeline for non-English text that transliterates to ASCII.'''
text = convert_to_ascii(text)
text = lowercase(text)
text = collapse_whitespace(text)
return text
def english_cleaners(text):
'''Pipeline for English text, including number and abbreviation expansion.'''
text = convert_to_ascii(text)
text = lowercase(text)
text = expand_numbers(text)
text = expand_abbreviations(text)
text = collapse_whitespace(text)
return text
此差异已折叠。
""" from https://github.com/keithito/tacotron """
import re
valid_symbols = [
'AA', 'AA0', 'AA1', 'AA2', 'AE', 'AE0', 'AE1', 'AE2', 'AH', 'AH0', 'AH1', 'AH2',
'AO', 'AO0', 'AO1', 'AO2', 'AW', 'AW0', 'AW1', 'AW2', 'AY', 'AY0', 'AY1', 'AY2',
'B', 'CH', 'D', 'DH', 'EH', 'EH0', 'EH1', 'EH2', 'ER', 'ER0', 'ER1', 'ER2', 'EY',
'EY0', 'EY1', 'EY2', 'F', 'G', 'HH', 'IH', 'IH0', 'IH1', 'IH2', 'IY', 'IY0', 'IY1',
'IY2', 'JH', 'K', 'L', 'M', 'N', 'NG', 'OW', 'OW0', 'OW1', 'OW2', 'OY', 'OY0',
'OY1', 'OY2', 'P', 'R', 'S', 'SH', 'T', 'TH', 'UH', 'UH0', 'UH1', 'UH2', 'UW',
'UW0', 'UW1', 'UW2', 'V', 'W', 'Y', 'Z', 'ZH'
]
_valid_symbol_set = set(valid_symbols)
class CMUDict:
'''Thin wrapper around CMUDict data. http://www.speech.cs.cmu.edu/cgi-bin/cmudict'''
def __init__(self, file_or_path, keep_ambiguous=True):
if isinstance(file_or_path, str):
with open(file_or_path, encoding='latin-1') as f:
entries = _parse_cmudict(f)
else:
entries = _parse_cmudict(file_or_path)
if not keep_ambiguous:
entries = {word: pron for word, pron in entries.items() if len(pron) == 1}
self._entries = entries
def __len__(self):
return len(self._entries)
def lookup(self, word):
'''Returns list of ARPAbet pronunciations of the given word.'''
return self._entries.get(word.upper())
_alt_re = re.compile(r'\([0-9]+\)')
def _parse_cmudict(file):
cmudict = {}
for line in file:
if len(line) and (line[0] >= 'A' and line[0] <= 'Z' or line[0] == "'"):
parts = line.split(' ')
word = re.sub(_alt_re, '', parts[0])
pronunciation = _get_pronunciation(parts[1])
if pronunciation:
if word in cmudict:
cmudict[word].append(pronunciation)
else:
cmudict[word] = [pronunciation]
return cmudict
def _get_pronunciation(s):
parts = s.strip().split(' ')
for part in parts:
if part not in _valid_symbol_set:
return None
return ' '.join(parts)
此差异已折叠。
""" from https://github.com/keithito/tacotron """
'''
Defines the set of symbols used in text input to the model.
The default is a set of ASCII characters that works well for English or text that has been run through Unidecode. For other data, you can modify _characters. See TRAINING_DATA.md for details. '''
from . import cmudict
_punctuation = '!\'",.:;? '
_math = '#%&*+-/[]()'
_special = '_@©°½—₩€$'
_accented = 'áçéêëñöøćž'
_numbers = '0123456789'
_letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
# Prepend "@" to ARPAbet symbols to ensure uniqueness (some are the same as
# uppercase letters):
_arpabet = ['@' + s for s in cmudict.valid_symbols]
# Export all symbols:
symbols = list(_punctuation + _math + _special + _accented + _numbers + _letters) + _arpabet
此差异已折叠。
jieba
inflect
unidecode
tqdm
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -10,3 +10,4 @@ Sphinx
tox
twine
wheel>=0.21
jieba
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册