[컴퓨터공학]/[마이크로 프로세서]

[마이크로 프로세서] 라즈베리파이 VQA 프로젝트 2 - VQA, TTS

딥러닝 도전기 2022. 6. 7. 06:17

[마이크로 프로세서] 라즈베리파이 VQA 프로젝트 - 2

안녕하세요. 딥러닝 도전기입니다.

이번 포스팅에서는 지난 포스팅 https://deep-learning-challenge.tistory.com/88 에 이어서 STT를 통하여 받은 질문과, 웹캠을 통해 촬영한 이미지를 서버로 전송하고 서버에서 이미 학습된 모델을 통해 추론을 진행, 추론된 답변 txt파일을 다시 라즈베리파이로 전송하여 TTS를 통해 스피커로 답변을 출력하는 과정에 대한 내용을 작성해보려 합니다.

 

[마이크로 프로세서] 라즈베리파이 VQA 프로젝트 1 - STT

[마이크로 프로세서] 라즈베리파이 VQA 프로젝트 1 - STT 안녕하세요. 딥러닝 도전기입니다. 학부 3학년 마이크로 프로세서 교과목 시간에 진행하는 라즈베리파이 Visual Question Answering프로젝트에 대

deep-learning-challenge.tistory.com


Process

1. 음성 질문$\to$ text (.txt파일로 저장)

2. 웹캠 사진 촬영 (.jpg파일로 저장)

3. .txt 파일과 .jpg파일을 서버로 전송 (암호 입력 과정을 생략하기 위해 sshpass사용)

4. ssh로 서버에 접속, 만들어 놓은 추론 파일(predict.py)를 실행 $\to$ answer.txt파일 서버에 생성

5. 서버에 생성된 answer.txt파일을 scp를 통해 라즈베리파이에 가져옴

6. TTS를 통해 (초기 Festival TTS 사용 $\to$ 한국어를 지원하지 않아서 eSpeak 사용 $\to$ 목소리 및 발음이 너무 안좋아서 Naver Clova Voice API 사용)

 

위와 같은 Process를 한 번에 진행하려고 하니까 조금 복잡했습니다.

라즈베리파이에 command.sh파일을 만들어서 한 개의 sh파일 실행으로 모든 process가 작동하게 했습니다.

 

command.sh

#사진 찍기
echo "\n************이미지 촬영*************\n"
fswebcam -r 1920x1080 /home/mjkmain/speech/input_image.jpg
echo "\n************이미지 촬영 완료********\n"

#이미지 열기
xdg-open /home/mjkmain/speech/input_image.jpg

echo "\n************질문 녹음 시작**************\n"
#Record and STT From Kakao API
python /home/mjkmain/speech/start.py
echo "\n************질문 녹음 완료************\n"

#Send image, text file to Server with Password
sshpass -p [password] scp -P [portnumber] /home/mjkmain/speech/input_image.jpg [username]@[IP]:/home/aailab/mjkim
sshpass -p [password] scp -P [portnumber] /home/mjkmain/speech/input_question.txt [username]@[IP]:/home/aailab/mjkim


echo "\n\n -----추론중입니다. 잠시만 기다려주세요-----\n\n"

#음성으로 잠시 기다려달라는 안내
espeak -v ko -f wait.txt -s 120

#ssh to remote server And activate predict.py
sshpass -p [password] ssh [username]@[IP] -p [portnumber] python3 /home/aailab/mjkim/predict.py

#Receive the answer.txt
sshpass -p [password] scp -P [portnumber] [username]@[IP]:/home/aailab/mjkim/answer.txt /home/mjkmain/speech/

#음성 출력을 위하여 기존의 cp949 encoded txt file을 utf-8로 변환
iconv -f cp949 -t utf-8 answer.txt>utf8.txt

#정답 출력
cat /home/mjkmain/speech/answer.txt

#음성으로 정답 출력
espeak -v ko -f utf8.txt -s 100

 

위와 같은 command.sh를 만들고

$ sh command.sh 2>/dev/null

