แพลตฟอร์มและสิ่งแวดล้อม

TensorFlow.js ทำงานในเบราว์เซอร์และ Node.js และในทั้งสองแพลตฟอร์มก็มีการกำหนดค่าที่แตกต่างกันมากมาย แต่ละแพลตฟอร์มมีชุดข้อควรพิจารณาที่แตกต่างกันซึ่งจะส่งผลต่อวิธีการพัฒนาแอปพลิเคชัน

ในเบราว์เซอร์ TensorFlow.js รองรับอุปกรณ์เคลื่อนที่และอุปกรณ์เดสก์ท็อป อุปกรณ์แต่ละชิ้นมีชุดข้อจำกัดเฉพาะ เช่น WebGL API ที่พร้อมใช้งาน ซึ่งจะกำหนดและกำหนดค่าให้คุณโดยอัตโนมัติ

ใน Node.js นั้น TensorFlow.js รองรับการเชื่อมโยงโดยตรงกับ TensorFlow API หรือทำงานโดยใช้ CPU แบบวานิลลาที่ช้ากว่า

สภาพแวดล้อม

เมื่อดำเนินการโปรแกรม TensorFlow.js การกำหนดค่าเฉพาะจะเรียกว่าสภาพแวดล้อม สภาพแวดล้อมประกอบด้วยแบ็กเอนด์ส่วนกลางเดียว รวมถึงชุดแฟล็กที่ควบคุมฟีเจอร์ที่ละเอียดของ TensorFlow.js

Backends

TensorFlow.js รองรับแบ็กเอนด์ต่างๆ มากมายที่ใช้พื้นที่เก็บข้อมูลเทนเซอร์และการดำเนินการทางคณิตศาสตร์ At any given time, only one backend is active. โดยส่วนใหญ่แล้ว TensorFlow.js จะเลือกแบ็กเอนด์ที่ดีที่สุดสำหรับคุณโดยอัตโนมัติตามสภาพแวดล้อมปัจจุบัน อย่างไรก็ตาม บางครั้งสิ่งสำคัญคือต้องทราบว่ามีการใช้แบ็กเอนด์ใดและจะเปลี่ยนอย่างไร

To find which backend you are using:

console.log(tf.getBackend());

If you want to manually change the backend:

tf.setBackend('cpu');
console.log(tf.getBackend());

WebGL backend

ปัจจุบันแบ็กเอนด์ WebGL หรือ 'webgl' เป็นแบ็กเอนด์ที่ทรงพลังที่สุดสำหรับเบราว์เซอร์ แบ็กเอนด์นี้เร็วกว่าแบ็กเอนด์ CPU วานิลลาถึง 100 เท่า เทนเซอร์จะถูกจัดเก็บเป็นพื้นผิว WebGL และการดำเนินการทางคณิตศาสตร์ถูกนำมาใช้ในเชเดอร์ WebGL ต่อไปนี้เป็นสิ่งที่มีประโยชน์บางประการที่ควรทราบเมื่อใช้แบ็กเอนด์นี้: \

Avoid blocking the UI thread

เมื่อเรียกใช้การดำเนินการ เช่น tf.matMul(a, b) ผลลัพธ์ tf.Tensor จะถูกส่งกลับพร้อมกัน อย่างไรก็ตาม การคำนวณการคูณเมทริกซ์อาจยังไม่พร้อมจริงๆ ซึ่งหมายความว่า tf.Tensor ที่ส่งคืนเป็นเพียงส่วนจัดการในการคำนวณ เมื่อคุณเรียก x.data() หรือ x.array() ค่าต่างๆ จะถูกแก้ไขเมื่อการคำนวณเสร็จสิ้นจริง สิ่งนี้ทำให้การใช้เมธอด x.data() และ x.array() แบบอะซิงโครนัสมีความสำคัญเหนือ x.dataSync() และ x.arraySync() แบบซิงโครนัส เพื่อหลีกเลี่ยงการบล็อกเธรด UI ในขณะที่การคำนวณเสร็จสิ้น

Memory management

ข้อแม้ประการหนึ่งเมื่อใช้แบ็กเอนด์ WebGL คือความจำเป็นในการจัดการหน่วยความจำที่ชัดเจน WebGLTextures ซึ่งเป็นที่จัดเก็บข้อมูล Tensor ในท้ายที่สุด จะไม่ถูกรวบรวมโดยเบราว์เซอร์โดยอัตโนมัติ

