Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug in #1690 #1700

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Fix bug in #1690 #1700

wants to merge 6 commits into from

Conversation

Cosmo-klara
Copy link

@Cosmo-klara Cosmo-klara commented Oct 17, 2024

具体的修改说明可以参见这个问题下我的回答: #1690

修复按英文句号.切分将句中数字(包含小数点)异常切分

在 GPT_SoVITS\TTS_infer_pack\text_segmentation_method.py 的 cut4 中:

  @register_method("cut4")
  def cut4(inp):
      inp = inp.strip("\n")
      opts = ["%s" % item for item in inp.strip(".").split(".")]
      opts = [item for item in opts if not set(item).issubset(punctuation)]
      return "\n".join(opts)

修改其

  opts = ["%s" % item for item in inp.strip(".").split(".")]

为:

  opts = re.split(r'(?<!\d)\.(?!\d)', inp.strip("."))

使用正则表达式保证**只有前后都不是数字(也就是不是数字内包含的小数点)**是才进行切分

此外,还需要在 ...\GPT_SoVITS\TTS_infer_pack\TextPreprocessor.py 中修改:

这里就是保证让输入的英文文本不去除句子结尾句号后面的空格,否则数字开头的句子和前面的句子不会切分开

  language = os.environ.get("language", "Auto")
  language = sys.argv[-1] if sys.argv[-1] in scan_language_list() else language
  i18n = I18nAuto(language=language)
  punctuation = set(['!', '?', '…', ',', '.', '-', " "])

修改

  punctuation = set(['!', '?', '…', ',', '.', '-', " "])

  punctuation = set(['!', '?', '…', ',', '.', '-'])

去掉其中的“ ”(空格);

为什么可以去掉?

在 preprocess 函数中

  text = self.replace_consecutive_punctuation(text) 
  texts = self.pre_seg_text(text, lang, text_split_method)

也就是在切分前先不去掉重复的空格,而在 pre_seg_text 中又调用了 filter_text 去掉无效的字符(比如空格),所以最后切分的文本还是正常的。个人理解,代码没看很全,有疏忽请多指教haha。

修复推理英文%未能正确读出

就是直接加了一个 text = re.sub("%", " percent", text) 在处理的时候把“%”替换了

...\GPT_SoVITS\text\english.py 中的 text_normalize 函数中,在

  text = re.sub("[^ A-Za-z'.,?!\-]", "", text)

前添加:

  text = re.sub("%", " percent", text)

一个 简单的测试:

目标文本:hello. 123.45 is a number. 23% should be read as 23 percent.

推理截图:

test

生成语音:

audio.mov

修改按英文句号.切分方式
删除punctuation中的“ ”,以便于按英文句号切分
@Cosmo-klara Cosmo-klara changed the title 修复按英文句号.切分将句中数字(包含小数点)异常切分和推理英文%未能正确读出的问题 Fix bug in #1690 Oct 18, 2024
@Cosmo-klara Cosmo-klara changed the title Fix bug in #1690 Fix bug in #1690 Oct 18, 2024
@Chi8wah
Copy link

Chi8wah commented Oct 18, 2024

那个小数点异常切分还有一个很关键的影响是,如果把句号后面的空格切掉,会导致单词变成 xxx.yyy,这样 wordSegment 是切分不出来的,导致如果 yyy 这个单词如果比较生僻的话,大模型可能不会读这个单词(特别是如果用户想自己加特殊词的时候,特殊词不被切分就很麻烦了)。所以这个空格的保留挺重要的。

@Cosmo-klara
Copy link
Author

Cosmo-klara commented Oct 19, 2024

那个小数点异常切分还有一个很关键的影响是,如果把句号后面的空格切掉,会导致单词变成 xxx.yyy,这样 wordSegment 是切分不出来的,导致如果 yyy 这个单词如果比较生僻的话,大模型可能不会读这个单词(特别是如果用户想自己加特殊词的时候,特殊词不被切分就很麻烦了)。所以这个空格的保留挺重要的。

