ecker commited on
Commit
96e9acd
·
1 Parent(s): 9c0e466

added preparation of LJSpeech-esque dataset

Browse files
Files changed (5) hide show
  1. README.md +3 -20
  2. requirements.txt +5 -3
  3. src/utils.py +54 -6
  4. src/webui.py +20 -2
  5. train.ipynb +1 -1
README.md CHANGED
@@ -1,14 +1,12 @@
1
  # AI Voice Cloning
2
 
3
- This [repo](https://git.ecker.tech/mrq/ai-voice-cloning)/[rentry](https://rentry.org/AI-Voice-Cloning/) aims to serve as both a foolproof guide for setting up AI voice cloning tools for legitimate, local use on Windows, as well as a stepping stone for anons that genuinely want to play around with [TorToiSe](https://github.com/neonbjb/tortoise-tts).
4
 
5
  Similar to my own findings for Stable Diffusion image generation, this rentry may appear a little disheveled as I note my new findings with TorToiSe. Please keep this in mind if the guide seems to shift a bit or sound confusing.
6
 
7
  >\>Ugh... why bother when I can just abuse 11.AI?
8
 
9
- I very much encourage (You) to use 11.AI while it's still viable to use. For the layman, it's easier to go through the hoops of coughing up the $5 or abusing the free trial over actually setting up a TorToiSe environment and dealing with its quirks.
10
-
11
- However, I also encourage your own experimentation with TorToiSe, as it's very, very promising, it just takes a little love and elbow grease.
12
 
13
  This is not endorsed by [neonbjb](https://github.com/neonbjb/). I do not expect this to run into any ethical issues, as it seems (like me), this is mostly for making funny haha vidya characters say funny lines.
14
 
@@ -302,19 +300,4 @@ I think this also highlights how just combining your entire source sample gung-h
302
  Output (`Is that really you, Mary?`, Ultra Fast preset, settings and latents embedded)
303
  * https://files.catbox.moe/gy1jvz.wav
304
 
305
- This was just a quick test for an adjustable setting, but this one turned out really nice (for being a quick test) on the off chance. It's not the original delivery, and it definitely sounds robotic still, but it's on the Ultra Fast preset, as expected.
306
-
307
- ## Caveats (and Upsides)
308
-
309
- To me, I find a few problems with TorToiSe over 11.AI:
310
- * computation time is quite an issue. Despite Stable Diffusion proving to be adequate on my 2060, TorToiSe takes quite some time with modest settings.
311
- - However, on my 6800XT, performance was drastically uplifted due to having more VRAM for larger batch sizes (at the cost of Krashing).
312
- * reproducability in a voice depends on the "compatibilty" with the model TorToiSe was trained on.
313
- - However, this also appears to be similar to 11.AI, where it was mostly trained on audiobook readings.
314
- * the lack of an obvious analog to the "stability" and "similarity" sliders kind of sucks, but it's not the end of the world.
315
- However, the `temperature` option seems to prove to be a proper analog to either of these.
316
-
317
- Although, I can look past these as TorToiSe offers, in comparison to 11.AI:
318
- * the "speaking too fast" issue does not exist with TorToiSe. I don't need to fight with it by pretending I'm a Gaia user in the early 2000s by sprinkling ellipses.
319
- * the overall delivery seems very natural, sometimes small, dramatic pauses gets added at the legitimately most convenient moments, and the inhales tend to be more natural. Many of vocaroos from 11.AI where it just does not seem properly delivered.
320
- * being able to run it locally means I do not have to worry about some Polack seeing me use the "dick" word.
 
1
  # AI Voice Cloning
2
 
3
+ This [repo](https://git.ecker.tech/mrq/ai-voice-cloning)/[rentry](https://rentry.org/AI-Voice-Cloning/) aims to serve as both a foolproof guide for setting up AI voice cloning tools for legitimate, local use on Windows/Linux, as well as a stepping stone for anons that genuinely want to play around with [TorToiSe](https://github.com/neonbjb/tortoise-tts).
4
 
5
  Similar to my own findings for Stable Diffusion image generation, this rentry may appear a little disheveled as I note my new findings with TorToiSe. Please keep this in mind if the guide seems to shift a bit or sound confusing.
6
 
7
  >\>Ugh... why bother when I can just abuse 11.AI?
8
 
9
+ You're more than welcome to, but TorToiSe is shaping up to be a very promising tool, especially with finetuning now on the horizon.
 
 
10
 
11
  This is not endorsed by [neonbjb](https://github.com/neonbjb/). I do not expect this to run into any ethical issues, as it seems (like me), this is mostly for making funny haha vidya characters say funny lines.
12
 
 
300
  Output (`Is that really you, Mary?`, Ultra Fast preset, settings and latents embedded)
301
  * https://files.catbox.moe/gy1jvz.wav
302
 
303
+ This was just a quick test for an adjustable setting, but this one turned out really nice (for being a quick test) on the off chance. It's not the original delivery, and it definitely sounds robotic still, but it's on the Ultra Fast preset, as expected.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,7 +1,9 @@
1
  git+https://git.ecker.tech/mrq/tortoise-tts.git
2
  # git+https://git.ecker.tech/mrq/DL-Art-School.git
3
-
4
- whisper
 
5
  gradio
6
  music-tag
7
- voicefixer
 
 
1
  git+https://git.ecker.tech/mrq/tortoise-tts.git
2
  # git+https://git.ecker.tech/mrq/DL-Art-School.git
3
+ git+https://github.com/openai/whisper.git
4
+ more-itertools
5
+ ffmpeg-python
6
  gradio
7
  music-tag
8
+ voicefixer
9
+ psutil
src/utils.py CHANGED
@@ -29,12 +29,12 @@ from tortoise.utils.audio import load_audio, load_voice, load_voices, get_voice_
29
  from tortoise.utils.text import split_and_recombine_text
30
  from tortoise.utils.device import get_device_name, set_device_name
31
 
 
32
 
33
  args = None
34
  tts = None
35
  webui = None
36
  voicefixer = None
37
- whisper = None
38
  dlas = None
39
 
40
  def get_args():
@@ -108,6 +108,13 @@ def setup_args():
108
 
109
  return args
110
 
 
 
 
 
 
 
 
111
  def generate(
112
  text,
113
  delimiter,
@@ -253,11 +260,8 @@ def generate(
253
  idx = keys[-1] + 1
254
 
255
  # I know there's something to pad I don't care
256
- pad = ""
257
- for i in range(4,0,-1):
258
- if idx < 10 ** i:
259
- pad = f"{pad}0"
260
- idx = f"{pad}{idx}"
261
 
262
  def get_name(line=0, candidate=0, combined=False):
263
  name = f"{idx}"
@@ -455,6 +459,50 @@ def save_training_settings( batch_size=None, learning_rate=None, print_rate=None
455
  with open(f'./training/{settings["name"]}.yaml', 'w', encoding="utf-8") as f:
456
  f.write(yaml)
457
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  def reset_generation_settings():
459
  with open(f'./config/generate.json', 'w', encoding="utf-8") as f:
460
  f.write(json.dumps({}, indent='\t') )
 
29
  from tortoise.utils.text import split_and_recombine_text
30
  from tortoise.utils.device import get_device_name, set_device_name
31
 
32
+ import whisper
33
 
34
  args = None
35
  tts = None
36
  webui = None
37
  voicefixer = None
 
38
  dlas = None
39
 
40
  def get_args():
 
108
 
109
  return args
110
 
111
+ def pad(num, zeroes):
112
+ s = ""
113
+ for i in range(zeroes,0,-1):
114
+ if num < 10 ** i:
115
+ s = f"{s}0"
116
+ return f"{s}{num}"
117
+
118
  def generate(
119
  text,
120
  delimiter,
 
260
  idx = keys[-1] + 1
261
 
262
  # I know there's something to pad I don't care
263
+
264
+ idx = pad(idx, 4)
 
 
 
265
 
266
  def get_name(line=0, candidate=0, combined=False):
267
  name = f"{idx}"
 
459
  with open(f'./training/{settings["name"]}.yaml', 'w', encoding="utf-8") as f:
460
  f.write(yaml)
461
 
462
+ whisper_model = None
463
+ def prepare_dataset( files, outdir ):
464
+ global whisper_model
465
+ if whisper_model is None:
466
+ whisper_model = whisper.load_model("base")
467
+
468
+ os.makedirs(outdir, exist_ok=True)
469
+
470
+ idx = 0
471
+ results = {}
472
+
473
+ for file in files:
474
+ print(f"Transcribing file: {file}")
475
+
476
+ result = whisper_model.transcribe(file)
477
+ results[os.path.basename(file)] = result
478
+
479
+ print(f"Transcribed file: {file}, {len(result['segments'])} found.")
480
+
481
+ waveform, sampling_rate = torchaudio.load(file)
482
+ num_channels, num_frames = waveform.shape
483
+
484
+ transcription = []
485
+ for segment in result['segments']:
486
+ start = int(segment['start'] * sampling_rate)-1
487
+ end = int(segment['end'] * sampling_rate)+1
488
+
489
+ print(segment['start'], segment['end'])
490
+ print(start, end)
491
+
492
+ sliced_waveform = waveform[:, start:end]
493
+ sliced_name = f"{pad(idx, 4)}.wav"
494
+
495
+ torchaudio.save(f"{outdir}/{sliced_name}", sliced_waveform, sampling_rate)
496
+
497
+ transcription.append(f"{sliced_name}|{segment['text'].trim()}")
498
+ idx = idx + 1
499
+
500
+ with open(f'{outdir}/whisper.json', 'w', encoding="utf-8") as f:
501
+ f.write(json.dumps(results, indent='\t'))
502
+
503
+ with open(f'{outdir}/train.txt', 'w', encoding="utf-8") as f:
504
+ f.write("\n".join(transcription))
505
+
506
  def reset_generation_settings():
507
  with open(f'./config/generate.json', 'w', encoding="utf-8") as f:
508
  f.write(json.dumps({}, indent='\t') )
src/webui.py CHANGED
@@ -15,7 +15,7 @@ import gradio.utils
15
  from datetime import datetime
16
 
17
  import tortoise.api
18
- from tortoise.utils.audio import get_voice_dir
19
 
20
  from utils import *
21
 
@@ -370,8 +370,24 @@ def setup_gradio():
370
  ]
371
  )
372
  with gr.Tab("Training"):
373
- with gr.Tab("Configuration"):
374
  with gr.Row():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
  with gr.Column():
376
  training_settings = [
377
  gr.Slider(label="Batch Size", value=128),
@@ -452,6 +468,7 @@ def setup_gradio():
452
  # YUCK
453
  def update_voices():
454
  return (
 
455
  gr.Dropdown.update(choices=get_voice_list()),
456
  gr.Dropdown.update(choices=get_voice_list("./results/")),
457
  )
@@ -463,6 +480,7 @@ def setup_gradio():
463
  inputs=None,
464
  outputs=[
465
  voice,
 
466
  history_voices
467
  ]
468
  )
 
15
  from datetime import datetime
16
 
17
  import tortoise.api
18
+ from tortoise.utils.audio import get_voice_dir, get_voices
19
 
20
  from utils import *
21
 
 
370
  ]
371
  )
372
  with gr.Tab("Training"):
 
373
  with gr.Row():
374
+ with gr.Column():
375
+ dataset_settings = [
376
+ gr.Dropdown( get_voice_list(), label="Dataset Source", type="value" ),
377
+ ]
378
+ dataset_voices = dataset_settings[0]
379
+
380
+ prepare_dataset_button = gr.Button(value="Prepare")
381
+
382
+ def prepare_dataset_proxy( voice ):
383
+ return prepare_dataset( get_voices(load_latents=False)[voice], outdir=f"./training/{voice}/" )
384
+
385
+ prepare_dataset_button.click(
386
+ prepare_dataset_proxy,
387
+ inputs=dataset_settings,
388
+ outputs=None
389
+ )
390
+
391
  with gr.Column():
392
  training_settings = [
393
  gr.Slider(label="Batch Size", value=128),
 
468
  # YUCK
469
  def update_voices():
470
  return (
471
+ gr.Dropdown.update(choices=get_voice_list()),
472
  gr.Dropdown.update(choices=get_voice_list()),
473
  gr.Dropdown.update(choices=get_voice_list("./results/")),
474
  )
 
480
  inputs=None,
481
  outputs=[
482
  voice,
483
+ dataset_voices,
484
  history_voices
485
  ]
486
  )
train.ipynb CHANGED
@@ -31,6 +31,7 @@
31
  "source":[
32
  "!git clone https://git.ecker.tech/mrq/DL-Art-School\n",
33
  "%cd DL-Art-School\n",
 
34
  "!pip install -r requirements.txt"
35
  ]
36
  },
@@ -40,7 +41,6 @@
40
  "from google.colab import drive\n",
41
  "drive.mount('/content/drive')",
42
  "%cd /content/DL-Art-School/\n",
43
- "#!rm -r experiments\n",
44
  "!ln -s /content/drive/MyDrive/experiments/\n",
45
  ],
46
  "metadata":{
 
31
  "source":[
32
  "!git clone https://git.ecker.tech/mrq/DL-Art-School\n",
33
  "%cd DL-Art-School\n",
34
+ "!rm -r experiments\n",
35
  "!pip install -r requirements.txt"
36
  ]
37
  },
 
41
  "from google.colab import drive\n",
42
  "drive.mount('/content/drive')",
43
  "%cd /content/DL-Art-School/\n",
 
44
  "!ln -s /content/drive/MyDrive/experiments/\n",
45
  ],
46
  "metadata":{