위와 같은 코드를 활용하여 출력했습니다.

2>/dev/null은 터미널에 출력될 때 경고나 에러문자는 생략해 주는 명령어입니다.

아무래도 추론 측에서 bert 계열 알고리즘을 hugging face에서 가져다 써서 출력 문자가 많이 나오더라구요.

 

이제 command.sh와 그에 딸려있는 python file을 한 개 한개 설명 드리도록 하겠습니다.

 

이전 포스팅과 겹치는 내용도 그냥 작성해보도록 하겠습니다.

 

혹시 모르는 마음에 모든 경로는 절대경로로 작성하였습니다.

 

1. 이미지 촬영

$ fswebcam -r 1920x1080 /home/mjkmain/speech/input_image.jpg

fswebcam에 -r 옵션을 줘서 해상도(resolution)을 1920x1080으로 준 후 이미지를 촬영합니다.

촬영된 이미지는 /home/mjkmain/speech/input_image.jpg로 저장됩니다.

 

2. 이미지 raspberry pi 모니터로 출력

$ xdg-open /home/mjkmain/speech/input_image.jpg

/home/mjkmain/speech/에 저장된 input_image.jpg 파일을 라즈베리 파이 모니터에 출력합니다.

 

3. 음성 질문

$ python /home/mjkmain/speech/start.py

home/mjkmain/speech/에 저장된 start.py 파이썬 파일을 실행합니다.

start.py는 다음과 같습니다.

 

start.py

import requests
import json
import os

os.system('arecord --format=S16_LE --duration=5 --rate=16000 --file-type=raw /home/mjkmain/speech/input_question.raw')
os.system('echo : "saving record ..."')

kakao_speech_url = "https://kakaoi-newtone-openapi.kakao.com/v1/recognize"

rest_api_key = 'MY API NUMBER'

headers = {
	"Content-Type" : "application/octet-stream",
	"X-DSS-Service" : "DICTATION",
	"Authorization" : "KakaoAK "+rest_api_key,
}

with open('/home/mjkmain/speech/input_question.raw', 'rb') as fp:
	audio = fp.read()

res = requests.post(kakao_speech_url, headers=headers, data=audio)
result_json_string = res.text[res.text.index('{"type":"finalResult"'):res.text.rindex('}')+1]
result = json.loads(result_json_string)

print(f'\tQuestion : {result["value"]}')

f = open("./input_question.txt", 'w')
f.write(result["value"])
f.close()

print("Success")

이 start.py를 자세히 들여다 보겠습니다.

 

os.system('arecord --format=S16_LE --duration=5 --rate=16000 --file-type=raw /home/mjkmain/speech/input_question.raw')
os.system('echo : "saving record ..."')

위의 코드에서 os.system을 사용하면 터미널에서 입력하는 것과 동일한 효과를 냅니다.

즉 터미널에

$ arecord --format=S16_LE --duration=5 --rate=16000 --file-type=raw /home/mjkmain/speech/input_question.raw

위와 같은 코드를 입력하고 echo로 출력 녹음 저장중이라고 한 것이지요.

 

arecord는 음성 녹음을 실행하는 것입니다.

duration = 5는 5초동안 진행하겠다는 것, rate=16000는 Hertz를 의미합니다.

또한 파일 형식을 raw로, /home/mjkmain/speech/에 input_question.raw로 저장하겠다는 내용입니다.

 

그 아래는 저장된 input_question.raw파일을 Kakao STT API를 통해 Text로 변환하는 내용인데요, 마지막 부분에

 print(f'\t Question : {result[value]}')

result[value]는 여러 STT 결과물 후보 중 점수가 가장 높은 text를 의미합니다.

 

이렇게 음성 질문입력 및 Text로 변환은 start.py라는 파이썬 파일을 실행 함으로 해결했습니다.

 

4. 서버 접속 및 데이터 전송

다음으로 scp와 ssh 관련한 내용입니다.

