mirror of
https://github.com/storytold/storyteller-ml.git
synced 2026-10-29 09:18:21 +00:00
Add sequencing, improvements to pipeline
This commit is contained in:
@@ -21,12 +21,14 @@ class GraphemeSquence:
|
|||||||
def __init__(self, sequence: str):
|
def __init__(self, sequence: str):
|
||||||
self.sequence = sequence
|
self.sequence = sequence
|
||||||
|
|
||||||
def parse_grapheme_and_arpabet_sequence(input_text: str) -> List[Union[ArpabetSequence, GraphemeSquence]]:
|
ParsedSequence = List[Union[ArpabetSequence, GraphemeSquence]]
|
||||||
|
|
||||||
|
def parse_grapheme_and_arpabet_sequence(input_text: str) -> ParsedSequence:
|
||||||
"""
|
"""
|
||||||
Parse a string into a list of ArpabetSequence and GraphemeSequence so that each
|
Parse a string into a list of ArpabetSequence and GraphemeSequence so that each
|
||||||
subsequence can be treated independently.
|
subsequence can be treated independently.
|
||||||
"""
|
"""
|
||||||
sequence : List[Union[ArpabetSequence, GraphemeSquence]] = []
|
sequence : ParsedSequence = []
|
||||||
|
|
||||||
# Check for curly braces and treat their contents as ARPAbet:
|
# Check for curly braces and treat their contents as ARPAbet:
|
||||||
while len(input_text):
|
while len(input_text):
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ Contents of this file are mostly from https://github.com/keithito/tacotron
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
# TODO: Don't use strings for arpabet phoneme representation, and share the memory.
|
||||||
|
|
||||||
# Relative to TTS codebase root
|
# Relative to TTS codebase root
|
||||||
# This does not include any CMUDict extensions or alternatives (eg. for other languages).
|
# This does not include any CMUDict extensions or alternatives (eg. for other languages).
|
||||||
DEFAULT_CMUDICT_PATH = 'dictionaries/cmudict-0.7b'
|
DEFAULT_CMUDICT_PATH = 'dictionaries/cmudict-0.7b'
|
||||||
|
|||||||
@@ -7,7 +7,12 @@ class EnglishPhonetization(BasePhonetization):
|
|||||||
def __init__(self, phoneme_dictionary: CMUDict):
|
def __init__(self, phoneme_dictionary: CMUDict):
|
||||||
super().__init__(phoneme_dictionary)
|
super().__init__(phoneme_dictionary)
|
||||||
|
|
||||||
def convert_to_phonemes(self, grapheme_sequence: str) -> List[str]:
|
def try_convert_to_phonemes(self, grapheme_sequence: str) -> List[str]:
|
||||||
|
"""
|
||||||
|
Attempt to enrich a grapheme sequence with phonemes where word lookup succeeds.
|
||||||
|
Grapheme symbols will be left in place.
|
||||||
|
The output list will need to be space-separated before inference.
|
||||||
|
"""
|
||||||
words = self._split_grapheme_sentence_to_words(grapheme_sequence)
|
words = self._split_grapheme_sentence_to_words(grapheme_sequence)
|
||||||
converted_words = []
|
converted_words = []
|
||||||
|
|
||||||
|
|||||||
@@ -6,27 +6,27 @@ class TestEnglishPhonetization:
|
|||||||
def test_no_input(self):
|
def test_no_input(self):
|
||||||
phoneme_dictionary = CMUDict(DEFAULT_CMUDICT_PATH)
|
phoneme_dictionary = CMUDict(DEFAULT_CMUDICT_PATH)
|
||||||
phonetization = EnglishPhonetization(phoneme_dictionary)
|
phonetization = EnglishPhonetization(phoneme_dictionary)
|
||||||
output = phonetization.convert_to_phonemes("")
|
output = phonetization.try_convert_to_phonemes("")
|
||||||
assert output == []
|
assert output == []
|
||||||
|
|
||||||
def test_all_words_in_dictionary(self):
|
def test_all_words_in_dictionary(self):
|
||||||
phoneme_dictionary = CMUDict(DEFAULT_CMUDICT_PATH)
|
phoneme_dictionary = CMUDict(DEFAULT_CMUDICT_PATH)
|
||||||
phonetization = EnglishPhonetization(phoneme_dictionary)
|
phonetization = EnglishPhonetization(phoneme_dictionary)
|
||||||
output = phonetization.convert_to_phonemes("this is a test")
|
output = phonetization.try_convert_to_phonemes("this is a test")
|
||||||
assert output == ["DH IH1 S", "IH1 Z", "AH0", "T EH1 S T"]
|
assert output == ["DH IH1 S", "IH1 Z", "AH0", "T EH1 S T"]
|
||||||
|
|
||||||
def test_most_words_in_dictionary(self):
|
def test_most_words_in_dictionary(self):
|
||||||
phoneme_dictionary = CMUDict(DEFAULT_CMUDICT_PATH)
|
phoneme_dictionary = CMUDict(DEFAULT_CMUDICT_PATH)
|
||||||
phonetization = EnglishPhonetization(phoneme_dictionary)
|
phonetization = EnglishPhonetization(phoneme_dictionary)
|
||||||
output = phonetization.convert_to_phonemes("nonword is a test")
|
output = phonetization.try_convert_to_phonemes("nonword is a test")
|
||||||
assert output == ["nonword", "IH1 Z", "AH0", "T EH1 S T"]
|
assert output == ["nonword", "IH1 Z", "AH0", "T EH1 S T"]
|
||||||
|
|
||||||
def test_punctuation(self):
|
def test_punctuation(self):
|
||||||
phoneme_dictionary = CMUDict(DEFAULT_CMUDICT_PATH)
|
phoneme_dictionary = CMUDict(DEFAULT_CMUDICT_PATH)
|
||||||
phonetization = EnglishPhonetization(phoneme_dictionary)
|
phonetization = EnglishPhonetization(phoneme_dictionary)
|
||||||
output = phonetization.convert_to_phonemes("this...")
|
output = phonetization.try_convert_to_phonemes("this...")
|
||||||
assert output == ["DH IH1 S", "..."]
|
assert output == ["DH IH1 S", "..."]
|
||||||
output = phonetization.convert_to_phonemes("this!")
|
output = phonetization.try_convert_to_phonemes("this!")
|
||||||
assert output == ["DH IH1 S", "!"]
|
assert output == ["DH IH1 S", "!"]
|
||||||
output = phonetization.convert_to_phonemes("this?")
|
output = phonetization.try_convert_to_phonemes("this?")
|
||||||
assert output == ["DH IH1 S", "?"]
|
assert output == ["DH IH1 S", "?"]
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
from enum import Enum, auto
|
|
||||||
|
|
||||||
from tts.text.input_parsing.parser import GraphemeSquence, parse_grapheme_and_arpabet_sequence
|
|
||||||
from tts.text.normalization.english_normalization import EnglishNormalization
|
|
||||||
from tts.text.normalization.spanish_normalization import SpanishNormalization
|
|
||||||
|
|
||||||
|
|
||||||
class PipelineType(Enum):
|
|
||||||
LEGACY_FAKEYOU = auto()
|
|
||||||
ENGLISH_FORCED_ARPABET_V1 = auto()
|
|
||||||
SPANISH_FORCED_ARPABET_V1 = auto()
|
|
||||||
|
|
||||||
_ENGLISH_NORMALIZER = EnglishNormalization()
|
|
||||||
_SPANISH_NORMALIZER = SpanishNormalization()
|
|
||||||
|
|
||||||
def _legacy_fakeyou_pipeline(input_text):
|
|
||||||
"""
|
|
||||||
Legacy FakeYou.com did not do Grapheme -> Arpabet conversions automatically.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def _english_forced_arpabet_v1(input_text):
|
|
||||||
parsed_sequence = parse_grapheme_and_arpabet_sequence(input_text)
|
|
||||||
for i in range(len(parsed_sequence)):
|
|
||||||
subsequence = parsed_sequence[i]
|
|
||||||
if isinstance(subsequence, GraphemeSquence):
|
|
||||||
normalized = _ENGLISH_NORMALIZER.normalize(subsequence.sequence)
|
|
||||||
parsed_sequence[i] = GraphemeSquence(normalized)
|
|
||||||
|
|
||||||
integer_sequence = []
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _spanish_forced_arpabet_v1(input_text):
|
|
||||||
parsed_sequence = parse_grapheme_and_arpabet_sequence(input_text)
|
|
||||||
|
|
||||||
|
|
||||||
def text_to_sequence(input_text: str, pipeline_type: PipelineType):
|
|
||||||
if pipeline_type == PipelineType.ENGLISH_FORCED_ARPABET_V1:
|
|
||||||
return _english_forced_arpabet_v1(input_text)
|
|
||||||
elif pipeline_type == PipelineType.SPANISH_FORCED_ARPABET_V1:
|
|
||||||
return _spanish_forced_arpabet_v1(input_text)
|
|
||||||
else:
|
|
||||||
return _legacy_fakeyou_pipeline(input_text)
|
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
|
class BasePipeline:
|
||||||
|
|
||||||
|
def user_input_to_sequence(self, input_text: str) -> List[int]:
|
||||||
|
"""Convert raw user input into a numerical sequence for ML inference."""
|
||||||
|
return []
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
from typing import List
|
||||||
|
from tts.text.input_parsing.parser import GraphemeSquence, ParsedSequence, parse_grapheme_and_arpabet_sequence
|
||||||
|
from tts.text.normalization.english_normalization import EnglishNormalization
|
||||||
|
from tts.text.phonetization.cmudict import CMUDict
|
||||||
|
from tts.text.phonetization.english_phonetization import EnglishPhonetization
|
||||||
|
from tts.text.pipeline.base_pipeline import BasePipeline
|
||||||
|
|
||||||
|
_ENGLISH_NORMALIZER = EnglishNormalization()
|
||||||
|
|
||||||
|
_ENGLISH_DICTIONARY = CMUDict()
|
||||||
|
_ENGLISH_PHONETIZER = EnglishPhonetization(_ENGLISH_DICTIONARY)
|
||||||
|
|
||||||
|
class EnglishPipelineV1(BasePipeline):
|
||||||
|
|
||||||
|
def user_input_to_sequence(self, input_text: str) -> List[int]:
|
||||||
|
"""Convert raw user input into a numerical sequence for ML inference."""
|
||||||
|
|
||||||
|
parsed_sequence = parse_grapheme_and_arpabet_sequence(input_text)
|
||||||
|
|
||||||
|
self._normalize_graphemes(parsed_sequence)
|
||||||
|
self._convert_phonemes(parsed_sequence)
|
||||||
|
|
||||||
|
|
||||||
|
integer_sequence = []
|
||||||
|
|
||||||
|
return integer_sequence
|
||||||
|
|
||||||
|
def _normalize_graphemes(self, parsed_sequence: ParsedSequence):
|
||||||
|
for i in range(len(parsed_sequence)):
|
||||||
|
subsequence = parsed_sequence[i]
|
||||||
|
if isinstance(subsequence, GraphemeSquence):
|
||||||
|
normalized = _ENGLISH_NORMALIZER.normalize(subsequence.sequence)
|
||||||
|
parsed_sequence[i] = GraphemeSquence(normalized)
|
||||||
|
|
||||||
|
|
||||||
|
def _convert_phonemes(self, parsed_sequence: ParsedSequence):
|
||||||
|
for i in range(len(parsed_sequence)):
|
||||||
|
subsequence = parsed_sequence[i]
|
||||||
|
if isinstance(subsequence, GraphemeSquence):
|
||||||
|
converted = _ENGLISH_PHONETIZER.try_convert_to_phonemes(subsequence.sequence)
|
||||||
|
converted = ' '.join(converted)
|
||||||
|
parsed_sequence[i] = GraphemeSquence(converted)
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
"""Adapted 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 tts.text.phonetization import cmudict
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
_pad = '_'
|
||||||
|
_punctuation = '!\'(),.:;? ' #NB: Includes space
|
||||||
|
_special = '-'
|
||||||
|
_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 = [_pad] + list(_special) + list(_punctuation) + list(_letters) + _arpabet
|
||||||
|
|
||||||
|
# Mappings from symbol to numeric ID and vice versa:
|
||||||
|
# The ordering **CANNOT** change.
|
||||||
|
_symbol_to_id = {s: i for i, s in enumerate(symbols)}
|
||||||
|
_id_to_symbol = {i: s for i, s in enumerate(symbols)}
|
||||||
|
|
||||||
|
|
||||||
|
def symbols_to_sequence(symbols: str) -> List[int]:
|
||||||
|
return [_symbol_to_id[s] for s in symbols if _should_keep_symbol(s)]
|
||||||
|
|
||||||
|
|
||||||
|
def arpabet_to_sequence(arpabet_string: str) -> List[int]:
|
||||||
|
return symbols_to_sequence(['@' + s for s in arpabet_string.split()])
|
||||||
|
|
||||||
|
|
||||||
|
def _should_keep_symbol(s):
|
||||||
|
return s in _symbol_to_id and s is not '_' and s is not '~'
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
from tts.text.sequencing.english_symbols_v1 import arpabet_to_sequence, symbols_to_sequence
|
||||||
|
|
||||||
|
class TestEnglishSymbols:
|
||||||
|
|
||||||
|
def test_no_input_arpabet(self):
|
||||||
|
output = arpabet_to_sequence('')
|
||||||
|
assert output == []
|
||||||
|
|
||||||
|
def test_no_input_symbols(self):
|
||||||
|
output = symbols_to_sequence('')
|
||||||
|
assert output == []
|
||||||
|
|
||||||
|
def test_arpabet_word(self):
|
||||||
|
output = arpabet_to_sequence('T EH1 S T')
|
||||||
|
assert output == [133, 94, 131, 133]
|
||||||
|
|
||||||
|
def test_grapheme_word(self):
|
||||||
|
output = symbols_to_sequence('test')
|
||||||
|
assert output == [57, 42, 56, 57]
|
||||||
Reference in New Issue
Block a user