يمكّنك بهذا السوار من إجراء العمليات الحسابية الأساسية على الفور بمجرد الإشارة إلى ما تريده في الهواء
الأشياء المستخدمة في هذا المشروع
BeagleBoard.org PocketBeagle
مستشعر DFRobot 6 DOF - MPU6050
Adafruit PiOLED - 128x32 أحادية اللون OLED
Jupyter notebook
Amazon Web Services Cloud9
طابعة ثلاثية الأبعاد (عامة)
قصة
قصة
أنا أعمل في معمل للأبحاث وأخلع القفازات لمجرد إجراء بعض العمليات الحسابية الأساسية على هاتفي يبدو دائمًا أنه غير فعال للغاية ومزعج نوعًا ما ، لأنه بمجرد خلع القفازات ، فإنه يعد كابوسًا لإعادة ارتدائها بعد ذلك مباشرة. لذلك ، صممت هذه الآلة الحاسبة للإيماءات التي تتيح لي إجراء كل تلك الحسابات الأساسية دون الحاجة إلى خلع القفازات أو القلق بشأن تلويث هاتفي. لقد أردت أيضًا الغوص في tinyML لفترة من الوقت الآن ، لذلك شعرت أن هذا المشروع مناسب لتنفيذ أول مشروع TFLite على PocketBeagle.
تعليمات البناء
من وجهة نظر الأجهزة ، هذا المشروع بسيط جدًا ، كل ما تحتاجه هو PocketBeagle و MPU6050 IMU وشاشة OLED. نظرًا لأن PocketBeagle قد يكون نظامًا أساسيًا غير مألوف للبعض منكم ، فأنا أرفق الرسم التخطيطي الخاص به هنا. يتوافق الجزء العلوي من الرسم البياني مع منفذ micro-USB.
قم بتوصيل Power Rail بـ P1_14 و / أو P2_23
قم بتوصيل السكة الأرضية بـ P1_16 و / أو P2_21
قم بتوصيل SCL من P1_28 إلى BreadBoard
قم بتوصيل SDA من P1_26 إلى BreadBoard
تستخدم كل من شاشة OLED و MPU6050 I2C ، لذلك قم بتوصيل SCL و SDA كما هو موضح في العبوات وفي الرسم التخطيطي
قم بملاءمة MPU6050 و PocketBeagle والشاشة في الهيكل المطبوع ثلاثي الأبعاد
يجب أن يبدو المنتج النهائي مثل هذا (على الرغم من أن إدارة الكابلات الخاصة بك قد تكون أفضل من إدارة الكابلات الخاصة به)
الشفرة
هناك 4 مستندات رئيسية في المستودع مرتبطة في نهاية المشروع ، بالإضافة إلى ملفين إضافيين مطلوبين لتكوين دبابيس PocketBeagle وتشغيل البرنامج النصي.
اكتساب
بجمع بيانات التسريع والجيروسكوب الخام من MPU6050. لقد قمت بتعيين عتبة تسريع 2Gs لاكتشاف وقت بدء إيماءة ما ، وبعد ذلك أقوم بجمع 350 عينة ثابتة ، تقابل حوالي ثانيتين ، لجعلها متسقة وسهلة الإدخال في نموذج TensorFlow لاحقًا.
التصور والتحويل الموجي
تتكون البيانات الأولية من IMU من 350 عينة بحيث يمكنها التقاط الحركة بأكملها ، ومع ذلك ، لا نحتاج حقًا إلى العديد من العينات لالتقاط الجوهر العام للحركة بشكل كامل. وهنا يأتي دور التحويل المويجي. ما يفعله هو الحفاظ على شكل الإشارة ، مع تغيير امتدادها الزمني ، مما يقلل بشكل أساسي من عدد العينات ، مع فقدان ضئيل للإشارة المفيدة. (cA1، cD1) تكون نتائج التحويل المويجي متجهين: أحدهما بمعامِلات تقريبية ، والآخر بمعامِلات تفصيلية. يضاعف هذا عدد الميزات المتاحة للتصنيف ، عن طريق تقسيم الإشارة إلى إشارتين منفصلتين. يمكننا أيضًا إنشاء المزيد من الميزات باستخدام موجات مختلفة (cA2 ، cD2).
تصور البيانات: يولدipynb أيضًا تصورات للبيانات الكاملة التي تم جمعها لإيماءة سمحت لي بتحليل كيف تبدو الإيماءات المختلفة كإشارة وتكييف حركات يدي.
تدريب نموذج التعلم الآلي
تم العثور على جميع معالجة البيانات والتدريب النموذجي في TrainingModel.ipynb في الريبو. يحتوي إطار البيانات من تحويل wavelet على 24 عمودًا ، بما يتوافق مع 6 أعمدة بيانات أولية مضروبًا في نتيجتين لكل تحويل مويجي مرة تحولين. تم تسوية مجموعة البيانات أولاً ، مع تعيين القيم من 0 إلى 1 ، ثم تم تسوية القيم في متجه واحد لكل إيماءة ، لتسهيل التكامل مع TensorFlow.
normalwavedata = (fullwavedata - fullwavedata.min()) / (fullwavedata.max()-fullwavedata.min())
formatwavedata = pd.DataFrame()
for idx, gesture in enumerate(gestures):
for i in range(1, num_samples+1):
index = idx*num_samples*wavelen + (i-1) * wavelen
wavedataf = normalwavedata.iloc[index:index+wavelen].to_numpy().flatten().tolist()
formatwavedata[idx*num_samples+i-1] = wavedataf
del wavedataf
formatwavedata = formatwavedata.transpose().to_numpy()
بعد ذلك ، تم تقسيم مجموعة البيانات إلى 3 أجزاء: التدريب (70٪) ، الاختبار (15٪) ، التحقق (15٪). لقد استخدمت التقسيم العشوائي الطبقي بدلاً من الانقسام النموذجي test_train. نظرًا لأن مجموعة بيانات التدريب الخاصة بي كانت صغيرة جدًا ، فقد كان هناك الكثير من التباين استنادًا إلى الإيماءات التي كانت أكثر انتشارًا أثناء التدريب ، لذا فإن التبديل الطبقي يضمن نفس التوزيع للإيماءات في جميع الأجزاء.
from sklearn.model_selection import StratifiedShuffleSplit
testsplit = StratifiedShuffleSplit(n_splits = 1, test_size = 0.15)
valsplit = StratifiedShuffleSplit(n_splits = 1, test_size = 0.15/0.85)
for train_index, test_index in testsplit.split(formatwavedata, labels):
X_train, X_test = formatwavedata[train_index], formatwavedata[test_index]
y_train, y_test = labels[train_index], labels[test_index]
for train_index, val_index in valsplit.split(X_train, y_train):
X_train, X_val = X_train[train_index], X_train[val_index]
y_train, y_val = y_train[train_index], y_train[val_index]
بالنسبة للنموذج الفعلي ، استخدمت نموذج Keras المتسلسل من TensorFlow. بعد بعض تحسين المعلمات ، وصلت إلى بنية النموذج الحالية الخاصة بي ، والتي توفر حل وسط جيد بين الدقة والحجم (نظرًا لأننا نعمل على SoC ، نريد أن يكون النموذج صغيرًا نسبيًا للحصول على أداء جيد). تمت إضافة طبقات التسرب لكل طبقة عصبية مخفية من أجل منع فرط احتواء مجموعة بيانات التدريب
opt = tf.keras.optimizers.Adam(learning_rate=0.0001)
model = None
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1024, activation='relu', name='data')) # relu is used for performance
model.add(tf.keras.layers.Dropout(0.25)) #dropout layers help prevent overfitting
model.add(tf.keras.layers.Dense(1024, activation='relu'))
model.add(tf.keras.layers.Dropout(0.25))
model.add(tf.keras.layers.Dense(1024, activation='relu'))
model.add(tf.keras.layers.Dropout(0.25))
model.add(tf.keras.layers.Dense(len(gestures), activation='softmax', name='result'))
model.compile(optimizer=opt,
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])
على الرغم من أن بيانات الإيماءات الأولية بدت صاخبة ومعقدة تمامًا ، إلا أنه بعد معالجة البيانات وتدريب الشبكة العصبية ، لا يزال النموذج يحقق دقة تزيد عن 90٪ في بيانات الاختبار.
لتسخير قوة TinyML حقًا ، تحتاج إلى جعل النموذج متوافقًا مع PocketBeagle. لقد قمت بتحويل النموذج إلى نموذج TensorFlowLite.
converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
الاستدلال أثناء التنقل
يحتوي ملف الشفرة الأخير في المستودع ، Forecast.py على رمز مشابه لما فعلته أعلاه. يكتسب البيانات باستخدام نفس الإجراء مثل الاستحواذ ، ثم يقوم بإجراء تحويلات المويجات والتطبيع ، والفرق الوحيد هو أنني قمت بتحسين الكود لاستخدام NumPy في الغالب لـ PocketBeagle. لتشغيل الاستنتاج الفعلي ، تحتاج أولاً إلى تخصيص الموترات من النموذج
interpreter = tf.lite.Interpreter(model_path='test_model.tflite')
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
بعد ذلك ، يمكنك فقط تمرير البيانات إلى المترجم الفوري وسوف ينتج مصفوفة بثقة كل توقع.
input_data = np.float32(np.resize(gesturewave, (1, 1152)))
interpreter.set_tensor(input_details[0]['index'], input_data)
interpreter.invoke()
output_data = interpreter.get_tensor(output_details[0]['index'])
تعليمات العملية
تم إعداد الجهاز لتشغيل كود الاستدلال عند الإقلاع ، لذلك تحتاج فقط إلى توصيل PocketBeagle ، وبعد الانتظار لبضع دقائق ، يجب أن يكون جاهزًا للتنبؤ بالإيماءات. يكون تدفق الآلة الحاسبة كما يلي:
ارسم الرقم الأول في الهواء
حرك معصمك (يؤدي هذا إلى تقدم الآلة الحاسبة إلى محدد المشغل)
ارسم رقمًا من 1 إلى 5 لتحديد العامل الذي تريده
ارسم الرقم الثاني في الهواء
حرك معصمك مرة أخرى لحساب النتيجة
الخطوات التالية
على الرغم من أن النموذج يحقق أثناء التدريب دقة تزيد عن 90٪ في بيانات الاختبار ، عند استخدام الجهاز فعليًا وتنفيذ الإيماءات ، تكون الدقة أقل بالتأكيد ، ويرجع ذلك على الأرجح إلى الاختلاف المتأصل في كيفية تنفيذ الإيماءات المختلفة ومدى ضجيج الإشارة هو. إن جمع المزيد من بيانات التدريب من عدة أشخاص يقومون بالإيماءات سيسمح للشبكة بتعميم تعلمها بشكل أفضل على الإيماءات. يمكن أيضًا تنفيذ المزيد من عوامل التشغيل للآلة الحاسبة وطريقة أفضل لاختيارها في التكرار المستقبلي لهذا المشروع. حتى ذلك الحين ، أعتقد أن الإضافة الأكثر أهمية ستكون إنشاء غلاف أفضل يسمح بقراءات أكثر اتساقًا وتثبيت شاشة OLED.
نظرًا لأن الجهاز يُلبس كسوار معصم ، فإن إضافة شكل من أشكال جهاز القياس الحيوي (مثل PPG) ، سيسمح باستخدام جهاز مشابه لمراقبة الحالة الصحية أو النشاط البدني من خلال تدريب النموذج على معايير مختلفة.
الأجزاء والمرفقات المخصصة
ليست هناك تعليقات:
إرسال تعليق