ภาพรวม
TensorFlow.js 3.0 ให้การสนับสนุนสำหรับ การสร้างชุดเบราว์เซอร์ที่เน้นการใช้งานจริงและปรับขนาดให้เหมาะสม กล่าวอีกนัยหนึ่ง เราต้องการทำให้คุณจัดส่ง JavaScript ไปยังเบราว์เซอร์น้อยลงได้ง่ายขึ้น
คุณลักษณะนี้เหมาะสำหรับผู้ใช้ที่มีกรณีการใช้งานจริงซึ่งจะได้รับประโยชน์เป็นพิเศษจากการลดจำนวนไบต์ออกจากเพย์โหลด (และยินดีที่จะพยายามอย่างเต็มที่เพื่อให้บรรลุเป้าหมายนี้) หากต้องการใช้คุณลักษณะนี้ คุณควรคุ้นเคยกับ ES Modules เครื่องมือการรวมกลุ่ม JavaScript เช่น webpack หรือ rollup และแนวคิดต่างๆ เช่น การกำจัดแบบ tree-shaking/dead-code
บทช่วยสอนนี้สาธิตวิธีสร้างโมดูล tensorflow.js แบบกำหนดเองที่สามารถใช้กับบันเดิลเพื่อสร้างบิลด์ที่ปรับขนาดให้เหมาะสมสำหรับโปรแกรมที่ใช้ tensorflow.js
คำศัพท์เฉพาะทาง
ในบริบทของเอกสารนี้มีคำศัพท์สำคัญบางประการที่เราจะใช้:
ES Modules - ระบบโมดูล JavaScript มาตรฐาน เปิดตัวใน ES6/ES2015 สามารถระบุได้โดยใช้คำสั่ง นำเข้า และ ส่งออก
การรวมกลุ่ม - การนำชุดของเนื้อหา JavaScript และการจัดกลุ่ม/การรวมกลุ่มไว้ในเนื้อหา JavaScript หนึ่งรายการขึ้นไปที่สามารถใช้งานได้ในเบราว์เซอร์ นี่คือขั้นตอนที่มักจะสร้างเนื้อหาสุดท้ายที่ส่งไปยังเบราว์เซอร์ โดยทั่วไปแอปพลิเคชันจะรวมกลุ่มของตัวเองโดยตรงจากแหล่งไลบรารีที่ทรานสไพล์ Bundler ทั่วไป ได้แก่ rollup และ webpack ผลลัพธ์สุดท้ายของการรวมกลุ่มเรียกว่า การรวมกลุ่ม (หรือบางครั้งเรียกว่าการ รวมกลุ่ม หากแบ่งออกเป็นหลายส่วน)
การกำจัดโค้ดที่เขย่าต้นไม้ / โค้ดที่ไม่ทำงาน - การลบโค้ดที่ไม่ได้ใช้โดยแอปพลิเคชันที่เขียนขั้นสุดท้าย ซึ่งทำได้ในระหว่างการรวมกลุ่ม โดยทั่วไปจะ อยู่ในขั้นตอนการย่อขนาด
การดำเนินการ (Ops) - การดำเนินการทางคณิตศาสตร์กับเทนเซอร์ตั้งแต่หนึ่งตัวขึ้นไปที่สร้างเทนเซอร์ตั้งแต่หนึ่งตัวขึ้นไปเป็นเอาท์พุต Ops คือโค้ด 'ระดับสูง' และสามารถใช้ ops อื่นเพื่อกำหนดตรรกะได้
เคอร์เนล - การใช้งานเฉพาะของ op ที่เชื่อมโยงกับความสามารถของฮาร์ดแวร์เฉพาะ เคอร์เนลเป็น 'ระดับต่ำ' และเฉพาะแบ็กเอนด์ ops บางตัวมีการแมปแบบหนึ่งต่อหนึ่งจาก op ไปยังเคอร์เนล ในขณะที่ ops อื่น ๆ ใช้หลายเคอร์เนล
ขอบเขตและกรณีการใช้งาน
การอนุมานเฉพาะแบบจำลองกราฟเท่านั้น
กรณีการใช้งานหลักที่เราได้ยินจากผู้ใช้ที่เกี่ยวข้องกับเรื่องนี้ และได้รับการสนับสนุนในรุ่นนี้คือการ อนุมานด้วย โมเดลกราฟ TensorFlow.js หากคุณใช้ โมเดลเลเยอร์ TensorFlow.js คุณสามารถแปลงสิ่งนี้ให้เป็นรูปแบบกราฟ-โมเดลได้โดยใช้ tfjs-converter รูปแบบแบบจำลองกราฟมีประสิทธิภาพมากกว่าสำหรับกรณีการใช้งานเชิงอนุมาน
การจัดการเทนเซอร์ระดับต่ำด้วย tfjs-core
กรณีการใช้งานอื่นๆ ที่เรารองรับคือโปรแกรมที่ใช้แพ็คเกจ @tensorflow/tjfs-core โดยตรงสำหรับการจัดการเทนเซอร์ระดับล่าง
แนวทางของเราในการสร้างแบบกำหนดเอง
หลักการสำคัญของเราเมื่อออกแบบฟังก์ชันการทำงานนี้ประกอบด้วยดังต่อไปนี้:
- ใช้ประโยชน์สูงสุดจากระบบโมดูล JavaScript (ESM) และอนุญาตให้ผู้ใช้ TensorFlow.js ทำเช่นเดียวกัน
- ทำให้ TensorFlow.js สั่นไหวแบบทรีได้มากที่สุดเท่าที่จะเป็นไปได้ โดยบันเดิลที่มีอยู่ (เช่น webpack, rollup ฯลฯ) สิ่งนี้ทำให้ผู้ใช้สามารถใช้ประโยชน์จากความสามารถทั้งหมดของบันเดิลเหล่านั้น รวมถึงคุณสมบัติต่างๆ เช่น การแยกโค้ด
- รักษา ความสะดวกในการใช้งานให้มากที่สุดเท่าที่จะเป็นไปได้สำหรับผู้ใช้ที่ไม่ไวต่อขนาดบันเดิล นี่หมายความว่าบิลด์ที่ใช้งานจริงจะต้องใช้ความพยายามมากขึ้น เนื่องจากค่าเริ่มต้นจำนวนมากในไลบรารีของเรารองรับความสะดวกในการใช้งานมากกว่าบิลด์ที่ปรับขนาดให้เหมาะสม
เป้าหมายหลักของขั้นตอนการทำงานของเราคือการสร้าง โมดูล JavaScript ที่กำหนดเองสำหรับ TensorFlow.js ที่มีเพียงฟังก์ชันที่จำเป็นสำหรับโปรแกรมที่เราพยายามเพิ่มประสิทธิภาพเท่านั้น เราอาศัยบันเดิลที่มีอยู่เพื่อทำการเพิ่มประสิทธิภาพจริง
แม้ว่าเราจะพึ่งพาระบบโมดูล JavaScript เป็นหลัก แต่เรายังมี เครื่องมือ CLI แบบกำหนดเอง เพื่อจัดการส่วนต่างๆ ที่ไม่สามารถระบุได้ง่ายผ่านระบบโมดูลในโค้ดแบบโต้ตอบกับผู้ใช้ สองตัวอย่างนี้คือ:
- ข้อมูลจำเพาะของโมเดลจัดเก็บไว้ในไฟล์
model.json
- ทางเลือกของระบบการจัดส่งเคอร์เนลเฉพาะแบ็กเอนด์ที่เราใช้
สิ่งนี้ทำให้การสร้าง tfjs แบบกำหนดเองมีความเกี่ยวข้องมากกว่าการชี้บันเดิลไปยังแพ็คเกจ @tensorflow/tfjs ปกติ
วิธีสร้างชุดรวมแบบกำหนดเองที่ปรับขนาดให้เหมาะสม
ขั้นตอนที่ 1: พิจารณาว่าโปรแกรมของคุณใช้เคอร์เนลใด
ขั้นตอนนี้ช่วยให้เราระบุเคอร์เนลทั้งหมดที่ใช้โดยโมเดลใดๆ ที่คุณเรียกใช้หรือโค้ดก่อน/หลังการประมวลผลโดยให้แบ็กเอนด์ที่คุณเลือกไว้
ใช้ tf.profile เพื่อเรียกใช้ส่วนต่างๆ ของแอปพลิเคชันของคุณที่ใช้ tensorflow.js และรับเคอร์เนล มันจะมีลักษณะเช่นนี้
const profileInfo = await tf.profile(() => {
// You must profile all uses of tf symbols.
runAllMyTfjsCode();
});
const kernelNames = profileInfo.kernelNames
console.log(kernelNames);
คัดลอกรายการเมล็ดนั้นไปยังคลิปบอร์ดของคุณสำหรับขั้นตอนต่อไป
คุณต้องกำหนดโปรไฟล์โค้ดโดยใช้แบ็กเอนด์เดียวกันกับที่คุณต้องการใช้ในบันเดิลที่กำหนดเอง
คุณจะต้องทำซ้ำขั้นตอนนี้หากโมเดลของคุณเปลี่ยนแปลงหรือโค้ดก่อน/หลังการประมวลผลของคุณเปลี่ยนแปลง
ขั้นตอนที่ 2 เขียนไฟล์การกำหนดค่าสำหรับโมดูล tfjs แบบกำหนดเอง
นี่คือตัวอย่างไฟล์ปรับแต่ง
ดูเหมือนว่านี้:
{
"kernels": ["Reshape", "_FusedMatMul", "Identity"],
"backends": [
"cpu"
],
"models": [
"./model/model.json"
],
"outputPath": "./custom_tfjs",
"forwardModeOnly": true
}
- เมล็ดพืช: รายการเมล็ดพืชที่จะรวมไว้ในชุดรวม คัดลอกสิ่งนี้จากผลลัพธ์ของขั้นตอนที่ 1
- แบ็กเอนด์: รายการแบ็กเอนด์ที่คุณต้องการรวม ตัวเลือกที่ถูกต้อง ได้แก่ "cpu", "webgl" และ "wasm"
- โมเดล: รายการไฟล์ model.json สำหรับโมเดลที่คุณโหลดในแอปพลิเคชันของคุณ สามารถเว้นว่างได้หากโปรแกรมของคุณไม่ได้ใช้ tfjs_converter เพื่อโหลดโมเดลกราฟ
- outputPath: เส้นทางไปยังโฟลเดอร์เพื่อใส่โมดูลที่สร้างขึ้น
- forwardModeOnly: ตั้งค่านี้เป็นเท็จหากคุณต้องการรวมการไล่ระดับสีสำหรับเคอร์เนลที่แสดงไว้ก่อนหน้า
ขั้นตอนที่ 3 สร้างโมดูล tfjs แบบกำหนดเอง
เรียกใช้เครื่องมือสร้างแบบกำหนดเองโดยใช้ไฟล์กำหนดค่าเป็นอาร์กิวเมนต์ คุณต้องติดตั้งแพ็คเกจ @tensorflow/tfjs จึงจะสามารถเข้าถึงเครื่องมือนี้ได้
npx tfjs-custom-module --config custom_tfjs_config.json
สิ่งนี้จะสร้างโฟลเดอร์ที่ outputPath
พร้อมไฟล์ใหม่บางไฟล์
ขั้นตอนที่ 4 กำหนดค่า Bundler ของคุณเป็นนามแฝง tfjs ไปยังโมดูลที่กำหนดเองใหม่
ในบันเดิลเช่น webpack และ rollup เราสามารถเรียกการอ้างอิงที่มีอยู่ไปยังโมดูล tfjs เพื่อชี้ไปที่โมดูล tfjs แบบกำหนดเองที่สร้างขึ้นใหม่ของเรา มีสามโมดูลที่ต้องมีนามแฝงเพื่อการประหยัดขนาดบันเดิลสูงสุด
นี่คือตัวอย่างสิ่งที่ดูเหมือนใน webpack ( ตัวอย่างเต็มที่นี่ ):
...
config.resolve = {
alias: {
'@tensorflow/tfjs$':
path.resolve(__dirname, './custom_tfjs/custom_tfjs.js'),
'@tensorflow/tfjs-core$': path.resolve(
__dirname, './custom_tfjs/custom_tfjs_core.js'),
'@tensorflow/tfjs-core/dist/ops/ops_for_converter': path.resolve(
__dirname, './custom_tfjs/custom_ops_for_converter.js'),
}
}
...
และนี่คือข้อมูลโค้ดที่เทียบเท่าสำหรับการยกเลิก ( ตัวอย่างเต็ม ที่นี่ ):
import alias from '@rollup/plugin-alias';
...
alias({
entries: [
{
find: /@tensorflow\/tfjs$/,
replacement: path.resolve(__dirname, './custom_tfjs/custom_tfjs.js'),
},
{
find: /@tensorflow\/tfjs-core$/,
replacement: path.resolve(__dirname, './custom_tfjs/custom_tfjs_core.js'),
},
{
find: '@tensorflow/tfjs-core/dist/ops/ops_for_converter',
replacement: path.resolve(__dirname, './custom_tfjs/custom_ops_for_converter.js'),
},
],
}));
...
หากบันเดิลของคุณไม่รองรับการกำหนดนามแฝงของโมดูล คุณจะต้องเปลี่ยนคำสั่ง
import
ของคุณเพื่อนำเข้า tensorflow.js จากcustom_tfjs.js
ที่สร้างขึ้นซึ่งสร้างขึ้นในขั้นตอนที่ 3 คำจำกัดความของ Op จะไม่ถูกเขย่าแบบทรี แต่เคอร์เนลยังคงเป็นแบบต้นไม้ -เขย่า โดยทั่วไปเมล็ดที่เขย่าต้นไม้จะช่วยประหยัดขนาดมัดสุดท้ายได้มากที่สุด
หากคุณใช้เพียงแพ็คเกจ @tensoflow/tfjs-core คุณจะต้องใช้นามแฝงแพ็คเกจเดียวเท่านั้น
ขั้นตอนที่ 5 สร้างชุดรวมของคุณ
เรียกใช้ Bundler ของคุณ (เช่น webpack
หรือ rollup
) เพื่อสร้าง Bundle ของคุณ ขนาดของบันเดิลควรเล็กกว่าถ้าคุณรันบันเดิลโดยไม่มีนามแฝงโมดูล คุณยังสามารถใช้วิชวลไลเซอร์เช่น นี้ เพื่อดูว่าอะไรทำให้มันกลายเป็นชุดสุดท้ายของคุณ
ขั้นตอนที่ 6 ทดสอบแอปของคุณ
อย่าลืมทดสอบว่าแอปของคุณทำงานตามที่คาดไว้!