30์ 1์ผ๋ถํฐ XNUMX์ XNUMX์ผ๊น์ง ๋์ฆ๋๋
ธ๋ธ๊ณ ๋ก๋์์ ๊ฐ์ต๋์์ต๋๋ค.
์ด ๊ธฐ์ฌ์์๋ ์ฐ๋ฆฌ๊ฐ ์ด๋ป๊ฒ ์ ํ์ ํ๋กํ ํ์ ์ ๋ง๋ค์๊ณ ๊ฒฐ๊ตญ XNUMX์๋ฅผ ์ฐจ์งํ๋์ง์ ๋ํด ์ค๋ช ํฉ๋๋ค.
์ด๋ฒ ํด์ปคํค์๋ 10๊ฐ ์ด์์ ํ์ด ์ฐธ๊ฐํ์ต๋๋ค. ๊ทธ๋ค ์ค ์ผ๋ถ๊ฐ ๋ค๋ฅธ ์ง์ญ์์ ์๋ค๋ ๊ฒ์ ์ข์ ์ผ์ ๋๋ค. ํด์ปคํค ์ฅ์๋ ๋์ฆ๋๋ ธ๋ธ๊ณ ๋ก๋์ ๊ณ ๋ ์ฌ์ง์ด ๋ด๋ถ์ ๊ฑธ๋ ค ์๋ "Kremlinsky on Pochain" ๋จ์ง์์ต๋๋ค! (ํ์ฌ Intel์ ์ค์ ์ฌ๋ฌด์ค์ Nizhny Novgorod์ ์์์ ์๊ธฐ์์ผ๋๋ฆฝ๋๋ค.) ์ฐธ๊ฐ์๋ค์๊ฒ๋ 26์๊ฐ ๋์ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ๋ง์ง๋ง์๋ ์๋ฃจ์ ์ ๋ฐํํด์ผ ํ์ต๋๋ค. ๋ณ๋์ ์ฅ์ ์ ๊ณํ๋ ๋ชจ๋ ๊ฒ์ด ์ค์ ๋ก ๊ตฌํ๋์์ผ๋ฉฐ ํ๋ ์ ํ ์ด์ ์ ์์ด๋์ด๊ฐ ๋จ์ ์์ง ์์์ง ํ์ธํ๋ ๋ฐ๋ชจ ์ธ์ ์ด ์๋ค๋ ๊ฒ์ ๋๋ค. ์ํ, ๊ฐ์, ์์ ๋ฑ ๋ชจ๋ ๊ฒ์ด ๊ฑฐ๊ธฐ์ ์์์ต๋๋ค!
๋ํ Intel์ ์ ํ์ ์ผ๋ก ์นด๋ฉ๋ผ, Raspberry PI, Neural Compute Stick 2๋ฅผ ์ ๊ณตํ์ต๋๋ค.
์์ ์ ํ
์์ ํ์ ํด์ปคํค์ ์ค๋นํ ๋ ๊ฐ์ฅ ์ด๋ ค์ด ๋ถ๋ถ ์ค ํ๋๋ ๋์ ๊ณผ์ ๋ฅผ ์ ํํ๋ ๊ฒ์ ๋๋ค. ์ฐ๋ฆฌ๋ ๋ฐํ์์ ์ด๊ฒ์ด ๋งค์ฐ ํ์๋ฐ๋๋ค๊ณ ๋งํ๊ธฐ ๋๋ฌธ์ ์์ง ์ ํ์ ์๋ ๊ฒ์ ์๊ฐํด๋ด๊ธฐ๋ก ์ฆ์ ๊ฒฐ์ ํ์ต๋๋ค.
๋ถ์ํ๊ณ
- ์ด๋ก ์ ์ผ๋ก๋ ์๋ฆฌ์ ์ด๋ฏธ์ง ๋ชจ๋์ ์๋ํ๋ ๊ฒฐํฉ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋ง๋๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ฏ๋ก ์ ํ๋๊ฐ ๋์์ง๋๋ค.
- ์นด๋ฉ๋ผ๋ ์ผ๋ฐ์ ์ผ๋ก ์์ผ๊ฐ์ด ์ข๊ธฐ ๋๋ฌธ์ ๋์ ์์ญ์ ์ปค๋ฒํ๋ ค๋ฉด ๋ ๋ ์ด์์ ์นด๋ฉ๋ผ๊ฐ ํ์ํฉ๋๋ค. ์๋ฆฌ์๋ ์ด๋ฌํ ์ ํ์ด ์์ต๋๋ค.
์์ด๋์ด๋ฅผ ๋ฐ์ ์ํค์. ์๋งค ๋ถ๋ฌธ์ ๋ํ ์์ด๋์ด๋ฅผ ๊ธฐ์ด๋ก ์ผ์. ๋งค์ฅ ๊ฒฐ์ ์ ๊ณ ๊ฐ ๋ง์กฑ๋๋ฅผ ์ธก์ ํ ์ ์์ต๋๋ค. ๊ณ ๊ฐ ์ค ํ ๋ช
์ด ์๋น์ค์ ๋ง์กฑํ์ง ๋ชปํ๊ณ ๋ชฉ์๋ฆฌ๋ฅผ ๋์ด๊ธฐ ์์ํ๋ฉด ์ฆ์ ๊ด๋ฆฌ์์๊ฒ ๋์์ ์์ฒญํ ์ ์์ต๋๋ค.
์ด ๊ฒฝ์ฐ ์ฌ๋์ ์์ฑ ์ธ์์ ์ถ๊ฐํด์ผ ํฉ๋๋ค. ์ด๋ฅผ ํตํด ๋งค์ฅ ์ง์๊ณผ ๊ณ ๊ฐ์ ๊ตฌ๋ณํ๊ณ ๊ฐ ๊ฐ์ธ์ ๋ํ ๋ถ์์ ์ ๊ณตํ ์ ์์ต๋๋ค. ๊ธ์์, ๋งค์ฅ ์ง์์ ํ๋์ ์ง์ ๋ถ์ํ๊ณ ํ์ ๋ถ์๊ธฐ๋ฅผ ํ๊ฐํ ์๋ ์์ต๋๋ค. ์ข์ ๊ฒ ๊ฐ์ต๋๋ค!
์ฐ๋ฆฌ๋ ์๋ฃจ์ ์ ๋ํ ์๊ตฌ ์ฌํญ์ ๊ณต์ํํฉ๋๋ค.
- ๋์ ์ฅ์น์ ์์ ํฌ๊ธฐ
- ์ค์๊ฐ ์ด์
- ์ ๋ ดํ ๊ฐ๊ฒฉ
- ์ฌ์ด ํ์ฅ์ฑ
๊ฒฐ๊ณผ์ ์ผ๋ก ์ฐ๋ฆฌ๋ Raspberry Pi 3 c๋ฅผ ๋์ ์ฅ์น๋ก ์ ํํ์ต๋๋ค.
์ฌ๊ธฐ์์ NCS์ ์ค์ํ ๊ธฐ๋ฅ ์ค ํ๋๋ฅผ ์ธ๊ธํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด๋ ํ์ค CNN ์ํคํ ์ฒ์์ ๊ฐ์ฅ ์ ์๋ํ์ง๋ง ์ฌ์ฉ์ ์ ์ ๋ ์ด์ด๊ฐ ์๋ ๋ชจ๋ธ์ ์คํํด์ผ ํ๋ ๊ฒฝ์ฐ ๋ฎ์ ์์ค์ ์ต์ ํ๋ฅผ ๊ธฐ๋ํฉ๋๋ค.
ํด์ผ ํ ์์ ์ผ์ด ํ๋ ์์ต๋๋ค. ๋ง์ดํฌ๋ฅผ ๊ตฌํด์ผ ํฉ๋๋ค. ์ผ๋ฐ USB ๋ง์ดํฌ๋ผ๋ฉด ๊ด์ฐฎ์ง๋ง RPI์ ํจ๊ป ์ฌ์ฉํ๋ฉด ๋ณด๊ธฐ์ ์ข์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ฌ๊ธฐ์๋ ํด๊ฒฐ์ฑ
์ ๋ฌธ์ ๊ทธ๋๋ก "๊ฐ๊น์ด ๊ณณ์ ์์ต๋๋ค." ์์ฑ์ ๋
น์ํ๊ธฐ ์ํด ํคํธ์ ํฌํจ๋ Voice Bonnet ๋ณด๋๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
๋ค์์์ Raspbian์ ๋ค์ด๋ก๋ํ์ธ์.
arecord -d 5 -r 16000 test.wav
๋ง์ดํฌ๊ฐ ๋งค์ฐ ๋ฏผ๊ฐํ๊ณ ์์์ ์ ํฌ์ฐฉํ๋ค๋ ์ ์ ์ฆ์ ์ฃผ๋ชฉํด์ผ ํฉ๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด alsamixer๋ก ์ด๋ํ์ฌ ์บก์ฒ ์ฅ์น๋ฅผ ์ ํํ๊ณ ์ ๋ ฅ ์ ํธ ๋ ๋ฒจ์ 50-60%๋ก ์ค์ด์ธ์.
ํ์ผ๋ก ๋ณธ์ฒด๋ฅผ ์์ ํ๋ฉด ๋ชจ๋ ๊ฒ์ด ๋ง๊ณ ๋๊ป์ผ๋ก ๋ซ์ ์๋ ์์ต๋๋ค.
ํ์๊ธฐ ๋ฒํผ ์ถ๊ฐ
AIY Voice Kit๋ฅผ ๋ถํดํ๋ฉด์ ์ํํธ์จ์ด๋ก ๋ฐฑ๋ผ์ดํธ๋ฅผ ์ ์ดํ ์ ์๋ RGB ๋ฒํผ์ด ์๋ค๋ ๊ฒ์ ๊ธฐ์ตํ์ต๋๋ค. "Google AIY Led"๋ฅผ ๊ฒ์ํ๊ณ ๋ฌธ์๋ฅผ ์ฐพ์ต๋๋ค.
์ธ์๋ ๊ฐ์ ์ ํ์ํ๊ธฐ ์ํด ์ด ๋ฒํผ์ ์ฌ์ฉํ๋ ๊ฒ์ ์ด๋จ๊น์? ํด๋์ค๋ 7๊ฐ๋ฟ์ด๊ณ ๋ฒํผ์๋ 8๊ฐ์ง ์์์ด ์์ต๋๋ค. ๋ฑ ๋ง์ต๋๋ค!
GPIO๋ฅผ ํตํด ๋ฒํผ์ Voice Bonnet์ ์ฐ๊ฒฐํ๊ณ ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ก๋ํฉ๋๋ค(AIY ํ๋ก์ ํธ์ ๋ฐฐํฌ ํคํธ์ ์ด๋ฏธ ์ค์น๋์ด ์์).
from aiy.leds import Leds, Color
from aiy.leds import RgbLeds
๊ฐ ๊ฐ์ ์ด RGB Tuple ํํ์ ํด๋น ์์๊ณผ aiy.leds.Leds ํด๋์ค์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ ์ฌ์ ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฅผ ํตํด ์์์ ์ ๋ฐ์ดํธํฉ๋๋ค.
led_dict = {'neutral': (255, 255, 255), 'happy': (0, 255, 0), 'sad': (0, 255, 255), 'angry': (255, 0, 0), 'fearful': (0, 0, 0), 'disgusted': (255, 0, 255), 'surprised': (255, 255, 0)}
leds = Leds()
๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง์ผ๋ก ๊ฐ์ ์ ๋ํ ๊ฐ๊ฐ์ ์๋ก์ด ์์ธก ํ์ ๊ทธ์ ๋ฐ๋ผ (ํค๋ณ๋ก) ๋ฒํผ์ ์์์ ์ ๋ฐ์ดํธํฉ๋๋ค.
leds.update(Leds.rgb_on(led_dict.get(classes[prediction])))
๋ฒํผ, ๋ถํ์๋ผ!
์์ฑ ์์
pyaudio๋ฅผ ์ฌ์ฉํ์ฌ ๋ง์ดํฌ์์ ์คํธ๋ฆผ์ ์บก์ฒํ๊ณ webrtcvad๋ฅผ ์ฌ์ฉํ์ฌ ์์์ ํํฐ๋งํ๊ณ ์์ฑ์ ๊ฐ์งํฉ๋๋ค. ๋ํ ์์ฑ ๋ฐ์ท๋ฅผ ๋น๋๊ธฐ์์ผ๋ก ์ถ๊ฐ ๋ฐ ์ ๊ฑฐํ ๋๊ธฐ์ด์ ์์ฑํฉ๋๋ค.
webrtcvad์๋ ์ ๊ณต๋ ์กฐ๊ฐ์ ํฌ๊ธฐ์ ์ ํ์ด ์์ผ๋ฏ๋ก(10/20/30ms์ ๊ฐ์์ผ ํ๋ฉฐ) ๊ฐ์ ์ธ์ ๋ชจ๋ธ์ ํ๋ จ(๋์ค์ ๋ฐฐ์ฐ๊ฒ ์ง๋ง)์ 48kHz ๋ฐ์ดํฐ์ธํธ์์ ์ํ๋์์ต๋๋ค. 48000ร20ms/1000ร1(๋ชจ๋ ธ)=960๋ฐ์ดํธ ํฌ๊ธฐ์ ์ฒญํฌ๋ฅผ ์บก์ฒํฉ๋๋ค. Webrtcvad๋ ๊ฐ ์ฒญํฌ์ ๋ํด True/False๋ฅผ ๋ฐํํ๋ฉฐ, ์ด๋ ์ฒญํฌ์ ํฌํ๊ฐ ์๋์ง ์ฌ๋ถ์ ํด๋นํฉ๋๋ค.
๋ค์ ๋ ผ๋ฆฌ๋ฅผ ๊ตฌํํด ๋ณด๊ฒ ์ต๋๋ค.
- ํฌํ๊ฐ ์๋ ์ฒญํฌ๋ฅผ ๋ชฉ๋ก์ ์ถ๊ฐํ๊ณ , ํฌํ๊ฐ ์์ผ๋ฉด ๋น ์ฒญํฌ์ ์นด์ดํฐ๋ฅผ ์ฆ๊ฐ์ํต๋๋ค.
- ๋น ์ฒญํฌ์ ์นด์ดํฐ๊ฐ 30(600ms)๋ณด๋ค ํฌ๋ฉด ๋์ ๋ ์ฒญํฌ ๋ชฉ๋ก์ ํฌ๊ธฐ๋ฅผ ํ์ธํ๊ณ , 250๋ณด๋ค ํฌ๋ฉด ํ์ ์ถ๊ฐํ๋ฉฐ, ๊ทธ๋ ์ง ์์ผ๋ฉด ๊ธธ์ด๋ฅผ ๊ณ ๋ คํฉ๋๋ค. ๊ธฐ๋ก์ ์์ ํ์๋ฅผ ์๋ณํ๊ธฐ ์ํด ๋ชจ๋ธ์ ์ ๊ณตํ๊ธฐ์ ์ถฉ๋ถํ์ง ์์ต๋๋ค.
- ๋น ์ฒญํฌ์ ์นด์ดํฐ๊ฐ ์ฌ์ ํ < 30์ด๊ณ ๋์ ์ฒญํฌ ๋ชฉ๋ก์ ํฌ๊ธฐ๊ฐ 300์ ์ด๊ณผํ๋ ๊ฒฝ์ฐ ๋ณด๋ค ์ ํํ ์์ธก์ ์ํด ์กฐ๊ฐ์ ๋๊ธฐ์ด์ ์ถ๊ฐํฉ๋๋ค. (๊ฐ์ ์ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๋ณํ๋ ๊ฒฝํฅ์ด ์๊ธฐ ๋๋ฌธ์)
def to_queue(frames):
d = np.frombuffer(b''.join(frames), dtype=np.int16)
return d
framesQueue = queue.Queue()
def framesThreadBody():
CHUNK = 960
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 48000
p = pyaudio.PyAudio()
vad = webrtcvad.Vad()
vad.set_mode(2)
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
false_counter = 0
audio_frame = []
while process:
data = stream.read(CHUNK)
if not vad.is_speech(data, RATE):
false_counter += 1
if false_counter >= 30:
if len(audio_frame) > 250:
framesQueue.put(to_queue(audio_frame,timestamp_start))
audio_frame = []
false_counter = 0
if vad.is_speech(data, RATE):
false_counter = 0
audio_frame.append(data)
if len(audio_frame) > 300:
framesQueue.put(to_queue(audio_frame,timestamp_start))
audio_frame = []
์ด์ ๊ณต๊ฐ ๋๋ฉ์ธ์์ ์ฌ์ ํ๋ จ๋ ๋ชจ๋ธ์ ์ฐพ๊ณ , github, Google๋ก ์ด๋ํด์ผ ํ ๋์ ๋๋ค. ํ์ง๋ง ์ฌ์ฉ๋๋ ์ํคํ ์ฒ์๋ ์ ํ์ด ์๋ค๋ ์ ์ ๊ธฐ์ตํ์ธ์. ์ ๋ ฅ ๋ฐ์ดํฐ์ ๋ํ ๋ชจ๋ธ์ ํ ์คํธํ๊ณ ์ถ๊ฐ๋ก OpenVINO์ ๋ด๋ถ ํ์์ธ IR(Intermediate Representation)๋ก ๋ณํํด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ด๋ ๋ค์ ์ด๋ ค์ด ๋ถ๋ถ์ ๋๋ค. ์ฐ๋ฆฌ๋ github์์ ์ฝ 5~7๊ฐ์ง์ ์๋ก ๋ค๋ฅธ ์๋ฃจ์ ์ ์๋ํ๊ณ , ๊ฐ์ ์ธ์ ๋ชจ๋ธ์ด ์ฆ์ ์๋ํ๋ค๋ฉด ์์ฑ ์ธ์์ ๊ฒฝ์ฐ ๋ ์ค๋ ๊ธฐ๋ค๋ ค์ผ ํ์ต๋๋ค. ์ฆ, ๋ ๋ณต์กํ ์ํคํ ์ฒ๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ฐ๋ฆฌ๋ ๋ค์ ์ฌํญ์ ์ค์ ์ ๋ก๋๋ค.
- ๋ชฉ์๋ฆฌ๋ก ๋๋ผ๋ ๊ฐ์ -
https://github.com/alexmuhr/Voice_Emotion
์ด๋ ๋ค์ ์๋ฆฌ์ ๋ฐ๋ผ ์๋ํฉ๋๋ค. ์ค๋์ค๋ ํน์ ํฌ๊ธฐ์ ๋ถ๋ถ์ผ๋ก ์๋ ค์ง๋ฉฐ, ๊ฐ ๋ถ๋ถ์ ๋ํด ์ฐ๋ฆฌ๊ฐ ์ ํํฉ๋๋ค.MFCC ๊ทธ๋ฐ ๋ค์ CNN์ ์ ๋ ฅ์ผ๋ก ์ ์ถํฉ๋๋ค. - ์์ฑ ์ธ์ -
https://github.com/linhdvu14/vggvox-speaker-identification
์ฌ๊ธฐ์๋ MFCC ๋์ ์คํํธ๋ก๊ทธ๋จ์ ์ฌ์ฉํ๊ณ FFT ํ ์ ํธ๋ฅผ CNN์ ๊ณต๊ธํ๊ณ ์ถ๋ ฅ์์ โโ์์ฑ์ ๋ฒกํฐ ํํ์ ์ป์ต๋๋ค.
๋ค์์ผ๋ก ์ด๋ก ๋ถํฐ ์์ํ์ฌ ๋ชจ๋ธ ๋ณํ์ ๋ํด ์ด์ผ๊ธฐํ๊ฒ ์ต๋๋ค. OpenVINO์๋ ์ฌ๋ฌ ๋ชจ๋์ด ํฌํจ๋์ด ์์ต๋๋ค.
- ๊ทํ์ ์ ํ์ ์ฌ์ฉ ๋ฐ ํฌํจ๋ ์ ์๋ ๋ชจ๋ธ์ธ Open Model Zoo
- Model Optimzer ๋๋ถ์ ๋ค์ํ ํ๋ ์์ํฌ ํ์(Tensorflow, ONNX ๋ฑ)์ ๋ชจ๋ธ์ ์ค๊ฐ ํํ ํ์์ผ๋ก ๋ณํํ ์ ์์ต๋๋ค.
- ์ถ๋ก ์์ง์ ์ฌ์ฉํ๋ฉด Intel ํ๋ก์ธ์, Myriad ์นฉ ๋ฐ Neural Compute Stick ๊ฐ์๊ธฐ์์ IR ํ์์ผ๋ก ๋ชจ๋ธ์ ์คํํ ์ ์์ต๋๋ค.
- OpenCV์ ๊ฐ์ฅ ํจ์จ์ ์ธ ๋ฒ์ (์ถ๋ก ์์ง ์ง์ ํฌํจ)
IR ํ์์ ๊ฐ ๋ชจ๋ธ์ .xml ๋ฐ .bin์ด๋ผ๋ ๋ ํ์ผ๋ก ์ค๋ช ๋ฉ๋๋ค.
๋ชจ๋ธ์ ๋ค์๊ณผ ๊ฐ์ด Model Optimizer๋ฅผ ํตํด IR ํ์์ผ๋ก ๋ณํ๋ฉ๋๋ค.python /opt/intel/openvino/deployment_tools/model_optimizer/mo_tf.py --input_model speaker.hdf5.pb --data_type=FP16 --input_shape [1,512,1000,1]
--data_type
๋ชจ๋ธ์ด ์๋ํ ๋ฐ์ดํฐ ํ์์ ์ ํํ ์ ์์ต๋๋ค. FP32, FP16, INT8์ด ์ง์๋ฉ๋๋ค. ์ต์ ์ ๋ฐ์ดํฐ ์ ํ์ ์ ํํ๋ฉด ์ฑ๋ฅ์ด ํฌ๊ฒ ํฅ์๋ ์ ์์ต๋๋ค.
--input_shape
์ ๋ ฅ ๋ฐ์ดํฐ์ ์ฐจ์์ ๋ํ๋ ๋๋ค. ๋์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ๊ธฐ๋ฅ์ C++ API์ ์๋ ๊ฒ ๊ฐ์ง๋ง ์ฐ๋ฆฌ๋ ๊ทธ๋ ๊ฒ๊น์ง ์์ธํ ์์๋ณด์ง ์๊ณ ๋จ์ํ ๋ชจ๋ธ ์ค ํ๋์ ๋ํด ์์ ํ์ต๋๋ค.
๋ค์์ผ๋ก ์ด๋ฏธ ๋ณํ๋ IR ํ์์ ๋ชจ๋ธ์ DNN ๋ชจ๋์ ํตํด OpenCV์ ๋ก๋ํ๊ณ ์ ๋ฌํด ๋ณด๊ฒ ์ต๋๋ค.import cv2 as cv emotionsNet = cv.dnn.readNet('emotions_model.bin', 'emotions_model.xml') emotionsNet.setPreferableTarget(cv.dnn.DNN_TARGET_MYRIAD)
์ด ๊ฒฝ์ฐ ๋ง์ง๋ง ์ค์ ์ฌ์ฉํ๋ฉด ๊ณ์ฐ์ Neural Compute Stick์ผ๋ก ๋ฆฌ๋๋ ์ ํ ์ ์์ผ๋ฉฐ ๊ธฐ๋ณธ ๊ณ์ฐ์ ํ๋ก์ธ์์์ ์ํ๋์ง๋ง Raspberry Pi์ ๊ฒฝ์ฐ ์๋ํ์ง ์์ผ๋ฏ๋ก ์คํฑ์ด ํ์ํฉ๋๋ค.
๋ค์์ผ๋ก ๋ ผ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ์ค๋์ค๋ฅผ ํน์ ํฌ๊ธฐ(0.4์ด)์ ์ฐฝ์ผ๋ก ๋๋๊ณ ์ด๋ฌํ ๊ฐ ์ฐฝ์ MFCC๋ก ๋ณํํ ๋ค์ ๊ทธ๋ฆฌ๋์ ๊ณต๊ธํฉ๋๋ค.
emotionsNet.setInput(MFCC_from_window) result = emotionsNet.forward()
๋ค์์ผ๋ก ๋ชจ๋ ์ฐฝ์ ๋ํด ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ํด๋์ค๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๊ฐ๋จํ ํด๊ฒฐ์ฑ ์ด์ง๋ง ํด์ปคํค์ ๊ฒฝ์ฐ ์๊ฐ์ด ์๋ ๊ฒฝ์ฐ์๋ง ๋๋ฌด ๋ํดํ ๊ฒ์ ์๊ฐํด๋ผ ํ์๊ฐ ์์ต๋๋ค. ์์ง ํด์ผ ํ ์ผ์ด ๋ง์ผ๋ ๋ค์์ผ๋ก ๋์ด๊ฐ์ ์์ฑ ์ธ์์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค. ๋ฏธ๋ฆฌ ๋ น์๋ ์์ฑ์ ์คํํธ๋ก๊ทธ๋จ์ ์ ์ฅํ ์ผ์ข ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ง๋๋ ๊ฒ์ด ํ์ํฉ๋๋ค. ์๊ฐ์ด ๊ฑฐ์ ๋จ์ง ์์์ผ๋ฏ๋ก ์ต์ ์ ๋คํด ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ฒ ์ต๋๋ค.
์ฆ, ์์ฑ ๋ฐ์ท๋ฅผ ๋ น์ํ๊ธฐ ์ํ ์คํฌ๋ฆฝํธ๋ฅผ ๋ง๋ญ๋๋ค(์์์ ์ค๋ช ํ ๊ฒ๊ณผ ๋์ผํ ๋ฐฉ์์ผ๋ก ์๋ํ๋ฉฐ ํค๋ณด๋์์ ์ค๋จ๋๋ ๊ฒฝ์ฐ์๋ง ์์ฑ์ ํ์ผ์ ์ ์ฅํฉ๋๋ค).
ํด๋ณด์:
python3 voice_db/record_voice.py test.wav
์ฌ๋ฌ ์ฌ๋์ ๋ชฉ์๋ฆฌ๋ฅผ ๋ น์ํฉ๋๋ค. (์ ํฌ ๊ฒฝ์ฐ์๋ ํ์ XNUMX๋ช )
๋ค์์ผ๋ก, ๋ น์๋ ๊ฐ ์์ฑ์ ๋ํด ๋น ๋ฅธ ํธ๋ฆฌ์ ๋ณํ์ ์ํํ๊ณ ์คํํธ๋ก๊ทธ๋จ์ ์ป์ ๋ค์ ์ด๋ฅผ numpy ๋ฐฐ์ด(.npy)๋ก ์ ์ฅํฉ๋๋ค.for file in glob.glob("voice_db/*.wav"): spec = get_fft_spectrum(file) np.save(file[:-4] + '.npy', spec)
์์ธํ ๋ด์ฉ์ ํ์ผ์
create_base.py
๊ฒฐ๊ณผ์ ์ผ๋ก ๋ฉ์ธ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๋ฉด ๋งจ ์ฒ์๋ถํฐ ์ด๋ฌํ ์คํํธ๋ก๊ทธ๋จ์์ ์๋ฒ ๋ฉ์ ์ป๊ฒ ๋ฉ๋๋ค.for file in glob.glob("voice_db/*.npy"): spec = np.load(file) spec = spec.astype('float32') spec_reshaped = spec.reshape(1, 1, spec.shape[0], spec.shape[1]) srNet.setInput(spec_reshaped) pred = srNet.forward() emb = np.squeeze(pred)
์๋ฆฌ๊ฐ ๋๋ ์ธ๊ทธ๋จผํธ์์ ์๋ฒ ๋ฉ์ ๋ฐ์ ํ, ๊ตฌ์ ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ชจ๋ ์์ฑ๊น์ง์ ์ฝ์ฌ์ธ ๊ฑฐ๋ฆฌ๋ฅผ ์ทจํ์ฌ(๋ ์์์๋ก ๊ฐ๋ฅ์ฑ์ด ๋์) ๊ทธ๊ฒ์ด ๋๊ตฌ์ ์ํ๋์ง ๊ฒฐ์ ํ ์ ์์ต๋๋ค. ๋ฐ๋ชจ์์๋ ์๊ณ๊ฐ์ ์ค์ ํ์ต๋๋ค. 0.3์ผ๋ก):
dist_list = cdist(emb, enroll_embs, metric="cosine") distances = pd.DataFrame(dist_list, columns = df.speaker)
๊ฒฐ๊ตญ ์ถ๋ก ์๋๊ฐ ๋นจ๋ผ์ ๋ชจ๋ธ์ 1~2๊ฐ ๋ ์ถ๊ฐํ ์ ์๊ฒ ๋์๋ค๋ ์ ์ ์ง์ ํ๊ณ ์ถ์ต๋๋ค. (์ํ 7์ด์ ๊ฒฝ์ฐ ์ถ๋ก ์ 2.5๊ฐ ๊ฑธ๋ ธ์ต๋๋ค.) ์ฐ๋ฆฌ๋ ๋ ์ด์ ์๋ก์ด ๋ชจ๋ธ์ ์ถ๊ฐํ ์๊ฐ์ด ์์๊ณ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ํ๋กํ ํ์ ์ ์์ฑํ๋ ๋ฐ ์ง์คํ์ต๋๋ค.
์น ์ ํ๋ฆฌ์ผ์ด์
์ค์ํ ์ ์ ์ง์์ ๋ผ์ฐํฐ๋ฅผ ๊ฐ์ ธ๊ฐ ๋ก์ปฌ ๋คํธ์ํฌ๋ฅผ ์ค์ ํ๋ฉด ๋คํธ์ํฌ๋ฅผ ํตํด ์ฅ์น์ ๋ ธํธ๋ถ์ ์ฐ๊ฒฐํ๋ ๋ฐ ๋์์ด ๋๋ค๋ ๊ฒ์ ๋๋ค.
๋ฐฑ์๋๋ websocket ๊ธฐ์ (http over tcp ํ๋กํ ์ฝ)์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ ํ๋ฐํธ์ Raspberry Pi ๊ฐ์ ์๋ํฌ์๋ ๋ฉ์์ง ์ฑ๋์ ๋๋ค.
์ฒซ ๋ฒ์งธ ๋จ๊ณ๋ ๋ผ์ฆ๋ฒ ๋ฆฌ๋ก๋ถํฐ ๊ฐ๊ณต๋ ์ ๋ณด๋ฅผ ๋ฐ๋ ๊ฒ์ ๋๋ค. ์ฆ, json์ผ๋ก ํฌ์ฅ๋ ์์ธก์๋ ์ฌ์ ์ค๊ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋์ด ํด๋น ๊ธฐ๊ฐ ๋์ ์ฌ์ฉ์์ ๊ฐ์ ์ ๋ฐฐ๊ฒฝ์ ๋ํ ํต๊ณ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ด ํจํท์ ๊ตฌ๋ ์ ์ฌ์ฉํ๊ณ websocket ๋์ ์์ ํจํท์ ์์ ํ๋ ํ๋ฐํธ์๋๋ก ์ ์ก๋ฉ๋๋ค. ์ ์ฒด ๋ฐฑ์๋ ๋ฉ์ปค๋์ฆ์ golang ์ธ์ด๋ก ๊ตฌ์ถ๋์์ผ๋ฉฐ, goroutine์ด ์ ์ฒ๋ฆฌํ๋ ๋น๋๊ธฐ ์์ ์ ๋งค์ฐ ์ ํฉํ๊ธฐ ๋๋ฌธ์ ์ ํ๋์์ต๋๋ค.
์๋ํฌ์ธํธ์ ์ก์ธ์คํ๋ฉด ์ฌ์ฉ์๊ฐ ๋ฑ๋ก๋๊ณ ๊ตฌ์กฐ์ ์ ๋ ฅ๋ ๋ค์ ํด๋น ๋ฉ์์ง๊ฐ ์์ ๋ฉ๋๋ค. ์ฌ์ฉ์์ ๋ฉ์์ง๋ ๋ชจ๋ ๊ณตํต ํ๋ธ์ ์ ๋ ฅ๋๋ฉฐ, ์ฌ๊ธฐ์์ ๋ฉ์์ง๋ ์ด๋ฏธ ์ถ๊ฐ๋ก(๊ตฌ๋ ํ ํ๋ฐํธ๋ก) ์ ์ก๋๊ณ , ์ฌ์ฉ์๊ฐ ์ฐ๊ฒฐ(๋ผ์ฆ๋ฒ ๋ฆฌ ๋๋ ํ๋ฐํธ)์ ๋ซ์ผ๋ฉด ๊ตฌ๋ ์ด ์ทจ์๋๊ณ ์์ ์ ๊ฑฐ๋ฉ๋๋ค. ํ๋ธ.
์ฐ๋ฆฌ๋ ๋ค์์ ์ฐ๊ฒฐ์ ๊ธฐ๋ค๋ฆฌ๊ณ ์์ต๋๋คํ๋ก ํธ์๋๋ ๊ฐ๋ฐ ํ๋ก์ธ์ค์ ์๋๋ฅผ ๋์ด๊ณ ๋จ์ํํ๊ธฐ ์ํด React ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ JavaScript๋ก ์์ฑ๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค. ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ชฉ์ ์ ๋ฐฑ์๋ ์ธก๊ณผ Raspberry Pi์์ ์ง์ ์คํ๋๋ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ์ฌ ์ป์ ๋ฐ์ดํฐ๋ฅผ ์๊ฐํํ๋ ๊ฒ์ ๋๋ค. ํ์ด์ง์๋ React-Router๋ฅผ ์ฌ์ฉํ์ฌ ์น์ ๋ผ์ฐํ ์ด ๊ตฌํ๋์ด ์์ง๋ง ๊ด์ฌ ์๋ ์ฃผ์ ํ์ด์ง๋ WebSocket ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ์๋ฒ์์ ์ค์๊ฐ์ผ๋ก ์ง์์ ์ธ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์์ ํ๋ ๋ฉ์ธ ํ์ด์ง์ ๋๋ค. ๋ผ์ฆ๋ฒ ๋ฆฌํ์ด๋ ์์ฑ์ ๊ฐ์งํ๊ณ ๋ฑ๋ก๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํน์ ์ธ์ ๊ฒ์ธ์ง ์ฌ๋ถ๋ฅผ ํ๋จํ ํ ํ๋ฅ ๋ชฉ๋ก์ ํด๋ผ์ด์ธํธ์ ๋ณด๋ ๋๋ค. ํด๋ผ์ด์ธํธ๋ ์ต์ ๊ด๋ จ ๋ฐ์ดํฐ๋ฅผ ํ์ํ๊ณ , ๋ง์ดํฌ์ ๋๊ณ ๋งํ์ ๊ฐ๋ฅ์ฑ์ด ๊ฐ์ฅ ๋์ ์ฌ๋์ ์๋ฐํ์ ๊ทธ๊ฐ ๋จ์ด๋ฅผ ๋ฐ์ํ ๋์ ๊ฐ์ ์ ํ์ํฉ๋๋ค.
์ ๋ฐ์ดํธ๋ ์์ธก์ด ํฌํจ๋ ํํ์ด์ง๊ฒฐ๋ก
๊ณํ๋๋ก ๋ชจ๋ ๊ฒ์ ์๋ฃํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ๊ณ ์๊ฐ๋ ์์์ต๋๋ค. ๊ทธ๋์ ์ฃผ๋ ํฌ๋ง์ ๋ชจ๋ ๊ฒ์ด ์๋ํ๋ ๋ฐ๋ชจ์ ์์์ต๋๋ค. ํ๋ ์ ํ ์ด์ ์์ ๊ทธ๋ค์ ๋ชจ๋ ๊ฒ์ด ์ด๋ป๊ฒ ์๋ํ๋์ง, ์ด๋ค ๋ชจ๋ธ์ ์ฌ์ฉํ๋์ง, ์ด๋ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋์ง์ ๋ํด ์ด์ผ๊ธฐํ์ต๋๋ค. ๋ค์์ ๋ฐ๋ชจ ๋ถ๋ถ์ด์์ต๋๋ค. ์ ๋ฌธ๊ฐ๋ค์ ๋ฌด์์ ์์๋ก ๋ฐฉ์ ๋์๋ค๋๋ฉฐ ๊ฐ ํ์ ์ ๊ทผํ์ฌ ์๋ ์ค์ธ ํ๋กํ ํ์ ์ ์ดํด๋ณด์์ต๋๋ค. ๊ทธ๋ค์ ์ฐ๋ฆฌ์๊ฒ๋ ์ง๋ฌธ์ ํ๊ณ , ๋ชจ๋๊ฐ ์์ ์ ์ญํ ์ ๋ตํ์ผ๋ฉฐ, ๋ ธํธ๋ถ์ ์น์ ๋จ๊ฒจ๋์๊ณ ๋ชจ๋ ๊ฒ์ด ์ค์ ๋ก ์์๋๋ก ์๋ํ์ต๋๋ค.
์ฐ๋ฆฌ ์๋ฃจ์ ์ ์ด ๋น์ฉ์ 150๋ฌ๋ฌ์์ต๋๋ค.
- ๋ผ์ฆ๋ฒ ๋ฆฌ ํ์ด 3 ~ $35
- Google AIY Voice Bonnet (์ฌ๋ฐ์ธ ๋น์ฉ ๋ถ๋ด ๊ฐ๋ฅ) ~ 15$
- ์ธํ NCS 2 ~ 100$
๊ฐ์ ๋ฐฉ๋ฒ:
- ํด๋ผ์ด์ธํธ์์ ๋ฑ๋ก ์ฌ์ฉ - ๋ฌด์์๋ก ์์ฑ๋ ํ ์คํธ๋ฅผ ์ฝ๋๋ก ์์ฒญํฉ๋๋ค.
- ๋ชจ๋ธ์ ๋ช ๊ฐ ๋ ์ถ๊ฐํ์ธ์. ์์ฑ์ผ๋ก ์ฑ๋ณ๊ณผ ๋์ด๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
- ๋์์ ๋ค๋ฆฌ๋ ์์ฑ ๋ถ๋ฆฌ(๋ถํ )
์ ์ฅ์:
https://github.com/vladimirwest/OpenEMO
ํผ๊ณคํ์ง๋ง ํ๋ณตํด์ ์ฐ๋ฆฌ๋์ผ๋ก ์ฃผ์ต์ธก๊ณผ ์ฐธ๊ฐ์๋ถ๋ค๊ป ๊ฐ์ฌ ์ธ์ฌ๋ฅผ ์ ํ๊ณ ์ถ์ต๋๋ค. ๋ค๋ฅธ ํ์ ํ๋ก์ ํธ ์ค์์ ์ฐ๋ฆฌ๋ ๊ฐ์ธ์ ์ผ๋ก ๋ฌด๋ฃ ์ฃผ์ฐจ ๊ณต๊ฐ์ ๋ชจ๋ํฐ๋งํ๋ ์๋ฃจ์ ์ ์ข์ํ์ต๋๋ค. ์ฐ๋ฆฌ์๊ฒ๋ ์ ํ๊ณผ ๊ฐ๋ฐ์ ๋ชฐ์ ํ๋ ์ ๋ง ๋ฉ์ง ๊ฒฝํ์ด์์ต๋๋ค. AI ์ฃผ์ ๋ฅผ ํฌํจํด ์ง์ญ์์ ์ ์ ๋ ํฅ๋ฏธ๋ก์ด ํ์ฌ๊ฐ ์ด๋ฆฌ๊ธธ ๋ฐ๋๋๋ค.
์ถ์ฒ : habr.com