14.2.2.2. בניית תמונת ROMFS¶
תמונת ROMFS היא מערכת קבצים לקריאה-בלבד השוכנת בפלאש שסביבת הריצה מתקינה אוטומטית בנתיב /rom. היא פותרת את בעיית הנכסים שהעמוד הקודם הסתיים עליה: קובצי מודלים של למידת מכונה, טבלאות תוויות, קונפיגורציית JSON, תבניות תמונה – כל דבר שהיישום פותח וקורא אך לעולם אינו כותב – נכנסים אל תוך ה-build בלי לשלם את המחיר של הטמעה כליטרלים של Python.
שלושה דברים הופכים את ROMFS לכלי הנכון עבור נכסים שנשלחים:
מערכת הקבצים היא חלק מתמונת הקושחה. משתמשי הקצה אינם יכולים למחוק קובץ מתוך
/rom, לערוך אחד או להחליף אחד בשלהם.קבצים ב-
/romנגישים במקומם. צרכנים כמו מודולmlהטוען קובץ מודל מקבלים מבט ישיר אל תוך הפלאש ללא עותק ב-RAM – מודל בגודל מספר מגה-בייטים על/rom”נטען“ בעצם בחינם, בעוד אותו קובץ על/sdcardנקרא אל תוך ה-RAM בזמן הטעינה ונשאר שם לכל אורך חיי ההפניה.open()רגיל +readמעתיק לפי דרישה: כל קריאתread(n)מעתיקהnבייטים מהפלאש ל-RAM ברגע הקריאה, כאשרread()חשוף מבקש את כל הקובץ./romו-/rom/libמתווספים ל-sys.pathבאתחול. חבילות Python המוצבות בתוך התמונה ניתנות לייבוא לפי שם; שום דבר מיוחד באתר הקריאה.
14.2.2.2.1. בניית תמונה¶
תמונות ROMFS נוצרות, נערכות ונצרבות דרך ה-IDE. השתמשו בו כמקור האמת לתוכן של כל מחיצת ROMFS שנשלחת.
הסיבה שזה חשוב: קובצי מודלים מגיעים עם דרישות יישור (alignment) שהטוען אוכף בזמן ריצה. קובצי .tflite חייבים להיות מרופדים לגבולות של 16 בייטים, וה-NPU של ה-N6 דורש יישור של 32 בייטים עבור מודלים מהודרים. ה-IDE מיישם ריפוד זה אוטומטית כשהוא כותב את התמונה. כלים העוברים על עץ המקור בלי ליישם את הריפוד – mpremote romfs בפרט – מייצרים תמונה שמותקנת בנקיון אך מודליה נכשלים בקריאת ההסקה הראשונה.
עורך ה-ROMFS של ה-IDE הוא מבט אינטראקטיבי על תוכן התמונה. ניתן להוסיף, לשנות שם ולמחוק קבצים ותיקיות בזיכרון; שמירה כותבת את התוצאה החוצה כקובץ .img מוכן לצריבה. מבנה טיפוסי ליישום שמשלוח מודל לצד כמה נכסים וחבילת Python נראה כך:
model.tflite
labels.txt
config.json
templates/
calibration.jpg
lib/
mylib/
__init__.py
helpers.py
טיפ
הן ה-IDE והן mpremote מבצעים הידור-צולב (cross-compile) של קובצי .py ל-בייטקוד .mpy בדרכם אל תוך תמונת ROMFS, כך שהמצלמה מייבאת אותם בלי לשלם את עלות הניתוח (parse) בזמן הטעינה. קובצי המקור בעורך נשארים .py; התמונה מכילה .mpy.
ברגע שהתמונה נצרבת, העץ נראה מ-MicroPython בנתיב /rom/
>>> import os
>>> os.listdir('/rom')
['model.tflite', 'labels.txt', 'config.json', 'templates', 'lib']
>>> import mylib
>>> mylib.helpers
<module 'mylib.helpers' from '/rom/lib/mylib/helpers.mpy'>
14.2.2.2.2. רוב היישום שוכן ב-ROMFS¶
ROMFS הוא הבית הנכון כמעט לכל מה שיישום משלוח: הספריות שהוא מייבא, קובצי המודלים שהוא טוען, הקונפיגורציה שהוא קורא, כל נכס שהפלט שלו הגיע מכלי build שפולט עץ קבצים (ממירי מודלים, צינורות עיבוד תמונה, אורזי נכסים), ו– חשוב מכך – קוד היישום עצמו.
צד המודולים-המוקפאים אמור להישאר קטן: boot.py להגדרה שלפני ה-REPL, main.py כנקודת כניסה דקה, ורק הספריות שהמצלמה באמת אינה יכולה לאתחל בלעדיהן. כל השאר נכנס ל-ROMFS, שבו האיטרציה עליו היא קובץ .img חדש שנשמר מתוך ה-IDE ונצרב מחדש – ללא צורך בבנייה מחדש של הקושחה, ללא toolchain זמין כדי לעשות זאת.
התבנית שנובעת מכך היא main.py שאינו עושה דבר מלבד להאציל אל היישום השוכן ב-ROMFS:
# main.py (frozen)
import app
app.run()
# /rom/app/__init__.py (in ROMFS)
def run():
...
שינוי ל-app הוא עריכת ROMFS וצריבה מחדש. בניית הקושחה נשארת במקומה לכל אורך חיי המוצר אלא אם משהו בצד המוקפא באמת חייב להשתנות.