Spaces:
Runtime error
Runtime error
lhzstar
commited on
Commit
·
6bc94ac
0
Parent(s):
initial commits
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .github/workflows/main.yml +20 -0
- .gitignore +24 -0
- Dockerfile +31 -0
- README.md +13 -0
- app.py +122 -0
- celebbot.py +150 -0
- data.json +290 -0
- gen_embeds.py +124 -0
- requirements.txt +31 -0
- rtvc/.gitattributes +1 -0
- rtvc/.gitignore +27 -0
- rtvc/CHANGELOG.md +18 -0
- rtvc/LICENSE.md +24 -0
- rtvc/README.md +132 -0
- rtvc/css/bootstrap.min.css +0 -0
- rtvc/css/custom.css +196 -0
- rtvc/css/normalize.css +427 -0
- rtvc/css/skeleton.css +418 -0
- rtvc/demo_cli.py +330 -0
- rtvc/demo_results/text1/1688-142285-0000_syn.wav +0 -0
- rtvc/demo_results/text1/260-123286-0000_syn.wav +0 -0
- rtvc/demo_results/text1/4294-9934-0000_syn.wav +0 -0
- rtvc/demo_results/text1/7176-88083-0000_syn.wav +0 -0
- rtvc/demo_results/text1/README.md +1 -0
- rtvc/demo_results/text2/1688-142285-0000_syn.wav +0 -0
- rtvc/demo_results/text2/260-123286-0000_syn.wav +0 -0
- rtvc/demo_results/text2/4294-9934-0000_syn.wav +0 -0
- rtvc/demo_results/text2/7176-88083-0000_syn.wav +0 -0
- rtvc/demo_results/text2/README.md +1 -0
- rtvc/demo_results/text3/1688-142285-0000_syn.wav +0 -0
- rtvc/demo_results/text3/260-123286-0000_syn.wav +0 -0
- rtvc/demo_results/text3/4294-9934-0000_syn.wav +0 -0
- rtvc/demo_results/text3/7176-88083-0000_syn.wav +0 -0
- rtvc/demo_results/text3/README.md +1 -0
- rtvc/demo_toolbox.py +41 -0
- rtvc/docs/images/audio_icon.png +0 -0
- rtvc/docs/images/voice_cloning_arch.png +0 -0
- rtvc/encoder/__init__.py +0 -0
- rtvc/encoder/audio.py +136 -0
- rtvc/encoder/config.py +45 -0
- rtvc/encoder/data_objects/__init__.py +2 -0
- rtvc/encoder/data_objects/random_cycler.py +37 -0
- rtvc/encoder/data_objects/speaker.py +40 -0
- rtvc/encoder/data_objects/speaker_batch.py +13 -0
- rtvc/encoder/data_objects/speaker_verification_dataset.py +76 -0
- rtvc/encoder/data_objects/utterance.py +29 -0
- rtvc/encoder/data_objects/utterance_batch.py +10 -0
- rtvc/encoder/inference.py +178 -0
- rtvc/encoder/model.py +135 -0
- rtvc/encoder/params_data.py +34 -0
.github/workflows/main.yml
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Sync to Hugging Face hub
|
2 |
+
on:
|
3 |
+
push:
|
4 |
+
branches: [main]
|
5 |
+
|
6 |
+
# to run this workflow manually from the Actions tab
|
7 |
+
workflow_dispatch:
|
8 |
+
|
9 |
+
jobs:
|
10 |
+
sync-to-hub:
|
11 |
+
runs-on: ubuntu-latest
|
12 |
+
steps:
|
13 |
+
- uses: actions/checkout@v3
|
14 |
+
with:
|
15 |
+
fetch-depth: 0
|
16 |
+
lfs: true
|
17 |
+
- name: Push to hub
|
18 |
+
env:
|
19 |
+
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
20 |
+
run: git push --force https://liuhaozhe6788:[email protected]/spaces/liuhaozhe6788/CelebChat main
|
.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
launch.json
|
2 |
+
*.pyc
|
3 |
+
*.aux
|
4 |
+
*.log
|
5 |
+
*.out
|
6 |
+
*.synctex.gz
|
7 |
+
*.suo
|
8 |
+
*__pycache__
|
9 |
+
*.idea
|
10 |
+
*.ipynb_checkpoints
|
11 |
+
*.pickle
|
12 |
+
*.npy
|
13 |
+
*.bz2
|
14 |
+
*.blg
|
15 |
+
*.bbl
|
16 |
+
*.bcf
|
17 |
+
*.toc
|
18 |
+
*.sh
|
19 |
+
*.pt
|
20 |
+
*.whl
|
21 |
+
*.m4a
|
22 |
+
*.csv
|
23 |
+
input_audios/
|
24 |
+
syn_results/
|
Dockerfile
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.9
|
2 |
+
|
3 |
+
WORKDIR /code
|
4 |
+
# Install ffmpeg, git and other dependencies for Whisper
|
5 |
+
RUN apt-get update && apt-get install -y \
|
6 |
+
build-essential \
|
7 |
+
ffmpeg \
|
8 |
+
git \
|
9 |
+
libsndfile1 \
|
10 |
+
software-properties-common \
|
11 |
+
&& rm -rf /var/lib/apt/lists/*
|
12 |
+
# Update pip and install dependencies
|
13 |
+
RUN pip install --upgrade pip
|
14 |
+
COPY ./requirements.txt /code/requirements.txt
|
15 |
+
|
16 |
+
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
17 |
+
|
18 |
+
RUN useradd -m -u 1000 user
|
19 |
+
|
20 |
+
USER user
|
21 |
+
|
22 |
+
ENV HOME=/home/user \
|
23 |
+
PATH=/home/user/.local/bin:$PATH
|
24 |
+
|
25 |
+
WORKDIR $HOME/app
|
26 |
+
|
27 |
+
COPY --chown=user . $HOME/app
|
28 |
+
|
29 |
+
# Launch app when container is run
|
30 |
+
CMD ["streamlit", "run", "app.py", "--server.port", "7860", "--server.address", "0.0.0.0"]
|
31 |
+
|
README.md
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: Img2txt App
|
3 |
+
emoji: 🌍
|
4 |
+
colorFrom: blue
|
5 |
+
colorTo: green
|
6 |
+
sdk: streamlit
|
7 |
+
sdk_version: 1.27.2
|
8 |
+
app_file: app.py
|
9 |
+
pinned: false
|
10 |
+
license: apache-2.0
|
11 |
+
---
|
12 |
+
|
13 |
+
# CelebChat
|
app.py
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from celebbot import CelebBot
|
2 |
+
import streamlit as st
|
3 |
+
import re
|
4 |
+
import spacy
|
5 |
+
import json
|
6 |
+
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, AutoModel
|
7 |
+
from utils import *
|
8 |
+
|
9 |
+
|
10 |
+
@st.cache_resource
|
11 |
+
def get_seq2seq_model(model_id):
|
12 |
+
return AutoModelForSeq2SeqLM.from_pretrained(model_id)
|
13 |
+
|
14 |
+
@st.cache_resource
|
15 |
+
def get_auto_model(model_id):
|
16 |
+
return AutoModel.from_pretrained(model_id)
|
17 |
+
|
18 |
+
@st.cache_resource
|
19 |
+
def get_tokenizer(model_id):
|
20 |
+
return AutoTokenizer.from_pretrained(model_id)
|
21 |
+
|
22 |
+
@st.cache_data
|
23 |
+
def get_celeb_data(fpath):
|
24 |
+
with open(fpath) as json_file:
|
25 |
+
return json.load(json_file)
|
26 |
+
|
27 |
+
@st.cache_resource
|
28 |
+
def preprocess_text(name, gender, text, model_id):
|
29 |
+
lname = name.split(" ")[-1]
|
30 |
+
lname_regex = re.compile(rf'\b({lname})\b')
|
31 |
+
name_regex = re.compile(rf'\b({name})\b')
|
32 |
+
lnames = lname+"’s" if not lname.endswith("s") else lname+"’"
|
33 |
+
lnames_regex = re.compile(rf'\b({lnames})\b')
|
34 |
+
names = name+"’s" if not name.endswith("s") else name+"’"
|
35 |
+
names_regex = re.compile(rf'\b({names})\b')
|
36 |
+
if gender == "M":
|
37 |
+
text = re.sub(he_regex, "I", text)
|
38 |
+
text = re.sub(his_regex, "my", text)
|
39 |
+
elif gender == "F":
|
40 |
+
text = re.sub(she_regex, "I", text)
|
41 |
+
text = re.sub(her_regex, "my", text)
|
42 |
+
text = re.sub(names_regex, "my", text)
|
43 |
+
text = re.sub(lnames_regex, "my", text)
|
44 |
+
text = re.sub(name_regex, "I", text)
|
45 |
+
text = re.sub(lname_regex, "I", text)
|
46 |
+
spacy_model = spacy.load(model_id)
|
47 |
+
texts = [i.text.strip() for i in spacy_model(text).sents]
|
48 |
+
return spacy_model, texts
|
49 |
+
|
50 |
+
def main():
|
51 |
+
hide_footer()
|
52 |
+
if "messages" not in st.session_state:
|
53 |
+
st.session_state["messages"] = []
|
54 |
+
if "QA_model_path" not in st.session_state:
|
55 |
+
st.session_state["QA_model_path"] = "google/flan-t5-base"
|
56 |
+
if "sentTr_model_path" not in st.session_state:
|
57 |
+
st.session_state["sentTr_model_path"] = "sentence-transformers/all-mpnet-base-v2"
|
58 |
+
if "start_chat" not in st.session_state:
|
59 |
+
st.session_state["start_chat"] = False
|
60 |
+
|
61 |
+
|
62 |
+
model_list = ["base", "large", "xl", "xxl"]
|
63 |
+
|
64 |
+
for message in st.session_state["messages"]:
|
65 |
+
with st.chat_message(message["role"]):
|
66 |
+
st.markdown(message["content"])
|
67 |
+
|
68 |
+
celeb_data = get_celeb_data(f'data.json')
|
69 |
+
|
70 |
+
# Create a Form Component on the Sidebar for accepting input data and parameters
|
71 |
+
celeb_name = st.sidebar.selectbox('Choose a celebrity', options=list(celeb_data.keys()))
|
72 |
+
celeb_gender = celeb_data[celeb_name]["gender"]
|
73 |
+
knowledge = celeb_data[celeb_name]["knowledge"]
|
74 |
+
model_choice = st.sidebar.selectbox("Choose Your Flan-T5 model",options=model_list)
|
75 |
+
st.session_state["QA_model_path"] = f"google/flan-t5-{model_choice}"
|
76 |
+
|
77 |
+
# submitted = st.form_submit_button(label="Start Chatting")
|
78 |
+
# if submitted:
|
79 |
+
# st.session_state["start_chat"] = True
|
80 |
+
|
81 |
+
|
82 |
+
# if st.session_state["start_chat"]:
|
83 |
+
|
84 |
+
celeb_bot = CelebBot(celeb_name,
|
85 |
+
get_tokenizer(st.session_state["QA_model_path"]),
|
86 |
+
get_seq2seq_model(st.session_state["QA_model_path"]),
|
87 |
+
get_tokenizer(st.session_state["sentTr_model_path"]),
|
88 |
+
get_auto_model(st.session_state["sentTr_model_path"]),
|
89 |
+
*preprocess_text(celeb_name, celeb_gender, knowledge, "en_core_web_sm")
|
90 |
+
)
|
91 |
+
|
92 |
+
prompt = st.chat_input("Say something")
|
93 |
+
print(prompt)
|
94 |
+
if prompt:
|
95 |
+
celeb_bot.text = prompt
|
96 |
+
# Display user message in chat message container
|
97 |
+
st.chat_message("user").markdown(prompt)
|
98 |
+
# Add user message to chat history
|
99 |
+
st.session_state["messages"].append({"role": "user", "content": prompt})
|
100 |
+
|
101 |
+
# Add assistant response to chat history
|
102 |
+
response = celeb_bot.question_answer()
|
103 |
+
|
104 |
+
# disable autoplay to play in HTML
|
105 |
+
b64 = celeb_bot.text_to_speech(autoplay=False)
|
106 |
+
md = f"""
|
107 |
+
<p>{response}</p>
|
108 |
+
<audio controls autoplay style="display:none;">
|
109 |
+
<source src="data:audio/wav;base64,{b64}" type="audio/wav">
|
110 |
+
Your browser does not support the audio element.
|
111 |
+
</audio>
|
112 |
+
"""
|
113 |
+
st.chat_message("assistant").markdown(
|
114 |
+
md,
|
115 |
+
unsafe_allow_html=True,
|
116 |
+
)
|
117 |
+
# Display assistant response in chat message container
|
118 |
+
st.session_state["messages"].append({"role": "assistant", "content": response})
|
119 |
+
|
120 |
+
|
121 |
+
if __name__ == "__main__":
|
122 |
+
main()
|
celebbot.py
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import datetime
|
2 |
+
import numpy as np
|
3 |
+
import torch
|
4 |
+
import torch.nn.functional as F
|
5 |
+
import os
|
6 |
+
import json
|
7 |
+
import speech_recognition as sr
|
8 |
+
import re
|
9 |
+
import time
|
10 |
+
import spacy
|
11 |
+
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, AutoModel
|
12 |
+
import pickle
|
13 |
+
import streamlit as st
|
14 |
+
from sklearn.metrics.pairwise import cosine_similarity
|
15 |
+
import run_tts
|
16 |
+
|
17 |
+
# Build the AI
|
18 |
+
class CelebBot():
|
19 |
+
def __init__(self, name, QA_tokenizer, QA_model, sentTr_tokenizer, sentTr_model, spacy_model, knowledge_sents):
|
20 |
+
self.name = name
|
21 |
+
print("--- starting up", self.name, "---")
|
22 |
+
self.text = ""
|
23 |
+
self.QA_tokenizer = QA_tokenizer
|
24 |
+
self.QA_model = QA_model
|
25 |
+
|
26 |
+
self.sentTr_tokenizer = sentTr_tokenizer
|
27 |
+
self.sentTr_model = sentTr_model
|
28 |
+
self.spacy_model = spacy_model
|
29 |
+
|
30 |
+
self.all_knowledge = knowledge_sents
|
31 |
+
|
32 |
+
@st.cache_resource
|
33 |
+
def get_seq2seq_model(self, _model_id):
|
34 |
+
return AutoModelForSeq2SeqLM.from_pretrained(_model_id)
|
35 |
+
|
36 |
+
@st.cache_resource
|
37 |
+
def get_model(self,_model_id):
|
38 |
+
return AutoModel.from_pretrained(_model_id)
|
39 |
+
|
40 |
+
@st.cache_resource
|
41 |
+
def get_tokenizer(self,_model_id):
|
42 |
+
return AutoTokenizer.from_pretrained(_model_id)
|
43 |
+
|
44 |
+
def speech_to_text(self):
|
45 |
+
recognizer = sr.Recognizer()
|
46 |
+
with sr.Microphone() as mic:
|
47 |
+
recognizer.adjust_for_ambient_noise(mic, duration=1)
|
48 |
+
# flag = input("Are you ready to record?\nProceed (Y/n)")
|
49 |
+
|
50 |
+
# try:
|
51 |
+
# assert flag=='Y'
|
52 |
+
# except:
|
53 |
+
# self.text = ""
|
54 |
+
# print(f"me --> Permission denied")
|
55 |
+
time.sleep(1)
|
56 |
+
|
57 |
+
print("listening")
|
58 |
+
audio = recognizer.listen(mic)
|
59 |
+
try:
|
60 |
+
self.text = recognizer.recognize_google(audio)
|
61 |
+
except:
|
62 |
+
self.text = ""
|
63 |
+
print(f"me --> No audio recognized")
|
64 |
+
|
65 |
+
|
66 |
+
def wake_up(self, text):
|
67 |
+
return True if "hey " + self.name in text.lower() else False
|
68 |
+
|
69 |
+
def text_to_speech(self, autoplay=True):
|
70 |
+
return run_tts.tts(self.text, "_".join(self.name.split(" ")), self.spacy_model, autoplay)
|
71 |
+
|
72 |
+
def sentence_embeds_inference(self, texts: list):
|
73 |
+
def _mean_pooling(model_output, attention_mask):
|
74 |
+
token_embeddings = model_output[0] #First element of model_output contains all token embeddings
|
75 |
+
input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
|
76 |
+
return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)
|
77 |
+
# Tokenize sentences
|
78 |
+
encoded_input = self.sentTr_tokenizer(texts, padding=True, truncation=True, return_tensors='pt')
|
79 |
+
encoded_input["input_ids"] = encoded_input["input_ids"]
|
80 |
+
encoded_input["attention_mask"] = encoded_input["attention_mask"]
|
81 |
+
|
82 |
+
# Compute token embeddings
|
83 |
+
with torch.no_grad():
|
84 |
+
model_output = self.sentTr_model(**encoded_input)
|
85 |
+
|
86 |
+
# Perform pooling
|
87 |
+
sentence_embeddings = _mean_pooling(model_output, encoded_input['attention_mask'])
|
88 |
+
|
89 |
+
# Normalize embeddings
|
90 |
+
sentence_embeddings = F.normalize(sentence_embeddings, p=2, dim=1)
|
91 |
+
|
92 |
+
return sentence_embeddings
|
93 |
+
|
94 |
+
def retrieve_knowledge_assertions(self):
|
95 |
+
question_embeddings = self.sentence_embeds_inference([self.name + ', ' + self.text])
|
96 |
+
|
97 |
+
all_knowledge_embeddings = self.sentence_embeds_inference(self.all_knowledge)
|
98 |
+
similarity = cosine_similarity(all_knowledge_embeddings.cpu(), question_embeddings.cpu())
|
99 |
+
similarity = np.reshape(similarity, (1, -1))[0]
|
100 |
+
K = min(8, len(self.all_knowledge))
|
101 |
+
top_K = np.sort(np.argpartition(similarity, -K)[-K: ])
|
102 |
+
all_knowledge_assertions = np.array(self.all_knowledge)[top_K]
|
103 |
+
|
104 |
+
# similarities = np.array(similarity)[top_K]
|
105 |
+
|
106 |
+
# print(*list(zip(all_knowledge_assertions, similarities)), sep='\n')
|
107 |
+
|
108 |
+
return ' '.join(all_knowledge_assertions)
|
109 |
+
|
110 |
+
def question_answer(self, instruction1='', knowledge=''):
|
111 |
+
if self.text != "":
|
112 |
+
## wake up
|
113 |
+
if self.wake_up(self.text) is True:
|
114 |
+
self.text = f"Hello I am {self.name} the AI, what can I do for you?"
|
115 |
+
## have a conversation
|
116 |
+
else:
|
117 |
+
# if re.search(you_regex, self.text) != None:
|
118 |
+
instruction1 = f'[Instruction] You are a celebrity named {self.name}. You need to answer the question based on knowledge and commonsense.'
|
119 |
+
|
120 |
+
knowledge = self.retrieve_knowledge_assertions()
|
121 |
+
# else:
|
122 |
+
# instruction1 = f'[Instruction] You need to answer the question based on commonsense.'
|
123 |
+
query = f"{instruction1} [knowledge] {knowledge} [question] {self.text} {self.name}!"
|
124 |
+
input_ids = self.QA_tokenizer(f"{query}", return_tensors="pt").input_ids
|
125 |
+
outputs = self.QA_model.generate(input_ids, max_length=1024)
|
126 |
+
self.text = self.QA_tokenizer.decode(outputs[0], skip_special_tokens=True)
|
127 |
+
|
128 |
+
# instruction2 = f'[Instruction] You are a celebrity named {self.name}. You need to answer the question based on knowledge'
|
129 |
+
# query = f"{instruction2} [knowledge] {self.text} {answer} [question] {self.name}, {self.text}"
|
130 |
+
# input_ids = self.QA_tokenizer(f"{query}", return_tensors="pt").input_ids
|
131 |
+
# outputs = self.QA_model.generate(input_ids, max_length=1024)
|
132 |
+
# self.text = self.QA_tokenizer.decode(outputs[0], skip_special_tokens=True)
|
133 |
+
|
134 |
+
return self.text
|
135 |
+
|
136 |
+
@staticmethod
|
137 |
+
def action_time():
|
138 |
+
return f"it's {datetime.datetime.now().time().strftime('%H:%M')}"
|
139 |
+
|
140 |
+
@staticmethod
|
141 |
+
def save_kb(kb, filename):
|
142 |
+
with open(filename, "wb") as f:
|
143 |
+
pickle.dump(kb, f)
|
144 |
+
|
145 |
+
@staticmethod
|
146 |
+
def load_kb(filename):
|
147 |
+
res = None
|
148 |
+
with open(filename, "rb") as f:
|
149 |
+
res = pickle.load(f)
|
150 |
+
return res
|
data.json
ADDED
@@ -0,0 +1,290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Cate Blanchett": {
|
3 |
+
"knowledge": "Blanchett, (born May 14, 1969, Melbourne, Victoria, Australia), Australian actress known for her multidimensional characters and wide range of roles. Blanchett grew up in suburban Melbourne with an Australian mother and an American father, who died when Blanchett was 10 years old. She studied art history at the University of Melbourne before graduating from the National Institute of Dramatic Art in 1992. Her professional acting career began on the Australian stage. She performed with the Sydney Theatre Company in Caryl Churchill’s Top Girls and Timothy Daly’s Kafka Dances. In 1993 she starred opposite Geoffrey Rush in David Mamet’s Oleanna, as a student who accuses her teacher of sexual harassment. Blanchett made her television debut in 1993, and she soon landed leading roles in the miniseries Heartland (1994) and Bordertown (1995). She moved to feature films with Paradise Road (1997), a historical drama about a Japanese war camp in World War II. Blanchett’s reputation grew with her next two feature films: the bittersweet romantic comedy Thank God He Met Lizzie (1997; later released as The Wedding Party) and Oscar and Lucinda (1997), in which she played a rebellious heiress ostracized from Australian society. Her breakthrough role was as young Queen Elizabeth I in the 1998 film Elizabeth, which earned her an Academy Award nomination and a Golden Globe Award for best actress. Blanchett was praised for capturing the emotional complexity of the queen’s development from a lovestruck adolescent to an indomitable political force who represses her emotional vulnerability. Blanchett subsequently appeared in films that covered numerous genres and character types, securing her reputation as a versatile actress. She took supporting parts in Pushing Tin (1999), a comedy about air traffic controllers, and in the dramatic thriller The Talented Mr. Ripley (1999). As the lead character in The Gift (2000), she played a psychic whose visions involve her in the investigation of a local woman’s murder. In 2001 she portrayed a kidnapped housewife who falls in love with her captors in Bandits. She next appeared as the elf queen Galadriel in The Lord of the Rings trilogy (2001, 2002, and 2003), the film adaptations of J.R.R. Tolkien’s epic fantasy. In the western The Missing (2003), Blanchett brought her trademark complexity to the role of a young woman forced to confront her estranged father (played by Tommy Lee Jones) in order to reclaim her kidnapped daughter. She earned further critical acclaim for her performance as an Irish journalist who runs afoul of the mob in Veronica Guerin (2003). In 2004 she starred in Wes Anderson’s offbeat comedy The Life Aquatic with Steve Zissou, playing a pregnant reporter in a bizarre love triangle with the ship’s captain (played by Bill Murray) and someone who may be his son (played by Owen Wilson). Returning to her study of historical characters, Blanchett portrayed Hollywood star Katharine Hepburn in The Aviator (2004), Martin Scorsese’s biopic of the eccentric millionaire Howard Hughes, and won an Academy Award for the role. She later appeared in the dramas Babel (2006), The Good German (2006), and Notes on a Scandal (2006). In the unconventional biopic I’m Not There (2007), she starred as one of several characters based on the musician Bob Dylan at different stages in his life. As the character Jude, a star making the dramatic shift from acoustic folk to electric rock, Blanchett was praised for capturing the elusive and bewildering qualities attributed to Dylan. Her performance earned her another Academy Award nomination and a Golden Globe Award for best supporting actress. In 2007 Blanchett reprised her role as the English queen in Elizabeth: The Golden Age, which explores Elizabeth’s political battles with Spain and her personal relationship with Sir Walter Raleigh; she earned another Oscar nomination for her performance. The following year she played the Soviet villain Irina Spalko in Steven Spielberg’s Indiana Jones and the Kingdom of the Crystal Skull (2008), another addition to the series of action-adventure films following the dashing archaeologist. In 2008 she also starred opposite Brad Pitt in The Curious Case of Benjamin Button, a drama about a man who ages backward. Two years later she appeared as Marion Loxley in Ridley Scott’s Robin Hood. The action drama starred Russell Crowe in the title role as the outlaw hero. In the thriller Hanna (2011), Blanchett portrayed a CIA agent in pursuit of a former agent and his teenage daughter, whom he has trained to be an assassin. Blanchett again assumed the role of Galadriel in the Hobbit trilogy—An Unexpected Journey (2012), The Desolation of Smaug (2013), and The Battle of the Five Armies (2014), all based on the Tolkien novel that preceded The Lord of the Rings. Her performance in Woody Allen’s Blue Jasmine (2013), as a socialite struggling to cope with a decline in circumstances, won her further acclaim, including an Oscar for best actress; she also received her third Golden Globe. She played a French art historian and Resistance member in The Monuments Men (2014), which fictionalized Allied efforts to recover art stolen by the Nazis during World War II. Blanchett then sank her teeth into the role of the wicked stepmother of the title character in Cinderella (2015). In Truth (2015) she played CBS producer Mary Mapes, who was fired after the accuracy of a segment by reporter Dan Rather on U.S. Pres. George W. Bush’s military service was called into question. Carol, a drama in which she played a married socialite who enters a romantic relationship with a younger store clerk (Rooney Mara), earned her a seventh Oscar nomination. She then joined the ensemble of Knight of Cups (2015), Terrence Malick’s experimental meditation on Hollywood, and later appeared in his film Song to Song (2017), a romantic drama set against the Austin, Texas, music scene. Also in 2017 Blanchett earned critical praise for her vivacious portrayal of Hela, the goddess of death, in Thor: Ragnarok. The next year she starred in Ocean’s 8, the female-driven reboot of the Ocean’s Eleven franchise from the early 2000s, and The House with a Clock in Its Walls, an adaptation of a 1973 children’s fantasy novel. Blanchett was then lauded for her guest appearance as a performance artist akin to Marina Abramović on the mockumentary TV series Documentary Now! in 2019. That year she also played the eponymous character in Where’d You Go, Bernadette, a film based on the best-selling novel. Blanchett’s credits from 2020 included the TV miniseries Mrs. America, in which she portrayed the activist Phyllis Schlafly, who opposed the Equal Rights Amendment. In 2021 Blanchett appeared in the films Don’t Look Up, a dramedy about an impending comet strike that will destroy Earth, and Guillermo del Toro’s Nightmare Alley. In the latter, a film noir adapted from a novel by William Lindsay Gresham, the actress played a manipulative psychoanalyst who meets a scheming carnival worker (Bradley Cooper). Blanchett earned widespread acclaim for her performance in Tár (2022), a character study about a trailblazing conductor whose career is derailed by allegations of sexual misconduct. In addition to winning a Golden Globe, she also earned her eighth Oscar nomination. In addition to her film work, Blanchett remained active in the theatre. In 2008 she and her husband, writer Andrew Upton, became artistic directors of the Sydney Theatre Company. Blanchett left the position in 2013, though Upton remained. Her performances with the company included Hedda Gabler (2004) and The War of the Roses (2009). In 2017 she made her Broadway debut in The Present, which was based on a play by Anton Chekhov. For her performance, Blanchett received a Tony Award nomination.",
|
4 |
+
"questions": [
|
5 |
+
"When and where were you born?",
|
6 |
+
"What was your educational background, and where did you study art history?",
|
7 |
+
"Where did you begin your professional acting career?",
|
8 |
+
"What was your breakthrough role, and what award did you receive for it?",
|
9 |
+
"In which films did you play historical figures, and what were your characters' names?",
|
10 |
+
"In which film did you portray a character with psychic abilities?",
|
11 |
+
"What role did you play in 'The Lord of the Rings' trilogy?",
|
12 |
+
"What character did you portray in 'The Missing' (2003)?",
|
13 |
+
"In which film did you play a Hollywood star and win an Academy Award?",
|
14 |
+
"Mention three films in which you appeared in 2006.",
|
15 |
+
"In 'I'm Not There' (2007), which musician's various stages of life did you portray?",
|
16 |
+
"What was your role in 'Elizabeth: The Golden Age' (2007), and what was the movie about?",
|
17 |
+
"Who did you play in 'Indiana Jones and the Kingdom of the Crystal Skull' (2008)?",
|
18 |
+
"Describe your character in 'Blue Jasmine' (2013) and the recognition you received for it.",
|
19 |
+
"What was your role in 'Cinderella' (2015)?",
|
20 |
+
"In 'Carol' (2015), what was the character you portrayed, and who played your love interest?",
|
21 |
+
"Name two films you appeared in directed by Terrence Malick.",
|
22 |
+
"What character did you play in 'Thor: Ragnarok' (2017)?",
|
23 |
+
"In which TV series did you portray an activist opposing the Equal Rights Amendment?",
|
24 |
+
"What were two of your notable film appearances in 2021, and what were these movies about?"
|
25 |
+
],
|
26 |
+
"answers": [
|
27 |
+
"I was born on May 14, 1969, in Melbourne, Victoria, Australia.",
|
28 |
+
"I studied art history at the University of Melbourne and graduated from the National Institute of Dramatic Art in 1992.",
|
29 |
+
"I began my professional acting career in Australia.",
|
30 |
+
"My breakthrough role was as young Queen Elizabeth I in the 1998 film 'Elizabeth,' for which I earned a Golden Globe Award.",
|
31 |
+
"I played historical figures in 'Elizabeth' (Queen Elizabeth I) and 'The Aviator' (Katharine Hepburn).",
|
32 |
+
"I portrayed a character with psychic abilities in 'The Gift'.",
|
33 |
+
"I played the character Galadriel.",
|
34 |
+
"I portrayed a young woman forced to confront my estranged father in order to reclaim my kidnapped daughter.",
|
35 |
+
"The Aviator",
|
36 |
+
"In 2006, I appeared in 'Babel,' 'The Good German,' and 'Notes on a Scandal.'",
|
37 |
+
"In 'I'm Not There' (2007), I portrayed Bob Dylan's character, Jude.",
|
38 |
+
"My role in 'Elizabeth: The Golden Age' (2007) was Queen Elizabeth I. The movie explored her political battles with Spain and her personal relationship with Sir Walter Raleigh.",
|
39 |
+
"I played the character Irina Spalko.",
|
40 |
+
"I played a socialite struggling to cope with a decline in circumstances and won an Oscar for Best Actress and a Golden Globe Award.",
|
41 |
+
"My role was the wicked stepmother.",
|
42 |
+
"I portrayed Carol, and Rooney Mara played my love interest.",
|
43 |
+
"I appeared in Terrence Malick's films 'Knight of Cups' and 'Song to Song.'",
|
44 |
+
"I played the character Hela, the goddess of death.",
|
45 |
+
"In the TV series 'Mrs. America.'",
|
46 |
+
"In 2021, I appeared in 'Don't Look Up', a dramedy about an impending comet strike that will destroy Earth, and 'Nightmare Alley', a film noir adapted from a novel by William Lindsay Gresham."
|
47 |
+
],
|
48 |
+
"gender": "F"
|
49 |
+
},
|
50 |
+
"David Beckham": {
|
51 |
+
"knowledge": "Beckham, (born May 2, 1975, Leytonstone, East London, England), English football (soccer) player who gained international fame for his on-field play as well as for his highly publicized personal life. At age 11 Beckham won a football contest, and as a teenager he competed on Manchester United’s youth squad, leading it to a national championship in 1992. Three years later he began playing with the professional team in league competition, and during the 1995–96 season he helped Manchester United win the league title and the Football Association (FA) Cup. Beckham attracted national attention in August 1996 when he scored a goal from the halfway line (a feat roughly equivalent to a golfer’s hole in one). The following year Manchester United successfully defended its league title, and Beckham was voted Young Player of the Year. In the 1998–99 season Manchester United won the league title, the FA Cup, and the European Cup. Beckham was named best midfielder and Most Valuable Player. Considered one of the sport’s elite players, he was perhaps best known for his free kicks and crosses; the 2002 film Bend It Like Beckham paid homage to his kicking ability. After helping Manchester United win three more league titles (2000, 2001, and 2003), he left the team in 2003 to join the Spanish football club Real Madrid. Four years later he signed a record-setting deal with the Los Angeles Galaxy of Major League Soccer (MLS) in the United States. In October 2008 Beckham signed to play with Italian football powerhouse AC Milan during the MLS off-season. In 2011 he helped the Galaxy win an MLS Cup title. The Galaxy won a second MLS Cup title in 2012, and Beckham left the team at the end of the season. In 2013 he joined the French first-league team Paris Saint-Germain (PSG), and PSG won the French domestic title in his one season with the team. Beckham retired from football soon after winning his championship with PSG. In 1996 Beckham first played on England’s national team, in a World Cup qualifying match. At the 1998 World Cup he drew much criticism after he was ejected from a game for kicking an opponent. England lost the match and was eliminated from the competition. In 2000 Beckham was made captain of the national team. At the 2002 and 2006 World Cups, England was defeated in the quarterfinals. After the 2006 tournament, Beckham stepped down as captain, and he was later dropped from England’s national team. He was recalled to the team in 2007, and the following year he posted his 100th international appearance, becoming the fifth person to do so in the history of English football. Beckham was poised to be the first Englishman to appear in four World Cups, but he tore his Achilles tendon while playing for AC Milan in March 2010 and was ruled out for the 2010 tournament. A healthy but older Beckham was not selected for the English side at the 2012 European Championship, and he finished his national career with 115 international games played, the most in his country’s history for a non-goalkeeper. After his playing days ended, Beckham remained involved in soccer. He notably was the owner and president of the MLS team Inter Miami CF, which made its debut in 2020. In 1999 Beckham married singer Victoria Adams, best known as “Posh Spice” of the Spice Girls pop group, in a lavish ceremony. The intense media attention to the couple increased Beckham’s popularity around the world, as did his style of dress and ever-changing hairstyles. In 2003 he was made an Officer of the Order of the British Empire (OBE). He released an eponymous memoir in 2014.",
|
52 |
+
"questions": [
|
53 |
+
"When and where were you born?",
|
54 |
+
"What did you win at the age of 11?",
|
55 |
+
"Which professional football team did you join as a teenager?",
|
56 |
+
"In which season did you and your team win the league title and the FA Cup?",
|
57 |
+
"What memorable feat did you achieve in August 1996?",
|
58 |
+
"In which season did you and your team win the league title, FA Cup, and the European Cup?",
|
59 |
+
"What were you particularly known for in your football career?",
|
60 |
+
"Which Spanish football club did you join in 2003?",
|
61 |
+
"Which team did you sign a record-setting deal with in 2007?",
|
62 |
+
"In which year did you help the LA Galaxy win an MLS Cup title?",
|
63 |
+
"How many MLS Cup titles did the LA Galaxy win during your time with the team?",
|
64 |
+
"Which French first-league team did you join in 2013, and what did you achieve during your time with them?",
|
65 |
+
"When did you retire from professional football?",
|
66 |
+
"In which year did you first play for England's national team, and in what type of match?",
|
67 |
+
"What controversy surrounded you at the 1998 World Cup?",
|
68 |
+
"When were you made the captain of England's national team?",
|
69 |
+
"How far did England go in the 2002 and 2006 World Cups with you as part of the team?",
|
70 |
+
"What happened to you in your football career after the 2006 World Cup?",
|
71 |
+
"How many international appearances did you make for England, and what record did you set in 2008?",
|
72 |
+
"What did you do after retiring from professional football, and which soccer team were you notably involved with?"
|
73 |
+
],
|
74 |
+
"answers": [
|
75 |
+
"I was born on May 2, 1975, in Leytonstone, East London, England.",
|
76 |
+
"I won a football contest at the age of 11.",
|
77 |
+
"I joined Manchester United's youth squad as a teenager.",
|
78 |
+
"In the 1995–96 season.",
|
79 |
+
"I scored a memorable goal from the halfway line.",
|
80 |
+
"In the 1998–99 season, Manchester United won the league title, the FA Cup, and the European Cup.",
|
81 |
+
"I was particularly known for my free kicks and crosses.",
|
82 |
+
"I joined the Spanish football club Real Madrid.",
|
83 |
+
"I signed a record-setting deal with the Los Angeles Galaxy of Major League Soccer (MLS) in 2007.",
|
84 |
+
"I helped the LA Galaxy win an MLS Cup title in 2011.",
|
85 |
+
"The LA Galaxy won two MLS Cup titles during my time with the team.",
|
86 |
+
"I joined Paris Saint-Germain (PSG) in 2013, and PSG won the French domestic title in my one season with the team.",
|
87 |
+
"I retired from football soon after winning the championship with PSG.",
|
88 |
+
"I first played on England's national team in a World Cup qualifying match in 1996.",
|
89 |
+
"I drew criticism at the 1998 World Cup when I was ejected from a game for kicking an opponent.",
|
90 |
+
"I was made captain of the national team in 2000.",
|
91 |
+
"At the 2002 and 2006 World Cups, England was defeated in the quarterfinals with me as part of the team.",
|
92 |
+
"I stepped down as captain, and I was later dropped from England's national team.",
|
93 |
+
"I posted my 100th international appearance, becoming the fifth person to do so in the history of English football.",
|
94 |
+
"I remained involved in soccer and was the owner and president of the MLS team Inter Miami CF."
|
95 |
+
],
|
96 |
+
"gender": "M"
|
97 |
+
},
|
98 |
+
"Emma Watson": {
|
99 |
+
"knowledge": "Watson, (born April 15, 1990, Paris, France), British actress and activist who was perhaps best known for playing the young wizard Hermione Granger in the Harry Potter films. She also garnered attention as a spokesperson for women’s equality. Watson was born in Paris to British parents who divorced when she was young. She and her brother went to live with their mother in Oxfordshire, England. While a child, Watson decided she wanted to be an actress. Besides attending school, she took acting and singing classes. She also appeared in several school plays. Watson began acting in earnest in 1999 after she auditioned for a part in the film adaptation of J.K. Rowling’s Harry Potter and the Sorcerer’s Stone (2001). She won the role of smart and logical Hermione, one of Harry Potter’s best friends. The film was a box-office hit, and Watson reprised her role in the franchise’s other movies: Harry Potter and the Chamber of Secrets (2002), Harry Potter and the Prisoner of Azkaban (2004), Harry Potter and the Goblet of Fire (2005), Harry Potter and the Order of the Phoenix (2007), Harry Potter and the Half-Blood Prince (2009), Harry Potter and the Deathly Hallows: Part 1 (2010), and Harry Potter and the Deathly Hallows: Part 2 (2011). After the Potter films ended, Watson began to look for more mature roles. Her first major part was in the drama The Perks of Being a Wallflower (2012), in which she played a high-school senior who becomes friends with a clinically depressed freshman. She subsequently appeared in the crime drama The Bling Ring (2013), the historical thriller The Colony (also known as Colonia; 2015), and the sci-fi thriller The Circle (2017). These films had limited success at the box-office, but Watson had another blockbuster hit with the live-action Disney adaptation (2017) of Beauty and the Beast. In 2019 she appeared as Meg March in Greta Gerwig’s acclaimed Little Women, which was based on Louisa May Alcott’s classic children’s book. Meanwhile, in the midst of her acting career, Watson pursued a college degree. In 2009 she began attending Brown University in Providence, Rhode Island. She took time off as needed for filming, and she also studied for a year at the University of Oxford. Watson graduated from Brown in 2014 with a bachelor’s degree in English literature. That year she was named a UN Women Goodwill Ambassador. She was an advocate for women’s rights and gender equality. From 2016 to 2020 Watson ran an online feminist book club, Our Shared Shelf, to read and discuss books by and about women.",
|
100 |
+
"questions": [
|
101 |
+
"When and where were you born?",
|
102 |
+
"What are you best known for in your career?",
|
103 |
+
"Where did you grow up and who did you live with after your parents' divorce?",
|
104 |
+
"What did you decide to be as a child?",
|
105 |
+
"What steps did you take to pursue your interest in acting as a child?",
|
106 |
+
"In which year did you begin your acting career?",
|
107 |
+
"How did you land the role of Hermione Granger in the Harry Potter films?",
|
108 |
+
"Can you name some of the Harry Potter films in which you played Hermione?",
|
109 |
+
"What was your first major role after the Harry Potter series ended?",
|
110 |
+
"What was the plot of 'The Perks of Being a Wallflower'?",
|
111 |
+
"In which films did you subsequently appear after 'The Perks of Being a Wallflower'?",
|
112 |
+
"Can you name the Disney adaptation in which you had a blockbuster hit?",
|
113 |
+
"In 2019, who did you portray in the film 'Little Women,' and what is the source of the story?",
|
114 |
+
"Where and when did you pursue your college degree?",
|
115 |
+
"What was your major at Brown University, and when did you graduate?",
|
116 |
+
"What role did you take on in 2014, and for what organization?",
|
117 |
+
"What were some of your advocacies and causes as a UN Women Goodwill Ambassador?",
|
118 |
+
"What was the purpose of 'Our Shared Shelf,' the online book club you ran from 2016 to 2020?",
|
119 |
+
"How did you balance your education with your acting career?",
|
120 |
+
"What are some of your notable achievements and contributions?"
|
121 |
+
],
|
122 |
+
"answers": [
|
123 |
+
"I was born on April 15, 1990, in Paris, France.",
|
124 |
+
"I am best known for playing the young wizard Hermione Granger in the Harry Potter films.",
|
125 |
+
"I grew up in Paris, France, and after my parents' divorce, I lived with my mother and brother in Oxfordshire, England.",
|
126 |
+
"I decided I wanted to be an actress when I was a child.",
|
127 |
+
"I took acting and singing classes and appeared in several school plays.",
|
128 |
+
"I began my acting career in 1999.",
|
129 |
+
"I auditioned for the role of Hermione Granger in the film adaptation of 'Harry Potter and the Sorcerer's Stone' (2001) and won the part.",
|
130 |
+
"I played Hermione Granger in the entire Harry Potter film series, including 'Harry Potter and the Chamber of Secrets' (2002), 'Harry Potter and the Prisoner of Azkaban' (2004), 'Harry Potter and the Goblet of Fire' (2005), 'Harry Potter and the Order of the Phoenix' (2007), 'Harry Potter and the Half-Blood Prince' (2009), 'Harry Potter and the Deathly Hallows: Part 1' (2010), and 'Harry Potter and the Deathly Hallows: Part 2' (2011).",
|
131 |
+
"My first major role after the Harry Potter series was in the drama 'The Perks of Being a Wallflower' (2012).",
|
132 |
+
"The film 'The Perks of Being a Wallflower' is about the journey of a clinically depressed high school freshman and the friendships he forms.",
|
133 |
+
"After 'The Perks of Being a Wallflower,' I appeared in films like 'The Bling Ring' (2013), 'The Colony' (also known as 'Colonia'; 2015), and 'The Circle' (2017).",
|
134 |
+
"I had a blockbuster hit with the live-action Disney adaptation of 'Beauty and the Beast' in 2017.",
|
135 |
+
"In 2019, I portrayed Meg March in Greta Gerwig's acclaimed adaptation of 'Little Women,' based on Louisa May Alcott's classic children's book.",
|
136 |
+
"I began attending Brown University in Providence, Rhode Island, in 2009. I took time off as needed for filming and also studied for a year at the University of Oxford.",
|
137 |
+
"I graduated from Brown in 2014 with a bachelor's degree in English literature.",
|
138 |
+
"In 2014, I was named a UN Women Goodwill Ambassador.",
|
139 |
+
"As a UN Women Goodwill Ambassador, I advocated for women's rights and gender equality.",
|
140 |
+
"I ran the book club to read and discuss books by and about women.",
|
141 |
+
"I took time off from university as needed for filming.",
|
142 |
+
"Some of my notable achievements and contributions include my acting career and advocacy for women's rights."
|
143 |
+
],
|
144 |
+
"gender": "F"
|
145 |
+
},
|
146 |
+
"Lady Gaga":{
|
147 |
+
"knowledge": "Lady Gaga, (born March 28, 1986, New York City, New York, U.S.), American singer-songwriter and performance artist, known for her flamboyant costumes, provocative lyrics, and strong vocal talents, who achieved enormous popular success with songs such as “Just Dance,” “Bad Romance,” and “Born This Way.” Germanotta was born into an Italian American family in New York City. She learned music at an early age and was performing onstage in New York City clubs by the time she was a teenager. She attended an all-girls school, Convent of the Sacred Heart, in Manhattan before going on to study music at the Tisch School of the Arts at New York University. She studied at Tisch for two years before dropping out to manage her own career. After dropping out, she began transforming herself from Germanotta into Lady Gaga, whose style combined glam rock and over-the-top fashion design. In 2007 she and performance artist Lady Starlight formed a revue called the Ultimate Pop Burlesque Rockshow. That same year Lady Gaga, who also wrote songs for other pop artists such as Fergie, the Pussycat Dolls, and Britney Spears, was signed by the singer Akon to Interscope Records and began preparing her debut album, The Fame, which was released in 2008. Although she modeled herself on such theatrical performers as David Bowie during his Ziggy Stardust period, the New York Dolls, Grace Slick, and Freddie Mercury—her adopted stage name was derived from Queen’s song “Radio Ga Ga”—she created a character that came to occupy a unique space in the music world. Her fashion combined with her up-tempo, synthetic dance music and her edgy, theatrical performance to create stunning sounds and visuals. Indeed, while producing music, Lady Gaga also created her own sexually charged fashions—replete with dazzling wigs and space-age bodysuits—through her creative team Haus of Gaga. Her first single, “Just Dance,” became popular in clubs throughout the United States and Europe and eventually landed at number one on the Billboard Pop Songs chart (also called the radio chart). Three other singles off The Fame—“Poker Face,” “LoveGame,” and “Paparazzi”—also reached number one on the radio chart, making Lady Gaga the first artist in the 17-year history of that chart to have four number ones from a debut album. The Fame was well received critically and proved enormously successful commercially, selling more than eight million copies worldwide by the end of 2009. The album also yielded Lady Gaga five Grammy nominations, including for album of the year and song of the year (“Poker Face”); she captured two Grammys—best dance recording (“Poker Face”) and best electronic/dance album (The Fame)—and her opening duet with Sir Elton John was among the most talked-about elements of the 2010 Grammys telecast. In February 2010 she also picked up three Brit Awards (the British equivalent of the Grammys)—for best international female, best album, and breakthrough act. Her second album, The Fame Monster, was released in November 2009 (it was originally conceived as a bonus disc) and almost instantly produced another hit, “Bad Romance.” Other popular singles from the album followed, including “Telephone” (which featured Beyoncé, as did a nine-minute video produced by Jonas Åkerlund starring the pair and referencing Quentin Tarantino’s film Kill Bill: Vol. 1 [2003]) and “Alejandro.” During 2010 Lady Gaga proved to be one of the most commercially successful artists, with a sold-out concert tour (which had been launched to coincide with the release of The Fame Monster), while she also headlined Chicago’s Lollapalooza music festival and played in front of a record 20,000 people at NBC’s Today show. She was named one of Time magazine’s 100 Most Influential People and was named by Forbes magazine as one of the world’s most powerful women, and she capped off 2010 by being named Billboard magazine’s artist of the year. After arriving at the 2011 Grammy Awards ceremony encased in a giant egg, Lady Gaga went on to claim honours for best pop vocal album (for The Fame Monster) and best female pop vocal performance and best short form video (for “Bad Romance”). Lady Gaga’s third album, Born This Way (2011), found the entertainer reaching back to earlier musical eras for inspiration. As a blonde dance-pop performer with a penchant for provocation, Lady Gaga had often earned comparisons to the singer Madonna, and on the album’s first two singles the similarities were especially pronounced. The title track was a self-empowerment anthem in the style of Madonna’s 1989 single “Express Yourself,” while “Judas” brazenly mixed sexual and religious imagery. Both songs quickly became hits. Other tracks on the album featured guest appearances from guitarist Brian May of Queen and saxophonist Clarence Clemons of Bruce Springsteen’s E Street Band. In 2013 Lady Gaga released Artpop. Although the energetic lead single “Applause” extended her string of chart successes, the album was perceived as a commercial disappointment. She came back the following year with Cheek to Cheek, a collection of standards that she recorded with Tony Bennett. The recording topped the Billboard 200 as well as the jazz and traditional jazz album charts, and it earned the Grammy for best traditional pop vocal album. The duo also won that award for their second collaboration, Love for Sale (2021), a tribute album to Cole Porter. During this time Lady Gaga continued to record solo albums. The relatively understated Joanne (2016) performed poorly until Lady Gaga’s halftime Super Bowl performance in February 2017 brought it favourable attention. For her sixth studio album, Chromatica (2020), Lady Gaga returned to her earlier music, mixing disco and electronic-pop. In addition to recording music, Lady Gaga made occasional film appearances, notably in Machete Kills (2013) and Sin City: A Dame to Kill For (2014). She played a vampiric countess with no regard for life or suffering in the fifth season of the television show American Horror Story: Hotel (2015–16). For her performance in the anthology series, Lady Gaga received a Golden Globe Award. She also appeared in the sixth season, which aired in 2016. Lady Gaga garnered critical acclaim and an Academy Award nomination for her first lead role, a guileless up-and-coming singer-songwriter in the 2018 remake of the movie A Star Is Born. She cowrote most of that movie’s songs, many of which she performed with costar and director Bradley Cooper. The lead single, “Shallow,” won two Grammy Awards and the Oscar for best original song. In 2021 Lady Gaga appeared in Ridley Scott’s House of Gucci, which centres on the true story of the murder of Maurizio Gucci, who headed his family’s luxury fashion brand. Lady Gaga also contributed songs to other films. She notably cowrote and performed “Til It Happens to You” for the documentary The Hunting Ground (2015) and “Hold My Hand” for Top Gun: Maverick (2022). Both tracks received Oscar nominations for best original song. Lady Gaga cultivated a devoted following, particularly among gay men (she acknowledged her own bisexuality), who became some of her most loyal fans. She became particularly outspoken on gay rights, especially same-sex marriage, and was a featured speaker at the 2009 National Equality March in Washington, D.C. In 2021 Lady Gaga sang the national anthem at the U.S. presidential inauguration of Joe Biden.",
|
148 |
+
"questions": [
|
149 |
+
"When and where were you born?",
|
150 |
+
"What is your family background?",
|
151 |
+
"Which New York City school did you attend before pursuing music?",
|
152 |
+
"Where did you study music before dropping out to manage your own career?",
|
153 |
+
"What was the name of the revue you formed with Lady Starlight in 2007?",
|
154 |
+
"Who signed you to Interscope Records in 2007?",
|
155 |
+
"What was the title of your debut album, and when was it released?",
|
156 |
+
"How many Grammy nominations did you receive for 'The Fame' album, and in which categories did you win?",
|
157 |
+
"What was the title of your second album, and what was its initial purpose?",
|
158 |
+
"Which hit single from 'The Fame Monster' was released in November 2009?",
|
159 |
+
"Which famous artist was featured in the song 'Telephone'?",
|
160 |
+
"In 2010, what was the capacity of the crowd at your performance on NBC's Today show?",
|
161 |
+
"Which magazines named you one of the most influential people and one of the world's most powerful women in 2010?",
|
162 |
+
"Who did you collaborate with for the album 'Cheek to Cheek'?",
|
163 |
+
"What type of songs did you record for 'Cheek to Cheek,' and which Grammy did it win?",
|
164 |
+
"What was the title of your sixth studio album, released in 2020?",
|
165 |
+
"In which television series did you portray a vampiric countess and receive a Golden Globe Award?",
|
166 |
+
"For which role did you receive an Academy Award nomination, and what was the name of the movie?",
|
167 |
+
"For which song from the movie 'A Star Is Born' did you win two Grammy Awards and an Oscar for Best Original Song?",
|
168 |
+
"In Ridley Scott's 'House of Gucci,' what true story does the movie center on?"
|
169 |
+
],
|
170 |
+
"answers": [
|
171 |
+
"I was born on March 28, 1986, in New York City.",
|
172 |
+
"I was born into an Italian American family.",
|
173 |
+
"I attended the Convent of the Sacred Heart in Manhattan.",
|
174 |
+
"I studied music at the Tisch School of the Arts at New York University before dropping out to manage my own career.",
|
175 |
+
"The revue I formed with Lady Starlight in 2007 was called the 'Ultimate Pop Burlesque Rockshow.'",
|
176 |
+
"I was signed by the singer Akon to Interscope Records in 2007.",
|
177 |
+
"My debut album was titled 'The Fame,' and it was released in 2008.",
|
178 |
+
"I received five Grammy nominations for 'The Fame,' and I won two Grammys for 'Poker Face' (best dance recording) and 'The Fame' (best electronic/dance album).",
|
179 |
+
"My second album was titled 'The Fame Monster,' and it was originally conceived as a bonus disc.",
|
180 |
+
"The hit single from 'The Fame Monster' that was released in November 2009 was 'Bad Romance.'",
|
181 |
+
"Beyoncé was featured in the song 'Telephone.'",
|
182 |
+
"In 2010, I played in front of a record 20,000 people at NBC's Today show.",
|
183 |
+
"I was named one of Time magazine's 100 Most Influential People and was named by Forbes magazine as one of the world's most powerful women in 2010.",
|
184 |
+
"I collaborated with Tony Bennett for the album 'Cheek to Cheek.'",
|
185 |
+
"'Cheek to Cheek' featured standards and won the Grammy for best traditional pop vocal album.",
|
186 |
+
"My sixth studio album, released in 2020, was titled 'Chromatica.'",
|
187 |
+
"In the fifth season of the television show 'American Horror Story: Hotel' (2015–16).",
|
188 |
+
"I received an Academy Award nomination for my lead role in the 2018 remake of the movie 'A Star Is Born.'",
|
189 |
+
"The song 'Shallow' from 'A Star Is Born'.",
|
190 |
+
"It centers on the true story of the murder of Maurizio Gucci, who headed his family's luxury fashion brand."
|
191 |
+
],
|
192 |
+
"gender": "F"
|
193 |
+
},
|
194 |
+
"Madonna":{
|
195 |
+
"knowledge": "Madonna, (born August 16, 1958, Bay City, Michigan, U.S.), American singer, songwriter, actress, and entrepreneur whose immense popularity in the 1980s and ’90s allowed her to achieve levels of power and control that were nearly unprecedented for a woman in the entertainment industry. Born into a large Italian American family, Madonna studied dance at the University of Michigan and with the Alvin Ailey American Dance Theater in New York City in the late 1970s before relocating briefly to Paris as a member of Patrick Hernandez’s disco revue. Returning to New York City, she performed with a number of rock groups before signing with Sire Records. Her first hit, “Holiday,” in 1983, provided the blueprint for her later material—an upbeat dance club sound with sharp production and an immediate appeal. Madonna’s melodic pop incorporated catchy choruses, and her lyrics concerned love, sex, and relationships—ranging from the breezy innocence of “True Blue” (1986) to the erotic fantasies of “Justify My Love” (1990) to the spirituality of later songs such as “Ray of Light” (1998). Criticized by some as being limited in range, her sweet girlish voice nonetheless was well suited to pop music. Madonna was the first female artist to exploit fully the potential of the music video. She collaborated with top designers (Jean-Paul Gaultier), photographers (Steven Meisel and Herb Ritts), and directors (Mary Lambert and David Fincher), drawing inspiration from underground club culture or the avant-garde to create distinctive sexual and satirical images—from the knowing ingenue of “Like a Virgin” (1984) to the controversial red-dressed “sinner” who kisses a Black saint in “Like a Prayer” (1989). By 1991 she had scored 21 top ten hits in the United States and sold some 70 million albums internationally, generating $1.2 billion in sales. Committed to controlling her image and career herself, Madonna became the head of Maverick, a subsidiary of Time Warner created by the entertainment giant as part of a $60 million deal with the performer. Her success signaled a clear message of financial control to other women in the industry, but in terms of image she was a more ambivalent role model. In 1992 Madonna took her role as a sexual siren to its full extent when she published Sex, a soft-core pornographic coffee-table book featuring her in a variety of “erotic” poses. She was criticized for being exploitative and overcalculating, and writer Norman Mailer said she had become “secretary to herself.” Soon afterward Madonna temporarily withdrew from pop music to concentrate on a film career that had begun with a strong performance in Desperately Seeking Susan (1985), faltered with the flimsy Shanghai Surprise (1986) and Dick Tracy (1990), and recovered with Truth or Dare (1991, also known as In Bed with Madonna), a documentary of one of her tours, and A League of Their Own (1992). She scored massive success in 1996 with the starring role in the film musical Evita. That year she also gave birth to a daughter. In 1998 Madonna released her first album of new material in four years, Ray of Light. A fusion of techno music and self-conscious lyrics, it was a commercial and critical success, earning the singer her first musical Grammy Awards, among them the award for best pop album (her previous win had been for a video). She won another Grammy the following year, for the song “Beautiful Stranger,” which she cowrote and performed for the movie Austin Powers: The Spy Who Shagged Me (1999). Her experimentation in electronica continued with Music (2000). In 2005 she returned to her roots with Confessions on a Dance Floor, which took the Grammy for best electronic/dance album. Despite a marriage in the 1980s to actor Sean Penn and another to English director Guy Ritchie (married 2000; divorced 2008), with whom she had a son, Madonna remained resolutely independent. (She also later adopted four children from Malawi.) That independent streak, however, did not prevent her from enlisting the biggest names in music to assist on specific projects. This fact was clear on Hard Candy (2008), a hip-hop-infused effort with writing and vocal and production work by Justin Timberlake, Timbaland, and Pharrell Williams of the hit-making duo the Neptunes. With MDNA (2012), which featured cameos from rappers M.I.A. and Nicki Minaj, she continued to prove herself a shrewd assimilator of cutting-edge musical styles. Rebel Heart (2015), featuring production work by Diplo and Kanye West and guest appearances from Minaj and Chance the Rapper, was an ode to her career. In 2019 Madonna released her 14th studio album, Madame X, which was inspired by her 2017 move to Lisbon, Portugal, and contained music influenced by Latin pop, art pop, and hip-hop. Madonna was inducted into the Rock and Roll Hall of Fame in 2008. In addition to acting in movies—she also starred in the romantic comedy The Next Best Thing (2000) and in Ritchie’s Swept Away (2002)—Madonna pursued work behind the camera. She cowrote and directed Filth and Wisdom (2008), a comedy about a trio of mismatched flatmates in London, as well as the drama W.E. (2011), which juxtaposed the historical romance between Wallis Simpson and King Edward VIII with the fictional story of a woman in the 1990s researching Simpson’s life.",
|
196 |
+
"questions": [
|
197 |
+
"When and where were you born?",
|
198 |
+
"Where did you study dance before your career took off?",
|
199 |
+
"Which was your first hit song, and what year was it released?",
|
200 |
+
"How did you pioneer the use of music videos in your career?",
|
201 |
+
"What was your role in Maverick, a subsidiary of Time Warner?",
|
202 |
+
"In 1992, you published a controversial coffee-table book called 'Sex.' What was the book about?",
|
203 |
+
"What significant documentary film did you release in 1991?",
|
204 |
+
"What major musical role did you play in the film 'Evita' in 1996?",
|
205 |
+
"Which album brought you your first Grammy Awards?",
|
206 |
+
"Who did you collaborate with on your albums 'Hard Candy' and 'MDNA'?",
|
207 |
+
"Where did you move to in 2017 and the place inspired which album in 2019?",
|
208 |
+
"When were you inducted into the Rock and Roll Hall of Fame?",
|
209 |
+
"Besides singing, in which films did you take on acting roles?",
|
210 |
+
"What was the subject of the film 'W.E.' that you directed?",
|
211 |
+
"Who were your notable spouses, and how many children did you adopt?",
|
212 |
+
"Which song did you perform for the movie 'Austin Powers: The Spy Who Shagged Me (1999)'?",
|
213 |
+
"How did your 1980s and '90s popularity empower you in the entertainment industry?",
|
214 |
+
"By 1991 how many top ten hits in the US had you scored and how many albums did you sell internationally?",
|
215 |
+
"What kind of music is your album 'Music' known for?",
|
216 |
+
"What was the focus of your 2015 album 'Rebel Heart'?"
|
217 |
+
],
|
218 |
+
"answers": [
|
219 |
+
"I was born on August 16, 1958, in Bay City, Michigan, U.S.",
|
220 |
+
"I studied dance at the University of Michigan and with the Alvin Ailey American Dance Theater in New York City in the late 1970s.",
|
221 |
+
"My first hit song was 'Holiday,' and it was released in 1983.",
|
222 |
+
"I was the first female artist to exploit fully the potential of the music video, collaborating with top designers, photographers, and directors to create distinctive sexual and satirical images.",
|
223 |
+
"I became the head of Maverick.",
|
224 |
+
"It was a controversial coffee-table book featuring soft-core pornographic content and her various erotic poses.",
|
225 |
+
"I released 'Truth or Dare,' also known as 'In Bed with Madonna.'",
|
226 |
+
"I played the starring role in the film musical 'Evita' in 1996.",
|
227 |
+
"I won my first Grammy Awards for the album, Ray of Light.",
|
228 |
+
"I collaborated with Justin Timberlake, Timbaland, and Pharrell Williams on my album 'Hard Candy' and rappers M.I.A. and Nicki Minaj on 'MDNA.'",
|
229 |
+
"I moved to Lisbon, Portugal in 2017, which inspired my 2019 album 'Madame X.'",
|
230 |
+
"I was inducted into the Rock and Roll Hall of Fame in 2008.",
|
231 |
+
"I took on acting roles in films such as 'Desperately Seeking Susan,' 'Shanghai Surprise,' and 'Dick Tracy.'",
|
232 |
+
"The subject of the film 'W.E.' juxtaposed the historical romance between Wallis Simpson and King Edward VIII with the fictional story of a woman in the 1990s researching Simpson's life.",
|
233 |
+
"My notable spouses included Sean Penn and Guy Ritchie, and I adopted four children from Malawi.",
|
234 |
+
"I performed the song 'Beautiful Stranger,'.",
|
235 |
+
"My immense popularity in the 1980s and '90s allowed me to achieve levels of power and control nearly unprecedented for a woman in the entertainment industry.",
|
236 |
+
"I had scored 21 top ten hits in the United States and sold some 70 million albums internationally.",
|
237 |
+
"My album 'Music' is known for my experimentation in electronica.",
|
238 |
+
"The focus of my 2015 album 'Rebel Heart' was an ode to my career."
|
239 |
+
],
|
240 |
+
"gender": "F"
|
241 |
+
},
|
242 |
+
"Mark Zuckerberg":{
|
243 |
+
"knowledge": "Zuckerberg, (born May 14, 1984, White Plains, New York, U.S.), American computer programmer who was cofounder and CEO (2004– ) of Facebook, a social networking website. After attending Phillips Exeter Academy, Zuckerberg enrolled at Harvard University in 2002. On February 4, 2004, he launched thefacebook dot com (renamed Facebook in 2005), a directory in which fellow Harvard students entered their own information and photos into a template that he had devised. Within two weeks half of the student body had signed up. Zuckerberg’s roommates, Dustin Moskovitz and Chris Hughes, helped him add features and make the site available to other campuses across the country. Facebook quickly became popular as registered users could create profiles, upload photos and other media, and keep in touch with friends. It differed from other social networking sites, however, in its emphasis on real names (and e-mail addresses), or “trusted connections.” It also laid particular emphasis on networking, with information disseminated not only to each individual’s network of friends but also to friends of friends—what Zuckerberg called the “social graph.” In the summer of 2004 the trio moved their headquarters to Palo Alto, California, where Zuckerberg talked venture capitalist Peter Thiel into giving them seed money. Zuckerberg dropped out of Harvard to concentrate on the fledgling company, of which he became CEO and president. In May 2005 Facebook received its first major infusion of venture capital ($12.7 million). Four months later Facebook opened to registration by high-school students. Meanwhile, foreign colleges and universities also began to sign up, and by September 2006 anyone with an e-mail address could join a regional network based on where he or she lived. About that time Zuckerberg turned down a $1 billion buyout offer from Yahoo!, but in 2007 Facebook struck a deal with Microsoft in which the software company paid $240 million for a 1.6 percent stake in Facebook; two years later Digital Sky Technologies purchased a 1.96 percent share for $200 million. In 2008 Zuckerberg’s new worth was estimated at about $1.5 billion. After Facebook’s initial public offering (IPO) of stock in 2012, Zuckerberg’s net worth was estimated at more than $19 billion. In October 2021 Facebook announced that it was changing the name of its parent company to Meta Platforms. The name change reflected an emphasis on the “metaverse”, in which users would interact in virtual reality environments.",
|
244 |
+
"questions": [
|
245 |
+
"When and where were you born?",
|
246 |
+
"Where did you attend school before enrolling at Harvard University?",
|
247 |
+
"What was the original name of Facebook when it was launched in 2004?",
|
248 |
+
"Who were your roommates and what role did they play in the development of Facebook?",
|
249 |
+
"What was the distinctive feature of Facebook in terms of user information?",
|
250 |
+
"In which city did you move the headquarters of Facebook in the summer of 2004?",
|
251 |
+
"How did you secure initial funding for Facebook?",
|
252 |
+
"Why did you decide to drop out of Harvard?",
|
253 |
+
"How much venture capital did Facebook receive in May 2005?",
|
254 |
+
"When did Facebook open registration to high-school students?",
|
255 |
+
"How did Facebook expand its user base to include regional networks?",
|
256 |
+
"Which company made a $240 million investment in Facebook in 2007?",
|
257 |
+
"What was your estimated net worth in 2008?",
|
258 |
+
"How did your net worth change after Facebook's initial public offering (IPO) in 2012?",
|
259 |
+
"In October 2021, Facebook announced a name change to Meta Platforms. What was the reason behind this name change?",
|
260 |
+
"What term did you use to describe the emphasis on virtual reality environments?",
|
261 |
+
"Can you describe the concept of the 'social graph' that Facebook emphasized?",
|
262 |
+
"What could registered Facebook users do in the beginning?",
|
263 |
+
"How quickly did half of the student body at Harvard sign up for Facebook when it was launched?",
|
264 |
+
"Who made an offer to buy Facebook for $1 billion in the mid-2000s?"
|
265 |
+
],
|
266 |
+
"answers": [
|
267 |
+
"I was born on May 14, 1984, in White Plains, New York, U.S.",
|
268 |
+
"I attended Phillips Exeter Academy before enrolling at Harvard University.",
|
269 |
+
"The original name of Facebook when it was launched in 2004 was 'thefacebook dot com.'",
|
270 |
+
"My roommates were Dustin Moskovitz and Chris Hughes, and they helped me add features and make Facebook available to other campuses across the country.",
|
271 |
+
"The distinctive feature of Facebook was its emphasis on real names and e-mail addresses.",
|
272 |
+
"I moved the headquarters of Facebook to Palo Alto, California, in the summer of 2004.",
|
273 |
+
"I talked venture capitalist Peter Thiel into giving me seed money to fund Facebook.",
|
274 |
+
"I dropped out of Harvard to concentrate on my fledgling company.",
|
275 |
+
"Facebook received $12.7 million in its first major infusion of venture capital in May 2005.",
|
276 |
+
"Facebook opened registration to high-school students four months after its launch.",
|
277 |
+
"Facebook expanded its user base to include regional networks, allowing anyone with an email address to join a network based on their location.",
|
278 |
+
"In 2007, Microsoft made a $240 million investment in Facebook.",
|
279 |
+
"My estimated net worth in 2008 was about $1.5 billion.",
|
280 |
+
"After Facebook's IPO in 2012, my net worth was estimated at more than $19 billion.",
|
281 |
+
"Facebook changed its name to Meta Platforms with an emphasis on the 'metaverse.'",
|
282 |
+
"I used the term 'metaverse' to describe the emphasis on virtual reality environments.",
|
283 |
+
"The 'social graph' in Facebook referred to the network of friends and friends of friends through which information was disseminated.",
|
284 |
+
"They could create profiles, upload photos and other media, and keep in touch with friends.",
|
285 |
+
"Half of the student body at Harvard signed up for Facebook within two weeks of its launch.",
|
286 |
+
"Yahoo! made the offer."
|
287 |
+
],
|
288 |
+
"gender": "M"
|
289 |
+
}
|
290 |
+
}
|
gen_embeds.py
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import argparse
|
2 |
+
from ctypes import alignment
|
3 |
+
import os
|
4 |
+
import sys
|
5 |
+
sys.path.append('rtvc/')
|
6 |
+
from pathlib import Path
|
7 |
+
import spacy
|
8 |
+
import matplotlib.pyplot as plt
|
9 |
+
|
10 |
+
import librosa
|
11 |
+
import numpy as np
|
12 |
+
import soundfile as sf
|
13 |
+
import torch
|
14 |
+
import noisereduce as nr
|
15 |
+
|
16 |
+
from rtvc.encoder import inference as encoder
|
17 |
+
from rtvc.encoder.params_data import *
|
18 |
+
from rtvc.synthesizer.inference import Synthesizer_infer
|
19 |
+
from rtvc.utils.argutils import print_args
|
20 |
+
from rtvc.utils.default_models import ensure_default_models
|
21 |
+
from rtvc.vocoder import inference as vocoder
|
22 |
+
from rtvc.speed_changer.fixSpeed import *
|
23 |
+
|
24 |
+
|
25 |
+
if __name__ == '__main__':
|
26 |
+
parser = argparse.ArgumentParser(
|
27 |
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
28 |
+
)
|
29 |
+
parser.add_argument("--run_id", type=str, default="default", help= \
|
30 |
+
"Name for this model. By default, training outputs will be stored to saved_models/<run_id>/. If a model state "
|
31 |
+
"from the same run ID was previously saved, the training will restart from there. Pass -f to overwrite saved "
|
32 |
+
"states and restart from scratch.")
|
33 |
+
parser.add_argument("-m", "--models_dir", type=Path, default="rtvc/saved_models",
|
34 |
+
help="Directory containing all saved models")
|
35 |
+
parser.add_argument("--weight", type=float, default=1,
|
36 |
+
help="weight of input audio for voice filter")
|
37 |
+
parser.add_argument("--griffin_lim",
|
38 |
+
action="store_true",
|
39 |
+
help="if True, use vocoder, else use griffin-lim")
|
40 |
+
parser.add_argument("--cpu", action="store_true", help=\
|
41 |
+
"If True, processing is done on CPU, even when a GPU is available.")
|
42 |
+
parser.add_argument("--no_sound", action="store_true", help=\
|
43 |
+
"If True, audio won't be played.")
|
44 |
+
parser.add_argument("--seed", type=int, default=None, help=\
|
45 |
+
"Optional random number seed value to make toolbox deterministic.")
|
46 |
+
args = parser.parse_args()
|
47 |
+
arg_dict = vars(args)
|
48 |
+
print_args(args, parser)
|
49 |
+
|
50 |
+
# Hide GPUs from Pytorch to force CPU processing
|
51 |
+
if arg_dict.pop("cpu"):
|
52 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
53 |
+
|
54 |
+
print("Running a test of your configuration...\n")
|
55 |
+
|
56 |
+
if torch.cuda.is_available():
|
57 |
+
device_id = torch.cuda.current_device()
|
58 |
+
gpu_properties = torch.cuda.get_device_properties(device_id)
|
59 |
+
## Print some environment information (for debugging purposes)
|
60 |
+
print("Found %d GPUs available. Using GPU %d (%s) of compute capability %d.%d with "
|
61 |
+
"%.1fGb total memory.\n" %
|
62 |
+
(torch.cuda.device_count(),
|
63 |
+
device_id,
|
64 |
+
gpu_properties.name,
|
65 |
+
gpu_properties.major,
|
66 |
+
gpu_properties.minor,
|
67 |
+
gpu_properties.total_memory / 1e9))
|
68 |
+
else:
|
69 |
+
print("Using CPU for inference.\n")
|
70 |
+
|
71 |
+
## Load the models one by one.
|
72 |
+
if not args.griffin_lim:
|
73 |
+
print("Preparing the encoder, the synthesizer and the vocoder...")
|
74 |
+
else:
|
75 |
+
print("Preparing the encoder and the synthesizer...")
|
76 |
+
ensure_default_models(args.run_id, Path("rtvc/saved_models"))
|
77 |
+
encoder.load_model(list(args.models_dir.glob(f"{args.run_id}/encoder.pt"))[0])
|
78 |
+
synthesizer = Synthesizer_infer(list(args.models_dir.glob(f"{args.run_id}/synthesizer.pt"))[0])
|
79 |
+
if not args.griffin_lim:
|
80 |
+
vocoder.load_model(list(args.models_dir.glob(f"{args.run_id}/vocoder.pt"))[0])
|
81 |
+
|
82 |
+
nlp = spacy.load('en_core_web_sm')
|
83 |
+
weight = arg_dict["weight"] # 声音美颜的用户语音权重
|
84 |
+
amp = 1
|
85 |
+
|
86 |
+
directory = "input_audios"
|
87 |
+
pathlist = Path(directory).rglob('*.*')
|
88 |
+
for path in pathlist:
|
89 |
+
path = str(path)
|
90 |
+
print(path)
|
91 |
+
# enter the number of reference audios
|
92 |
+
|
93 |
+
# Computing the embedding
|
94 |
+
# First, we load the wav using the function that the speaker encoder provides. This is
|
95 |
+
# important: there is preprocessing that must be applied.
|
96 |
+
|
97 |
+
# The following two methods are equivalent:
|
98 |
+
# - Directly load from the filepath:
|
99 |
+
# preprocessed_wav = encoder.preprocess_wav(in_fpath)
|
100 |
+
# - If the wav is already loaded:
|
101 |
+
|
102 |
+
# get duration info from input audio
|
103 |
+
in_fpath = Path(path.replace("\"", "").replace("\'", ""))
|
104 |
+
fpath_without_ext = os.path.splitext(str(in_fpath))[0]
|
105 |
+
speaker_name = os.path.normpath(fpath_without_ext).split(os.sep)[-1]
|
106 |
+
|
107 |
+
is_wav_file, wav, wav_path = TransFormat(in_fpath, 'wav')
|
108 |
+
# 除了m4a格式无法工作而必须转换以外,无论原格式是否为wav,从稳定性的角度考虑也最好再转为wav(因为某些wav本身不带比特率属性,无法在此代码中工作,因此需要转换以赋予其该属性)
|
109 |
+
|
110 |
+
if not is_wav_file:
|
111 |
+
os.remove(wav_path) # remove intermediate wav files
|
112 |
+
|
113 |
+
preprocessed_wav = encoder.preprocess_wav(wav)
|
114 |
+
|
115 |
+
print("Loaded input audio file succesfully")
|
116 |
+
|
117 |
+
# Then we derive the embedding. There are many functions and parameters that the
|
118 |
+
# speaker encoder interfaces. These are mostly for in-depth research. You will typically
|
119 |
+
# only use this function (with its default parameters):
|
120 |
+
embed = encoder.embed_utterance(preprocessed_wav)
|
121 |
+
embed[embed < set_zero_thres]=0 # 噪声值置零
|
122 |
+
if not os.path.exists("embeds"):
|
123 |
+
os.mkdir("embeds")
|
124 |
+
np.save(f"embeds/{speaker_name}.npy", embed)
|
requirements.txt
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
inflect==5.3.0
|
2 |
+
librosa==0.8.1
|
3 |
+
matplotlib==3.5.1
|
4 |
+
Pillow==8.4.0
|
5 |
+
PyQt5==5.15.6
|
6 |
+
scikit-learn==1.0.2
|
7 |
+
scipy==1.7.3
|
8 |
+
sounddevice==0.4.3
|
9 |
+
SoundFile==0.10.3.post1
|
10 |
+
tqdm==4.62.3
|
11 |
+
umap-learn==0.5.2
|
12 |
+
Unidecode==1.3.2
|
13 |
+
urllib3==1.26.7
|
14 |
+
visdom==0.1.8.9
|
15 |
+
noisereduce==2.0.1
|
16 |
+
pydub==0.25.1
|
17 |
+
ffmpeg==1.4
|
18 |
+
seaborn==0.12.1
|
19 |
+
spacy==3.7.2
|
20 |
+
praat-parselmouth==0.4.1
|
21 |
+
torch==1.11.0
|
22 |
+
torchaudio==0.11.0
|
23 |
+
tensorflow-cpu==2.9.0
|
24 |
+
denoiser==0.1.5
|
25 |
+
SpeechRecognition==3.10.0
|
26 |
+
transformers==4.25.1
|
27 |
+
streamlit==1.27.2
|
28 |
+
sentence-transformers==2.2.2
|
29 |
+
evaluate==0.4.1
|
30 |
+
https://huggingface.co/spacy/en_core_web_sm/resolve/main/en_core_web_sm-any-py3-none-any.whl
|
31 |
+
protobuf==3.20
|
rtvc/.gitattributes
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
rtvc/saved_models/default/*.pt filter=lfs diff=lfs merge=lfs -text
|
rtvc/.gitignore
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
out_audios/
|
2 |
+
launch.json
|
3 |
+
*.pyc
|
4 |
+
*.aux
|
5 |
+
*.log
|
6 |
+
*.out
|
7 |
+
*.synctex.gz
|
8 |
+
*.suo
|
9 |
+
*__pycache__
|
10 |
+
*.idea
|
11 |
+
*.ipynb_checkpoints
|
12 |
+
*.pickle
|
13 |
+
*.npy
|
14 |
+
*.bz2
|
15 |
+
*.blg
|
16 |
+
*.bbl
|
17 |
+
*.bcf
|
18 |
+
*.toc
|
19 |
+
*.sh
|
20 |
+
*.pt
|
21 |
+
*.whl
|
22 |
+
*.m4a
|
23 |
+
log/
|
24 |
+
|
25 |
+
syn_results
|
26 |
+
toolbox_results
|
27 |
+
dim_reduction_results
|
rtvc/CHANGELOG.md
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
## What's new
|
2 |
+
**2022.05.19:** We calculated GE2E loss in encoder with CUDA rather than originally-configured CPU. It speeds up the encoder training speed.<br>
|
3 |
+
**2022.07.15:** We added Loss animation plot for synthesizer and vocoder.<br>
|
4 |
+
**2022.07.19:** We added response time and Griffin-Lim vocoder results for demo_toolbox.<br>
|
5 |
+
**2022.07.29:** We added model validation for encoder, synthesizer and vocoder.<br>
|
6 |
+
**2022.08.02:** We added voxceleb train and dev data for encoder. We added [noisereduce](https://github.com/timsainb/noisereduce) denoiser for the output wav from vocoder.<br>
|
7 |
+
**2022.08.06:** We split the long text into short sentences using spacy for input of synthesizer. Make sure to install spaCy model en_core_web_sm by
|
8 |
+
`python -m spacy download en_core_web_sm`<br>
|
9 |
+
**2022.09.02:** We set prop_decrease=0.6 for male and 0.9 for female in noisereduce function.(输出滤波,男女声使用不同的滤波参数)<br>
|
10 |
+
**2022.09.26:** We added speed adjustment(声音变速) for output audios using praat, install parselmouth using pip: `pip install praat-parselmouth`<br>
|
11 |
+
**2022.10.10:** We added voice filter functioning(声音美颜) for input audios, the weight ratio of the input audio embed and the standard audio embed is 7: 3. <br>
|
12 |
+
**2022.10.25:** We set small values(<0.06) to zeros in embed.(对嵌入向量较小值置零)<br>
|
13 |
+
**2022.10.26:** The split frequency for input audio is 170Hz. The split frequency for output noise reduce is 165Hz.<br>
|
14 |
+
**2022.12.01:** merge the single sentences to input.<br>
|
15 |
+
**2022.12.31:** added speaker embeddings dimension reduction visualzation results.<br>
|
16 |
+
**2023.01.01:** did more text preprocessing and text cleaning for TTS text input.<br>
|
17 |
+
**2023.02.27:** preprocessed ascii chars and abbreviations.<br>
|
18 |
+
**2023.06.09:** We added VCTK train and dev data for synthesizer. We also combine a [deep learning denoiser](https://github.com/facebookresearch/denoiser) with the [noisereduce](https://github.com/timsainb/noisereduce) denoiser for optimized output wav quality.<br>
|
rtvc/LICENSE.md
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Modified & original work Copyright (c) 2019 Corentin Jemine (https://github.com/CorentinJ)
|
4 |
+
Original work Copyright (c) 2018 Rayhane Mama (https://github.com/Rayhane-mamah)
|
5 |
+
Original work Copyright (c) 2019 fatchord (https://github.com/fatchord)
|
6 |
+
Original work Copyright (c) 2015 braindead (https://github.com/braindead)
|
7 |
+
|
8 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
9 |
+
of this software and associated documentation files (the "Software"), to deal
|
10 |
+
in the Software without restriction, including without limitation the rights
|
11 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12 |
+
copies of the Software, and to permit persons to whom the Software is
|
13 |
+
furnished to do so, subject to the following conditions:
|
14 |
+
|
15 |
+
The above copyright notice and this permission notice shall be included in all
|
16 |
+
copies or substantial portions of the Software.
|
17 |
+
|
18 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
24 |
+
SOFTWARE.
|
rtvc/README.md
ADDED
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Real-Time Voice Cloning v2
|
2 |
+
|
3 |
+
### What is this?
|
4 |
+
It is an improved version of [Real-Time-Voice-Cloning](https://github.com/CorentinJ/Real-Time-Voice-Cloning). Our emotion voice cloning implementation is [here](https://github.com/liuhaozhe6788/voice-cloning-collab/tree/add_emotion)!
|
5 |
+
|
6 |
+
## Installation
|
7 |
+
1. Install [ffmpeg](https://ffmpeg.org/download.html#get-packages). This is necessary for reading audio files.
|
8 |
+
|
9 |
+
2. Create a new conda environment with
|
10 |
+
```
|
11 |
+
conda create -n rtvc python=3.7.13
|
12 |
+
```
|
13 |
+
3. Install [PyTorch](https://download.pytorch.org/whl/torch_stable.html). Pick the proposed CUDA version if you have a GPU, otherwise pick CPU.
|
14 |
+
My torch version: `torch=1.9.1+cu111`
|
15 |
+
`torchvision=0.10.1+cu111`
|
16 |
+
|
17 |
+
4. Install the remaining requirements with
|
18 |
+
```
|
19 |
+
pip install -r requirements.txt
|
20 |
+
```
|
21 |
+
|
22 |
+
5. Install spaCy model en_core_web_sm by
|
23 |
+
`python -m spacy download en_core_web_sm`
|
24 |
+
|
25 |
+
|
26 |
+
## Training
|
27 |
+
|
28 |
+
### Encoder
|
29 |
+
|
30 |
+
**Download dataset:**
|
31 |
+
|
32 |
+
1. [LibriSpeech](https://www.openslr.org/12): train-other-500 for training, dev-other for validation
|
33 |
+
(extract as <datasets_root>/LibriSpeech/<dataset_name>)
|
34 |
+
|
35 |
+
2. [VoxCeleb1](https://mm.kaist.ac.kr/datasets/voxceleb/): Dev A - D for training, Test for validation as well as the metadata file `vox1_meta.csv` (extract as <datasets_root>/VoxCeleb1/ and <datasets_root>/VoxCeleb1/vox1_meta.csv)
|
36 |
+
|
37 |
+
3. [VoxCeleb2](https://mm.kaist.ac.kr/datasets/voxceleb/): Dev A - H for training, Test for validation
|
38 |
+
(extract as <datasets_root>/VoxCeleb2/)
|
39 |
+
|
40 |
+
**Encoder preprocessing:**
|
41 |
+
```
|
42 |
+
python encoder_preprocess.py <datasets_root>
|
43 |
+
```
|
44 |
+
|
45 |
+
**Encoder training:**
|
46 |
+
|
47 |
+
it is recommended to start visdom server for monitor training with
|
48 |
+
```
|
49 |
+
visdom
|
50 |
+
```
|
51 |
+
then start training with
|
52 |
+
```
|
53 |
+
python encoder_train.py <model_id> <datasets_root>/SV2TTS/encoder
|
54 |
+
```
|
55 |
+
### Synthesizer
|
56 |
+
|
57 |
+
**Download dataset:**
|
58 |
+
1. [LibriSpeech](https://www.openslr.org/12): train-clean-100 and train-clean-360 for training, dev-clean for validation (extract as <datasets_root>/LibriSpeech/<dataset_name>)
|
59 |
+
2. [LibriSpeech alignments](https://drive.google.com/file/d/1WYfgr31T-PPwMcxuAq09XZfHQO5Mw8fE/view?usp=sharing): merge the directory structure with the LibriSpeech datasets you have downloaded (do not take the alignments from the datasets you haven't downloaded else the scripts will think you have them)
|
60 |
+
3. [VCTK](https://datashare.ed.ac.uk/handle/10283/3443): used for training and validation
|
61 |
+
|
62 |
+
**Synthesizer preprocessing:**
|
63 |
+
```
|
64 |
+
python synthesizer_preprocess_audio.py <datasets_root>
|
65 |
+
python synthesizer_preprocess_embeds.py <datasets_root>/SV2TTS/synthesizer
|
66 |
+
```
|
67 |
+
|
68 |
+
**Synthesizer training:**
|
69 |
+
```
|
70 |
+
python synthesizer_train.py <model_id> <datasets_root>/SV2TTS/synthesizer --use_tb
|
71 |
+
```
|
72 |
+
if you want to monitor the training progress, run
|
73 |
+
```
|
74 |
+
tensorboard --logdir log/vc/synthesizer --host localhost --port 8088
|
75 |
+
```
|
76 |
+
### Vocoder
|
77 |
+
|
78 |
+
**Download dataset:**
|
79 |
+
|
80 |
+
The same as synthesizer. You can skip this if you already download synthesizer training dataset.
|
81 |
+
|
82 |
+
**Vocoder preprocessing:**
|
83 |
+
```
|
84 |
+
python vocoder_preprocess.py <datasets_root>
|
85 |
+
```
|
86 |
+
|
87 |
+
**Vocoder training:**
|
88 |
+
```
|
89 |
+
python vocoder_train.py <model_id> <datasets_root> --use_tb
|
90 |
+
```
|
91 |
+
if you want to monitor the training progress, run
|
92 |
+
```
|
93 |
+
tensorboard --logdir log/vc/vocoder --host localhost --port 8080
|
94 |
+
```
|
95 |
+
**Note:**
|
96 |
+
|
97 |
+
Training breakpoints are saved periodically, so you can run the training command and resume training when the breakpoint exists.
|
98 |
+
|
99 |
+
## Inference
|
100 |
+
|
101 |
+
**Terminal:**
|
102 |
+
```
|
103 |
+
python demo_cli.py
|
104 |
+
```
|
105 |
+
First input the number of audios, then input the audio file paths, then input the text message. The attention alignments and mel spectrogram are stored in syn_results/. The generated audio is stored in out_audios/.
|
106 |
+
|
107 |
+
**GUI demo:**
|
108 |
+
```
|
109 |
+
python demo_toolbox.py
|
110 |
+
```
|
111 |
+
## Dimension reduction visualization
|
112 |
+
**Download dataset:**
|
113 |
+
|
114 |
+
[LibriSpeech](https://www.openslr.org/12): test-other
|
115 |
+
(extract as <datasets_root>/LibriSpeech/<dataset_name>)
|
116 |
+
|
117 |
+
**Preprocessing:**
|
118 |
+
```
|
119 |
+
python encoder_test_preprocess.py <datasets_root>
|
120 |
+
```
|
121 |
+
|
122 |
+
**Visualization:**
|
123 |
+
```
|
124 |
+
python encoder_test_visualization.py <model_id> <datasets_root>
|
125 |
+
```
|
126 |
+
The results are saved in dim_reduction_results/.
|
127 |
+
|
128 |
+
## Pretrained models
|
129 |
+
You can download the pretrained model from [this](https://drive.google.com/drive/folders/11DFU_JBGet_HEwUoPZGDfe-fDZ42eqiG) and extract as saved_models/default
|
130 |
+
|
131 |
+
## Demo results
|
132 |
+
The audio results are [here](https://liuhaozhe6788.github.io/voice-cloning-collab/index.html)
|
rtvc/css/bootstrap.min.css
ADDED
The diff for this file is too large to render.
See raw diff
|
|
rtvc/css/custom.css
ADDED
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body {
|
2 |
+
font-family: "Roboto", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
3 |
+
background-color: #FCFCFC;
|
4 |
+
-webkit-font-smoothing: antialiased;
|
5 |
+
font-size: 1.8em;
|
6 |
+
line-height: 1.5;
|
7 |
+
font-weight: 300;
|
8 |
+
width: 100%
|
9 |
+
}
|
10 |
+
|
11 |
+
h1, h2, h3, h4, h5, h6 {
|
12 |
+
color: #263c4c;
|
13 |
+
}
|
14 |
+
h2, h3, h4, h5, h6 {
|
15 |
+
margin-top: 5rem;
|
16 |
+
margin-bottom: 3rem;
|
17 |
+
font-weight: bold;
|
18 |
+
padding-bottom: 10px;
|
19 |
+
}
|
20 |
+
|
21 |
+
h1 { font-size: 3.0rem; }
|
22 |
+
h2 {
|
23 |
+
margin-top: 6rem;
|
24 |
+
font-size: 2.6rem;
|
25 |
+
}
|
26 |
+
h3 { font-size: 2.1rem; }
|
27 |
+
h4,
|
28 |
+
h5,
|
29 |
+
h6 { font-size: 1.9rem; }
|
30 |
+
|
31 |
+
h2.entry-title {
|
32 |
+
font-size: 2.1rem;
|
33 |
+
margin-top: 0;
|
34 |
+
font-weight: 400;
|
35 |
+
border-bottom: none;
|
36 |
+
}
|
37 |
+
|
38 |
+
li {
|
39 |
+
margin-bottom: 0.5rem;
|
40 |
+
margin-left: 0.7em;
|
41 |
+
}
|
42 |
+
|
43 |
+
img {
|
44 |
+
max-width: 100%;
|
45 |
+
height: auto;
|
46 |
+
vertical-align: middle;
|
47 |
+
border: 0;
|
48 |
+
margin: 1em 0;
|
49 |
+
}
|
50 |
+
|
51 |
+
header,
|
52 |
+
footer {
|
53 |
+
margin: 4rem 0;
|
54 |
+
text-align: center;
|
55 |
+
}
|
56 |
+
|
57 |
+
main {
|
58 |
+
margin: 4rem 0;
|
59 |
+
}
|
60 |
+
|
61 |
+
.container {
|
62 |
+
width: 90%;
|
63 |
+
/* max-width: 700px; */
|
64 |
+
}
|
65 |
+
|
66 |
+
.header-logo img {
|
67 |
+
border-radius: 50%;
|
68 |
+
border: 2px solid #E1E1E1;
|
69 |
+
}
|
70 |
+
|
71 |
+
.header-logo img:hover {
|
72 |
+
border-color: #F1F1F1;
|
73 |
+
}
|
74 |
+
|
75 |
+
.site-title {
|
76 |
+
margin-top: 2rem;
|
77 |
+
}
|
78 |
+
|
79 |
+
.entry-title {
|
80 |
+
margin-bottom: 0;
|
81 |
+
}
|
82 |
+
|
83 |
+
.entry-title a {
|
84 |
+
text-decoration: none;
|
85 |
+
}
|
86 |
+
|
87 |
+
.entry-meta {
|
88 |
+
display: inline-block;
|
89 |
+
margin-bottom: 2rem;
|
90 |
+
font-size: 1.6rem;
|
91 |
+
color: #888;
|
92 |
+
}
|
93 |
+
|
94 |
+
.footer-link {
|
95 |
+
margin: 2rem 0;
|
96 |
+
}
|
97 |
+
|
98 |
+
.hr {
|
99 |
+
height: 1px;
|
100 |
+
margin: 2rem 0;
|
101 |
+
background: #E1E1E1;
|
102 |
+
background: -webkit-gradient(linear, left top, right top, from(white), color-stop(#E1E1E1), to(white));
|
103 |
+
background: -webkit-linear-gradient(left, white, #E1E1E1, white);
|
104 |
+
background: linear-gradient(to right, white, #E1E1E1, white);
|
105 |
+
}
|
106 |
+
|
107 |
+
article .social {
|
108 |
+
height: 40px;
|
109 |
+
padding: 10px 0;
|
110 |
+
}
|
111 |
+
|
112 |
+
address {
|
113 |
+
margin: 0;
|
114 |
+
font-size:0.9em;
|
115 |
+
max-height: 60px;
|
116 |
+
font-weight: 300;
|
117 |
+
font-style: normal;
|
118 |
+
display: block;
|
119 |
+
}
|
120 |
+
|
121 |
+
address a {
|
122 |
+
text-decoration: none;
|
123 |
+
}
|
124 |
+
|
125 |
+
.avatar-bottom img {
|
126 |
+
border-radius: 50%;
|
127 |
+
border: 1px solid #E1E1E1;
|
128 |
+
float: left;
|
129 |
+
max-width: 100%;
|
130 |
+
vertical-align: middle;
|
131 |
+
width: 32px;
|
132 |
+
height: 32px;
|
133 |
+
margin: 0 20px 0 0;
|
134 |
+
margin-top: -7px;
|
135 |
+
}
|
136 |
+
|
137 |
+
.avatar-bottom img:hover {
|
138 |
+
border-color: #F1F1F1;
|
139 |
+
}
|
140 |
+
|
141 |
+
.copyright {
|
142 |
+
font-size:0.9em;
|
143 |
+
font-weight: 300;
|
144 |
+
}
|
145 |
+
|
146 |
+
.github {
|
147 |
+
float: right;
|
148 |
+
}
|
149 |
+
|
150 |
+
blockquote {
|
151 |
+
position: relative;
|
152 |
+
padding: 10px 10px 10px 32px;
|
153 |
+
box-sizing: border-box;
|
154 |
+
font-style: italic;
|
155 |
+
color: #464646;
|
156 |
+
background: #e0e0e0;
|
157 |
+
}
|
158 |
+
|
159 |
+
blockquote:before{
|
160 |
+
display: inline-block;
|
161 |
+
position: absolute;
|
162 |
+
top: 0;
|
163 |
+
left: 0;
|
164 |
+
vertical-align: middle;
|
165 |
+
content: "\f10d";
|
166 |
+
font-family: FontAwesome;
|
167 |
+
color: #e0e0e0;
|
168 |
+
font-size: 22px;
|
169 |
+
line-height: 1;
|
170 |
+
z-index: 2;
|
171 |
+
}
|
172 |
+
|
173 |
+
blockquote:after{
|
174 |
+
position: absolute;
|
175 |
+
content: '';
|
176 |
+
left: 0;
|
177 |
+
top: 0;
|
178 |
+
border-width: 0 0 40px 40px;
|
179 |
+
border-style: solid;
|
180 |
+
border-color: transparent #ffffff;
|
181 |
+
}
|
182 |
+
|
183 |
+
blockquote p {
|
184 |
+
position: relative;
|
185 |
+
padding: 0;
|
186 |
+
margin: 10px 0;
|
187 |
+
z-index: 3;
|
188 |
+
line-height: 1.7;
|
189 |
+
}
|
190 |
+
|
191 |
+
blockquote cite {
|
192 |
+
display: block;
|
193 |
+
text-align: right;
|
194 |
+
color: #888888;
|
195 |
+
font-size: 0.9em;
|
196 |
+
}
|
rtvc/css/normalize.css
ADDED
@@ -0,0 +1,427 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
|
2 |
+
|
3 |
+
/**
|
4 |
+
* 1. Set default font family to sans-serif.
|
5 |
+
* 2. Prevent iOS text size adjust after orientation change, without disabling
|
6 |
+
* user zoom.
|
7 |
+
*/
|
8 |
+
|
9 |
+
html {
|
10 |
+
font-family: sans-serif; /* 1 */
|
11 |
+
-ms-text-size-adjust: 100%; /* 2 */
|
12 |
+
-webkit-text-size-adjust: 100%; /* 2 */
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Remove default margin.
|
17 |
+
*/
|
18 |
+
|
19 |
+
body {
|
20 |
+
margin: 0;
|
21 |
+
}
|
22 |
+
|
23 |
+
/* HTML5 display definitions
|
24 |
+
========================================================================== */
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Correct `block` display not defined for any HTML5 element in IE 8/9.
|
28 |
+
* Correct `block` display not defined for `details` or `summary` in IE 10/11
|
29 |
+
* and Firefox.
|
30 |
+
* Correct `block` display not defined for `main` in IE 11.
|
31 |
+
*/
|
32 |
+
|
33 |
+
article,
|
34 |
+
aside,
|
35 |
+
details,
|
36 |
+
figcaption,
|
37 |
+
figure,
|
38 |
+
footer,
|
39 |
+
header,
|
40 |
+
hgroup,
|
41 |
+
main,
|
42 |
+
menu,
|
43 |
+
nav,
|
44 |
+
section,
|
45 |
+
summary {
|
46 |
+
display: block;
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* 1. Correct `inline-block` display not defined in IE 8/9.
|
51 |
+
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
|
52 |
+
*/
|
53 |
+
|
54 |
+
audio,
|
55 |
+
canvas,
|
56 |
+
progress,
|
57 |
+
video {
|
58 |
+
display: inline-block; /* 1 */
|
59 |
+
vertical-align: baseline; /* 2 */
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Prevent modern browsers from displaying `audio` without controls.
|
64 |
+
* Remove excess height in iOS 5 devices.
|
65 |
+
*/
|
66 |
+
|
67 |
+
audio:not([controls]) {
|
68 |
+
display: none;
|
69 |
+
height: 0;
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Address `[hidden]` styling not present in IE 8/9/10.
|
74 |
+
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
|
75 |
+
*/
|
76 |
+
|
77 |
+
[hidden],
|
78 |
+
template {
|
79 |
+
display: none;
|
80 |
+
}
|
81 |
+
|
82 |
+
/* Links
|
83 |
+
========================================================================== */
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Remove the gray background color from active links in IE 10.
|
87 |
+
*/
|
88 |
+
|
89 |
+
a {
|
90 |
+
background-color: transparent;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Improve readability when focused and also mouse hovered in all browsers.
|
95 |
+
*/
|
96 |
+
|
97 |
+
a:active,
|
98 |
+
a:hover {
|
99 |
+
outline: 0;
|
100 |
+
}
|
101 |
+
|
102 |
+
/* Text-level semantics
|
103 |
+
========================================================================== */
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
|
107 |
+
*/
|
108 |
+
|
109 |
+
abbr[title] {
|
110 |
+
border-bottom: 1px dotted;
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
|
115 |
+
*/
|
116 |
+
|
117 |
+
b,
|
118 |
+
strong {
|
119 |
+
font-weight: bold;
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Address styling not present in Safari and Chrome.
|
124 |
+
*/
|
125 |
+
|
126 |
+
dfn {
|
127 |
+
font-style: italic;
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Address variable `h1` font-size and margin within `section` and `article`
|
132 |
+
* contexts in Firefox 4+, Safari, and Chrome.
|
133 |
+
*/
|
134 |
+
|
135 |
+
h1 {
|
136 |
+
font-size: 2em;
|
137 |
+
margin: 0.67em 0;
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Address styling not present in IE 8/9.
|
142 |
+
*/
|
143 |
+
|
144 |
+
mark {
|
145 |
+
background: #ff0;
|
146 |
+
color: #000;
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Address inconsistent and variable font size in all browsers.
|
151 |
+
*/
|
152 |
+
|
153 |
+
small {
|
154 |
+
font-size: 80%;
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
159 |
+
*/
|
160 |
+
|
161 |
+
sub,
|
162 |
+
sup {
|
163 |
+
font-size: 75%;
|
164 |
+
line-height: 0;
|
165 |
+
position: relative;
|
166 |
+
vertical-align: baseline;
|
167 |
+
}
|
168 |
+
|
169 |
+
sup {
|
170 |
+
top: -0.5em;
|
171 |
+
}
|
172 |
+
|
173 |
+
sub {
|
174 |
+
bottom: -0.25em;
|
175 |
+
}
|
176 |
+
|
177 |
+
/* Embedded content
|
178 |
+
========================================================================== */
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Remove border when inside `a` element in IE 8/9/10.
|
182 |
+
*/
|
183 |
+
|
184 |
+
img {
|
185 |
+
border: 0;
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Correct overflow not hidden in IE 9/10/11.
|
190 |
+
*/
|
191 |
+
|
192 |
+
svg:not(:root) {
|
193 |
+
overflow: hidden;
|
194 |
+
}
|
195 |
+
|
196 |
+
/* Grouping content
|
197 |
+
========================================================================== */
|
198 |
+
|
199 |
+
/**
|
200 |
+
* Address margin not present in IE 8/9 and Safari.
|
201 |
+
*/
|
202 |
+
|
203 |
+
figure {
|
204 |
+
margin: 1em 40px;
|
205 |
+
}
|
206 |
+
|
207 |
+
/**
|
208 |
+
* Address differences between Firefox and other browsers.
|
209 |
+
*/
|
210 |
+
|
211 |
+
hr {
|
212 |
+
-moz-box-sizing: content-box;
|
213 |
+
box-sizing: content-box;
|
214 |
+
height: 0;
|
215 |
+
}
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Contain overflow in all browsers.
|
219 |
+
*/
|
220 |
+
|
221 |
+
pre {
|
222 |
+
overflow: auto;
|
223 |
+
}
|
224 |
+
|
225 |
+
/**
|
226 |
+
* Address odd `em`-unit font size rendering in all browsers.
|
227 |
+
*/
|
228 |
+
|
229 |
+
code,
|
230 |
+
kbd,
|
231 |
+
pre,
|
232 |
+
samp {
|
233 |
+
font-family: monospace, monospace;
|
234 |
+
font-size: 1em;
|
235 |
+
}
|
236 |
+
|
237 |
+
/* Forms
|
238 |
+
========================================================================== */
|
239 |
+
|
240 |
+
/**
|
241 |
+
* Known limitation: by default, Chrome and Safari on OS X allow very limited
|
242 |
+
* styling of `select`, unless a `border` property is set.
|
243 |
+
*/
|
244 |
+
|
245 |
+
/**
|
246 |
+
* 1. Correct color not being inherited.
|
247 |
+
* Known issue: affects color of disabled elements.
|
248 |
+
* 2. Correct font properties not being inherited.
|
249 |
+
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
|
250 |
+
*/
|
251 |
+
|
252 |
+
button,
|
253 |
+
input,
|
254 |
+
optgroup,
|
255 |
+
select,
|
256 |
+
textarea {
|
257 |
+
color: inherit; /* 1 */
|
258 |
+
font: inherit; /* 2 */
|
259 |
+
margin: 0; /* 3 */
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Address `overflow` set to `hidden` in IE 8/9/10/11.
|
264 |
+
*/
|
265 |
+
|
266 |
+
button {
|
267 |
+
overflow: visible;
|
268 |
+
}
|
269 |
+
|
270 |
+
/**
|
271 |
+
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
272 |
+
* All other form control elements do not inherit `text-transform` values.
|
273 |
+
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
|
274 |
+
* Correct `select` style inheritance in Firefox.
|
275 |
+
*/
|
276 |
+
|
277 |
+
button,
|
278 |
+
select {
|
279 |
+
text-transform: none;
|
280 |
+
}
|
281 |
+
|
282 |
+
/**
|
283 |
+
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
284 |
+
* and `video` controls.
|
285 |
+
* 2. Correct inability to style clickable `input` types in iOS.
|
286 |
+
* 3. Improve usability and consistency of cursor style between image-type
|
287 |
+
* `input` and others.
|
288 |
+
*/
|
289 |
+
|
290 |
+
button,
|
291 |
+
html input[type="button"], /* 1 */
|
292 |
+
input[type="reset"],
|
293 |
+
input[type="submit"] {
|
294 |
+
-webkit-appearance: button; /* 2 */
|
295 |
+
cursor: pointer; /* 3 */
|
296 |
+
}
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Re-set default cursor for disabled elements.
|
300 |
+
*/
|
301 |
+
|
302 |
+
button[disabled],
|
303 |
+
html input[disabled] {
|
304 |
+
cursor: default;
|
305 |
+
}
|
306 |
+
|
307 |
+
/**
|
308 |
+
* Remove inner padding and border in Firefox 4+.
|
309 |
+
*/
|
310 |
+
|
311 |
+
button::-moz-focus-inner,
|
312 |
+
input::-moz-focus-inner {
|
313 |
+
border: 0;
|
314 |
+
padding: 0;
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
|
319 |
+
* the UA stylesheet.
|
320 |
+
*/
|
321 |
+
|
322 |
+
input {
|
323 |
+
line-height: normal;
|
324 |
+
}
|
325 |
+
|
326 |
+
/**
|
327 |
+
* It's recommended that you don't attempt to style these elements.
|
328 |
+
* Firefox's implementation doesn't respect box-sizing, padding, or width.
|
329 |
+
*
|
330 |
+
* 1. Address box sizing set to `content-box` in IE 8/9/10.
|
331 |
+
* 2. Remove excess padding in IE 8/9/10.
|
332 |
+
*/
|
333 |
+
|
334 |
+
input[type="checkbox"],
|
335 |
+
input[type="radio"] {
|
336 |
+
box-sizing: border-box; /* 1 */
|
337 |
+
padding: 0; /* 2 */
|
338 |
+
}
|
339 |
+
|
340 |
+
/**
|
341 |
+
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
|
342 |
+
* `font-size` values of the `input`, it causes the cursor style of the
|
343 |
+
* decrement button to change from `default` to `text`.
|
344 |
+
*/
|
345 |
+
|
346 |
+
input[type="number"]::-webkit-inner-spin-button,
|
347 |
+
input[type="number"]::-webkit-outer-spin-button {
|
348 |
+
height: auto;
|
349 |
+
}
|
350 |
+
|
351 |
+
/**
|
352 |
+
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
|
353 |
+
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
|
354 |
+
* (include `-moz` to future-proof).
|
355 |
+
*/
|
356 |
+
|
357 |
+
input[type="search"] {
|
358 |
+
-webkit-appearance: textfield; /* 1 */
|
359 |
+
-moz-box-sizing: content-box;
|
360 |
+
-webkit-box-sizing: content-box; /* 2 */
|
361 |
+
box-sizing: content-box;
|
362 |
+
}
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
|
366 |
+
* Safari (but not Chrome) clips the cancel button when the search input has
|
367 |
+
* padding (and `textfield` appearance).
|
368 |
+
*/
|
369 |
+
|
370 |
+
input[type="search"]::-webkit-search-cancel-button,
|
371 |
+
input[type="search"]::-webkit-search-decoration {
|
372 |
+
-webkit-appearance: none;
|
373 |
+
}
|
374 |
+
|
375 |
+
/**
|
376 |
+
* Define consistent border, margin, and padding.
|
377 |
+
*/
|
378 |
+
|
379 |
+
fieldset {
|
380 |
+
border: 1px solid #c0c0c0;
|
381 |
+
margin: 0 2px;
|
382 |
+
padding: 0.35em 0.625em 0.75em;
|
383 |
+
}
|
384 |
+
|
385 |
+
/**
|
386 |
+
* 1. Correct `color` not being inherited in IE 8/9/10/11.
|
387 |
+
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
388 |
+
*/
|
389 |
+
|
390 |
+
legend {
|
391 |
+
border: 0; /* 1 */
|
392 |
+
padding: 0; /* 2 */
|
393 |
+
}
|
394 |
+
|
395 |
+
/**
|
396 |
+
* Remove default vertical scrollbar in IE 8/9/10/11.
|
397 |
+
*/
|
398 |
+
|
399 |
+
textarea {
|
400 |
+
overflow: auto;
|
401 |
+
}
|
402 |
+
|
403 |
+
/**
|
404 |
+
* Don't inherit the `font-weight` (applied by a rule above).
|
405 |
+
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
|
406 |
+
*/
|
407 |
+
|
408 |
+
optgroup {
|
409 |
+
font-weight: bold;
|
410 |
+
}
|
411 |
+
|
412 |
+
/* Tables
|
413 |
+
========================================================================== */
|
414 |
+
|
415 |
+
/**
|
416 |
+
* Remove most spacing between table cells.
|
417 |
+
*/
|
418 |
+
|
419 |
+
table {
|
420 |
+
border-collapse: collapse;
|
421 |
+
border-spacing: 0;
|
422 |
+
}
|
423 |
+
|
424 |
+
td,
|
425 |
+
th {
|
426 |
+
padding: 0;
|
427 |
+
}
|
rtvc/css/skeleton.css
ADDED
@@ -0,0 +1,418 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
* Skeleton V2.0.4
|
3 |
+
* Copyright 2014, Dave Gamache
|
4 |
+
* www.getskeleton.com
|
5 |
+
* Free to use under the MIT license.
|
6 |
+
* http://www.opensource.org/licenses/mit-license.php
|
7 |
+
* 12/29/2014
|
8 |
+
*/
|
9 |
+
|
10 |
+
|
11 |
+
/* Table of contents
|
12 |
+
––––––––––––––––––––––––––––––––––––––––––––––––––
|
13 |
+
- Grid
|
14 |
+
- Base Styles
|
15 |
+
- Typography
|
16 |
+
- Links
|
17 |
+
- Buttons
|
18 |
+
- Forms
|
19 |
+
- Lists
|
20 |
+
- Code
|
21 |
+
- Tables
|
22 |
+
- Spacing
|
23 |
+
- Utilities
|
24 |
+
- Clearing
|
25 |
+
- Media Queries
|
26 |
+
*/
|
27 |
+
|
28 |
+
|
29 |
+
/* Grid
|
30 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
31 |
+
.container {
|
32 |
+
position: relative;
|
33 |
+
width: 100%;
|
34 |
+
max-width: 960px;
|
35 |
+
margin: 0 auto;
|
36 |
+
padding: 0 20px;
|
37 |
+
box-sizing: border-box; }
|
38 |
+
.column,
|
39 |
+
.columns {
|
40 |
+
width: 100%;
|
41 |
+
float: left;
|
42 |
+
box-sizing: border-box; }
|
43 |
+
|
44 |
+
/* For devices larger than 400px */
|
45 |
+
@media (min-width: 400px) {
|
46 |
+
.container {
|
47 |
+
width: 85%;
|
48 |
+
padding: 0; }
|
49 |
+
}
|
50 |
+
|
51 |
+
/* For devices larger than 550px */
|
52 |
+
@media (min-width: 550px) {
|
53 |
+
.container {
|
54 |
+
width: 80%; }
|
55 |
+
.column,
|
56 |
+
.columns {
|
57 |
+
margin-left: 4%; }
|
58 |
+
.column:first-child,
|
59 |
+
.columns:first-child {
|
60 |
+
margin-left: 0; }
|
61 |
+
|
62 |
+
.one.column,
|
63 |
+
.one.columns { width: 4.66666666667%; }
|
64 |
+
.two.columns { width: 13.3333333333%; }
|
65 |
+
.three.columns { width: 22%; }
|
66 |
+
.four.columns { width: 30.6666666667%; }
|
67 |
+
.five.columns { width: 39.3333333333%; }
|
68 |
+
.six.columns { width: 48%; }
|
69 |
+
.seven.columns { width: 56.6666666667%; }
|
70 |
+
.eight.columns { width: 65.3333333333%; }
|
71 |
+
.nine.columns { width: 74.0%; }
|
72 |
+
.ten.columns { width: 82.6666666667%; }
|
73 |
+
.eleven.columns { width: 91.3333333333%; }
|
74 |
+
.twelve.columns { width: 100%; margin-left: 0; }
|
75 |
+
|
76 |
+
.one-third.column { width: 30.6666666667%; }
|
77 |
+
.two-thirds.column { width: 65.3333333333%; }
|
78 |
+
|
79 |
+
.one-half.column { width: 48%; }
|
80 |
+
|
81 |
+
/* Offsets */
|
82 |
+
.offset-by-one.column,
|
83 |
+
.offset-by-one.columns { margin-left: 8.66666666667%; }
|
84 |
+
.offset-by-two.column,
|
85 |
+
.offset-by-two.columns { margin-left: 17.3333333333%; }
|
86 |
+
.offset-by-three.column,
|
87 |
+
.offset-by-three.columns { margin-left: 26%; }
|
88 |
+
.offset-by-four.column,
|
89 |
+
.offset-by-four.columns { margin-left: 34.6666666667%; }
|
90 |
+
.offset-by-five.column,
|
91 |
+
.offset-by-five.columns { margin-left: 43.3333333333%; }
|
92 |
+
.offset-by-six.column,
|
93 |
+
.offset-by-six.columns { margin-left: 52%; }
|
94 |
+
.offset-by-seven.column,
|
95 |
+
.offset-by-seven.columns { margin-left: 60.6666666667%; }
|
96 |
+
.offset-by-eight.column,
|
97 |
+
.offset-by-eight.columns { margin-left: 69.3333333333%; }
|
98 |
+
.offset-by-nine.column,
|
99 |
+
.offset-by-nine.columns { margin-left: 78.0%; }
|
100 |
+
.offset-by-ten.column,
|
101 |
+
.offset-by-ten.columns { margin-left: 86.6666666667%; }
|
102 |
+
.offset-by-eleven.column,
|
103 |
+
.offset-by-eleven.columns { margin-left: 95.3333333333%; }
|
104 |
+
|
105 |
+
.offset-by-one-third.column,
|
106 |
+
.offset-by-one-third.columns { margin-left: 34.6666666667%; }
|
107 |
+
.offset-by-two-thirds.column,
|
108 |
+
.offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
|
109 |
+
|
110 |
+
.offset-by-one-half.column,
|
111 |
+
.offset-by-one-half.columns { margin-left: 52%; }
|
112 |
+
|
113 |
+
}
|
114 |
+
|
115 |
+
|
116 |
+
/* Base Styles
|
117 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
118 |
+
/* NOTE
|
119 |
+
html is set to 62.5% so that all the REM measurements throughout Skeleton
|
120 |
+
are based on 10px sizing. So basically 1.5rem = 15px :) */
|
121 |
+
html {
|
122 |
+
font-size: 62.5%; }
|
123 |
+
body {
|
124 |
+
font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
|
125 |
+
line-height: 1.6;
|
126 |
+
font-weight: 400;
|
127 |
+
font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
128 |
+
color: #222; }
|
129 |
+
|
130 |
+
|
131 |
+
/* Typography
|
132 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
133 |
+
h1, h2, h3, h4, h5, h6 {
|
134 |
+
margin-top: 0;
|
135 |
+
margin-bottom: 2rem;
|
136 |
+
font-weight: 300; }
|
137 |
+
h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
|
138 |
+
h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
|
139 |
+
h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
|
140 |
+
h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
|
141 |
+
h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
|
142 |
+
h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
|
143 |
+
|
144 |
+
/* Larger than phablet */
|
145 |
+
@media (min-width: 550px) {
|
146 |
+
h1 { font-size: 5.0rem; }
|
147 |
+
h2 { font-size: 4.2rem; }
|
148 |
+
h3 { font-size: 3.6rem; }
|
149 |
+
h4 { font-size: 3.0rem; }
|
150 |
+
h5 { font-size: 2.4rem; }
|
151 |
+
h6 { font-size: 1.5rem; }
|
152 |
+
}
|
153 |
+
|
154 |
+
p {
|
155 |
+
margin-top: 0; }
|
156 |
+
|
157 |
+
|
158 |
+
/* Links
|
159 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
160 |
+
a {
|
161 |
+
color: #1EAEDB; }
|
162 |
+
a:hover {
|
163 |
+
color: #0FA0CE; }
|
164 |
+
|
165 |
+
|
166 |
+
/* Buttons
|
167 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
168 |
+
.button,
|
169 |
+
button,
|
170 |
+
input[type="submit"],
|
171 |
+
input[type="reset"],
|
172 |
+
input[type="button"] {
|
173 |
+
display: inline-block;
|
174 |
+
height: 38px;
|
175 |
+
padding: 0 30px;
|
176 |
+
color: #555;
|
177 |
+
text-align: center;
|
178 |
+
font-size: 11px;
|
179 |
+
font-weight: 600;
|
180 |
+
line-height: 38px;
|
181 |
+
letter-spacing: .1rem;
|
182 |
+
text-transform: uppercase;
|
183 |
+
text-decoration: none;
|
184 |
+
white-space: nowrap;
|
185 |
+
background-color: transparent;
|
186 |
+
border-radius: 4px;
|
187 |
+
border: 1px solid #bbb;
|
188 |
+
cursor: pointer;
|
189 |
+
box-sizing: border-box; }
|
190 |
+
.button:hover,
|
191 |
+
button:hover,
|
192 |
+
input[type="submit"]:hover,
|
193 |
+
input[type="reset"]:hover,
|
194 |
+
input[type="button"]:hover,
|
195 |
+
.button:focus,
|
196 |
+
button:focus,
|
197 |
+
input[type="submit"]:focus,
|
198 |
+
input[type="reset"]:focus,
|
199 |
+
input[type="button"]:focus {
|
200 |
+
color: #333;
|
201 |
+
border-color: #888;
|
202 |
+
outline: 0; }
|
203 |
+
.button.button-primary,
|
204 |
+
button.button-primary,
|
205 |
+
input[type="submit"].button-primary,
|
206 |
+
input[type="reset"].button-primary,
|
207 |
+
input[type="button"].button-primary {
|
208 |
+
color: #FFF;
|
209 |
+
background-color: #33C3F0;
|
210 |
+
border-color: #33C3F0; }
|
211 |
+
.button.button-primary:hover,
|
212 |
+
button.button-primary:hover,
|
213 |
+
input[type="submit"].button-primary:hover,
|
214 |
+
input[type="reset"].button-primary:hover,
|
215 |
+
input[type="button"].button-primary:hover,
|
216 |
+
.button.button-primary:focus,
|
217 |
+
button.button-primary:focus,
|
218 |
+
input[type="submit"].button-primary:focus,
|
219 |
+
input[type="reset"].button-primary:focus,
|
220 |
+
input[type="button"].button-primary:focus {
|
221 |
+
color: #FFF;
|
222 |
+
background-color: #1EAEDB;
|
223 |
+
border-color: #1EAEDB; }
|
224 |
+
|
225 |
+
|
226 |
+
/* Forms
|
227 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
228 |
+
input[type="email"],
|
229 |
+
input[type="number"],
|
230 |
+
input[type="search"],
|
231 |
+
input[type="text"],
|
232 |
+
input[type="tel"],
|
233 |
+
input[type="url"],
|
234 |
+
input[type="password"],
|
235 |
+
textarea,
|
236 |
+
select {
|
237 |
+
height: 38px;
|
238 |
+
padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
|
239 |
+
background-color: #fff;
|
240 |
+
border: 1px solid #D1D1D1;
|
241 |
+
border-radius: 4px;
|
242 |
+
box-shadow: none;
|
243 |
+
box-sizing: border-box; }
|
244 |
+
/* Removes awkward default styles on some inputs for iOS */
|
245 |
+
input[type="email"],
|
246 |
+
input[type="number"],
|
247 |
+
input[type="search"],
|
248 |
+
input[type="text"],
|
249 |
+
input[type="tel"],
|
250 |
+
input[type="url"],
|
251 |
+
input[type="password"],
|
252 |
+
textarea {
|
253 |
+
-webkit-appearance: none;
|
254 |
+
-moz-appearance: none;
|
255 |
+
appearance: none; }
|
256 |
+
textarea {
|
257 |
+
min-height: 65px;
|
258 |
+
padding-top: 6px;
|
259 |
+
padding-bottom: 6px; }
|
260 |
+
input[type="email"]:focus,
|
261 |
+
input[type="number"]:focus,
|
262 |
+
input[type="search"]:focus,
|
263 |
+
input[type="text"]:focus,
|
264 |
+
input[type="tel"]:focus,
|
265 |
+
input[type="url"]:focus,
|
266 |
+
input[type="password"]:focus,
|
267 |
+
textarea:focus,
|
268 |
+
select:focus {
|
269 |
+
border: 1px solid #33C3F0;
|
270 |
+
outline: 0; }
|
271 |
+
label,
|
272 |
+
legend {
|
273 |
+
display: block;
|
274 |
+
margin-bottom: .5rem;
|
275 |
+
font-weight: 600; }
|
276 |
+
fieldset {
|
277 |
+
padding: 0;
|
278 |
+
border-width: 0; }
|
279 |
+
input[type="checkbox"],
|
280 |
+
input[type="radio"] {
|
281 |
+
display: inline; }
|
282 |
+
label > .label-body {
|
283 |
+
display: inline-block;
|
284 |
+
margin-left: .5rem;
|
285 |
+
font-weight: normal; }
|
286 |
+
|
287 |
+
|
288 |
+
/* Lists
|
289 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
290 |
+
ul {
|
291 |
+
list-style: circle inside; }
|
292 |
+
ol {
|
293 |
+
list-style: decimal inside; }
|
294 |
+
ol, ul {
|
295 |
+
padding-left: 0;
|
296 |
+
margin-top: 0; }
|
297 |
+
ul ul,
|
298 |
+
ul ol,
|
299 |
+
ol ol,
|
300 |
+
ol ul {
|
301 |
+
margin: 1.5rem 0 1.5rem 3rem;
|
302 |
+
font-size: 90%; }
|
303 |
+
li {
|
304 |
+
margin-bottom: 1rem; }
|
305 |
+
|
306 |
+
|
307 |
+
/* Code
|
308 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
309 |
+
code {
|
310 |
+
padding: .2rem .5rem;
|
311 |
+
margin: 0 .2rem;
|
312 |
+
font-size: 90%;
|
313 |
+
white-space: nowrap;
|
314 |
+
background: #F1F1F1;
|
315 |
+
border: 1px solid #E1E1E1;
|
316 |
+
border-radius: 4px; }
|
317 |
+
pre > code {
|
318 |
+
display: block;
|
319 |
+
padding: 1rem 1.5rem;
|
320 |
+
white-space: pre; }
|
321 |
+
|
322 |
+
|
323 |
+
/* Tables
|
324 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
325 |
+
th,
|
326 |
+
td {
|
327 |
+
padding: 6px 5px;
|
328 |
+
text-align: left;
|
329 |
+
border-bottom: 1px solid #E1E1E1; }
|
330 |
+
th:first-child,
|
331 |
+
td:first-child {
|
332 |
+
padding-left: 0; }
|
333 |
+
th:last-child,
|
334 |
+
td:last-child {
|
335 |
+
padding-right: 0; }
|
336 |
+
|
337 |
+
|
338 |
+
/* Spacing
|
339 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
340 |
+
button,
|
341 |
+
.button {
|
342 |
+
margin-bottom: 1rem; }
|
343 |
+
input,
|
344 |
+
textarea,
|
345 |
+
select,
|
346 |
+
fieldset {
|
347 |
+
margin-bottom: 0.5rem; }
|
348 |
+
pre,
|
349 |
+
blockquote,
|
350 |
+
dl,
|
351 |
+
figure,
|
352 |
+
table,
|
353 |
+
p,
|
354 |
+
ul,
|
355 |
+
ol,
|
356 |
+
form {
|
357 |
+
margin-bottom: 1.5rem; }
|
358 |
+
|
359 |
+
|
360 |
+
/* Utilities
|
361 |
+
–––––––––––––––––––––––���–––––––––––––––––––––––––– */
|
362 |
+
.u-full-width {
|
363 |
+
width: 100%;
|
364 |
+
box-sizing: border-box; }
|
365 |
+
.u-max-full-width {
|
366 |
+
max-width: 100%;
|
367 |
+
box-sizing: border-box; }
|
368 |
+
.u-pull-right {
|
369 |
+
float: right; }
|
370 |
+
.u-pull-left {
|
371 |
+
float: left; }
|
372 |
+
|
373 |
+
|
374 |
+
/* Misc
|
375 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
376 |
+
hr {
|
377 |
+
margin-top: 3rem;
|
378 |
+
margin-bottom: 3.5rem;
|
379 |
+
border-width: 0;
|
380 |
+
border-top: 1px solid #E1E1E1; }
|
381 |
+
|
382 |
+
|
383 |
+
/* Clearing
|
384 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
385 |
+
|
386 |
+
/* Self Clearing Goodness */
|
387 |
+
.container:after,
|
388 |
+
.row:after,
|
389 |
+
.u-cf {
|
390 |
+
content: "";
|
391 |
+
display: table;
|
392 |
+
clear: both; }
|
393 |
+
|
394 |
+
|
395 |
+
/* Media Queries
|
396 |
+
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
397 |
+
/*
|
398 |
+
Note: The best way to structure the use of media queries is to create the queries
|
399 |
+
near the relevant code. For example, if you wanted to change the styles for buttons
|
400 |
+
on small devices, paste the mobile query code up in the buttons section and style it
|
401 |
+
there.
|
402 |
+
*/
|
403 |
+
|
404 |
+
|
405 |
+
/* Larger than mobile */
|
406 |
+
@media (min-width: 400px) {}
|
407 |
+
|
408 |
+
/* Larger than phablet (also point when grid becomes active) */
|
409 |
+
@media (min-width: 550px) {}
|
410 |
+
|
411 |
+
/* Larger than tablet */
|
412 |
+
@media (min-width: 750px) {}
|
413 |
+
|
414 |
+
/* Larger than desktop */
|
415 |
+
@media (min-width: 1000px) {}
|
416 |
+
|
417 |
+
/* Larger than Desktop HD */
|
418 |
+
@media (min-width: 1200px) {}
|
rtvc/demo_cli.py
ADDED
@@ -0,0 +1,330 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import argparse
|
2 |
+
from ctypes import alignment
|
3 |
+
import os
|
4 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
5 |
+
from pathlib import Path
|
6 |
+
import spacy
|
7 |
+
import time
|
8 |
+
|
9 |
+
|
10 |
+
if __name__ == '__main__':
|
11 |
+
parser = argparse.ArgumentParser(
|
12 |
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
13 |
+
)
|
14 |
+
parser.add_argument("--run_id", type=str, default="default", help= \
|
15 |
+
"Name for this model. By default, training outputs will be stored to saved_models/<run_id>/. If a model state "
|
16 |
+
"from the same run ID was previously saved, the training will restart from there. Pass -f to overwrite saved "
|
17 |
+
"states and restart from scratch.")
|
18 |
+
parser.add_argument("-m", "--models_dir", type=Path, default="saved_models",
|
19 |
+
help="Directory containing all saved models")
|
20 |
+
parser.add_argument("--weight", type=float, default=1,
|
21 |
+
help="weight of input audio for voice filter")
|
22 |
+
parser.add_argument("--griffin_lim",
|
23 |
+
action="store_true",
|
24 |
+
help="if True, use griffin-lim, else use vocoder")
|
25 |
+
parser.add_argument("--cpu", action="store_true", help=\
|
26 |
+
"If True, processing is done on CPU, even when a GPU is available.")
|
27 |
+
parser.add_argument("--no_sound", action="store_true", help=\
|
28 |
+
"If True, audio won't be played.")
|
29 |
+
parser.add_argument("--seed", type=int, default=None, help=\
|
30 |
+
"Optional random number seed value to make toolbox deterministic.")
|
31 |
+
args = parser.parse_args()
|
32 |
+
arg_dict = vars(args)
|
33 |
+
# print_args(args, parser)
|
34 |
+
|
35 |
+
# Hide GPUs from Pytorch to force CPU processing
|
36 |
+
if arg_dict.pop("cpu"):
|
37 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
38 |
+
|
39 |
+
print("Running a test of your configuration...\n")
|
40 |
+
|
41 |
+
import numpy as np
|
42 |
+
import soundfile as sf
|
43 |
+
import torch
|
44 |
+
|
45 |
+
import encoder.inference
|
46 |
+
import encoder.params_data
|
47 |
+
from synthesizer.inference import Synthesizer_infer
|
48 |
+
from synthesizer.utils.cleaners import add_breaks, english_cleaners_predict
|
49 |
+
from vocoder import inference as vocoder
|
50 |
+
from vocoder.display import save_attention_multiple, save_spectrogram, save_stop_tokens
|
51 |
+
from utils.argutils import print_args
|
52 |
+
from utils.default_models import ensure_default_models
|
53 |
+
from speed_changer.fixSpeed import *
|
54 |
+
if torch.cuda.is_available():
|
55 |
+
device_id = torch.cuda.current_device()
|
56 |
+
gpu_properties = torch.cuda.get_device_properties(device_id)
|
57 |
+
## Print some environment information (for debugging purposes)
|
58 |
+
print("Found %d GPUs available. Using GPU %d (%s) of compute capability %d.%d with "
|
59 |
+
"%.1fGb total memory.\n" %
|
60 |
+
(torch.cuda.device_count(),
|
61 |
+
device_id,
|
62 |
+
gpu_properties.name,
|
63 |
+
gpu_properties.major,
|
64 |
+
gpu_properties.minor,
|
65 |
+
gpu_properties.total_memory / 1e9))
|
66 |
+
else:
|
67 |
+
print("Using CPU for inference.\n")
|
68 |
+
|
69 |
+
## Load the models one by one.
|
70 |
+
if not args.griffin_lim:
|
71 |
+
print("Preparing the encoder, the synthesizer and the vocoder...")
|
72 |
+
else:
|
73 |
+
print("Preparing the encoder and the synthesizer...")
|
74 |
+
ensure_default_models(args.run_id, Path("saved_models"))
|
75 |
+
encoder.inference.load_model(list(args.models_dir.glob(f"{args.run_id}/encoder.pt"))[0])
|
76 |
+
synthesizer = Synthesizer_infer(list(args.models_dir.glob(f"{args.run_id}/synthesizer.pt"))[0])
|
77 |
+
if not args.griffin_lim:
|
78 |
+
vocoder.load_model(list(args.models_dir.glob(f"{args.run_id}/vocoder.pt"))[0])
|
79 |
+
|
80 |
+
|
81 |
+
# ## Run a test
|
82 |
+
# print("Testing your configuration with small inputs.")
|
83 |
+
# # Forward an audio waveform of zeroes that lasts 1 second. Notice how we can get the encoder's
|
84 |
+
# # sampling rate, which may differ.
|
85 |
+
# # If you're unfamiliar with digital audio, know that it is encoded as an array of floats
|
86 |
+
# # (or sometimes integers, but mostly floats in this projects) ranging from -1 to 1.
|
87 |
+
# # The sampling rate is the number of values (samples) recorded per second, it is set to
|
88 |
+
# # 16000 for the encoder. Creating an array of length <sampling_rate> will always correspond
|
89 |
+
# # to an audio of 1 second.
|
90 |
+
# print("\tTesting the encoder...")
|
91 |
+
# encoder.embed_utterance(np.zeros(encoder.sampling_rate))
|
92 |
+
|
93 |
+
# # Create a dummy embedding. You would normally use the embedding that encoder.embed_utterance
|
94 |
+
# # returns, but here we're going to make one ourselves just for the sake of showing that it's
|
95 |
+
# # possible.
|
96 |
+
# embed = np.random.rand(speaker_embedding_size)
|
97 |
+
# # Embeddings are L2-normalized (this isn't important here, but if you want to make your own
|
98 |
+
# # embeddings it will be).
|
99 |
+
# embed /= np.linalg.norm(embed)
|
100 |
+
# # The synthesizer can handle multiple inputs with batching. Let's create another embedding to
|
101 |
+
# # illustrate that
|
102 |
+
# embeds = [embed, np.zeros(speaker_embedding_size)]
|
103 |
+
# texts = ["test 1", "test 2"]
|
104 |
+
# print("\tTesting the synthesizer... (loading the model will output a lot of text)")
|
105 |
+
# mels = synthesizer.synthesize_spectrograms(texts, embeds)
|
106 |
+
|
107 |
+
# # The vocoder synthesizes one waveform at a time, but it's more efficient for long ones. We
|
108 |
+
# # can concatenate the mel spectrograms to a single one.
|
109 |
+
# mel = np.concatenate(mels, axis=1)
|
110 |
+
# # The vocoder can take a callback function to display the generation. More on that later. For
|
111 |
+
# # now we'll simply hide it like this:
|
112 |
+
# if not args.griffin_lim:
|
113 |
+
# no_action = lambda *args: None
|
114 |
+
# print("\tTesting the vocoder...")
|
115 |
+
# # For the sake of making this test short, we'll pass a short target length. The target length
|
116 |
+
# # is the length of the wav segments that are processed in parallel. E.g. for audio sampled
|
117 |
+
# # at 16000 Hertz, a target length of 8000 means that the target audio will be cut in chunks of
|
118 |
+
# # 0.5 seconds which will all be generated together. The parameters here are absurdly short, and
|
119 |
+
# # that has a detrimental effect on the quality of the audio. The default parameters are
|
120 |
+
# # recommended in general.
|
121 |
+
# vocoder.infer_waveform(mel, target=200, overlap=50, progress_callback=no_action)
|
122 |
+
|
123 |
+
# print("All test passed! You can now synthesize speech.\n\n")
|
124 |
+
|
125 |
+
|
126 |
+
## Interactive speech generation
|
127 |
+
print("This is a GUI-less example of interface to SV2TTS. The purpose of this script is to "
|
128 |
+
"show how you can interface this project easily with your own. See the source code for "
|
129 |
+
"an explanation of what is happening.\n")
|
130 |
+
|
131 |
+
print("Interactive generation loop")
|
132 |
+
num_generated = 0
|
133 |
+
|
134 |
+
nlp = spacy.load('en_core_web_sm')
|
135 |
+
weight = arg_dict["weight"] # 声音美颜的用户语音权重
|
136 |
+
amp = 1
|
137 |
+
|
138 |
+
while True:
|
139 |
+
# try:
|
140 |
+
# Get the reference audio filepath
|
141 |
+
num_of_input_audio = 1
|
142 |
+
|
143 |
+
for i in range(num_of_input_audio):
|
144 |
+
# Computing the embedding
|
145 |
+
# First, we load the wav using the function that the speaker encoder provides. This is
|
146 |
+
# important: there is preprocessing that must be applied.
|
147 |
+
|
148 |
+
# The following two methods are equivalent:
|
149 |
+
# - Directly load from the filepath:
|
150 |
+
# preprocessed_wav = encoder.preprocess_wav(in_fpath)
|
151 |
+
# - If the wav is already loaded:
|
152 |
+
|
153 |
+
# get duration info from input audio
|
154 |
+
message2 = "Reference voice: enter an audio folder of a voice to be cloned (mp3, " \
|
155 |
+
f"wav, m4a, flac, ...):({i+1}/{num_of_input_audio})\n"
|
156 |
+
in_fpath = Path(input(message2).replace("\"", "").replace("\'", ""))
|
157 |
+
|
158 |
+
fpath_without_ext = os.path.splitext(str(in_fpath))[0]
|
159 |
+
speaker_name = os.path.normpath(fpath_without_ext).split(os.sep)[-1]
|
160 |
+
|
161 |
+
is_wav_file, single_wav, wav_path = TransFormat(in_fpath, 'wav')
|
162 |
+
|
163 |
+
if not is_wav_file:
|
164 |
+
os.remove(wav_path) # remove intermediate wav files
|
165 |
+
# merge
|
166 |
+
if i == 0:
|
167 |
+
wav = single_wav
|
168 |
+
else:
|
169 |
+
wav = np.append(wav, single_wav)
|
170 |
+
# write to disk
|
171 |
+
path_ori, _ = os.path.split(wav_path)
|
172 |
+
file_ori = 'temp.wav'
|
173 |
+
fpath = os.path.join(path_ori, file_ori)
|
174 |
+
sf.write(fpath, wav, samplerate=encoder.params_data.sampling_rate)
|
175 |
+
|
176 |
+
# adjust the speed
|
177 |
+
totDur_ori, nPause_ori, arDur_ori, nSyl_ori, arRate_ori = AudioAnalysis(path_ori, file_ori)
|
178 |
+
DelFile(path_ori, '.TextGrid')
|
179 |
+
os.remove(fpath)
|
180 |
+
|
181 |
+
preprocessed_wav = encoder.inference.preprocess_wav(wav)
|
182 |
+
|
183 |
+
print("Loaded input audio file succesfully")
|
184 |
+
|
185 |
+
# Then we derive the embedding. There are many functions and parameters that the
|
186 |
+
# speaker encoder interfaces. These are mostly for in-depth research. You will typically
|
187 |
+
# only use this function (with its default parameters):
|
188 |
+
input_embed = encoder.inference.embed_utterance(preprocessed_wav)
|
189 |
+
# Choose standard audio
|
190 |
+
|
191 |
+
fft_max_freq = vocoder.get_dominant_freq(preprocessed_wav)
|
192 |
+
print(f"\nthe dominant frequency of input audio is {fft_max_freq}Hz")
|
193 |
+
if fft_max_freq < encoder.params_data.split_freq:
|
194 |
+
vocoder.hp.sex = 1
|
195 |
+
standard_fpath = "standard_audios/male_1.wav"
|
196 |
+
else:
|
197 |
+
vocoder.hp.sex = 0
|
198 |
+
standard_fpath = "standard_audios/female_1.wav"
|
199 |
+
|
200 |
+
if os.path.exists(standard_fpath):
|
201 |
+
|
202 |
+
standard_wav = Synthesizer_infer.load_preprocess_wav(standard_fpath)
|
203 |
+
preprocessed_standard_wav = encoder.inference.preprocess_wav(standard_wav)
|
204 |
+
print("Loaded standard audio file successfully")
|
205 |
+
|
206 |
+
standard_embed = encoder.inference.embed_utterance(preprocessed_standard_wav)
|
207 |
+
|
208 |
+
embed1=np.copy(input_embed).dot(weight)
|
209 |
+
embed2=np.copy(standard_embed).dot(1 - weight)
|
210 |
+
embed=embed1+embed2
|
211 |
+
else:
|
212 |
+
embed = np.copy(input_embed)
|
213 |
+
|
214 |
+
embed[embed < encoder.params_data.set_zero_thres]=0 # 噪声值置零
|
215 |
+
embed = embed * amp
|
216 |
+
|
217 |
+
start_syn = time.time()
|
218 |
+
# Generating the spectrogram
|
219 |
+
text = input("Write a sentence to be synthesized:\n")
|
220 |
+
|
221 |
+
# If seed is specified, reset torch seed and force synthesizer reload
|
222 |
+
if args.seed is not None:
|
223 |
+
torch.manual_seed(args.seed)
|
224 |
+
synthesizer = Synthesizer_infer(args.syn_model_fpath)
|
225 |
+
|
226 |
+
# The synthesizer works in batch, so you need to put your data in a list or numpy array
|
227 |
+
def preprocess_text(text):
|
228 |
+
text = add_breaks(text)
|
229 |
+
text = english_cleaners_predict(text)
|
230 |
+
texts = [i.text.strip() for i in nlp(text).sents] # split paragraph to sentences
|
231 |
+
return texts
|
232 |
+
|
233 |
+
texts = preprocess_text(text)
|
234 |
+
print(f"the list of inputs texts:\n{texts}")
|
235 |
+
|
236 |
+
# embeds = [embed] * len(texts)
|
237 |
+
|
238 |
+
specs = []
|
239 |
+
alignments = []
|
240 |
+
stop_tokens = []
|
241 |
+
|
242 |
+
for text in texts:
|
243 |
+
spec, align, stop_token = synthesizer.synthesize_spectrograms([text], [embed], require_visualization=True)
|
244 |
+
specs.append(spec[0])
|
245 |
+
alignments.append(align[0])
|
246 |
+
stop_tokens.append(stop_token[0])
|
247 |
+
|
248 |
+
breaks = [spec.shape[1] for spec in specs]
|
249 |
+
spec = np.concatenate(specs, axis=1)
|
250 |
+
|
251 |
+
## Save synthesizer visualization results
|
252 |
+
if not os.path.exists("syn_results"):
|
253 |
+
os.mkdir("syn_results")
|
254 |
+
save_attention_multiple(alignments, "syn_results/attention")
|
255 |
+
save_stop_tokens(stop_tokens, "syn_results/stop_tokens")
|
256 |
+
save_spectrogram(spec, "syn_results/mel")
|
257 |
+
print("Created the mel spectrogram")
|
258 |
+
|
259 |
+
end_syn = time.time()
|
260 |
+
print(f"Prediction time of synthesizer is {end_syn - start_syn}s")
|
261 |
+
|
262 |
+
start_voc = time.time()
|
263 |
+
## Generating the waveform
|
264 |
+
print("Synthesizing the waveform:")
|
265 |
+
|
266 |
+
# If seed is specified, reset torch seed and reload vocoder
|
267 |
+
if args.seed is not None:
|
268 |
+
torch.manual_seed(args.seed)
|
269 |
+
vocoder.load_model(args.voc_model_fpath)
|
270 |
+
|
271 |
+
# Synthesizing the waveform is fairly straightforward. Remember that the longer the
|
272 |
+
# spectrogram, the more time-efficient the vocoder.
|
273 |
+
if not args.griffin_lim:
|
274 |
+
wav = vocoder.infer_waveform(spec, target=vocoder.hp.voc_target, overlap=vocoder.hp.voc_overlap, crossfade=vocoder.hp.is_crossfade)
|
275 |
+
else:
|
276 |
+
wav = Synthesizer_infer.griffin_lim(spec)
|
277 |
+
|
278 |
+
end_voc = time.time()
|
279 |
+
print(f"Prediction time of vocoder is {end_voc - start_voc}s")
|
280 |
+
print(f"Prediction time of TTS is {end_voc - start_syn}s")
|
281 |
+
|
282 |
+
# Add breaks
|
283 |
+
b_ends = np.cumsum(np.array(breaks) * Synthesizer_infer.hparams.hop_size)
|
284 |
+
b_starts = np.concatenate(([0], b_ends[:-1]))
|
285 |
+
wavs = [wav[start:end] for start, end, in zip(b_starts, b_ends)]
|
286 |
+
breaks = [np.zeros(int(0.15 * Synthesizer_infer.sample_rate))] * len(breaks)
|
287 |
+
wav = np.concatenate([i for w, b in zip(wavs, breaks) for i in (w, b)])
|
288 |
+
|
289 |
+
# Trim excess silences to compensate for gaps in spectrograms (issue #53)
|
290 |
+
# generated_wav = encoder.inference.preprocess_wav(wav)
|
291 |
+
wav = wav / np.abs(wav).max() * 4
|
292 |
+
|
293 |
+
# Save it on the disk
|
294 |
+
# filename = "demo_output_%02d.wav" % num_generated
|
295 |
+
if not os.path.exists("out_audios"):
|
296 |
+
os.mkdir("out_audios")
|
297 |
+
|
298 |
+
dir_path = os.path.dirname(os.path.realpath(__file__)) # current dir
|
299 |
+
filename = os.path.join(dir_path, f"out_audios/{speaker_name}_syn.wav")
|
300 |
+
# print(wav.dtype)
|
301 |
+
sf.write(filename, wav.astype(np.float32), synthesizer.sample_rate)
|
302 |
+
num_generated += 1
|
303 |
+
print("\nSaved output (havent't change speed) as %s\n\n" % filename)
|
304 |
+
|
305 |
+
# Fix Speed(generate new audio)
|
306 |
+
fix_file = work(totDur_ori,
|
307 |
+
nPause_ori,
|
308 |
+
arDur_ori,
|
309 |
+
nSyl_ori,
|
310 |
+
arRate_ori,
|
311 |
+
filename)
|
312 |
+
print(f"\nSaved output (fixed speed) as {fix_file}\n\n")
|
313 |
+
|
314 |
+
|
315 |
+
# # Play the audio (non-blocking)
|
316 |
+
# if not args.no_sound:
|
317 |
+
# import sounddevice as sd
|
318 |
+
# try:
|
319 |
+
# sd.stop()
|
320 |
+
# sd.play(wav, synthesizer.sample_rate)
|
321 |
+
# except sd.PortAudioError as e:
|
322 |
+
# print("\nCaught exception: %s" % repr(e))
|
323 |
+
# print("Continuing without audio playback. Suppress this message with the \"--no_sound\" flag.\n")
|
324 |
+
# except:
|
325 |
+
# raise
|
326 |
+
|
327 |
+
|
328 |
+
# except Exception as e:
|
329 |
+
# print("Caught exception: %s" % repr(e))
|
330 |
+
# print("Restarting\n")
|
rtvc/demo_results/text1/1688-142285-0000_syn.wav
ADDED
Binary file (108 kB). View file
|
|
rtvc/demo_results/text1/260-123286-0000_syn.wav
ADDED
Binary file (112 kB). View file
|
|
rtvc/demo_results/text1/4294-9934-0000_syn.wav
ADDED
Binary file (104 kB). View file
|
|
rtvc/demo_results/text1/7176-88083-0000_syn.wav
ADDED
Binary file (104 kB). View file
|
|
rtvc/demo_results/text1/README.md
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
Life was like a box of chocolates, you never know what you're gonna get.
|
rtvc/demo_results/text2/1688-142285-0000_syn.wav
ADDED
Binary file (650 kB). View file
|
|
rtvc/demo_results/text2/260-123286-0000_syn.wav
ADDED
Binary file (611 kB). View file
|
|
rtvc/demo_results/text2/4294-9934-0000_syn.wav
ADDED
Binary file (617 kB). View file
|
|
rtvc/demo_results/text2/7176-88083-0000_syn.wav
ADDED
Binary file (595 kB). View file
|
|
rtvc/demo_results/text2/README.md
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
In 2014, P&G recorded $83.1 billion in sales. On August 1, 2014, P&G announced it was streamlining the company, dropping and selling off around 100 brands from its product portfolio in order to focus on the remaining 65 brands, which produced 95% of the company's profits.
|
rtvc/demo_results/text3/1688-142285-0000_syn.wav
ADDED
Binary file (746 kB). View file
|
|
rtvc/demo_results/text3/260-123286-0000_syn.wav
ADDED
Binary file (812 kB). View file
|
|
rtvc/demo_results/text3/4294-9934-0000_syn.wav
ADDED
Binary file (744 kB). View file
|
|
rtvc/demo_results/text3/7176-88083-0000_syn.wav
ADDED
Binary file (720 kB). View file
|
|
rtvc/demo_results/text3/README.md
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
Mechanics is a branch of physics that deals with the behavior of physical bodies under the influence of various forces. The study of mechanics is important in understanding the behavior of machines, the motion of objects, and the principles of engineering. Mechanics has been an essential part of physics since ancient times and has continued to evolve with advancements in science and technology. This paper will discuss the principles of mechanics, the laws of motion, and the applications of mechanics in engineering and technology.
|
rtvc/demo_toolbox.py
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import argparse
|
2 |
+
import os
|
3 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
4 |
+
from pathlib import Path
|
5 |
+
|
6 |
+
from toolbox import Toolbox
|
7 |
+
from utils.argutils import print_args
|
8 |
+
from utils.default_models import ensure_default_models
|
9 |
+
|
10 |
+
|
11 |
+
if __name__ == '__main__':
|
12 |
+
parser = argparse.ArgumentParser(
|
13 |
+
description="Runs the toolbox.",
|
14 |
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
15 |
+
)
|
16 |
+
parser.add_argument("--run_id", type=str, default="20230609", help= \
|
17 |
+
"Name for this model. By default, training outputs will be stored to saved_models/<run_id>/. If a model state "
|
18 |
+
"from the same run ID was previously saved, the training will restart from there. Pass -f to overwrite saved "
|
19 |
+
"states and restart from scratch.")
|
20 |
+
parser.add_argument("-d", "--datasets_root", type=Path, help= \
|
21 |
+
"Path to the directory containing your datasets. See toolbox/__init__.py for a list of "
|
22 |
+
"supported datasets.", default=None)
|
23 |
+
parser.add_argument("-m", "--models_dir", type=Path, default="saved_models",
|
24 |
+
help="Directory containing all saved models")
|
25 |
+
parser.add_argument("--cpu", action="store_true", help=\
|
26 |
+
"If True, all inference will be done on CPU")
|
27 |
+
parser.add_argument("--seed", type=int, default=None, help=\
|
28 |
+
"Optional random number seed value to make toolbox deterministic.")
|
29 |
+
args = parser.parse_args()
|
30 |
+
arg_dict = vars(args)
|
31 |
+
print_args(args, parser)
|
32 |
+
|
33 |
+
# Hide GPUs from Pytorch to force CPU processing
|
34 |
+
if arg_dict.pop("cpu"):
|
35 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
36 |
+
|
37 |
+
# Remind the user to download pretrained models if needed
|
38 |
+
ensure_default_models(args.run_id, args.models_dir)
|
39 |
+
|
40 |
+
# Launch the toolbox
|
41 |
+
Toolbox(**arg_dict)
|
rtvc/docs/images/audio_icon.png
ADDED
![]() |
rtvc/docs/images/voice_cloning_arch.png
ADDED
![]() |
rtvc/encoder/__init__.py
ADDED
File without changes
|
rtvc/encoder/audio.py
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from scipy.ndimage.morphology import binary_dilation
|
2 |
+
from encoder.params_data import *
|
3 |
+
from pathlib import Path
|
4 |
+
from typing import Optional, Union
|
5 |
+
from warnings import warn
|
6 |
+
import numpy as np
|
7 |
+
import librosa
|
8 |
+
import struct
|
9 |
+
import os
|
10 |
+
from pydub import AudioSegment
|
11 |
+
import noisereduce
|
12 |
+
|
13 |
+
try:
|
14 |
+
import webrtcvad
|
15 |
+
except:
|
16 |
+
warn("Unable to import 'webrtcvad'. This package enables noise removal and is recommended.")
|
17 |
+
webrtcvad=None
|
18 |
+
|
19 |
+
int16_max = (2 ** 15) - 1
|
20 |
+
|
21 |
+
|
22 |
+
def preprocess_wav(fpath_or_wav: Union[str, Path, np.ndarray],
|
23 |
+
source_sr: Optional[int] = None,
|
24 |
+
normalize: Optional[bool] = True,
|
25 |
+
trim_silence: Optional[bool] = True):
|
26 |
+
"""
|
27 |
+
Applies the preprocessing operations used in training the Speaker Encoder to a waveform
|
28 |
+
either on disk or in memory. The waveform will be resampled to match the data hyperparameters.
|
29 |
+
|
30 |
+
:param fpath_or_wav: either a filepath to an audio file (many extensions are supported, not
|
31 |
+
just .wav), either the waveform as a numpy array of floats.
|
32 |
+
:param source_sr: if passing an audio waveform, the sampling rate of the waveform before
|
33 |
+
preprocessing. After preprocessing, the waveform's sampling rate will match the data
|
34 |
+
hyperparameters. If passing a filepath, the sampling rate will be automatically detected and
|
35 |
+
this argument will be ignored.
|
36 |
+
"""
|
37 |
+
# Load the wav from disk if needed
|
38 |
+
if isinstance(fpath_or_wav, str) or isinstance(fpath_or_wav, Path):
|
39 |
+
# if str(fpath_or_wav).endswith(".m4a"):
|
40 |
+
# try:
|
41 |
+
# track = AudioSegment.from_file(fpath_or_wav, format="m4a")
|
42 |
+
# except:
|
43 |
+
# return []
|
44 |
+
# fpath = os.path.splitext(str(fpath_or_wav))[0]
|
45 |
+
# path_components = os.path.normpath(fpath).split(os.sep)
|
46 |
+
# wav_dir = Path("D:\\liuhaozhe").joinpath(f"VoxCeleb2_wav") # local path
|
47 |
+
# wav_dir.mkdir(exist_ok=True)
|
48 |
+
# wav_name = "_".join(path_components[-6: ])
|
49 |
+
# wav_path = wav_dir.joinpath(f"{wav_name}.wav")
|
50 |
+
# track.export(wav_path, format="wav")
|
51 |
+
# wav, source_sr = librosa.load(str(wav_path), sr=None)
|
52 |
+
# else:
|
53 |
+
wav, source_sr = librosa.load(str(fpath_or_wav), sr=None)
|
54 |
+
else:
|
55 |
+
wav = fpath_or_wav
|
56 |
+
|
57 |
+
|
58 |
+
|
59 |
+
# Resample the wav if needed
|
60 |
+
if source_sr is not None and source_sr != sampling_rate:
|
61 |
+
wav = librosa.resample(wav, source_sr, sampling_rate)
|
62 |
+
|
63 |
+
# Apply the preprocessing: normalize volume and shorten long silences
|
64 |
+
if normalize:
|
65 |
+
wav = normalize_volume(wav, audio_norm_target_dBFS, increase_only=True)
|
66 |
+
if webrtcvad and trim_silence:
|
67 |
+
wav = trim_long_silences(wav)
|
68 |
+
|
69 |
+
return wav
|
70 |
+
|
71 |
+
|
72 |
+
def wav_to_mel_spectrogram(wav):
|
73 |
+
"""
|
74 |
+
Derives a mel spectrogram ready to be used by the encoder from a preprocessed audio waveform.
|
75 |
+
Note: this not a log-mel spectrogram.
|
76 |
+
"""
|
77 |
+
frames = librosa.feature.melspectrogram(
|
78 |
+
wav,
|
79 |
+
sampling_rate,
|
80 |
+
n_fft=int(sampling_rate * mel_window_length / 1000),
|
81 |
+
hop_length=int(sampling_rate * mel_window_step / 1000),
|
82 |
+
n_mels=mel_n_channels
|
83 |
+
)
|
84 |
+
return frames.astype(np.float32).T
|
85 |
+
|
86 |
+
|
87 |
+
def trim_long_silences(wav):
|
88 |
+
"""
|
89 |
+
Ensures that segments without voice in the waveform remain no longer than a
|
90 |
+
threshold determined by the VAD parameters in params.py.
|
91 |
+
|
92 |
+
:param wav: the raw waveform as a numpy array of floats
|
93 |
+
:return: the same waveform with silences trimmed away (length <= original wav length)
|
94 |
+
"""
|
95 |
+
# Compute the voice detection window size
|
96 |
+
samples_per_window = (vad_window_length * sampling_rate) // 1000
|
97 |
+
|
98 |
+
# Trim the end of the audio to have a multiple of the window size
|
99 |
+
wav = wav[:len(wav) - (len(wav) % samples_per_window)]
|
100 |
+
|
101 |
+
# Convert the float waveform to 16-bit mono PCM
|
102 |
+
pcm_wave = struct.pack("%dh" % len(wav), *(np.round(wav * int16_max)).astype(np.int16))
|
103 |
+
|
104 |
+
# Perform voice activation detection
|
105 |
+
voice_flags = []
|
106 |
+
vad = webrtcvad.Vad(mode=3)
|
107 |
+
for window_start in range(0, len(wav), samples_per_window):
|
108 |
+
window_end = window_start + samples_per_window
|
109 |
+
voice_flags.append(vad.is_speech(pcm_wave[window_start * 2:window_end * 2],
|
110 |
+
sample_rate=sampling_rate))
|
111 |
+
voice_flags = np.array(voice_flags)
|
112 |
+
|
113 |
+
# Smooth the voice detection with a moving average
|
114 |
+
def moving_average(array, width):
|
115 |
+
array_padded = np.concatenate((np.zeros((width - 1) // 2), array, np.zeros(width // 2)))
|
116 |
+
ret = np.cumsum(array_padded, dtype=float)
|
117 |
+
ret[width:] = ret[width:] - ret[:-width]
|
118 |
+
return ret[width - 1:] / width
|
119 |
+
|
120 |
+
audio_mask = moving_average(voice_flags, vad_moving_average_width)
|
121 |
+
audio_mask = np.round(audio_mask).astype(np.bool)
|
122 |
+
|
123 |
+
# Dilate the voiced regions
|
124 |
+
audio_mask = binary_dilation(audio_mask, np.ones(vad_max_silence_length + 1))
|
125 |
+
audio_mask = np.repeat(audio_mask, samples_per_window)
|
126 |
+
|
127 |
+
return wav[audio_mask == True]
|
128 |
+
|
129 |
+
|
130 |
+
def normalize_volume(wav, target_dBFS, increase_only=False, decrease_only=False):
|
131 |
+
if increase_only and decrease_only:
|
132 |
+
raise ValueError("Both increase only and decrease only are set")
|
133 |
+
dBFS_change = target_dBFS - 10 * np.log10(np.mean(wav ** 2))
|
134 |
+
if (dBFS_change < 0 and increase_only) or (dBFS_change > 0 and decrease_only):
|
135 |
+
return wav
|
136 |
+
return wav * (10 ** (dBFS_change / 20))
|
rtvc/encoder/config.py
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
librispeech_datasets = {
|
2 |
+
"train": {
|
3 |
+
"clean": ["LibriSpeech/train-clean-100", "LibriSpeech/train-clean-360"],
|
4 |
+
"other": ["LibriSpeech/train-other-500"]
|
5 |
+
},
|
6 |
+
"test": {
|
7 |
+
"clean": ["LibriSpeech/test-clean"],
|
8 |
+
"other": ["LibriSpeech/test-other"]
|
9 |
+
},
|
10 |
+
"dev": {
|
11 |
+
"clean": ["LibriSpeech/dev-clean"],
|
12 |
+
"other": ["LibriSpeech/dev-other"]
|
13 |
+
},
|
14 |
+
}
|
15 |
+
libritts_datasets = {
|
16 |
+
"train": {
|
17 |
+
"clean": ["LibriTTS/train-clean-100", "LibriTTS/train-clean-360"],
|
18 |
+
"other": ["LibriTTS/train-other-500"]
|
19 |
+
},
|
20 |
+
"test": {
|
21 |
+
"clean": ["LibriTTS/test-clean"],
|
22 |
+
"other": ["LibriTTS/test-other"]
|
23 |
+
},
|
24 |
+
"dev": {
|
25 |
+
"clean": ["LibriTTS/dev-clean"],
|
26 |
+
"other": ["LibriTTS/dev-other"]
|
27 |
+
},
|
28 |
+
}
|
29 |
+
voxceleb_datasets = {
|
30 |
+
"voxceleb1" : {
|
31 |
+
"train": ["VoxCeleb1/wav"],
|
32 |
+
"test": ["VoxCeleb1/test_wav"]
|
33 |
+
},
|
34 |
+
"voxceleb2" : {
|
35 |
+
"train": ["VoxCeleb2/dev/aac"],
|
36 |
+
"test": ["VoxCeleb2/test_wav"]
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
other_datasets = [
|
41 |
+
"LJSpeech-1.1",
|
42 |
+
"VCTK-Corpus/wav48",
|
43 |
+
]
|
44 |
+
|
45 |
+
anglophone_nationalites = ["australia", "canada", "ireland", "uk", "usa"]
|
rtvc/encoder/data_objects/__init__.py
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
from encoder.data_objects.speaker_verification_dataset import Train_Dataset, Dev_Dataset
|
2 |
+
from encoder.data_objects.speaker_verification_dataset import DataLoader
|
rtvc/encoder/data_objects/random_cycler.py
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import random
|
2 |
+
|
3 |
+
class RandomCycler:
|
4 |
+
"""
|
5 |
+
Creates an internal copy of a sequence and allows access to its items in a constrained random
|
6 |
+
order. For a source sequence of n items and one or several consecutive queries of a total
|
7 |
+
of m items, the following guarantees hold (one implies the other):
|
8 |
+
- Each item will be returned between m // n and ((m - 1) // n) + 1 times.
|
9 |
+
- Between two appearances of the same item, there may be at most 2 * (n - 1) other items.
|
10 |
+
"""
|
11 |
+
|
12 |
+
def __init__(self, source):
|
13 |
+
if len(source) == 0:
|
14 |
+
raise Exception("Can't create RandomCycler from an empty collection")
|
15 |
+
self.all_items = list(source)
|
16 |
+
self.next_items = []
|
17 |
+
|
18 |
+
def sample(self, count: int):
|
19 |
+
shuffle = lambda l: random.sample(l, len(l))
|
20 |
+
|
21 |
+
out = []
|
22 |
+
while count > 0:
|
23 |
+
if count >= len(self.all_items):
|
24 |
+
out.extend(shuffle(list(self.all_items)))
|
25 |
+
count -= len(self.all_items)
|
26 |
+
continue
|
27 |
+
n = min(count, len(self.next_items))
|
28 |
+
out.extend(self.next_items[:n])
|
29 |
+
count -= n
|
30 |
+
self.next_items = self.next_items[n:]
|
31 |
+
if len(self.next_items) == 0:
|
32 |
+
self.next_items = shuffle(list(self.all_items))
|
33 |
+
return out
|
34 |
+
|
35 |
+
def __next__(self):
|
36 |
+
return self.sample(1)[0]
|
37 |
+
|
rtvc/encoder/data_objects/speaker.py
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from encoder.data_objects.random_cycler import RandomCycler
|
2 |
+
from encoder.data_objects.utterance import Utterance
|
3 |
+
from pathlib import Path
|
4 |
+
|
5 |
+
# Contains the set of utterances of a single speaker
|
6 |
+
class Speaker:
|
7 |
+
def __init__(self, root: Path):
|
8 |
+
self.root = root
|
9 |
+
self.name = root.name
|
10 |
+
self.utterances = None
|
11 |
+
self.utterance_cycler = None
|
12 |
+
|
13 |
+
def _load_utterances(self):
|
14 |
+
with self.root.joinpath("_sources.txt").open("r") as sources_file:
|
15 |
+
sources = [l.split(",") for l in sources_file]
|
16 |
+
sources = {frames_fname: wave_fpath for frames_fname, wave_fpath in sources}
|
17 |
+
self.utterances = [Utterance(self.root.joinpath(f), w) for f, w in sources.items()]
|
18 |
+
self.utterance_cycler = RandomCycler(self.utterances)
|
19 |
+
|
20 |
+
def random_partial(self, count, n_frames):
|
21 |
+
"""
|
22 |
+
Samples a batch of <count> unique partial utterances from the disk in a way that all
|
23 |
+
utterances come up at least once every two cycles and in a random order every time.
|
24 |
+
|
25 |
+
:param count: The number of partial utterances to sample from the set of utterances from
|
26 |
+
that speaker. Utterances are guaranteed not to be repeated if <count> is not larger than
|
27 |
+
the number of utterances available.
|
28 |
+
:param n_frames: The number of frames in the partial utterance.
|
29 |
+
:return: A list of tuples (utterance, frames, range) where utterance is an Utterance,
|
30 |
+
frames are the frames of the partial utterances and range is the range of the partial
|
31 |
+
utterance with regard to the complete utterance.
|
32 |
+
"""
|
33 |
+
if self.utterances is None:
|
34 |
+
self._load_utterances()
|
35 |
+
|
36 |
+
utterances = self.utterance_cycler.sample(count)
|
37 |
+
|
38 |
+
a = [(u,) + u.random_partial(n_frames) for u in utterances]
|
39 |
+
|
40 |
+
return a
|
rtvc/encoder/data_objects/speaker_batch.py
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
from typing import List
|
3 |
+
from encoder.data_objects.speaker import Speaker
|
4 |
+
|
5 |
+
|
6 |
+
class SpeakerBatch:
|
7 |
+
def __init__(self, speakers: List[Speaker], utterances_per_speaker: int, n_frames: int):
|
8 |
+
self.speakers = speakers
|
9 |
+
self.partials = {s: s.random_partial(utterances_per_speaker, n_frames) for s in speakers}
|
10 |
+
|
11 |
+
# Array of shape (n_speakers * n_utterances, n_frames, mel_n), e.g. for 3 speakers with
|
12 |
+
# 4 utterances each of 160 frames of 40 mel coefficients: (12, 160, 40)
|
13 |
+
self.data = np.array([frames for s in speakers for _, frames, _ in self.partials[s]])
|
rtvc/encoder/data_objects/speaker_verification_dataset.py
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from encoder.data_objects.random_cycler import RandomCycler
|
2 |
+
from encoder.data_objects.speaker_batch import SpeakerBatch
|
3 |
+
from encoder.data_objects.utterance_batch import UtteranceBatch
|
4 |
+
from encoder.data_objects.speaker import Speaker
|
5 |
+
from encoder.params_data import partials_n_frames
|
6 |
+
from torch.utils.data import Dataset, DataLoader
|
7 |
+
from pathlib import Path
|
8 |
+
from os import listdir
|
9 |
+
from os.path import isfile
|
10 |
+
import numpy as np
|
11 |
+
|
12 |
+
# TODO: improve with a pool of speakers for data efficiency
|
13 |
+
|
14 |
+
class Train_Dataset(Dataset):
|
15 |
+
def __init__(self, datasets_root: Path):
|
16 |
+
self.root = datasets_root
|
17 |
+
speaker_dirs = [f for f in self.root.glob("*") if f.is_dir()]
|
18 |
+
if len(speaker_dirs) == 0:
|
19 |
+
raise Exception("No speakers found. Make sure you are pointing to the directory "
|
20 |
+
"containing all preprocessed speaker directories.")
|
21 |
+
self.speakers = [Speaker(speaker_dir) for speaker_dir in speaker_dirs]
|
22 |
+
self.speaker_cycler = RandomCycler(self.speakers)
|
23 |
+
|
24 |
+
def __len__(self):
|
25 |
+
return int(1e8)
|
26 |
+
|
27 |
+
def __getitem__(self, index):
|
28 |
+
return next(self.speaker_cycler)
|
29 |
+
|
30 |
+
def get_logs(self):
|
31 |
+
log_string = ""
|
32 |
+
for log_fpath in self.root.glob("*.txt"):
|
33 |
+
with log_fpath.open("r") as log_file:
|
34 |
+
log_string += "".join(log_file.readlines())
|
35 |
+
return log_string
|
36 |
+
|
37 |
+
|
38 |
+
class Dev_Dataset(Dataset):
|
39 |
+
def __init__(self, datasets_root: Path):
|
40 |
+
self.root = datasets_root
|
41 |
+
speaker_dirs = [f for f in self.root.glob("*") if f.is_dir()]
|
42 |
+
if len(speaker_dirs) == 0:
|
43 |
+
raise Exception("No speakers found. Make sure you are pointing to the directory "
|
44 |
+
"containing all preprocessed speaker directories.")
|
45 |
+
self.speakers = [Speaker(speaker_dir) for speaker_dir in speaker_dirs]
|
46 |
+
self.speaker_cycler = RandomCycler(self.speakers)
|
47 |
+
|
48 |
+
def __len__(self):
|
49 |
+
return len(self.speakers)
|
50 |
+
|
51 |
+
def __getitem__(self, index):
|
52 |
+
return next(self.speaker_cycler)
|
53 |
+
|
54 |
+
|
55 |
+
class DataLoader(DataLoader):
|
56 |
+
def __init__(self, dataset, speakers_per_batch, utterances_per_speaker, shuffle, sampler=None,
|
57 |
+
batch_sampler=None, num_workers=0, pin_memory=False, timeout=0,
|
58 |
+
worker_init_fn=None):
|
59 |
+
self.utterances_per_speaker = utterances_per_speaker
|
60 |
+
|
61 |
+
super().__init__(
|
62 |
+
dataset=dataset,
|
63 |
+
batch_size=speakers_per_batch,
|
64 |
+
shuffle=shuffle,
|
65 |
+
sampler=sampler,
|
66 |
+
batch_sampler=batch_sampler,
|
67 |
+
num_workers=num_workers,
|
68 |
+
collate_fn=self.collate,
|
69 |
+
pin_memory=pin_memory,
|
70 |
+
drop_last=False,
|
71 |
+
timeout=timeout,
|
72 |
+
worker_init_fn=worker_init_fn
|
73 |
+
)
|
74 |
+
|
75 |
+
def collate(self, speakers):
|
76 |
+
return SpeakerBatch(speakers, self.utterances_per_speaker, partials_n_frames)
|
rtvc/encoder/data_objects/utterance.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
|
3 |
+
|
4 |
+
class Utterance:
|
5 |
+
def __init__(self, frames_fpath, wave_fpath):
|
6 |
+
self.frames_fpath = frames_fpath
|
7 |
+
self.wave_fpath = wave_fpath
|
8 |
+
|
9 |
+
def get_frames(self):
|
10 |
+
# frame_len = len(np.load(self.frames_fpath))
|
11 |
+
return np.load(self.frames_fpath)
|
12 |
+
|
13 |
+
def random_partial(self, n_frames):
|
14 |
+
"""
|
15 |
+
Crops the frames into a partial utterance of n_frames
|
16 |
+
|
17 |
+
:param n_frames: The number of frames of the partial utterance
|
18 |
+
:return: the partial utterance frames and a tuple indicating the start and end of the
|
19 |
+
partial utterance in the complete utterance.
|
20 |
+
"""
|
21 |
+
frames = self.get_frames()
|
22 |
+
if frames.shape[0] == n_frames:
|
23 |
+
start = 0
|
24 |
+
else:
|
25 |
+
start = np.random.randint(0, frames.shape[0] - n_frames)
|
26 |
+
end = start + n_frames
|
27 |
+
# frame_len = end - start
|
28 |
+
# frames_trim = frames[start:end]
|
29 |
+
return frames[start:end], (start, end)
|
rtvc/encoder/data_objects/utterance_batch.py
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pathlib import Path
|
2 |
+
import numpy as np
|
3 |
+
from typing import List
|
4 |
+
from encoder.data_objects.utterance import Utterance
|
5 |
+
|
6 |
+
|
7 |
+
class UtteranceBatch:
|
8 |
+
def __init__(self, utterance_path: List[Path], n_frames: int):
|
9 |
+
self.utterance = Utterance(utterance_path, None)
|
10 |
+
self.data = np.array(self.utterance.random_partial(n_frames)[0])
|
rtvc/encoder/inference.py
ADDED
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from encoder.params_data import *
|
2 |
+
from encoder.model import SpeakerEncoder
|
3 |
+
from encoder.audio import preprocess_wav # We want to expose this function from here
|
4 |
+
from matplotlib import cm
|
5 |
+
from encoder import audio
|
6 |
+
from pathlib import Path
|
7 |
+
import numpy as np
|
8 |
+
import torch
|
9 |
+
|
10 |
+
_model = None # type: SpeakerEncoder
|
11 |
+
_device = None # type: torch.device
|
12 |
+
|
13 |
+
|
14 |
+
def load_model(weights_fpath: Path, device=None):
|
15 |
+
"""
|
16 |
+
Loads the model in memory. If this function is not explicitely called, it will be run on the
|
17 |
+
first call to embed_frames() with the default weights file.
|
18 |
+
|
19 |
+
:param weights_fpath: the path to saved model weights.
|
20 |
+
:param device: either a torch device or the name of a torch device (e.g. "cpu", "cuda"). The
|
21 |
+
model will be loaded and will run on this device. Outputs will however always be on the cpu.
|
22 |
+
If None, will default to your GPU if it"s available, otherwise your CPU.
|
23 |
+
"""
|
24 |
+
# TODO: I think the slow loading of the encoder might have something to do with the device it
|
25 |
+
# was saved on. Worth investigating.
|
26 |
+
global _model, _device
|
27 |
+
if device is None:
|
28 |
+
_device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
29 |
+
elif isinstance(device, str):
|
30 |
+
_device = torch.device(device)
|
31 |
+
_model = SpeakerEncoder(_device, torch.device("cpu"))
|
32 |
+
checkpoint = torch.load(weights_fpath, _device)
|
33 |
+
_model.load_state_dict(checkpoint["model_state"])
|
34 |
+
_model.eval()
|
35 |
+
print("Loaded encoder \"%s\" trained to step %d" % (weights_fpath.name, checkpoint["step"]))
|
36 |
+
|
37 |
+
|
38 |
+
def is_loaded():
|
39 |
+
return _model is not None
|
40 |
+
|
41 |
+
|
42 |
+
def embed_frames_batch(frames_batch):
|
43 |
+
"""
|
44 |
+
Computes embeddings for a batch of mel spectrogram.
|
45 |
+
|
46 |
+
:param frames_batch: a batch mel of spectrogram as a numpy array of float32 of shape
|
47 |
+
(batch_size, n_frames, n_channels)
|
48 |
+
:return: the embeddings as a numpy array of float32 of shape (batch_size, model_embedding_size)
|
49 |
+
"""
|
50 |
+
if _model is None:
|
51 |
+
raise Exception("Model was not loaded. Call load_model() before inference.")
|
52 |
+
|
53 |
+
frames = torch.from_numpy(frames_batch).to(_device)
|
54 |
+
embed = _model.forward(frames).detach().cpu().numpy()
|
55 |
+
return embed
|
56 |
+
|
57 |
+
|
58 |
+
def compute_partial_slices(n_samples, partial_utterance_n_frames=partials_n_frames,
|
59 |
+
min_pad_coverage=0.75, overlap=0.5):
|
60 |
+
"""
|
61 |
+
Computes where to split an utterance waveform and its corresponding mel spectrogram to obtain
|
62 |
+
partial utterances of <partial_utterance_n_frames> each. Both the waveform and the mel
|
63 |
+
spectrogram slices are returned, so as to make each partial utterance waveform correspond to
|
64 |
+
its spectrogram. This function assumes that the mel spectrogram parameters used are those
|
65 |
+
defined in params_data.py.
|
66 |
+
|
67 |
+
The returned ranges may be indexing further than the length of the waveform. It is
|
68 |
+
recommended that you pad the waveform with zeros up to wave_slices[-1].stop.
|
69 |
+
|
70 |
+
:param n_samples: the number of samples in the waveform
|
71 |
+
:param partial_utterance_n_frames: the number of mel spectrogram frames in each partial
|
72 |
+
utterance
|
73 |
+
:param min_pad_coverage: when reaching the last partial utterance, it may or may not have
|
74 |
+
enough frames. If at least <min_pad_coverage> of <partial_utterance_n_frames> are present,
|
75 |
+
then the last partial utterance will be considered, as if we padded the audio. Otherwise,
|
76 |
+
it will be discarded, as if we trimmed the audio. If there aren't enough frames for 1 partial
|
77 |
+
utterance, this parameter is ignored so that the function always returns at least 1 slice.
|
78 |
+
:param overlap: by how much the partial utterance should overlap. If set to 0, the partial
|
79 |
+
utterances are entirely disjoint.
|
80 |
+
:return: the waveform slices and mel spectrogram slices as lists of array slices. Index
|
81 |
+
respectively the waveform and the mel spectrogram with these slices to obtain the partial
|
82 |
+
utterances.
|
83 |
+
"""
|
84 |
+
assert 0 <= overlap < 1
|
85 |
+
assert 0 < min_pad_coverage <= 1
|
86 |
+
|
87 |
+
samples_per_frame = int((sampling_rate * mel_window_step / 1000))
|
88 |
+
n_frames = int(np.ceil((n_samples + 1) / samples_per_frame))
|
89 |
+
frame_step = max(int(np.round(partial_utterance_n_frames * (1 - overlap))), 1)
|
90 |
+
|
91 |
+
# Compute the slices
|
92 |
+
wav_slices, mel_slices = [], []
|
93 |
+
steps = max(1, n_frames - partial_utterance_n_frames + frame_step + 1)
|
94 |
+
for i in range(0, steps, frame_step):
|
95 |
+
mel_range = np.array([i, i + partial_utterance_n_frames])
|
96 |
+
wav_range = mel_range * samples_per_frame
|
97 |
+
mel_slices.append(slice(*mel_range))
|
98 |
+
wav_slices.append(slice(*wav_range))
|
99 |
+
|
100 |
+
# Evaluate whether extra padding is warranted or not
|
101 |
+
last_wav_range = wav_slices[-1]
|
102 |
+
coverage = (n_samples - last_wav_range.start) / (last_wav_range.stop - last_wav_range.start)
|
103 |
+
if coverage < min_pad_coverage and len(mel_slices) > 1:
|
104 |
+
mel_slices = mel_slices[:-1]
|
105 |
+
wav_slices = wav_slices[:-1]
|
106 |
+
|
107 |
+
return wav_slices, mel_slices
|
108 |
+
|
109 |
+
|
110 |
+
def embed_utterance(wav, using_partials=True, return_partials=False, **kwargs):
|
111 |
+
"""
|
112 |
+
Computes an embedding for a single utterance.
|
113 |
+
|
114 |
+
# TODO: handle multiple wavs to benefit from batching on GPU
|
115 |
+
:param wav: a preprocessed (see audio.py) utterance waveform as a numpy array of float32
|
116 |
+
:param using_partials: if True, then the utterance is split in partial utterances of
|
117 |
+
<partial_utterance_n_frames> frames and the utterance embedding is computed from their
|
118 |
+
normalized average. If False, the utterance is instead computed from feeding the entire
|
119 |
+
spectogram to the network.
|
120 |
+
:param return_partials: if True, the partial embeddings will also be returned along with the
|
121 |
+
wav slices that correspond to the partial embeddings.
|
122 |
+
:param kwargs: additional arguments to compute_partial_splits()
|
123 |
+
:return: the embedding as a numpy array of float32 of shape (model_embedding_size,). If
|
124 |
+
<return_partials> is True, the partial utterances as a numpy array of float32 of shape
|
125 |
+
(n_partials, model_embedding_size) and the wav partials as a list of slices will also be
|
126 |
+
returned. If <using_partials> is simultaneously set to False, both these values will be None
|
127 |
+
instead.
|
128 |
+
"""
|
129 |
+
# Process the entire utterance if not using partials
|
130 |
+
if not using_partials:
|
131 |
+
frames = audio.wav_to_mel_spectrogram(wav)
|
132 |
+
embed = embed_frames_batch(frames[None, ...])[0]
|
133 |
+
if return_partials:
|
134 |
+
return embed, None, None
|
135 |
+
return embed
|
136 |
+
|
137 |
+
# Compute where to split the utterance into partials and pad if necessary
|
138 |
+
wave_slices, mel_slices = compute_partial_slices(len(wav), **kwargs)
|
139 |
+
max_wave_length = wave_slices[-1].stop
|
140 |
+
if max_wave_length >= len(wav):
|
141 |
+
wav = np.pad(wav, (0, max_wave_length - len(wav)), "constant")
|
142 |
+
|
143 |
+
# Split the utterance into partials
|
144 |
+
frames = audio.wav_to_mel_spectrogram(wav)
|
145 |
+
frames_batch = np.array([frames[s] for s in mel_slices])
|
146 |
+
partial_embeds = embed_frames_batch(frames_batch)
|
147 |
+
|
148 |
+
# Compute the utterance embedding from the partial embeddings
|
149 |
+
raw_embed = np.mean(partial_embeds, axis=0)
|
150 |
+
embed = raw_embed / np.linalg.norm(raw_embed, 2)
|
151 |
+
|
152 |
+
if return_partials:
|
153 |
+
return embed, partial_embeds, wave_slices
|
154 |
+
return embed
|
155 |
+
|
156 |
+
|
157 |
+
def embed_speaker(wavs, **kwargs):
|
158 |
+
raise NotImplemented()
|
159 |
+
|
160 |
+
|
161 |
+
def plot_embedding_as_heatmap(embed, ax=None, title="", shape=None, color_range=(0, 0.30)):
|
162 |
+
import matplotlib.pyplot as plt
|
163 |
+
if ax is None:
|
164 |
+
ax = plt.gca()
|
165 |
+
|
166 |
+
if shape is None:
|
167 |
+
height = int(np.sqrt(len(embed)))
|
168 |
+
shape = (height, -1)
|
169 |
+
embed = embed.reshape(shape)
|
170 |
+
|
171 |
+
cmap = cm.get_cmap()
|
172 |
+
mappable = ax.imshow(embed, cmap=cmap)
|
173 |
+
cbar = plt.colorbar(mappable, ax=ax, fraction=0.046, pad=0.04)
|
174 |
+
sm = cm.ScalarMappable(cmap=cmap)
|
175 |
+
sm.set_clim(*color_range)
|
176 |
+
|
177 |
+
ax.set_xticks([]), ax.set_yticks([])
|
178 |
+
ax.set_title(title)
|
rtvc/encoder/model.py
ADDED
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from encoder.params_model import *
|
2 |
+
from encoder.params_data import *
|
3 |
+
from scipy.interpolate import interp1d
|
4 |
+
from sklearn.metrics import roc_curve
|
5 |
+
from torch.nn.utils import clip_grad_norm_
|
6 |
+
from scipy.optimize import brentq
|
7 |
+
from torch import nn
|
8 |
+
import numpy as np
|
9 |
+
import torch
|
10 |
+
|
11 |
+
|
12 |
+
class SpeakerEncoder(nn.Module):
|
13 |
+
def __init__(self, device, loss_device):
|
14 |
+
super().__init__()
|
15 |
+
self.loss_device = loss_device
|
16 |
+
|
17 |
+
# Network defition
|
18 |
+
self.lstm = nn.LSTM(input_size=mel_n_channels,
|
19 |
+
hidden_size=model_hidden_size,
|
20 |
+
num_layers=model_num_layers,
|
21 |
+
batch_first=True).to(device)
|
22 |
+
self.linear = nn.Linear(in_features=model_hidden_size,
|
23 |
+
out_features=model_embedding_size).to(device)
|
24 |
+
self.relu = torch.nn.ReLU().to(device)
|
25 |
+
|
26 |
+
# Cosine similarity scaling (with fixed initial parameter values)
|
27 |
+
self.similarity_weight = nn.Parameter(torch.tensor([10.], device=loss_device))
|
28 |
+
self.similarity_bias = nn.Parameter(torch.tensor([-5.], device=loss_device)) ####modified####
|
29 |
+
|
30 |
+
# Loss
|
31 |
+
self.loss_fn = nn.CrossEntropyLoss().to(loss_device)
|
32 |
+
|
33 |
+
def do_gradient_ops(self):
|
34 |
+
# Gradient scale
|
35 |
+
self.similarity_weight.grad *= 0.01
|
36 |
+
self.similarity_bias.grad *= 0.01
|
37 |
+
|
38 |
+
# Gradient clipping
|
39 |
+
clip_grad_norm_(self.parameters(), 3, norm_type=2)
|
40 |
+
|
41 |
+
def forward(self, utterances, hidden_init=None):
|
42 |
+
"""
|
43 |
+
Computes the embeddings of a batch of utterance spectrograms.
|
44 |
+
|
45 |
+
:param utterances: batch of mel-scale filterbanks of same duration as a tensor of shape
|
46 |
+
(batch_size, n_frames, n_channels)
|
47 |
+
:param hidden_init: initial hidden state of the LSTM as a tensor of shape (num_layers,
|
48 |
+
batch_size, hidden_size). Will default to a tensor of zeros if None.
|
49 |
+
:return: the embeddings as a tensor of shape (batch_size, embedding_size)
|
50 |
+
"""
|
51 |
+
# Pass the input through the LSTM layers and retrieve all outputs, the final hidden state
|
52 |
+
# and the final cell state.
|
53 |
+
out, (hidden, cell) = self.lstm(utterances, hidden_init)
|
54 |
+
|
55 |
+
# We take only the hidden state of the last layer
|
56 |
+
embeds_raw = self.relu(self.linear(hidden[-1]))
|
57 |
+
|
58 |
+
# L2-normalize it
|
59 |
+
embeds = embeds_raw / (torch.norm(embeds_raw, dim=1, keepdim=True) + 1e-5)
|
60 |
+
|
61 |
+
return embeds
|
62 |
+
|
63 |
+
def similarity_matrix(self, embeds):
|
64 |
+
"""
|
65 |
+
Computes the similarity matrix according the section 2.1 of GE2E.
|
66 |
+
|
67 |
+
:param embeds: the embeddings as a tensor of shape (speakers_per_batch,
|
68 |
+
utterances_per_speaker, embedding_size)
|
69 |
+
:return: the similarity matrix as a tensor of shape (speakers_per_batch,
|
70 |
+
utterances_per_speaker, speakers_per_batch)
|
71 |
+
"""
|
72 |
+
speakers_per_batch, utterances_per_speaker = embeds.shape[:2]
|
73 |
+
|
74 |
+
# Inclusive centroids (1 per speaker). Cloning is needed for reverse differentiation
|
75 |
+
centroids_incl = torch.mean(embeds, dim=1, keepdim=True)
|
76 |
+
centroids_incl = centroids_incl.clone() / (torch.norm(centroids_incl, dim=2, keepdim=True) + 1e-5)
|
77 |
+
|
78 |
+
# Exclusive centroids (1 per utterance)
|
79 |
+
centroids_excl = (torch.sum(embeds, dim=1, keepdim=True) - embeds)
|
80 |
+
centroids_excl /= (utterances_per_speaker - 1)
|
81 |
+
centroids_excl = centroids_excl.clone() / (torch.norm(centroids_excl, dim=2, keepdim=True) + 1e-5)
|
82 |
+
|
83 |
+
# Similarity matrix. The cosine similarity of already 2-normed vectors is simply the dot
|
84 |
+
# product of these vectors (which is just an element-wise multiplication reduced by a sum).
|
85 |
+
# We vectorize the computation for efficiency.
|
86 |
+
sim_matrix = torch.zeros(speakers_per_batch, utterances_per_speaker,
|
87 |
+
speakers_per_batch).to(self.loss_device)
|
88 |
+
mask_matrix = 1 - np.eye(speakers_per_batch, dtype=np.int)
|
89 |
+
for j in range(speakers_per_batch):
|
90 |
+
mask = np.where(mask_matrix[j])[0]
|
91 |
+
sim_matrix[mask, :, j] = (embeds[mask] * centroids_incl[j]).sum(dim=2)
|
92 |
+
sim_matrix[j, :, j] = (embeds[j] * centroids_excl[j]).sum(dim=1)
|
93 |
+
|
94 |
+
## Even more vectorized version (slower maybe because of transpose)
|
95 |
+
# sim_matrix2 = torch.zeros(speakers_per_batch, speakers_per_batch, utterances_per_speaker
|
96 |
+
# ).to(self.loss_device)
|
97 |
+
# eye = np.eye(speakers_per_batch, dtype=np.int)
|
98 |
+
# mask = np.where(1 - eye)
|
99 |
+
# sim_matrix2[mask] = (embeds[mask[0]] * centroids_incl[mask[1]]).sum(dim=2)
|
100 |
+
# mask = np.where(eye)
|
101 |
+
# sim_matrix2[mask] = (embeds * centroids_excl).sum(dim=2)
|
102 |
+
# sim_matrix2 = sim_matrix2.transpose(1, 2)
|
103 |
+
|
104 |
+
sim_matrix = sim_matrix * self.similarity_weight + self.similarity_bias
|
105 |
+
return sim_matrix
|
106 |
+
|
107 |
+
def loss(self, embeds):
|
108 |
+
"""
|
109 |
+
Computes the softmax loss according the section 2.1 of GE2E.
|
110 |
+
|
111 |
+
:param embeds: the embeddings as a tensor of shape (speakers_per_batch,
|
112 |
+
utterances_per_speaker, embedding_size)
|
113 |
+
:return: the loss and the EER for this batch of embeddings.
|
114 |
+
"""
|
115 |
+
speakers_per_batch, utterances_per_speaker = embeds.shape[:2]
|
116 |
+
|
117 |
+
# Loss
|
118 |
+
sim_matrix = self.similarity_matrix(embeds)
|
119 |
+
sim_matrix = sim_matrix.reshape((speakers_per_batch * utterances_per_speaker,
|
120 |
+
speakers_per_batch))
|
121 |
+
ground_truth = np.repeat(np.arange(speakers_per_batch), utterances_per_speaker)
|
122 |
+
target = torch.from_numpy(ground_truth).long().to(self.loss_device)
|
123 |
+
loss = self.loss_fn(sim_matrix, target)
|
124 |
+
|
125 |
+
# EER (not backpropagated)
|
126 |
+
with torch.no_grad():
|
127 |
+
inv_argmax = lambda i: np.eye(1, speakers_per_batch, i, dtype=np.int)[0]
|
128 |
+
labels = np.array([inv_argmax(i) for i in ground_truth])
|
129 |
+
preds = sim_matrix.detach().cpu().numpy()
|
130 |
+
|
131 |
+
# Snippet from https://yangcha.github.io/EER-ROC/
|
132 |
+
fpr, tpr, thresholds = roc_curve(labels.flatten(), preds.flatten())
|
133 |
+
eer = brentq(lambda x: 1. - x - interp1d(fpr, tpr)(x), 0., 1.)
|
134 |
+
|
135 |
+
return loss, eer
|
rtvc/encoder/params_data.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
## Mel-filterbank
|
3 |
+
mel_window_length = 25 # In milliseconds
|
4 |
+
mel_window_step = 10 # In milliseconds
|
5 |
+
mel_n_channels = 40
|
6 |
+
|
7 |
+
|
8 |
+
## Audio
|
9 |
+
sampling_rate = 16000
|
10 |
+
# Number of spectrogram frames in a partial utterance
|
11 |
+
partials_n_frames = 160 # 1600 ms
|
12 |
+
# Number of spectrogram frames at inference
|
13 |
+
inference_n_frames = 80 # 800 ms
|
14 |
+
|
15 |
+
|
16 |
+
## Voice Activation Detection
|
17 |
+
# Window size of the VAD. Must be either 10, 20 or 30 milliseconds.
|
18 |
+
# This sets the granularity of the VAD. Should not need to be changed.
|
19 |
+
vad_window_length = 30 # In milliseconds
|
20 |
+
# Number of frames to average together when performing the moving average smoothing.
|
21 |
+
# The larger this value, the larger the VAD variations must be to not get smoothed out.
|
22 |
+
vad_moving_average_width = 8
|
23 |
+
# Maximum number of consecutive silent frames a segment can have.
|
24 |
+
vad_max_silence_length = 6
|
25 |
+
|
26 |
+
|
27 |
+
## Audio volume normalization
|
28 |
+
audio_norm_target_dBFS = -30
|
29 |
+
|
30 |
+
# 判断用户输入语音为男声或女声的分界频率
|
31 |
+
split_freq = 170
|
32 |
+
# embed去噪置零的阈值
|
33 |
+
set_zero_thres=0.06
|
34 |
+
|