$ sshpass -p [password] scp -P [portnumber] /home/mjkmain/speech/input_image.jpg [username]@[IP]:/home/aailab/mjkim
$ sshpass -p [password] scp -P [portnumber] /home/mjkmain/speech/input_question.txt [username]@[IP]:/home/aailab/mjkim

sshpass는 해당 프로젝트를 진행하다가 처음 만나보았습니다.

 

저는 한 개의 파일 실행으로 모든 process를 진행하고 싶었기 때문에, 서버 접속 및 scp로 데이터 전송 시 입력해야하는 비밀번호를 처리해야 했습니다.

 

방법이 없을까.. 고민하다가 구글링을 통해 sshpass라는 것을 알게되었습니다.

$ sudo apt-get install sshpass

위의 명령어를 통해 다운받아서 사용할 수 있고, 기존에 사용하던 scp 명령어 앞에 sshpass -p [password]를 입력해주시면 됩니다. (p는 소문자입니다)

 

sshpass를 통하여 비밀번호도 따로 입력하지 않고 한 번에 입력이 가능해졌습니다.

 

아무래도 서버에 접속하여 추론을 진행하다보니 정답을 받는 것 까지 30초 정도의 시간이 소요됩니다.

따라서 잠시 기다려 달라는 안내를 echo를 통해 넣었습니다.

 

5. 추론

다음으로 sshpass를 통해 직접 서버에 접속합니다.

$ sshpass -p [password] ssh [username]@[IP] -p [portnumber] python3 /home/aailab/mjkim/predict.py

직접 접속해서 predict.py라는 파일을 실행시킵니다.

predict.py에는 좀 전에 scp로 전송받은 이미지와 질문 파일을 통하여 정답을 추론합니다.

이미 학습된 VQA모델인 model.tar 을 통해서 진행됩니다.

 

정답은 answer.txt로 서버에 저장합니다.

$ sshpass -p [password] scp -P [portnumber] [username]@[IP]:/home/aailab/mjkim/answer.txt /home/mjkmain/speech/

그 다음 서버에 저장된 answer.txt파일을 scp를 통하여 가져옵니다.

가져온 answer.txt는 /home/mjkmain/speech/ 아래에 저장됩니다.

 

6. 정답 음성 출력

이제 이 answer.txt파일을 음성으로 변환하여 출력하려고 합니다.

그런데 여기에서 문제가 발생하였습니다.

저는 기존에 cp949 인코딩 방식을 사용했는데, espeak로 출력하기 위해서는 utf-8이여야 하는 것 같습니다.

다음의 명령어를 통하여 cp949 $\to$ utf-8로 변환합니다.

 

$ iconv -f cp949 -t utf-8 answer.txt>utf8.txt

-f는 from, -t는 to 일 것 같습니다.

변환한 파일은 utf8.txt라고 저장합니다.

 

이제 변환된 txt파일을 화면에 출력 후 음성으로 출력합니다.

#정답 출력
$ cat /home/mjkmain/speech/answer.txt

#음성으로 정답 출력
$ espeak -v ko -f utf8.txt -s 100

espeak를 사용하여 따로 api를 사용하지 않고 간단하게 해결하였습니다.

 

-v ko는 한국어로 출력하겠다는 것이고, -f utf8.txt는 utf8.txt파일의 내용을 출력하겠다는 내용입니다.

-s 는 말소리의 speed를 의미합니다. 조금 빨라서 100으로 줄였습니다. (default 160?)

 


수정

 

espeak를 사용하다 보니, 말을 못알아들을 정도로 발음이 너무 안좋았습니다.

그래서 API를 찾아보니, 네이버 Clova에서 개발한 API가 잘 나와있었습니다.

9만원짜리였지만.. 첫 가입 크레딧으로 10만원을 받아서 사용해버렸습니다

 

Clova voice는 text to mp3기능을 제공합니다.

mpg321을 사용하여 mp3를 스피커로 출력하는 것을 해결했습니다.

 

$ mpg321 test.mp3


여기에서 포스팅을 마치도록 하겠습니다.

 

긴 글 읽어주셔서 감사합니다

반응형