앞의 (1), (2)에서 영상에서 음성(wav) 데이터를 추출하는 법, 음성의 배경음악 제거하는 법 등을 알아보았다.
이제 마지막으로 해야 할 것은 바로 우리가 만든 wav데이터의 text값을 얻는 것이다.
즉 stt(speech to text)의 과정을 거쳐야 한다.
다행히도 stt를 지원하는 라이브러리나 api는 많이 있다. 이 중에서 내가 사용한 것들로 글을 이어가겠다.
1. google web speech
https://www.google.com/intl/en/chrome/demos/speech.html
https://wicg.github.io/speech-api/
google web speech는 기본 키가 존재해서 api key를 별도로 발급받지 않아도 사용이 가능하다.
(한도가 50번 정도라는 글이 있었는데, 700개 정도의 wav파일에 google web speech를 사용했는데 전부 결과물이 나왔다. 한도가 없어진 것인지는 잘 모르겠다.)
import speech_recognition as sr
# wav_path는 wav파일의 path
def googleweb(wav_path):
r = sr.Recognizer()
korean_audio = sr.AudioFile(wav_path)
with korean_audio as source:
audio = r.record(source)
try:
text = r.recognize_google(audio_data=audio, language='ja-JP')
except sr.UnknownValueError:
text = 'this file is too short'
print(text)
위의 코드는 google web speech를 사용하는 함수이다. (위의 함수는 파이썬 라이브러리 speech_recognition을 이용하여 google web speech를 사용하는 방법이다.)
가끔 UnknownValueError가 뜰 때가 있는데 wav파일이 너무 짧으면 저런 오류가 뜨는 것 같다.
그래서 예외처리를 해 주었다.
비교적 간단히 stt작업이 가능하다는 점을 이유로 처음에는 google web speech를 이용했다. 하지만 문제가 생겼다.
stt작업이 끝난 후 speech와 text가 매칭이 되는지 한 번 훑어봤는데.. 완전 난장판이었다..
우선 단어 수준의 짧은 음성을 인식하지 못한다. 짧은 음성의 경우 UnknownValueError가 계속 났다.
그리고 앞 뒤의 음성을 잘 인식하지 못한다.
예를들면, 盗んだ物を返して(음성)에서 뒤의 음성이 잘린 채로 盗んだ 만 출력된다던가..
마지막으로 그냥 text로 출력해준 값이 음성과 맞지 않는다.
예를 들면 ほかの(호카노(음성)) -> わかな(와카나(text)) 이런 식으로..
위의 3가지 문제 중 1개 이상이 포함되어있는 데이터가 약 30%가 넘었다. (대충)
이 방법을 선택하게 되면 귀중한 데이터의 30%를 못쓰게 되는 것은 물론, 뭐가 못쓰는 데이터인지 일일이 확인해봐야 한다. 그래서 이 방법은 패스한다.
2. google cloud stt
https://cloud.google.com/speech-to-text
그래서 다음 선택은 google cloud stt이다.
위의 링크를 타고 들어가면 간단하게 stt작업을 미리 해볼 수 있다.
google web speech에서 오류가 나거나 깔끔하게 나오지 않는 wav파일들을 넣어봤을 때, 깔끔하게 나왔고, 다른 사람들이 stt작업에 많이 사용하는 api라는 것을 이유로 이것을 선택하게 되었다.
이 api는 유료이고, api키를 받아 환경변수에 저장하거나 실행할 때마다 set을 해줘야 한다는 귀찮은 점이 있지만, 한번 사용해보기로 했다.
유료이긴 하지만 처음 사용자에게는 90일간 300달러의 무료크레딧을 준다. 그래서 부담 없이 사용하기로 결정했다.
(계산기 두드려보니 내 wav파일 전부 stt 작업하는데 드는 비용이 천원도 안 되는 건 나중에 안 사실..)
사용하려면 우선 api키를 발급받아야 한다. api키를 발급받는 법을 여기서 설명하면 너무 길어지기도 하고 홈페이지에 들어가면 상세하게 설명을 해주므로 생략한다.
api key(json파일)을 받고 환경변수 등록까지 마쳤다면, google cloud stt를 사용해볼 수 있다.
from google.cloud import speech_v1
import io
def google_cloud_stt(wav_path):
"""Transcribe the given audio file."""
text = ""
client = speech_v1.SpeechClient()
with io.open(wav_path, "rb") as audio_file:
content = audio_file.read()
audio = speech_v1.RecognitionAudio(content=content)
config = speech_v1.RecognitionConfig(
encoding=speech_v1.RecognitionConfig.AudioEncoding.LINEAR16,
sample_rate_hertz=22050,
language_code="ja-JP",
audio_channel_count=1,
)
response = client.recognize(config=config, audio=audio)
if response.results == []:
text = "None"
print(f'google_cloud_speech: = {text}')
# print(response.results)
# Each result is for a consecutive portion of the audio. Iterate through
# them to get the transcripts for the entire audio file.
for result in response.results:
# The first alternative is the most likely one for this portion.
text = format(result.alternatives[0].transcript)
print(f'google_cloud_speech: = {text}')
위의 코드는 google cloud stt에서 올려놓은 예시 코드를 약간 변형해서 들고 온 코드다.
google cloud stt에서는 google web speech보다 확실히 성능이 좋았다.
wav파일을 인식하지 못하는 횟수가 줄었고(없진 않다) 뭉텅이로 텍스트가 잘리는 일이 줄긴 했다.
하지만
여전히 앞 뒤 음성을 잘 인식하지 못하고, 번역이 좀 이상했다.
예를 들면, えっと(엣또)을 ペット(펫또)처럼 이상하게 번역하는 게 간간히 보였고,
だから潔く盗んだものを返して(다카라 이사기요쿠 누슨다 모노오 카에시테)를 だから潔く寝たい(다카라 이사기요쿠 네타이)처럼 끝부분이 이상하게 번역되는 게 종종 보였다.
그리고 자주 일어난 이슈는 아니지만 짧은 단어 수준의 음성은 그냥 무시를 해버린다.
(정확히는 요청 값을 받는 부분, 위 코드에서는 response가 아무것도 없는 값이 리턴된다.)
이러한 문제가 발생하는 이유가 분명 api문제가 아닌 wav데이터의 문제일 수도 있다. (의심 가는 부분이 있긴 하다)
하지만 데이터를 다시 만들 수는 없는 노릇이므로..(엄청 시간 많이 걸림)
다른 api를 찾기로 했다.
3. azure stt
https://azure.microsoft.com/ko-kr/services/cognitive-services/speech-to-text/#overview
사실 azure stt는 처음에는 알지 못했다. stt api가 어떤 것이 있는지 찾아보다가 알게 된 것이다.
위의 홈페이지에 들어가면 stt체험이 가능하다. 나는 google cloud stt에서 문제가 발생했던 wav파일들을 넣어보면서 문제가 발생하는지 확인해보았다.
그런데! 문제가 발생하지 않았다!
짧은 단어 수준의 wav파일도 인식하고, 앞 뒤 음성을 번역하지 않는 이슈도 거의 없었다.
무엇보다 제일 마음에 드는 부분은 캐릭터의 이름이라던가 왕국 이름 등 일본어 정식? 단어가 아닌 단어도 정확하게 번역을 했다. 앞의 stt들은 캐릭터 이름에서 이상하게 번역하는 부분이 많이 보였다.
(내 예상으로는 캐릭터 이름을 일본어 정식? 단어로 인식하고 최대한 그쪽으로 번역하려고 하는 것 같았다.)
예를 들어 캐릭터 이름 중 하나인 렘이 들어간 문장을 보면
"렘이라니"(레무테)를 google cloud stt 같은 경우는 眠って(네무테)로 번역하고, azure stt는 レムって(레무테)로 인식했다. (뒤의 경우가 알맞은 번역, 앞의 경우는 잠들다(眠)로 인식하고 번역했음)
물론 약간식 뒤틀린 번역이 있긴 했다. 하지만 거의 없다 해도 무방할 정도에, 앞 뒤 잘리는 부분은 거의 없었다.
따라서 나는 azure stt를 사용하기로 정했다.
정리하자면, 최종 선택은 Azure stt서비스이고, 선택이유는 google web speech, google cloud stt의 단점이 모두 해결되어 있고, 캐릭터, 지명 등의 이름도 제대로 번역을 해서이다.
azure stt서비스는 기본적으로는 유료서비스이다.
하지만 처음 사용하는 사용자에게는 한 달간 무료크레딧 200달러를 제공하고, 매달 5시간은 무료로 사용이 가능하다.
(사용하기 전, 꼭 밑의 링크의 가격표를 참고하자. 혹시 모르니..)
https://azure.microsoft.com/ko-kr/pricing/details/cognitive-services/speech-services/
api키를 받는 법은 홈페이지에 자세히 설명되어 있으므로 생략하겠다.
google cloud stt처럼 환경 변수 설정을 하거나 할 필요 없이, api키를 받고, 코드에 넣어주면 된다.
(밑의 코드에서 'azure_key'에 api키 값을 넣어주면 된다.)
import azure.cognitiveservices.speech as speechsdk
def azure_stt(wav_path):
speech_config = speechsdk.SpeechConfig(subscription=azure_key, region="koreacentral")
speech_config.speech_recognition_language = "ja-JP"
# To recognize speech from an audio file, use `filename` instead of `use_default_microphone`:
text = ""
audio_config = speechsdk.audio.AudioConfig(
filename=wav_path)
# audio_config = speechsdk.audio.AudioConfig(use_default_microphone=True)
speech_recognizer = speechsdk.SpeechRecognizer(speech_config=speech_config, audio_config=audio_config)
speech_recognition_result = speech_recognizer.recognize_once_async().get()
text = speech_recognition_result.text
if speech_recognition_result.reason == speechsdk.ResultReason.RecognizedSpeech:
print("Azure : {}".format(text))
elif speech_recognition_result.reason == speechsdk.ResultReason.NoMatch:
print("No speech could be recognized: {}".format(speech_recognition_result.no_match_details))
elif speech_recognition_result.reason == speechsdk.ResultReason.Canceled:
cancellation_details = speech_recognition_result.cancellation_details
print("Speech Recognition canceled: {}".format(cancellation_details.reason))
if cancellation_details.reason == speechsdk.CancellationReason.Error:
print("Error details: {}".format(cancellation_details.error_details))
print("Did you set the speech resource key and region values?")
이 코드는 공식 홈페이지에서의 api사용 예제를 조금 변형시킨 코드이다.
이렇게 해서 stt작업을 수행할 api를 골랐다.
위의 함수를 바탕으로 각각의 wav파일에 stt작업을 수행하고 결과를 json파일에 저장하자.
작업을 수행하면 speech-text(일본어) 셋이 완성된다.
ex) "1_001_spl.wav" : "そこまでよ" ......
다음은 위의 결과물을 실사용하기 위해 어떤 변형이 필요한지 말해보겠다.
'프로젝트 > 음성합성(tts)' 카테고리의 다른 글
캐릭터 보이스 만들기#6-학습 진행 (0) | 2022.05.03 |
---|---|
캐릭터 보이스 만들기#5-데이터 셋 제작(3-2) (0) | 2022.05.02 |
캐릭터 보이스 만들기#5-데이터 셋 제작(2) (0) | 2022.04.11 |
캐릭터 보이스 만들기#5-데이터 셋 제작(1) (2) | 2022.04.06 |
캐릭터 보이스 만들기#4-계획 정리 (0) | 2022.03.29 |