מבוא ל- Tensorflow עבור Java

1. סקירה כללית

TensorFlow הוא ספריית קוד פתוח לתכנות זרימת נתונים. זה פותח במקור על ידי גוגל והוא זמין למגוון רחב של פלטפורמות. למרות ש- TensorFlow יכול לעבוד על ליבה אחת, זה יכול להיות כמו ליהנות בקלות ממספר מעבדים, GPU או TPU זמינים.

במדריך זה נעבור על יסודות TensorFlow וכיצד להשתמש בו ב- Java. שים לב שממשק ה- API של Java של TensorFlow הוא ממשק API ניסיוני, ולכן אינו מכוסה בשום אחריות ליציבות. אנו נעסוק בהמשך ההדרכה במקרי שימוש אפשריים לשימוש ב- TensorFlow Java API.

2. יסודות

חישוב TensorFlow בעצם סובב סביב שני מושגים בסיסיים: גרף והפעלה. בואו נעבור אותם במהירות כדי להשיג את הרקע הדרוש כדי לעבור על שאר ההדרכה.

2.1. גרף TensorFlow

ראשית, בואו נבין את אבני הבניין הבסיסיות של תוכניות TensorFlow. חישובים מיוצגים כגרפים ב- TensorFlow. גרף הוא בדרך כלל גרף א-מחזורי מכוון של פעולות ונתונים, למשל:

התמונה לעיל מייצגת את הגרף החישובי למשוואה הבאה:

f (x, y) = z = a * x + b * y

גרף חישוב TensorFlow מורכב משני אלמנטים:

  1. Tensor: אלה יחידת הליבה של הנתונים ב- TensorFlow. הם מיוצגים כקצוות בגרף חישובי, המתארים את זרימת הנתונים דרך הגרף. לטנסור יכולה להיות צורה עם מספר ממדים כלשהו. מספר הממדים בטנזור מכונה בדרך כלל דרגתו. אז סקלר הוא דרגה 0 טנסור, וקטור הוא דרגה 1 טנסור, מטריצה ​​היא דרגה 2 טנסור, וכן הלאה וכן הלאה.
  2. פעולה: אלה הצמתים בגרף חישובי. הם מתייחסים למגוון רחב של חישובים שיכולים לקרות על הטנורים המוזנים לפעולה. לעיתים קרובות הם מביאים גם לטנורים הנובעים מהפעולה בגרף חישובי.

2.2. מושב TensorFlow

כעת, גרף TensorFlow הוא סכמטי גרידא של החישוב שלמעשה אינו מחזיק בערכים. כגון יש להריץ גרף בתוך מה שמכונה הפעלה של TensorFlow לצורך הערכת הטנסורים בגרף. ההפעלה יכולה לקחת חבורה של טנזורים להעריך מתוך גרף כפרמטרים של קלט. ואז הוא רץ לאחור בגרף ומריץ את כל הצמתים הדרושים להערכת אותם טנזורים.

עם הידע הזה, אנו מוכנים כעת לקחת זאת ולהחיל אותו על ה- API של Java!

3. הגדרת Maven

נקים פרויקט Maven מהיר ליצירה והפעלה של גרף TensorFlow בג'אווה. אנחנו פשוט צריכים את זורם טנסור תלות:

 org.tensorflow tensorflow 1.12.0 

4. יצירת הגרף

בואו ננסה לבנות את הגרף עליו דנו בפרק הקודם באמצעות ה- API של Java של TensorFlow. ליתר דיוק, לצורך הדרכה זו נשתמש ב- TensorFlow Java API כדי לפתור את הפונקציה המיוצגת על ידי המשוואה הבאה:

z = 3 * x + 2 * y

השלב הראשון הוא הכרזה וניתוח של גרף:

גרף גרף = גרף חדש ()

כעת עלינו להגדיר את כל הפעולות הנדרשות. זכור את זה פעולות ב- TensorFlow צורכות ומייצרות אפס טנסור או יותר. יתר על כן, כל צומת בגרף הוא פעולה הכוללת קבועים ושומרי מיקום. זה אולי נראה אינטואיטיבי, אבל נשא את זה לרגע!

