ماژول Coral USB Accelerator گوگل
شرکت گوگل سال گذشته در کنفرانس «Google Next» اعلام کرد که در حال ساخت دو سختافزار جدید در «Edge TPU» هستند. هدف گوگل از ساخت وسیلههایی مثل «Raspberry Pi» و سایر ریزکنترلکنندهها این است که از قدرت نرمافزارهای هوش مصنوعی از قبیل دستهبندی تصاویر Image classification و تشخیص اشیاء Object detection استفاده کرده و آنها را به عنوان رابط مدلهایِ از پیشآموزشدیده تنسورفلو لایت در سختافزارهای خودشان به کار گیرند. این اقدام نه تنها امنتر از داشتنِ سرور ابری است که درخواست یادگیری ماشین را رفع میکند، بلکه میتواند تاخیر را نیز قدری کاهش دهد. در ادامه به معرفی ماژول Coral USB Accelerator خواهیم پرداخت
Coral USB Accelerator
ماژول Coral USB Accelerator با ابعاد 65×30×8 میلیمتر عرضه شده و از رقیبش « Intel Movidius NeuralCompute Stick» کوچکتر است. شاید درابتدا فکر کنید این مورد کماهمیتی است اما توجه داشته باشید که Intel Stick پورتهای USB نزدیک را مسدود کرده و استفاده از بخشهای جانبی را دشوار میکرد. ماژول Coral USB Accelerator مبلغ 75 یورو قیمتگذاری شده و از طریق Mouser، Seeed و Gravitylink میتواند سفارش داده شود. به لحاظ جنبه سختافزاری، این ماژول حاوی واحد پردازش تنسور اِج (TPU) است که رابط سریعی را برای مدلهای یادگیری عمیق با مصرف برق کمتر فراهم میکند.
در حال حاضر، USB Accelerator فقط با Debian 6.0+ یا مشتقات آن مثل Ubuntu یا Raspbian عمل میکند. این ماژول زمانی بهترین عملکردش را بر جای میگذارد که به USB 3 متصل باشد؛ البته با USB 2.0 نیز قابل استفاده است. بنابراین، میتواند با ریزکنترلکنندههایی مثل Raspberry 3 که فاقد پورت USB 3 است نیز مورد استفاده قرار گیرد.
ماژول Coral USB Accelerator بدون هیچ دردسر خاصی نصب میشود. دفترچه راهنمای موجود در وبسایت رسمی در Raspberry Pi خیلی مفید ظاهر شد و کاربران توانستند خیلی زود پس از چند دقیقه روش کار را یاد بگیرند. نکته مهمی که باید در ذهن داشت این است که Coral کماکان در مرحله انتشار بِتا است؛ پس انتظار میرود نرمافزار و دستورالعملهای نصب آن در طی زمان تغییر یابد، اما سعی خواهیم کرد مقاله را بهروزرسانی کنیم تا از عملکردِ مناسب همه دستورالعملها مطمئن شویم. اکنون، باید آخرین نسخه Edge TPU و کتابخانه پایتون را با اجرای فرمان زیر دانلود کنید:
cd ~/ wget https://dl.google.com/coral/edgetpu_api/edgetpu_api_latest.tar.gz -O edgetpu_api.tar.gz --trust-server-names tar xzf edgetpu_api.tar.gz cd edgetpu_api bash ./install.sh[irp posts=”21489″]
در حین اجرای فایل install.sh این سوال از کاربر پرسیده خواهد شد: «آیا تمایل دارید فرکانس کاری بیشینه را فعال کنید؟» فعالسازی این گزینه باعث افزایش سرعت استنباط میشود، اما میتواند دمای USB Accelerator را بالا ببرد. باید به این نکته اشاره کنیم که ما در حین استفاده از این مورد با افزایش دما روبرو نشدیم. توصیه میکنیم این گزینه را برای استفاده عادی غیرفعال کنید زیرا عملکرد را به میزان چشمگیری ارتقاء نمیبخشد. به مجرد اینکه فرایند نصب به پایان رسید، USB Accelerator را به Raspberry Pi یا هر دستگاه Debian Device دیگر وصل کنید. اگر آن را در حین نصب وصل کرده باشید، باید دوباره به وصل آن اقدام کنید.
اجرای فایل های دمو
حالا که میدانید Coral USB Accelerator چیست و نرمافزار Edge TPU را نصب کردهاید، به چند مثال زیر توجه کنید. نصب ماژول Edge TPU Python یک API ساده در اختیارمان میگذارد تا دستهبندی تصاویر ، تشخیص اشیاء و یادگیری انتقال Transfer learning در Edge TPU امکانپذیر شود. برای اینکه مثالهای زیر را اجرا کنید، باید یک مدل سازگار Edge TPU و چند فایل ورودی داشته باشید. میتوانید مدلهایِ از قبلآموزشدیده مربوط به دستهبندی تصاویر و تشخیص اشیاء و همچنین چند تصویر نمونه را با کد زیر دانلود کنید:
cd ~/Downloads # Download files for classification demo: curl -O https://dl.google.com/coral/canned_models/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite \ -O \ -O https://dl.google.com/coral/canned_models/inat_bird_labels.txt # Download files for object detection demo: curl -O https://dl.google.com/coral/canned_models/mobilenet_ssd_v2_face_quant_postprocess_edgetpu.tflite \ -O
حالا که مدلها و فایلهای نمونه را در اختیار دارید، میتوانید یکی از مثالها را با بررسی فهرست دِمو و اجرای یکی از فایلها با پارامترهای صحیح اجرا کنید.
# If using the USB Accelerator with Debian/Ubuntu: cd /usr/local/lib/python3.6/dist-packages/edgetpu/demo # If using the USB Accelerator with Raspberry Pi: cd /usr/local/lib/python3.5/dist-packages/edgetpu/demo
اکنون زمینه برای اجرای مدل دستهبندی تصاویر به صورت زیر فراهم شده است:
python3 classify_image.py \ --model ~/Downloads/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite \ --label ~/Downloads/inat_bird_labels.txt \ --image ~/Downloads/parrot.jpg
اسکریپت زیر از دسته و درصد خروجی میگیرد:
—————————
Ara macao (Scarlet Macaw)
Score : 0.761719
پوشه دِمو (آزمایشی) همچنین دربرگیرندۀ فایل تشخیص اشیاء (به نام object_detection.py) است.
# Download files for object detection demo: curl -O https://dl.google.com/coral/canned_models/mobilenet_ssd_v2_face_quant_postprocess_edgetpu.tflite \ -O /usr/local/lib/python3.5/dist-packages/edgetpu/demopython3 object_detection.py \ --model ~/Downloads/mobilenet_ssd_v2_face_quant_postprocess_edgetpu.tflite \ --input ~/Downloads/face.jpg \ --output ~/detection_results.jpg
نگاهی دقیق تر به اسکریپتهای نمونه
همانطور که ملاحظه میکنید، کار کردن با Google Coral USB Accelerator آسان است، اما این تنها نقطه قوتِ USB Accelerator نیست زیرا ماژول Edge TPU Python خواندنِ اسکریپتهای نمونه و نوشتن اسکریپت خودتان آسان میکند. به عنوان مثال، یک نگاه دقیقتر به فایل classify_image.py می اندازیم که به ما در پیش بینی دسته بندی تصویر ورودی کمک می کند.
import argparse import re from edgetpu.classification.engine import ClassificationEngine from PIL import Image # Function to read labels from text files. def ReadLabelFile(file_path): """Reads labels from text file and store it in a dict. Each line in the file contains id and description separted by colon or space. Example: '0:cat' or '0 cat'. Args: file_path: String, path to the label file. Returns: Dict of (int, string) which maps label id to description. """ with open(file_path, 'r', encoding='utf-8') as f: lines = f.readlines() ret = {} for line in lines: pair = re.split(r'[:\s]+', line.strip(), maxsplit=1) ret[int(pair[0])] = pair[1].strip() return ret def main(): parser = argparse.ArgumentParser() parser.add_argument( '--model', help='File path of Tflite model.', required=True) parser.add_argument( '--label', help='File path of label file.', required=True) parser.add_argument( '--image', help='File path of the image to be recognized.', required=True) args = parser.parse_args() # Prepare labels. labels = ReadLabelFile(args.label) # Initialize engine. engine = ClassificationEngine(args.model) # Run inference. img = Image.open(args.image) for result in engine.ClassifyWithImage(img, top_k=3): print('---------------------------') print(labels[result[0]]) print('Score : ', result[1]) if __name__ == '__main__': main()
اولین بخش مهم اسکریپت، وارد کردنِ کتابخانه EdgeTPU و به طور خاص ClassificationEngine است که در انجام دستهبندی در Edge TPU نقش اصلی را بر عهده دارد. ReadLabelFile فایلهای متنی ورودی را باز میکند (این فایلها حاوی برچسب طبقه بندها هستند). تابع مذکور یک متغیر دیکشنری برای تکتک برچسبها ایجاد میکند. در خطّ 30 تا 37 تابع main، از کتابخانه argparse library برای ایجاد ArgumentParser استفاده میکنیم. حالا میتوانیم برچسبها را با استفاده از ReadLabelFile در خط 56 و مدل را با ایجاد شیء جدید ClassificationEngine در خط 58 بدست آوریم. در نهایت،کد نوشته شده, تصویری را با استفاده از Pillow باز کرده و آن را با استفاده از تابع ClassifyWithImage که مربوط به شیء ClassificationEngine می باشد دستهبندی میکند. شیوه کارکرد اسکریپت تشخیص اشیاء تقریباً با اسکریپت دستهبندی یکسان است؛ تنها تغییر این است که از DetectionEngine به جای ClassificationEngine استفاده میشود. پس به جای ایجاد مدل خودمان با ایجاد ClassificationEngine جدید و استفاده از روش ClassifyWithImage در اشیاء، یک DetectionEngine ساخته و از تابع DetectWithImage برای انجام پیشبینی استفاده میکنیم.
# Initialize engine. engine = DetectionEngine(args.model) labels = ReadLabelFile(args.label) if args.label else None # Open image. img = Image.open(args.input) draw = ImageDraw.Draw(img) # Run inference. ans = engine.DetectWithImage(img, threshold=0.05, keep_aspect_ratio=True, relative_coord=False, top_k=10) # Display result. if ans: for obj in ans: print ('-----------------------------------------') if labels: print(labels[obj.label_id]) print ('score = ', obj.score) box = obj.bounding_box.flatten().tolist() print ('box = ', box) # Draw a rectangle. draw.rectangle(box, outline='red') img.save(output_name) if platform.machine() == 'x86_64': # For gLinux, simply show the image. img.show() elif platform.machine() == 'armv7l': # For Raspberry Pi, you need to install 'feh' to display image. subprocess.Popen(['feh', output_name]) else: print ('Please check ', output_name) else: print ('No object detected!')[irp posts=”19246″]
دستهبندی و تشخیص تصاویر و حمایت دوربین بیرونی
ماژول Coral امکان دسترسی به اسکریپت دستهبندی تصاویر classify_capture.py را نیز فراهم میکند. بر اساس این اسکریپت، از کتابخانه PiCamera library برای دریافت تصاویر از وبکم (Webcam) استفاده میشود. تنها مشکل این اسکریپت آن است که فقط با PiCamera قابل استفاده است. برای اینکه زمینه را برای پشتیبانی از سایر وبکمها فراهم کنیم، باید کد PiCamera را با imutils VideoStream عوض کنیم تا هم با PiCamera و هم دوربین عادی کار کنیم.
import cv2 import numpy import argparse import time import re from edgetpu.classification.engine import ClassificationEngine from PIL import Image, ImageDraw, ImageFont from imutils.video import FPS from imutils.video import VideoStream def ReadLabelFile(file_path): with open(file_path, 'r', encoding='utf-8') as f: lines = f.readlines() ret = {} for line in lines: pair = re.split(r'[:\s]+', line.strip(), maxsplit=1) ret[int(pair[0])] = pair[1].strip() return ret def draw_image(image, result): draw = ImageDraw.Draw(image) draw.text((0, 0), result, font=ImageFont.truetype("/usr/share/fonts/truetype/piboto/Piboto-Regular.ttf", 20)) displayImage = numpy.asarray(image) cv2.imshow('Live Inference', displayImage) def main(): parser = argparse.ArgumentParser() parser.add_argument( '--model', help='File path of Tflite model.', required=True) parser.add_argument( '--label', help='File path of label file.', required=True) parser.add_argument( '--picamera', action='store_true', help="Use PiCamera for image capture", default=False) args = parser.parse_args() # Prepare labels. labels = ReadLabelFile(args.label) if args.label else None # Initialize engine. engine = ClassificationEngine(args.model) # Initialize video stream vs = VideoStream(usePiCamera=args.picamera, resolution=(640, 480)).start() time.sleep(1) fps = FPS().start() while True: try: # Read frame from video screenshot = vs.read() image = Image.fromarray(screenshot) # Perform inference results = engine.ClassifyWithImage(image, top_k=1) result = labels[results[0][0]] if results!=[] else 'None' draw_image(image, result) if cv2.waitKey(5) & 0xFF == ord('q'): fps.stop() break fps.update() except KeyboardInterrupt: fps.stop() break print("Elapsed time: " + str(fps.elapsed())) print("Approx FPS: :" + str(fps.fps())) cv2.destroyAllWindows() vs.stop() time.sleep(2) if __name__ == '__main__': main()
این اسکریپت علاوه بر دستهبندی تصاویر به صورت آنی, میتواند پنجره ای ایجاد میکند که فریم فعلی و برچسب آن را به صورت جریانی Stream نشان میدهد. این کار با استفاده از ماژول Pillows ImageDraw انجام میشود و امکان افزودن متن در تصویر را فراهم میکند.
این کار برای تشخیص اشیا هم انجام شود. تفاوت اصلی این است که از DetectionEngine به جای ClassificationEngine استفاده شده و تغییرات در تابع draw_image نیز اِعمال میشود. این کارها ضروری است زیرا باید کادرهای محصورکننده Bounding boxes را نیز ترسیم کنیم.
import cv2 import numpy import argparse import time import re from edgetpu.detection.engine import DetectionEngine from PIL import Image, ImageDraw, ImageFont from imutils.video import FPS from imutils.video import VideoStream def ReadLabelFile(file_path): with open(file_path, 'r', encoding='utf-8') as f: lines = f.readlines() ret = {} for line in lines: pair = re.split(r'[:\s]+', line.strip(), maxsplit=1) ret[int(pair[0])] = pair[1].strip() return ret def draw_image(image, results, labels): result_size = len(results) for idx, obj in enumerate(results): # Prepare image for drawing draw = ImageDraw.Draw(image) # Prepare boundary box box = obj.bounding_box.flatten().tolist() # Draw rectangle to desired thickness for x in range( 0, 4 ): draw.rectangle(box, outline=(255, 255, 0)) # Annotate image with label and confidence score display_str = labels[obj.label_id] + ": " + str(round(obj.score*100, 2)) + "%" draw.text((box[0], box[1]), display_str, font=ImageFont.truetype("/usr/share/fonts/truetype/piboto/Piboto-Regular.ttf", 20)) displayImage = numpy.asarray(image) cv2.imshow('Coral Live Object Detection', displayImage) def main(): parser = argparse.ArgumentParser() parser.add_argument( '--model', help='File path of Tflite model.', required=True) parser.add_argument( '--label', help='File path of label file.', required=True) parser.add_argument( '--maxobjects', type=int, default=3, help='Maximum objects') parser.add_argument( '--threshold', type=float, default=0.3, help="Minimum threshold") parser.add_argument( '--picamera', action='store_true', help="Use PiCamera for image capture", default=False) args = parser.parse_args() # Prepare labels. labels = ReadLabelFile(args.label) if args.label else None # Initialize engine. engine = DetectionEngine(args.model) # Initialize video stream vs = VideoStream(usePiCamera=args.picamera, resolution=(640, 480)).start() time.sleep(1) fps = FPS().start() while True: try: # Read frame from video screenshot = vs.read() image = Image.fromarray(screenshot) # Perform inference results = engine.DetectWithImage(image, threshold=args.threshold, keep_aspect_ratio=True, relative_coord=False, top_k=args.maxobjects) # draw image draw_image(image, results, labels) # closing condition if cv2.waitKey(5) & 0xFF == ord('q'): fps.stop() break fps.update() except KeyboardInterrupt: fps.stop() break print("Elapsed time: " + str(fps.elapsed())) print("Approx FPS: :" + str(fps.fps())) cv2.destroyAllWindows() vs.stop() time.sleep(2) if __name__ == '__main__': main()
ساخت مدل دلخواه
اگرچه شرکت گوگل چندین مدلِ از پیشکامپایلشده عرضه میکند و این مدلها با USB Accelerator نیز استفاده میشوند، اما شاید کاربری بخواهد مدل شخصی خودش را اجرا کند. به همین منظور، چند گزینه پیش رویتان قرار دارد. به جای اینکه از ابتدا به ساخت مدلتان بپردازید، میتوانید یکی از مدلهای موجود را که با Edge TPU سازگاری دارد، انتخاب کنید. این کار با روشی موسوم به «یادگیری انتقال» انجام میپذیرد. میتوانید برای کسب جزئیات بیشتر به دورههای آموزشی رسمی مدل تشخیص اشیاء و دستهبندی تصاویر مراجعه کنید. اگر میخواهید مدلی را از ابتدا آموزش دهید، یقیناً میتوانید این کار را انجام دهید و هیچ مشکلی نیست؛ اما باید چند محدودیت را در نظر بگیرید که بر استفاده از مدل در ماژول USB Accelerator سایه افکنده است.
نتیجهگیری
ماژول Google Coral USB Accelerator یک سختافزار عالی است که این فرصت را به دستگاههای edge مثل Raspberry Pi یا سایر میکروکنترلکنندهها میدهد تا از نیروی نرمافزارهای هوش مصنوعی استفاده کنند. این ماژول حاوی مستندات خوبی متشکل از نرمافزارهای آزمایشی، نصب، ساخت مدل شخصی و مستندات جامع Python API است.