หากต้องการทำลายหน่วยความจำของ tf.Tensor คุณสามารถใช้เมธอด dispose() ได้:

const a = tf.tensor([[1, 2], [3, 4]]);
a.dispose();

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

const a = tf.tensor([[1, 2], [3, 4]]);
const y = tf.tidy(() => {
  const result = a.square().log().neg();
  return result;
});
ความแม่นยำ

บนอุปกรณ์เคลื่อนที่ WebGL อาจรองรับพื้นผิวจุดลอยตัว 16 บิตเท่านั้น อย่างไรก็ตาม โมเดลแมชชีนเลิร์นนิงส่วนใหญ่ได้รับการฝึกฝนด้วยน้ำหนักจุดลอยตัว 32 บิตและการเปิดใช้งาน ซึ่งอาจทำให้เกิดปัญหาด้านความแม่นยำเมื่อย้ายโมเดลสำหรับอุปกรณ์เคลื่อนที่ เนื่องจากตัวเลขลอยตัว 16 บิตสามารถแสดงเฉพาะตัวเลขในช่วง [0.000000059605, 65504] เท่านั้น ซึ่งหมายความว่าคุณควรระวังว่าน้ำหนักและการเปิดใช้งานในโมเดลของคุณไม่เกินช่วงนี้ หากต้องการตรวจสอบว่าอุปกรณ์รองรับพื้นผิว 32 บิตหรือไม่ ให้ตรวจสอบค่าของ tf.ENV.getBool('WEBGL_RENDER_FLOAT32_CAPABLE') หากเป็นเท็จ แสดงว่าอุปกรณ์รองรับเฉพาะพื้นผิวจุดลอยตัว 16 บิตเท่านั้น คุณสามารถใช้ tf.ENV.getBool('WEBGL_RENDER_FLOAT32_ENABLED') เพื่อตรวจสอบว่า TensorFlow.js กำลังใช้พื้นผิว 32 บิตอยู่หรือไม่

Shader compilation & texture uploads

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

TensorFlow.js ยังจัดเก็บข้อมูล tf.Tensor เป็น WebGLTextures เมื่อมีการสร้าง tf.Tensor เราจะไม่อัปโหลดข้อมูลไปยัง GPU ทันที แต่เราเก็บข้อมูลไว้ใน CPU จนกว่า tf.Tensor จะถูกนำมาใช้ในการดำเนินการ หากใช้ tf.Tensor ครั้งที่สอง ข้อมูลจะอยู่ใน GPU แล้ว ดังนั้นจึงไม่มีค่าใช้จ่ายในการอัปโหลด ในโมเดลแมชชีนเลิร์นนิงทั่วไป หมายความว่าน้ำหนักจะถูกอัปโหลดระหว่างการคาดการณ์ครั้งแรกผ่านโมเดล และการส่งผ่านโมเดลครั้งที่สองจะเร็วขึ้นมาก

หากคุณสนใจประสิทธิภาพของการคาดการณ์ครั้งแรกผ่านโมเดลของคุณหรือโค้ด TensorFlow.js เราขอแนะนำให้อุ่นโมเดลโดยส่ง Tensor อินพุตที่มีรูปร่างเดียวกันก่อนที่จะใช้ข้อมูลจริง

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

const model = await tf.loadLayersModel(modelUrl);

// Warmup the model before using real data.
const warmupResult = model.predict(tf.zeros(inputShape));
warmupResult.dataSync();
warmupResult.dispose();

// The second predict() will be much faster
const result = model.predict(userData);

Node.js TensorFlow backend

ในแบ็กเอนด์ TensorFlow Node.js "โหนด" นั้น TensorFlow C API ใช้เพื่อเร่งการดำเนินการ ซึ่งจะใช้การเร่งด้วยฮาร์ดแวร์ที่มีอยู่ของเครื่อง เช่น CUDA หากมี