הכיתה גרָף יש פונקציה גנרית הנקראת opBuilder () לבנות כל סוג של פעולה על TensorFlow.

4.1. הגדרת קבועים

ראשית, נגדיר פעולות קבועות בגרף שלנו לעיל. שים לב כי א פעולה קבועה תזדקק לטנסור לערכו:

פעולה a = graph.opBuilder ("Const", "a") .setAttr ("dtype", DataType.fromClass (Double.class)) .setAttr ("value", Tensor.create (3.0, Double.class)). לִבנוֹת(); פעולה b = graph.opBuilder ("Const", "b") .setAttr ("dtype", DataType.fromClass (Double.class)) .setAttr ("value", Tensor.create (2.0, Double.class)). לִבנוֹת();

הנה, הגדרנו מבצע מסוג קבוע, האכלה ב מוֹתֵחַ עם לְהַכפִּיל ערכים 2.0 ו- 3.0. זה אולי נראה מעט מכריע מלכתחילה, אבל ככה זה ב API של Java לעת עתה. מבנים אלה תמציתיים הרבה יותר בשפות כמו פייתון.

4.2. הגדרת מצייני מקום

בעוד שאנחנו צריכים לספק ערכים לקבועים שלנו, מצייני מיקום אינם זקוקים לערך בזמן ההגדרה. יש לספק את הערכים למקומות המיקום כאשר הגרף מופעל בתוך מושב. נעבור את החלק הזה בהמשך ההדרכה.

לעת עתה, בוא נראה כיצד אנו יכולים להגדיר את מצייני המיקום שלנו:

פעולה x = graph.opBuilder ("מציין מיקום", "x") .setAttr ("dtype", DataType.fromClass (Double.class)) .build (); פעולה y = graph.opBuilder ("מציין מיקום", "y") .setAttr ("dtype", DataType.fromClass (Double.class)) .build ();

שים לב שלא היינו צריכים לספק שום ערך עבור מצייני המקום שלנו. ערכים אלה יוזנו כ- טנזורים כאשר רצים.

4.3. הגדרת פונקציות

לבסוף, עלינו להגדיר את הפעולות המתמטיות של המשוואה שלנו, כלומר כפל ותוספת כדי לקבל את התוצאה.

אלה שוב אינם אלא מבצעב- TensorFlow ו- Graph.opBuilder () הוא שימושי שוב:

מבצע ax = graph.opBuilder ("Mul", "ax") .addInput (a.output (0)) .addInput (x.output (0)) .build (); פעולה על ידי = graph.opBuilder ("Mul", "על ידי") .addInput (b.output (0)) .addInput (y.output (0)) .build (); פעולה z = graph.opBuilder ("הוסף", "z") .addInput (ax.output (0)) .addInput (by.output (0)) .build ();

הנה, הגדרנו שם מבצע, שניים להכפלת התשומות שלנו והאחרונה לסיכום תוצאות הביניים. שים לב שפעולות כאן זוכות לטנדרים שאינם אלא תפוקת הפעולות הקודמות שלנו.

שימו לב שאנחנו מקבלים את התפוקה מוֹתֵחַ מ ה מבצע באמצעות אינדקס '0'. כפי שדנו קודם, an מבצע יכול לגרום לאחת או יותר מוֹתֵחַ ומכאן שבעת שאיבת ידית עבורה, עלינו להזכיר את האינדקס. מכיוון שאנו יודעים שהפעילות שלנו מחזירה רק אחת מוֹתֵחַ, '0' עובד בסדר גמור!

5. הדמיה של הגרף

קשה לשמור על כרטיסייה בגרף מכיוון שהוא גדל בגודלו. זה מצליח חשוב לדמיין את זה בצורה כלשהי. אנחנו תמיד יכולים ליצור ציור יד כמו הגרף הקטן שיצרנו בעבר, אך הוא אינו מעשי עבור גרפים גדולים יותר. TensorFlow מספק כלי שנקרא TensorBoard כדי להקל על כך.

למרבה הצער, ל- Java API אין את היכולת ליצור קובץ אירועים הנצרך על ידי TensorBoard. אך באמצעות ממשקי API ב- Python אנו יכולים ליצור קובץ אירוע כמו:

כותב = tf.summary.FileWriter ('.') ...... writer.add_graph (tf.get_default_graph ()) writer.flush ()

בבקשה אל תטרח אם זה לא הגיוני בהקשר של ג'אווה, זה נוסף כאן רק למען השלמות ולא הכרחי להמשך שאר ההדרכה.

כעת אנו יכולים לטעון ולראות את קובץ האירוע ב- TensorBoard כמו:

טנורבורד - logdir.

TensorBoard מגיע כחלק מהתקנת TensorFlow.

שימו לב לדמיון בין זה לגרף המצויר ידנית קודם!

6. עבודה עם מושב

כעת יצרנו גרף חישובי למשוואה הפשוטה שלנו ב- TensorFlow Java API. אבל איך ננהל את זה? לפני שנתייחס לכך, בוא נראה מה המצב גרָף בדיוק יצרנו בשלב זה. אם ננסה להדפיס את פלט הגמר שלנו מבצע "Z":

System.out.println (z.output (0));

זה יביא למשהו כמו:

זה לא מה שציפינו! אך אם ניזכר במה שדנו קודם, זה ממש הגיוני. ה גרָף הגדרנו זה עתה לא הופעל, כך שהטנסורים בו למעשה אינם מחזיקים בשווי ממשי. התפוקה שלמעלה רק אומרת שזה יהיה מוֹתֵחַ מהסוג לְהַכפִּיל.

בואו נגדיר כעת א מוֹשָׁב לנהל את שלנו גרָף:

מושב מושב = מושב חדש (גרף)

לבסוף, כעת אנו מוכנים להריץ את הגרף שלנו ולקבל את התפוקה שציפינו לה:

טנסור טנסור = sess.runner (). אחזר ("z"). הזנה ("x", Tensor.create (3.0, Double.class)). Feed ("y", Tensor.create (6.0, Double.class) ) .run (). get (0) .expect (Double.class); System.out.println (tensor.doubleValue ());

אז מה אנחנו עושים כאן? זה צריך להיות אינטואיטיבי למדי:

  • לקבל רָץ מ ה מוֹשָׁב
  • תגדיר את מבצע להביא בשמו "z"
  • הזן טנזורים עבור מצייני המיקום שלנו "x" ו- "y"
  • הפעל את גרָף בתוך ה מוֹשָׁב

ועכשיו אנו רואים את התפוקה הסקלרית:

21.0

זה מה שציפינו, לא!

7. תיק השימוש ב- API של Java

בשלב זה, TensorFlow עשוי להישמע כמו יתר על המידה לביצוע פעולות בסיסיות. אבל כמובן ש, TensorFlow נועד להריץ גרפים הרבה יותר גדולים מאשר זה.

בנוסף, הטנדרים שהוא עוסק בהם בדגמים בעולם האמיתי הם הרבה יותר גדולים בגודל ובדרגה. אלה המודלים הלמידה בפועל של מכונה שבהם TensorFlow מוצא את השימוש האמיתי שלה.

לא קשה לראות שעבודה עם ממשק ה- API הליבה ב- TensorFlow יכולה להיות מסורבלת מאוד ככל שגודל הגרף גדל. עד לכאן, TensorFlow מספקת ממשקי API ברמה גבוהה כמו Keras לעבודה עם מודלים מורכבים. למרבה הצער, עדיין אין כמעט תמיכה רשמית בקראס בג'אווה.

עם זאת, אנחנו יכולים השתמש בפייתון כדי להגדיר ולהכשיר מודלים מורכבים ישירות ב- TensorFlow או באמצעות ממשקי API ברמה גבוהה כמו Keras. לאחר מכן, אנו יכולים לייצא מודל מאומן ולהשתמש בזה ב- Java באמצעות ה- API של Java של TensorFlow.

עכשיו, למה שנרצה לעשות משהו כזה? זה שימושי במיוחד במצבים שבהם אנו רוצים להשתמש בתכונות המאפשרות לימוד מכונה אצל לקוחות קיימים הפועלים ב- Java. למשל, המלצה על כיתוב לתמונות משתמשים במכשיר אנדרואיד. עם זאת, ישנם מספר מקרים בהם אנו מעוניינים בתפוקה של מודל למידת מכונה, אך לא בהכרח רוצים ליצור ולהכשיר את המודל בג'אווה.

זה המקום בו TensorFlow Java API מוצא את עיקר השימוש בו. נעבור כיצד ניתן להשיג זאת בחלק הבא.

8. שימוש בדגמים שמורים

כעת נבין כיצד אנו יכולים לשמור מודל ב- TensorFlow למערכת הקבצים ולהעמיס אותו בחזרה, אולי בשפה ופלטפורמה אחרים לחלוטין. TensorFlow מספק ממשקי API ליצירת קבצי מודל במבנה ניטרלי שפה ופלטפורמה הנקרא Protocol Buffer.

8.1. שמירת דגמים במערכת הקבצים

נתחיל בהגדרת אותו גרף שיצרנו קודם ב- Python ונשמור אותו במערכת הקבצים.

בואו נראה שאנחנו יכולים לעשות זאת בפייתון:

יבוא זרימת טנסור כגרף tf = tf.Graph () בונה = tf.saved_model.builder.SavedModelBuilder ('./ דגם') עם graph.as_default (): a = tf.constant (2, שם = "a") b = tf.constant (3, name = "b") x = tf.placeholder (tf.int32, name = "x") y = tf.placeholder (tf.int32, name = "y") z = tf.math. הוסף (a * x, b * y, name = "z") sess = tf.Session () sess.run (z, feed_dict = {x: 2, y: 3}) builder.add_meta_graph_and_variables (sess, [tf. saved_model.tag_constants.SERVING]) builder.save ()

כמוקד הדרכה זו ב- Java, אל נקדיש תשומת לב רבה לפרטי הקוד הזה ב- Python, למעט העובדה שהוא מייצר קובץ בשם "saved_model.pb". שים לב במעבר הקצר בהגדרת גרף דומה בהשוואה ל- Java!

8.2. טעינת מודלים ממערכת הקבצים

כעת נטען את "saved_model.pb" ל- Java. ל- API של Java TensorFlow יש SavedModelBundle לעבודה עם דגמים שמורים:

SavedModelBundle model = SavedModelBundle.load ("./ model", "serve"); טנסור טנסור = model.session (). רץ (). אחזר ("z") .feed ("x", Tensor.create (3, Integer.class)) .feed ("y", Tensor.create (3, Integer.class)) .run (). Get (0) .expect (Integer.class); System.out.println (tensor.intValue ());

זה אמור להיות אינטואיטיבי למדי להבין מה הקוד הקודם עושה. זה פשוט טוען את גרף המודל ממאגר הפרוטוקול ומנגיש את ההפעלה בו. משם והלאה, אנחנו יכולים לעשות כמעט הכל עם גרף זה כפי שהיינו עושים עבור גרף שהוגדר באופן מקומי.

9. מסקנה

לסיכום, במדריך זה עברנו את המושגים הבסיסיים הקשורים לגרף החישוב TensorFlow. ראינו כיצד להשתמש ב- TensorFlow Java API ליצירה והפעלה של גרף כזה. לאחר מכן דיברנו על מקרי השימוש ב- API של Java ביחס ל- TensorFlow.

בתהליך הבנו גם כיצד לדמיין את הגרף באמצעות TensorBoard, ולשמור וטען מחדש מודל באמצעות פרוטוקול מאגר.

כמו תמיד, הקוד לדוגמאות זמין ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found