30 พฤศจิกายน - 1 ธันวาคมที่เมือง Nizhny Novgorod จัดขึ้น
ในบทความนี้ เราจะบอกคุณเกี่ยวกับวิธีที่เราสร้างผลิตภัณฑ์ต้นแบบ ซึ่งในที่สุดเราก็ได้ที่หนึ่ง
มีทีมมากกว่า 10 ทีมเข้าร่วมในแฮ็คกาธอน ดีที่บางอันมาจากภูมิภาคอื่น สถานที่จัดงานแฮ็กกาธอนคือคอมเพล็กซ์ "Kremlinsky on Pochain" ซึ่งมีรูปถ่ายโบราณของ Nizhny Novgorod แขวนอยู่ข้างในพร้อมผู้ติดตาม! (ฉันขอเตือนคุณว่าขณะนี้สำนักงานกลางของ 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( mono)=960 bytes Webrtcvad จะส่งคืนค่า True/False สำหรับแต่ละส่วนเหล่านี้ ซึ่งสอดคล้องกับการมีหรือไม่มีการลงคะแนนในส่วนนั้น
ลองใช้ตรรกะต่อไปนี้:
- เราจะเพิ่มชิ้นส่วนที่มีการลงคะแนนลงในรายการ หากไม่มีคะแนน เราจะเพิ่มตัวนับของชิ้นส่วนว่าง
- ถ้าตัวนับของชิ้นว่างคือ >=30 (600 ms) เราจะดูขนาดของรายการชิ้นที่สะสม ถ้าเป็น >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) เราลองใช้วิธีแก้ปัญหาที่แตกต่างกันประมาณ 5-7 วิธีจาก GitHub และหากแบบจำลองสำหรับการจดจำอารมณ์ใช้งานได้ทันที ด้วยการจดจำเสียง เราต้องรออีกต่อไป - พวกเขาใช้สถาปัตยกรรมที่ซับซ้อนมากขึ้น
เรามุ่งเน้นไปที่สิ่งต่อไปนี้:
- อารมณ์จากเสียง -
https://github.com/alexmuhr/Voice_Emotion
มันทำงานตามหลักการต่อไปนี้: เสียงจะถูกตัดเป็นข้อความในขนาดที่กำหนด สำหรับแต่ละข้อความที่เราเลือกมฟช แล้วส่งเป็นข้อมูลเข้า CNN - การจดจำเสียง -
https://github.com/linhdvu14/vggvox-speaker-identification
ที่นี่ แทนที่จะใช้ MFCC เราทำงานกับสเปกโตรแกรม หลังจาก FFT เราป้อนสัญญาณไปยัง CNN โดยที่เอาต์พุตเราจะได้การแสดงเวกเตอร์ของเสียง
ต่อไปเราจะพูดถึงการแปลงโมเดล โดยเริ่มจากทฤษฎี OpenVINO มีหลายโมดูล:
- Open Model Zoo ซึ่งเป็นโมเดลที่สามารถนำมาใช้และรวมไว้ในผลิตภัณฑ์ของคุณได้
- Model Optimzer ซึ่งคุณสามารถแปลงโมเดลจากรูปแบบเฟรมเวิร์กต่างๆ (Tensorflow, ONNX ฯลฯ) ให้เป็นรูปแบบ Intermediate Representation ซึ่งเราจะทำงานต่อไป
- Inference Engine ช่วยให้คุณสามารถรันโมเดลในรูปแบบ IR บนโปรเซสเซอร์ Intel, ชิป Myriad และตัวเร่งความเร็ว Neural Compute Stick
- OpenCV เวอร์ชันที่มีประสิทธิภาพสูงสุด (พร้อมรองรับ Inference Engine)
แต่ละรุ่นในรูปแบบ IR อธิบายด้วยสองไฟล์: .xml และ .bin
โมเดลจะถูกแปลงเป็นรูปแบบ IR ผ่าน Model Optimizer ดังนี้: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()
ต่อไป เรามาเรียนคลาสทั่วไปสำหรับหน้าต่างทั้งหมดกัน วิธีแก้ปัญหาง่ายๆ แต่สำหรับ Hackathon คุณไม่จำเป็นต้องคิดอะไรที่ลึกซึ้งเกินไป เพียงแค่คุณมีเวลาเท่านั้น เรายังมีงานอีกมากที่ต้องทำ ดังนั้นมาดำเนินการต่อ - เราจะจัดการกับการจดจำเสียง มีความจำเป็นต้องสร้างฐานข้อมูลบางประเภทที่จะจัดเก็บสเปกโตรแกรมของเสียงที่บันทึกไว้ล่วงหน้า เนื่องจากมีเวลาเหลือน้อย เราจะแก้ไขปัญหานี้ให้ดีที่สุด
กล่าวคือ เราสร้างสคริปต์สำหรับการบันทึกเสียงที่ตัดตอนมา (ทำงานในลักษณะเดียวกับที่อธิบายไว้ข้างต้น เฉพาะเมื่อถูกขัดจังหวะจากแป้นพิมพ์เท่านั้นที่จะบันทึกเสียงลงในไฟล์)
มาลองกัน:
python3 voice_db/record_voice.py test.wav
เราบันทึกเสียงของคนหลายคน (ในกรณีของเราคือสมาชิกในทีมสามคน)
ต่อไป สำหรับแต่ละเสียงที่บันทึกไว้ เราทำการแปลงฟูริเยร์อย่างรวดเร็ว รับสเปกโตรแกรมและบันทึกเป็นอาร์เรย์ 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 วินาที) เราไม่มีเวลาเพิ่มโมเดลใหม่ๆ อีกต่อไปและมุ่งเน้นไปที่การเขียนต้นแบบของเว็บแอปพลิเคชัน
เว็บแอปพลิเคชัน
จุดสำคัญ: เราใช้เราเตอร์กับเราจากที่บ้านและตั้งค่าเครือข่ายท้องถิ่นซึ่งช่วยเชื่อมต่ออุปกรณ์และแล็ปท็อปผ่านเครือข่าย
แบ็กเอนด์เป็นช่องทางข้อความจากต้นทางถึงปลายทางระหว่างด้านหน้าและ Raspberry Pi โดยใช้เทคโนโลยี websocket (http ผ่านโปรโตคอล tcp)
ขั้นตอนแรกคือการได้รับข้อมูลที่ประมวลผลจากราสเบอร์รี่ นั่นคือตัวทำนายที่บรรจุอยู่ใน json ซึ่งจะถูกบันทึกไว้ในฐานข้อมูลครึ่งทางของการเดินทาง เพื่อให้สามารถสร้างสถิติเกี่ยวกับภูมิหลังทางอารมณ์ของผู้ใช้ในช่วงเวลานั้นได้ จากนั้นแพ็กเก็ตนี้จะถูกส่งไปยังส่วนหน้า ซึ่งใช้การสมัครสมาชิกและรับแพ็กเก็ตจากจุดสิ้นสุดของ websocket กลไกแบ็กเอนด์ทั้งหมดสร้างขึ้นในภาษา golang มันถูกเลือกเนื่องจากเหมาะสำหรับงานอะซิงโครนัสซึ่ง goroutines จัดการได้ดี
เมื่อเข้าถึงตำแหน่งข้อมูล ผู้ใช้จะถูกลงทะเบียนและเข้าสู่โครงสร้าง จากนั้นจะได้รับข้อความของเขา ทั้งผู้ใช้และข้อความถูกป้อนในฮับทั่วไปซึ่งมีการส่งข้อความต่อไปแล้ว (ไปยังส่วนหน้าที่สมัครรับข้อมูล) และหากผู้ใช้ปิดการเชื่อมต่อ (ราสเบอร์รี่หรือด้านหน้า) การสมัครจะถูกยกเลิกและเขาจะถูกลบออกจาก ฮับ
เรากำลังรอการเชื่อมต่อจากด้านหลังFront-end เป็นเว็บแอปพลิเคชันที่เขียนด้วย JavaScript โดยใช้ไลบรารี React เพื่อเพิ่มความเร็วและลดความซับซ้อนของกระบวนการพัฒนา วัตถุประสงค์ของแอปพลิเคชันนี้คือการแสดงภาพข้อมูลที่ได้รับโดยใช้อัลกอริธึมที่ทำงานที่ด้านหลังและบน Raspberry Pi โดยตรง หน้านี้มีการกำหนดเส้นทางแบบแบ่งส่วนที่ใช้งานโดยใช้ react-router แต่หน้าหลักที่น่าสนใจคือหน้าหลัก ซึ่งรับกระแสข้อมูลอย่างต่อเนื่องแบบเรียลไทม์จากเซิร์ฟเวอร์โดยใช้เทคโนโลยี WebSocket Raspberry Pi ตรวจจับเสียง กำหนดว่าเป็นของบุคคลใดบุคคลหนึ่งจากฐานข้อมูลที่ลงทะเบียน และส่งรายการความน่าจะเป็นไปยังไคลเอนต์ ลูกค้าจะแสดงข้อมูลที่เกี่ยวข้องล่าสุด แสดงรูปประจำตัวของบุคคลที่มีแนวโน้มจะพูดผ่านไมโครโฟนมากที่สุด รวมถึงอารมณ์ความรู้สึกที่เขาออกเสียงคำนั้นๆ
หน้าแรกพร้อมคำทำนายที่อัปเดตข้อสรุป
เป็นไปไม่ได้ที่จะทำทุกอย่างให้เสร็จสิ้นตามแผนที่วางไว้ เนื่องจากเราไม่มีเวลา ดังนั้นความหวังหลักจึงอยู่ที่การสาธิตว่าทุกอย่างจะทำงานได้ ในการนำเสนอพวกเขาคุยกันเกี่ยวกับวิธีการทำงานของทุกอย่าง แบบจำลองที่พวกเขาใช้ ปัญหาที่พวกเขาพบ ต่อไปคือส่วนสาธิต โดยผู้เชี่ยวชาญจะสุ่มเดินไปรอบๆ ห้องและเข้าหาแต่ละทีมเพื่อดูต้นแบบการทำงาน พวกเขาถามคำถามกับเราด้วย ทุกคนตอบคำถามของพวกเขา พวกเขาออกจากเว็บบนแล็ปท็อป และทุกอย่างทำงานได้ตามที่คาดไว้จริงๆ
โปรดทราบว่าต้นทุนรวมของโซลูชันของเราคือ 150 ดอลลาร์:
- ราสเบอร์รี่ Pi 3 ~ $35
- Google AIY Voice Bonnet (คุณสามารถเสียค่าธรรมเนียมผู้พูดได้) ~ 15$
- อินเทล NCS 2 ~ 100$
วิธีปรับปรุง:
- ใช้การลงทะเบียนจากไคลเอนต์ - ขอให้อ่านข้อความที่สร้างขึ้นแบบสุ่ม
- เพิ่มโมเดลอีกสองสามแบบ: คุณสามารถกำหนดเพศและอายุได้ด้วยเสียง
- แยกเสียงที่ทำให้เกิดเสียงพร้อมกัน (การแยกแยะ)
พื้นที่เก็บข้อมูล:
https://github.com/vladimirwest/OpenEMO
เหนื่อยแต่เราก็มีความสุขโดยสรุปผมอยากจะกล่าวขอบคุณผู้จัดงานและผู้เข้าร่วม ในบรรดาโครงการของทีมอื่นๆ เราชอบโซลูชันสำหรับตรวจสอบที่จอดรถฟรีเป็นการส่วนตัว สำหรับเรา มันเป็นประสบการณ์ที่ยอดเยี่ยมมากในการดื่มด่ำกับผลิตภัณฑ์และการพัฒนา ฉันหวังว่าจะมีการจัดกิจกรรมที่น่าสนใจมากขึ้นในภูมิภาค รวมถึงหัวข้อ AI ด้วย
ที่มา: will.com