ในแบ็กเอนด์นี้ เช่นเดียวกับแบ็กเอนด์ WebGL การดำเนินการส่งคืน tf.Tensor แบบซิงโครนัส อย่างไรก็ตาม การดำเนินการจะเสร็จสิ้นก่อนที่คุณจะได้รับเทนเซอร์กลับคืนมา ซึ่งต่างจากแบ็กเอนด์ WebGL ซึ่งหมายความว่าการเรียก tf.matMul(a, b) จะบล็อกเธรด UI

ด้วยเหตุนี้ หากคุณตั้งใจจะใช้สิ่งนี้ในแอปพลิเคชันที่ใช้งานจริง คุณควรรัน TensorFlow.js ในเธรดของผู้ปฏิบัติงานเพื่อไม่ให้บล็อกเธรดหลัก

For more information on Node.js, see this guide.

WASM backend

TensorFlow.js มี แบ็กเอนด์ WebAssembly ( wasm ) ซึ่งให้การเร่งความเร็วของ CPU และสามารถใช้เป็นทางเลือกแทนแบ็กเอนด์ vanilla JavaScript CPU ( cpu ) และ WebGL เร่ง ( webgl ) To use it:

// Set the backend to WASM and wait for the module to be ready.
tf.setBackend('wasm');
tf.ready().then(() => {...});

หากเซิร์ฟเวอร์ของคุณให้บริการไฟล์ .wasm บนพาธอื่นหรือชื่ออื่น ให้ใช้ setWasmPath ก่อนที่จะเริ่มต้นแบ็กเอนด์ ดูส่วน "การใช้ Bundlers" ใน README สำหรับข้อมูลเพิ่มเติม:

import {setWasmPath} from '@tensorflow/tfjs-backend-wasm';
setWasmPath(yourCustomPath);
tf.setBackend('wasm');
tf.ready().then(() => {...});
Why WASM?

WASM เปิดตัวในปี 2558 ในรูปแบบไบนารีบนเว็บใหม่ โดยให้โปรแกรมที่เขียนด้วย JavaScript, C, C++ และอื่นๆ เป็นเป้าหมายในการคอมไพล์สำหรับการทำงานบนเว็บ WASM ได้รับ การสนับสนุน โดย Chrome, Safari, Firefox และ Edge ตั้งแต่ปี 2017 และได้รับการสนับสนุนโดย อุปกรณ์ 90% ทั่วโลก

ผลงาน

แบ็กเอนด์ WASM ใช้ประโยชน์จาก ไลบรารี XNNPACK เพื่อการใช้งานที่เหมาะสมที่สุดของผู้ให้บริการโครงข่ายประสาทเทียม

เมื่อเทียบกับ JavaScript : โดยทั่วไปไบนารีของ WASM จะเร็วกว่าชุด JavaScript มากสำหรับเบราว์เซอร์ในการโหลด แยกวิเคราะห์ และดำเนินการ JavaScript ถูกพิมพ์แบบไดนามิกและรวบรวมขยะ ซึ่งอาจทำให้รันไทม์ช้าลง

เทียบกับ WebGL : WebGL เร็วกว่า WASM สำหรับรุ่นส่วนใหญ่ แต่สำหรับรุ่นเล็ก WASM สามารถทำงานได้ดีกว่า WebGL เนื่องจากต้นทุนค่าใช้จ่ายคงที่ในการรัน WebGL shaders ส่วน “ฉันควรใช้ WASM เมื่อใด” ด้านล่างจะกล่าวถึงการวิเคราะห์พฤติกรรมในการตัดสินใจครั้งนี้

Portability and Stability

WASM มีเลขคณิตทศนิยมแบบ 32 บิตแบบพกพา ซึ่งให้ความเท่าเทียมกันที่แม่นยำในทุกอุปกรณ์ ในทางกลับกัน WebGL เป็นฮาร์ดแวร์เฉพาะ และอุปกรณ์ที่แตกต่างกันอาจมีความแม่นยำที่แตกต่างกัน (เช่น ทางเลือกสำรองเป็น 16 บิตแบบลอยบนอุปกรณ์ iOS)

เช่นเดียวกับ WebGL WASM ได้รับการสนับสนุนอย่างเป็นทางการจากเบราว์เซอร์หลักๆ ทั้งหมด WASM ต่างจาก WebGL ตรงที่สามารถทำงานใน Node.js และใช้งานฝั่งเซิร์ฟเวอร์ได้โดยไม่จำเป็นต้องคอมไพล์ไลบรารีดั้งเดิม