我没太理解你的意思(你的意思是这个bug还会引发一个问题,还是我修改中去除空格会引发问题),能请你给我提供一个测试用例吗?

@Cosmo-klara
Copy link
Author

@RVC-Boss 花佬帮我看看呗((๑Ő௰Ő๑)

@RVC-Boss
Copy link
Owner

@RVC-Boss 花佬帮我看看呗((๑Ő௰Ő๑)

我近期看看

@KamioRinn
Copy link
Contributor

这个问题主要是容易和“序号”冲突,导致“序号”后接数字变成小数点识别

@Cosmo-klara
Copy link
Author

Cosmo-klara commented Oct 27, 2024

这个问题主要是容易和“序号”冲突,导致“序号”后接数字变成小数点识别

确实哈,不过如果输入规范的话( 我觉得输入规范是用户要考虑的事情(懒比专属手动狗头)),(eg. ”1. 6 billion dollars“, 在序号后和正文有一个空格,这样在做正则的时候就能先把序号项读走,再处理后面的部分) ,还有一个问题就是我不太清楚 这样的序号项应该怎么读,是转化为序数词 First 吗?确定读法后我去加一个正则处理到 normalize_numbers 就可以了。

PS:

今天空了又看了下英文处理这块,好像还有很多的小问题,我打算去开一个 issue 修一修

  • 小数的读法

    要和 > 1 的数区分开,“0.5”这种应该读作”point five“,”0.25“=”point two five“

  • 分数的读法

    • 规则1:分子使用基数词读法,分母用序数词读法。
    • 规则2:如果分子大于 1,在读分母的时候使用序数词复数读法。
    • 规则3:当分母为 2 的时候,分母读做 half,并且当分子大于 1 的时候,half 要用复数读法,读为 halves。
    例子 读法
    1/3 one third
    3/4 three fourths
    1/2 one half
    3/2 three halves
  • 钱的读法

    • 差了 25$ 这样的形式

    • 读法矫正,”$43.25“ 貌似是读做 ”forty-three dollars and twenty-five cents“

    • 没有欧元(euros,€ )的识别

  • 计量单位的读法

    例子 读法
    60m sixty meters
    25km/h twenty-five kilometers per hour
    11ft eleven feet
    2L two liters
    3tbsp three tablespoons
    1tsp one teaspoon
    20⁰C twenty degrees
  • 一些其他的小问题

    • 之前在一个 issue 里面看到的,-20 里面对 - 没有做处理,实际上减法也没有处理

    • zero 的读音好像经常丢失前半部分,而且好像不是参考音频的问题,我测试了20个随机种子,只有一个完整读出了 zero(目标文本是 how to say zero),可惜忘了保存好的随机种子

    • 一些特殊读法的实现, 比如:

      • 零下温度 :“-20⁰C” = ”twenty degrees below zero.“

      • 电话号 :”0171 390 1062“ = ”zero one seven one, three nine zero, one zero six two“

      • 时间 :“4:13” = “Four O'Clock”

      • 街道号( 感觉不太需要就没写了 )

@KamioRinn
Copy link
Contributor

这几个数字日期时间啥的可以参考下中文的试试?

@Cosmo-klara
Copy link
Author

这几个数字日期时间啥的可以参考下中文的试试?

嗯嗯,我等下看看

@Cosmo-klara
Copy link
Author

Cosmo-klara commented Oct 31, 2024

这个问题主要是容易和“序号”冲突,导致“序号”后接数字变成小数点识别

@KamioRinn

我对中英文的序号进行了测试,中文的测试用例就不打出来了,确实在英文序号存在问题,不过如果输入规范的话 ( 就是序号的"."后加上空格 )( 我觉得输入规范是用户要考虑的事情(懒比专属手动狗头)),(eg. "1. 6 billion dollars", 在序号后和正文有一个空格,这样在做正则的时候就能先把序号项读走,再处理后面的部分)

然而, 在后面的测试中, 我发现在英文中如果使用下面的测试用例:

按照标准的英文规范进行输入,"."后存在空格

1. 6.3 hello it is a test. 2. hello it is a test.

得到的结果如下图所示:

这里已经为序号写好了对应的转化代码, 因此处理为 First

test1

定位到 TTS_infer_pack/TextPreprocessor 如下:

print 部分是添加的检查点, 显然在调用 LangSegment.setfilters(["en"]) 进行文本过滤的时候存在问题

def get_phones_and_bert(self, text: str, language: str, version: str, final: bool = False):
    # 格式化前,也就是传入的文本
    print("\n"+ "a "+text)
    if language in {"en", "all_zh", "all_ja", "all_ko", "all_yue"}:
        language = language.replace("all_", "")
        # LangSegment 的 setfilters["en"] 存在一些问题
        if language == "en":
            LangSegment.setfilters(["en"])
            formattext = " ".join(tmp["text"]
                                    for tmp in LangSegment.getTexts(text))
        else:
            # 因无法区别中日韩文汉字,以用户输入为准
            formattext = text
        # formattext = text
        while "  " in formattext:
            formattext = formattext.replace("  ", " ")
        # 格式化文本后
        print("b "+ formattext)

我想这可能是因为序号项后接数字 ( 不只是小数, "1. 6 billion dollars" 也会被吞掉前面的序号和数字) 这种不规范的输入 ( "1. 6" 或者 "1. 6") 会被过滤器直接去除, 这不太符合我们的期望.

要解决这个问题, 有两个方案:

  • 简单粗暴的去掉过滤器

    我不太清楚在这个地方调用这段代码的意义, 为了保证传进去用户的输入是纯英文吗? 但是这应该是用户的问题吧, 如果混用的话应该让用户选择混合推理吧. 既然如此, 直接去掉过滤器貌似也不是不行? 我不太清楚

    LangSegment.setfilters(["en"])
    formattext = " ".join(tmp["text"] for tmp in LangSegment.getTexts(text))
  • 在过滤前预处理被过滤器认为不规范的内容

    如果上面的暴力解决不行的话, 也可以把现在发现的问题单独处理, 比如先一步将序号项变成英文格式在过滤.

    在过滤前添加下面的代码即可:(ordinal_map是序号映射表)

    for key, value in ordinal_map.items():
                    text = re.sub(rf"{re.escape(key)}\s?", value + ", ", text)

方案效果:

  • 直接去除法

result1

  • 预处理法

result2

可以看到都符合期望输出了正确的结果。

修改代码风格和zh处理保持一致
删除了英文预处理的过滤器
添加英文序号转化
@KamioRinn
Copy link
Contributor

  1. LangSegment处理改掉问题不大,之前那么写是因为经常有人混着输入选单语言。
  2. 文字进入g2p方法前有个坑,inference_webui和inference_webui_fast的文字处理不同,@XXXXRT666 这个看看鲨佬能不能把他们统一掉(
  3. 有个建议,修改english.py的时候,对比原g2p_en新增的功能最好标注下,日后有人需要来抄作业可以比较好理解。

@Cosmo-klara
Copy link
Author

  1. LangSegment处理改掉问题不大,之前那么写是因为经常有人混着输入选单语言。
  2. 文字进入g2p方法前有个坑,inference_webui和inference_webui_fast的文字处理不同,@XXXXRT666 这个看看鲨佬能不能把他们统一掉(
  3. 有个建议,修改english.py的时候,对比原g2p_en新增的功能最好标注下,日后有人需要来抄作业可以比较好理解。
  1. OK,那我就按照删除的方法继续往后做了
  2. 到时候做完了我加点注释上去,我现在想的就是把g2p_en里面那个从一个库里面调的text_normalize()给改一改,以原先那个包的代码为基准修正和添加一些功能。(本来是想照着中文那个来做的,但是实在是代码风格不太一样,看着头大学不来)

@RVC-Boss
Copy link
Owner

RVC-Boss commented Nov 7, 2024

等你俩好消息

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants