API เลเยอร์ TensorFlow.js สำหรับผู้ใช้ Keras

Layers API ของ TensorFlow.js ได้รับการออกแบบตาม Keras และเรามุ่งมั่นที่จะทำให้ Layers API มีความคล้ายคลึงกับ Keras อย่างเหมาะสม เนื่องจากความแตกต่างระหว่าง JavaScript และ Python สิ่งนี้ทำให้ผู้ใช้ที่มีประสบการณ์ในการพัฒนาโมเดล Keras ใน Python ย้ายไปยัง TensorFlow.js Layers ใน JavaScript ได้ง่ายขึ้น ตัวอย่างเช่น รหัส Keras ต่อไปนี้แปลเป็น JavaScript:

# Python:
import keras
import numpy as np

# Build and compile model.
model = keras.Sequential()
model.add(keras.layers.Dense(units=1, input_shape=[1]))
model.compile(optimizer='sgd', loss='mean_squared_error')

# Generate some synthetic data for training.
xs = np.array([[1], [2], [3], [4]])
ys = np.array([[1], [3], [5], [7]])

# Train model with fit().
model.fit(xs, ys, epochs=1000)

# Run inference with predict().
print(model.predict(np.array([[5]])))
// JavaScript:
import * as tf from '@tensorflow/tfjs';

// Build and compile model.
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));
model.compile({optimizer: 'sgd', loss: 'meanSquaredError'});

// Generate some synthetic data for training.
const xs = tf.tensor2d([[1], [2], [3], [4]], [4, 1]);
const ys = tf.tensor2d([[1], [3], [5], [7]], [4, 1]);

// Train model with fit().
await model.fit(xs, ys, {epochs: 1000});

// Run inference with predict().
model.predict(tf.tensor2d([[5]], [1, 1])).print();

อย่างไรก็ตาม มีความแตกต่างบางประการที่เราต้องการอธิบายและอธิบายในเอกสารนี้ เมื่อคุณเข้าใจความแตกต่างเหล่านี้และเหตุผลเบื้องหลังแล้ว การโยกย้าย Python เป็น JavaScript (หรือการย้ายในทิศทางตรงกันข้าม) น่าจะเป็นประสบการณ์ที่ค่อนข้างราบรื่น

ตัวสร้างใช้วัตถุ JavaScript เป็นการกำหนดค่า

เปรียบเทียบบรรทัด Python และ JavaScript ต่อไปนี้จากตัวอย่างด้านบน: ทั้งคู่สร้างเลเยอร์ Dense

# Python:
keras.layers.Dense(units=1, inputShape=[1])
// JavaScript:
tf.layers.dense({units: 1, inputShape: [1]});

ฟังก์ชัน JavaScript ไม่เทียบเท่ากับอาร์กิวเมนต์คำหลักในฟังก์ชัน Python เราต้องการหลีกเลี่ยงการใช้ตัวเลือกคอนสตรัคเตอร์เป็นอาร์กิวเมนต์ตำแหน่งใน JavaScript ซึ่งจะยุ่งยากเป็นพิเศษในการจดจำและใช้สำหรับคอนสตรัคเตอร์ที่มีอาร์กิวเมนต์คำหลักจำนวนมาก (เช่น LSTM ) นี่คือเหตุผลที่เราใช้วัตถุการกำหนดค่า JavaScript อ็อบเจ็กต์ดังกล่าวมีความแปรปรวนของตำแหน่งและความยืดหยุ่นในระดับเดียวกับอาร์กิวเมนต์ของคีย์เวิร์ด Python

วิธีการบางอย่างของคลาส Model เช่น Model.compile() ก็ใช้อ็อบเจ็กต์การกำหนดค่า JavaScript เป็นอินพุตเช่นกัน อย่างไรก็ตาม โปรดทราบว่า Model.fit() , Model.evaluate() และ Model.predict() แตกต่างกันเล็กน้อย เนื่องจากวิธีการเหล่านี้ใช้ข้อมูลบังคับ x (คุณสมบัติ) และ y (ป้ายกำกับหรือเป้าหมาย) เป็นอินพุต x และ y เป็นอาร์กิวเมนต์ตำแหน่งที่แยกจากออบเจ็กต์การกำหนดค่าที่ตามมาซึ่งมีบทบาทเป็นอาร์กิวเมนต์ของคำหลัก ตัวอย่างเช่น:

// JavaScript:
await model.fit(xs, ys, {epochs: 1000});

Model.fit() ไม่ตรงกัน

Model.fit() เป็นวิธีการหลักที่ผู้ใช้ดำเนินการฝึกโมเดลใน TensorFlow.js วิธีนี้มักจะใช้เวลานาน นานเพียงไม่กี่วินาทีหรือนาที ดังนั้นเราจึงใช้คุณสมบัติ async ของภาษา JavaScript เพื่อให้สามารถใช้ฟังก์ชันนี้ในลักษณะที่ไม่บล็อกเธรด UI หลักเมื่อทำงานในเบราว์เซอร์ ซึ่งคล้ายกับฟังก์ชันอื่นๆ ที่อาจใช้เวลานานใน JavaScript เช่น การดึงข้อมูล async โปรดทราบว่า async เป็นโครงสร้างที่ไม่มีอยู่ใน Python ในขณะที่เมธอด fit() ใน Keras ส่งคืนออบเจ็กต์ History ส่วนคู่ของเมธอด fit() ใน JavaScript จะส่งคืน Promise of History ซึ่งสามารถ รอ การแก้ไขได้ (ดังตัวอย่างด้านบน) หรือใช้ร่วมกับเมธอด then()

ไม่มี NumPy สำหรับ TensorFlow.js

ผู้ใช้ Python Keras มักใช้ NumPy เพื่อดำเนินการตัวเลขและอาร์เรย์พื้นฐาน เช่น การสร้างเทนเซอร์ 2D ในตัวอย่างด้านบน

# Python:
xs = np.array([[1], [2], [3], [4]])

ใน TensorFlow.js การดำเนินการเชิงตัวเลขพื้นฐานประเภทนี้จะดำเนินการกับแพ็คเกจเอง ตัวอย่างเช่น:

// JavaScript:
const xs = tf.tensor2d([[1], [2], [3], [4]], [4, 1]);

เนมสเปซ tf.* ยังมีฟังก์ชันอื่นๆ อีกจำนวนหนึ่งสำหรับการดำเนินการอาร์เรย์และพีชคณิตเชิงเส้น เช่น การคูณเมทริกซ์ ดู เอกสาร TensorFlow.js Core สำหรับข้อมูลเพิ่มเติม

ใช้วิธีการแบบโรงงาน ไม่ใช่แบบก่อสร้าง

บรรทัดนี้ใน Python (จากตัวอย่างด้านบน) เป็นการเรียกตัวสร้าง:

# Python:
model = keras.Sequential()

หากแปลเป็น JavaScript อย่างเคร่งครัด การเรียก Constructor ที่เทียบเท่าจะมีลักษณะดังนี้:

// JavaScript:
const model = new tf.Sequential();  // !!! DON'T DO THIS !!!

อย่างไรก็ตาม เราตัดสินใจที่จะไม่ใช้ตัวสร้าง "ใหม่" เนื่องจาก 1) คีย์เวิร์ด "ใหม่" จะทำให้โค้ดมีขนาดใหญ่ขึ้น และ 2) ตัวสร้าง "ใหม่" ถือเป็น "ส่วนที่ไม่ดี" ของ JavaScript: ข้อผิดพลาดที่อาจเกิดขึ้น เนื่องจาก มีการโต้แย้งใน JavaScript: the Good Parts หากต้องการสร้างโมเดลและเลเยอร์ใน TensorFlow.js คุณจะต้องเรียกเมธอดของโรงงานซึ่งมีชื่อ lowerCamelCase เช่น

// JavaScript:
const model = tf.sequential();

const layer = tf.layers.batchNormalization({axis: 1});

ค่าสตริงตัวเลือกคือ lowerCamelCase ไม่ใช่ Snake_case

ใน JavaScript เป็นเรื่องปกติที่จะใช้ตัวพิมพ์เล็กสำหรับชื่อสัญลักษณ์ (เช่น ดู คู่มือสไตล์ Google JavaScript ) เมื่อเปรียบเทียบกับ Python โดยที่ตัวพิมพ์งูเป็นเรื่องธรรมดา (เช่นใน Keras) ด้วยเหตุนี้ เราจึงตัดสินใจใช้ lowerCamelCase สำหรับค่าสตริงสำหรับตัวเลือกต่างๆ ดังต่อไปนี้:

  • DataFormat เช่น channelsFirst แทนที่จะเป็น channels_first
  • Initializer เช่น glorotNormal แทนที่จะเป็น glorot_normal
  • การสูญเสียและตัวชี้วัด เช่น meanSquaredError แทนที่จะเป็น mean_squared_error , categoricalCrossentropy แทนที่จะเป็น categorical_crossentropy

ตัวอย่างเช่น ดังตัวอย่างข้างต้น:

// JavaScript:
model.compile({optimizer: 'sgd', loss: 'meanSquaredError'});

ในส่วนของการทำให้เป็นอนุกรมและดีซีเรียลไลซ์ของโมเดล คุณมั่นใจได้ กลไกภายในของ TensorFlow.js ช่วยให้มั่นใจได้ว่าเคสงูในออบเจ็กต์ JSON ได้รับการจัดการอย่างถูกต้อง เช่น เมื่อโหลดโมเดลที่ได้รับการฝึกล่วงหน้าจาก Python Keras

เรียกใช้วัตถุเลเยอร์ด้วย Apply() ไม่ใช่โดยการเรียกวัตถุเหล่านั้นว่าเป็นฟังก์ชัน

ใน Keras วัตถุ Layer มี __call__ วิธีการกำหนด ดังนั้นผู้ใช้สามารถเรียกใช้ลอจิกของเลเยอร์ได้โดยการเรียกอ็อบเจ็กต์เป็นฟังก์ชัน เช่น

# Python:
my_input = keras.Input(shape=[2, 4])
flatten = keras.layers.Flatten()

print(flatten(my_input).shape)

น้ำตาลไวยากรณ์ Python นี้ถูกนำมาใช้เป็นเมธอด Apply() ใน TensorFlow.js:

// JavaScript:
const myInput = tf.input({shape: [2, 4]});
const flatten = tf.layers.flatten();

console.log(flatten.apply(myInput).shape);

Layer.apply() รองรับการประเมินที่จำเป็น (กระตือรือร้น) บนเทนเซอร์ที่เป็นรูปธรรม

ปัจจุบันใน Keras วิธี การโทร สามารถทำงานได้เฉพาะกับวัตถุ tf.Tensor ของ (Python) TensorFlow เท่านั้น (สมมติว่าแบ็กเอนด์ TensorFlow) ซึ่งเป็นสัญลักษณ์และไม่เก็บค่าตัวเลขจริง นี่คือสิ่งที่แสดงในตัวอย่างในส่วนก่อนหน้า อย่างไรก็ตาม ใน TensorFlow.js เมธอด Apply() ของเลเยอร์สามารถทำงานได้ทั้งในโหมดสัญลักษณ์และโหมดจำเป็น หาก apply() ด้วย SymbolicTensor (การเปรียบเทียบอย่างใกล้ชิดของ tf.Tensor) ค่าที่ส่งคืนจะเป็น SymbolicTensor โดยทั่วไปสิ่งนี้จะเกิดขึ้นระหว่างการสร้างแบบจำลอง แต่หากเรียกใช้ apply() ด้วยค่า Tensor ที่เป็นรูปธรรมจริง ก็จะส่งคืน Tensor ที่เป็นรูปธรรม ตัวอย่างเช่น:

// JavaScript:
const flatten = tf.layers.flatten();

flatten.apply(tf.ones([2, 3, 4])).print();

คุณลักษณะนี้ชวนให้นึกถึง Eager Execution ของ (Python) TensorFlow ช่วยให้มีการโต้ตอบและแก้ไขจุดบกพร่องได้มากขึ้นในระหว่างการพัฒนาโมเดล นอกเหนือจากการเปิดประตูสู่การสร้างโครงข่ายประสาทเทียมแบบไดนามิก

เครื่องมือเพิ่มประสิทธิภาพอยู่ระหว่างการฝึก ไม่ใช่เครื่องมือเพิ่มประสิทธิภาพ

ใน Keras ตัวสร้างสำหรับออบเจ็กต์ Optimizer จะอยู่ภายใต้เนมสเปซ keras.optimizers.* ในเลเยอร์ TensorFlow.js วิธีการจากโรงงานสำหรับเครื่องมือเพิ่มประสิทธิภาพจะอยู่ภายใต้เนมสเปซ tf.train.* ตัวอย่างเช่น:

# Python:
my_sgd = keras.optimizers.sgd(lr=0.2)
// JavaScript:
const mySGD = tf.train.sgd({lr: 0.2});

loadLayersModel() โหลดจาก URL ไม่ใช่ไฟล์ HDF5

ใน Keras โมเดลมักจะ ถูกบันทึก เป็นไฟล์ HDF5 (.h5) ซึ่งสามารถโหลดได้ในภายหลังโดยใช้เมธอด keras.models.load_model() วิธีการนี้ใช้เส้นทางไปยังไฟล์ .h5 คู่ของ load_model() ใน TensorFlow.js คือ tf.loadLayersModel() เนื่องจาก HDF5 ไม่ใช่รูปแบบไฟล์ที่เหมาะกับเบราว์เซอร์ tf.loadLayersModel() จึงใช้รูปแบบเฉพาะของ TensorFlow.js tf.loadLayersModel() รับไฟล์ model.json เป็นอาร์กิวเมนต์อินพุต model.json สามารถแปลงจากไฟล์ Keras HDF5 ได้โดยใช้แพ็คเกจ pip tensorflowjs

// JavaScript:
const model = await tf.loadLayersModel('https://foo.bar/model.json');

โปรดทราบว่า tf.loadLayersModel() ส่งคืน Promise of tf.Model

โดยทั่วไป การบันทึกและการโหลด tf.Model s ใน TensorFlow.js จะดำเนินการโดยใช้วิธี tf.Model.save และ tf.loadLayersModel ตามลำดับ เราออกแบบ API เหล่านี้ให้คล้ายกับ save และ load_model API ของ Keras แต่สภาพแวดล้อมของเบราว์เซอร์ค่อนข้างแตกต่างจากสภาพแวดล้อมแบ็กเอนด์ที่เฟรมเวิร์กการเรียนรู้เชิงลึกหลักเช่น Keras ทำงาน โดยเฉพาะอย่างยิ่งในอาร์เรย์ของเส้นทางสำหรับการคงอยู่และการส่งข้อมูล ดังนั้นจึงมีความแตกต่างที่น่าสนใจระหว่างบันทึก/โหลด API ใน TensorFlow.js และใน Keras ดูบทช่วยสอนของเราเกี่ยวกับ การบันทึกและการโหลด tf.Model สำหรับรายละเอียดเพิ่มเติม

ใช้ fitDataset() เพื่อฝึกโมเดลโดยใช้ออบเจ็กต์ tf.data.Dataset

ใน tf.keras ของ Python TensorFlow โมเดลสามารถฝึกได้โดยใช้ออบเจ็ กต์ชุดข้อมูล วิธีการ fit() ของโมเดลยอมรับวัตถุดังกล่าวโดยตรง คุณสามารถฝึกโมเดล TensorFlow.js ด้วย JavaScript ที่เทียบเท่ากับออบเจ็กต์ Dataset ได้เช่นกัน (ดู เอกสารประกอบของ tf.data API ใน TensorFlow.js ) อย่างไรก็ตาม การฝึกอบรมตามชุดข้อมูลไม่เหมือนกับ Python ตรงที่ใช้วิธีเฉพาะ นั่นคือ fitDataset วิธีการ fit() ใช้สำหรับการฝึกโมเดลที่ใช้เทนเซอร์เท่านั้น

การจัดการหน่วยความจำของออบเจ็กต์เลเยอร์และโมเดล

TensorFlow.js ทำงานบน WebGL ในเบราว์เซอร์ โดยที่น้ำหนักของออบเจ็กต์ Layer และ Model ได้รับการสนับสนุนโดยพื้นผิว WebGL อย่างไรก็ตาม WebGL ไม่มีการสนับสนุนการรวบรวมขยะในตัว ออบเจ็กต์เลเยอร์และโมเดลจะจัดการหน่วยความจำเทนเซอร์ภายในสำหรับผู้ใช้ในระหว่างการอนุมานและการโทรฝึกอบรม แต่ยังอนุญาตให้ผู้ใช้กำจัดทิ้งเพื่อเพิ่มหน่วยความจำ WebGL ที่พวกเขาครอบครอง สิ่งนี้มีประโยชน์ในกรณีที่มีการสร้างและเผยแพร่อินสแตนซ์แบบจำลองจำนวนมากภายในการโหลดเพจเดียว หากต้องการกำจัดวัตถุ Layer หรือ Model ให้ใช้เมธอด dispose()