When should I use WASM?

Model size and computational demand

โดยทั่วไป WASM เป็นตัวเลือกที่ดีเมื่อโมเดลมีขนาดเล็กกว่าหรือคุณสนใจอุปกรณ์ระดับล่างที่ไม่รองรับ WebGL (ส่วนขยาย OES_texture_float ) หรือมี GPU ที่ทรงพลังน้อยกว่า The chart below shows inference times (as of TensorFlow.js 1.5.2) in Chrome on a 2018 MacBook Pro for 5 of our officially supported models across the WebGL, WASM, and CPU backends:

Smaller models

แบบอย่าง WebGL WASM ซีพียู หน่วยความจำ
BlazeFace 22.5 ms 15.6 ms 315.2 ms .4 MB
FaceMesh 19.3 มิลลิวินาที 19.2 มิลลิวินาที 335 มิลลิวินาที 2.8 ลบ

รุ่นใหญ่

แบบอย่าง WebGL WASM ซีพียู หน่วยความจำ
โพเซเน็ต 42.5 มิลลิวินาที 173.9 มิลลิวินาที 1514.7 มิลลิวินาที 4.5 ลบ
บอดี้พิกซ์ 77 มิลลิวินาที 188.4 มิลลิวินาที 2683 ม 4.6 MB
MobileNet v2 37 ms 94 ms 923.6 ms 13 MB

The table above shows that WASM is 10-30x faster than the plain JS CPU backend across models, and competitive with WebGL for smaller models like BlazeFace , which is lightweight (400KB), yet has a decent number of ops (~140). เนื่องจากโปรแกรม WebGL มีต้นทุนค่าใช้จ่ายคงที่ต่อการดำเนินการ สิ่งนี้อธิบายว่าทำไมโมเดลอย่าง BlazeFace จึงเร็วกว่าบน WASM

ผลลัพธ์เหล่านี้จะแตกต่างกันไปขึ้นอยู่กับอุปกรณ์ของคุณ วิธีที่ดีที่สุดในการพิจารณาว่า WASM เหมาะกับแอปพลิเคชันของคุณหรือไม่คือการทดสอบบนแบ็กเอนด์ต่างๆ ของเรา

Inference vs Training

To address the primary use-case for deployment of pre-trained models, the WASM backend development will prioritize inference over training support. ดู รายการ Ops ที่รองรับล่าสุด ใน WASM และ แจ้งให้เราทราบ หากโมเดลของคุณมี Ops ที่ไม่รองรับ สำหรับโมเดลการฝึก เราขอแนะนำให้ใช้แบ็กเอนด์ Node (TensorFlow C++) หรือแบ็กเอนด์ WebGL

CPU backend

แบ็คเอนด์ CPU หรือ 'cpu' เป็นแบ็กเอนด์ที่มีประสิทธิภาพน้อยที่สุด แต่ก็เป็นวิธีที่ง่ายที่สุด การดำเนินการทั้งหมดถูกนำไปใช้ใน vanilla JavaScript ซึ่งทำให้การทำงานแบบขนานน้อยลง They also block the UI thread.

แบ็กเอนด์นี้มีประโยชน์มากสำหรับการทดสอบหรือบนอุปกรณ์ที่ WebGL ไม่พร้อมใช้งาน

ธง

TensorFlow.js มีชุดแฟล็กสภาพแวดล้อมที่ได้รับการประเมินโดยอัตโนมัติและกำหนดการกำหนดค่าที่ดีที่สุดในแพลตฟอร์มปัจจุบัน แฟล็กเหล่านี้ส่วนใหญ่เป็นแบบภายใน แต่แฟล็กส่วนกลางบางส่วนสามารถควบคุมได้ด้วย API สาธารณะ

  • tf.enableProdMode(): enables production mode, which will remove model validation, NaN checks, and other correctness checks in favor of performance.
  • tf.enableDebugMode() : enables debug mode, which will log to the console every operation that is executed, as well as runtime performance information like memory footprint and total kernel execution time. โปรดทราบว่าการดำเนินการนี้จะทำให้แอปพลิเคชันของคุณช้าลงอย่างมาก โปรดอย่าใช้สิ่งนี้ในการผลิต