in Computer, Diary

การติดตั้ง เขียนโค้ดเพื่อใช้งาน ONNX.js และข้อสังเกต

การนำโมเดลที่ได้รับการเรียนรู้แล้วมาทำงานบนเว็บเบราว์เซอร์ไม่ได้เป็นเรื่องใหม่นัก เพราะบริษัทกูเกิ้ลพัฒนาไลบรารีชื่อ Tensorflow.js โดยเรานำโมเดลที่ได้รับการเรียนรู้แล้วมาทำนาย หรือเรียนรู้ข้อมูลใหม่บนเว็บไซต์ได้เลยโดยไม่จำเป็นต้องส่งข้อมูลไปทำนายบนเซิร์ฟเวอร์

ส่วนไลบรารี ONNX.js เป็นส่วนหนึ่งของไลบรารี ONNX (Open Neural Network Exchange) ที่ได้รับการพัฒนาโดยบริษัทไมโครซอฟท์ เพื่อให้นำโมเดลที่ได้รับการเรียนรู้จากไลบรารี Deep learning ต่าง ๆ ได้แก่ PyTorch, Mxnet, Scikit learn เป็นต้น มาแปลงเพื่อนำไปใช้กันกับไลบรารีอื่นได้เลย หรือนำโมเดลที่เรียนรู้มาทำนายข้อมูล (Inference) ได้ โดยไลบรารี ONNX.js นี้ เปิดให้นักพัฒนาที่เทรนข้อมูลมาแล้ว เอามาทำนายข้อมูลที่มีอยู่บนเว็บเบราวเซอร์ (หรือบนคอมพิวเตอร์ผ่าน Node.js) ได้โดยไม่จำเป็นต้องมาเรียนรู้ใหม่อีก

ไลบรารี ONNX

ข้อดีของการนำโมเดลที่ได้รับการเรียนรู้มาทำงานบนเว็บเบราวเซอร์โดยการใช้ไลบรารี ONNX.js หรือ Tensorflow.js เมื่อเปรียบเทียบกับการส่งข้อมูลไปทำงานบนเซิร์ฟเวอร์ มี 3 ข้อ ได้แก่

  1. ความเป็นส่วนตัว (Privacy) ที่เหนือกว่าการส่งข้อมูลไปยังเซิร์ฟเวอร์ เพราะเราไม่ต้องส่งข้อมูลส่วนตัว ข้อมูลที่ sensitive ไปให้เซิร์ฟเวอร์อ่าน
  2. ระยะเวลาที่ทำงานโมเดลน้อยกว่าเนื่องจากมีค่า Latency ที่ต่ำกว่า เพราะเราไม่ต้องส่งข้อมูลไป และนำข้อมูลที่มีอยู่ในคอมของลูกค้ามาทำนายในเว็บเบราวเซอร์ได้เลย
  3. สามารทำงานข้ามแพลตฟอร์ม (Cross-platform) ได้เลยโดยไม่ต้องคอมไพล์ใหม่ หรือไม่ต้องมาลงไลบรารีใหม่แบบที่เคยพัฒนา และทำนายโดยใช้ภาษาไพทอน

เมื่อเห็นข้อดีการใช้ไลบรารีขนาดนี้แล้ว จะรอช้าอยู่ไรล่ะ เรามาติดตั้ง พร้อมกับเขียนโปรแกรมเพื่อใช้งาน ONNX.js กันดีกว่า

การติดตั้งและใช้ไลบรารี ONNX.js

การติดตั้งไลบรารี ONNX.js

ของเราเดิมทีมีตัวจับภาพใบหน้า (Face detection) ที่นำอัลกอริทีม RetinaFace ที่ผ่านการเรียนรู้โดย PyTorch มาแปลงเก็บไว้ในรูปแบบไฟล์ที่ ONNX อ่านได้เพื่อนำมาใช้งานกับธีสิสที่ต้องการทำนายบนเว็บแทน เนื่องจากโค้ดได้รับการพัฒนาโดย JavaScript วิธีการทำนายข้อมูลนี้ทำได้โดย

การติดตั้งไลบรารี ONNX.js ทำได้โดยกรณีที่ต้องการทำงานบนเบราวเซอร์แบบที่ไม่ได้ใช้ไลบรารีอื่นอย่าง React, Angular, Vue.js ทำได้โดยดาวน์โหลดจากลิ้งค์นี้ได้เลยครับ เมื่อดาวน์โหลดมาแล้ว นำไฟล์ของไลบรารีเข้าไปในตัวเว็บไซต์โดยผ่านการใช้ <script> ตามด้านล่างนี้

<script src="https://cdn.jsdelivr.net/npm/onnxjs/dist/onnx.min.js"></script>

ส่วนคนที่ใช้ไลบรารีตามที่กล่าวไว้ข้างต้น หรือไลบรารีอื่นใด เราสามารถนำเข้า ONNX.js ผ่านการติดตั้งจาก NPM โดยใช้คำสั่ง npm install หรือ yarn add ได้ตามสะดวก จากนั้นใช้คำสั่ง import เข้ามาครับตามด้านล่างนี้

import { Tensor, InferenceSession } from "onnxjs";

การเขียนโค้ดเพื่ออินพอร์ทโมเดล

เมื่อเรานำเข้าไลบรารีมาแล้ว ขั้นตอนต่อไปคือเขียนโค้ดด้วยภาษา JavaScript เพื่ออิมพอร์ทตัวโมเดลเพื่อที่จะทำนายข้อมูลที่เรามีอยู่ ทำได้โดย

const onnxsession = new onnx.InferenceSession({ backendHint: 'webgl' });
await onnxsession.loadModel("model path in http:// form");

โดยในตัวโค้ดจะใช้คำสั่ง await (เรียกการใช้งานแบบนี้ว่า async await) แต่ถ้าจะใช้ Promise ก็ใช้ได้เช่นกัน ส่วนสำหรับคนที่ไม่ทราบเรื่อง async await กับ Promise ผู้อ่านสามารถตามได้ที่ลิ้งค์ข้างบน

ทำข้อมูลมาทำนาย (Inference)

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

var inputTensor = new onnx.Tensor(preprocessedimg, 'float32', [batch_size, channels, imgwidth, imgheight]);

ข้อมูลที่ได้จะอยู่ในรูป Tensor จากนั้นนำมาทำนายโดยพิมพ์ว่า

var output = await onnx_session.run([inputTensor]);

ข้อมูลนั้นจะถูกทำนายโดยโมเดลที่เราเรียนรู้ไว้

ผลลัพธ์

ผลการนำข้อมูลมาทำนาย

ข้อมูลเราทำนายเสร็จแล้ว จะเอาไปทำอะไรก็ได้ตามใจ ส่วนของเราเมื่อนำไฟล์รูปภาพที่มีใบหน้าคนมาทำนายแล้ว จากนั้นนำข้อมูลที่ได้มาเล่นแร่แปรธาตุสักเล็กน้อยเพื่อให้ได้ข้อมูลตำแหน่งใบหน้าใบภาพ (Bounding box) ตำแหน่งจุดบนใบหน้า (Landmark) และค่าความมั่นใจ (Confidence) ผลที่ได้ตามภาพ

ประสิทธิภาพในการทำงาน

ความเร็วในการทำงานขึ้นกับว่าเราใช้ Backend ของอะไรตั้งแต่การเขียนโค้ดเพื่ออินพอร์ทโมเดลในหัวข้อก่อนหน้า โดย Backend เราเลือกได้ 3 รูปแบบได้แก่ cpu ซึ่งทำงานได้ช้าที่สุด, wasm ทำงานโดยใช้ Webassembly ซึ่งตัวโค้ดผ่านการคอมไพล์จะทำงานได้เร็วกว่าตัวเลือก cpu ส่วน webgl ทำงานโดยใช้การ์ดจอซึ่งโดยปกติจะทำงานได้เร็วที่สุด ตามที่ไมโครซอฟท์ได้ทดสอบจะแสดงผลตามกราฟด้านล่างนี้ (เอามาจากในเว็บ GitHub ครับ)

alt text
กราฟแสดงผลการทดสอบของ ONNX.js (เอามาจาก Github นะ)

ข้อสังเกต

หลังจากที่นำไลบรารีตัวนี้มาใช้งานแล้ว เราสังเกตได้ว่า

ตัวโค้ดมีบัคจากการรันโมเดล

จากการนำตัวโมเดลเพื่อนำไปทดสอบบนเว็บเบราวเซอร์จะขึ้น error ประมาณว่าไม่รองรับ operation บางอย่างในโมเดล deep learning ที่เรานำเข้ามา ซึ่งของเราเป็นโมเดล RetinaFace ที่มี backbone ResNet-50 กับ MobileNetV2 ครับ เท่าที่อ่านใน Issue ของ Github ไลบรารีนี้จะพบว่ามีคนรายงานตัวไลบรารีไม่รองรับ operation Shape แล้วไม่มีทีมงานตอบกลับ แต่ของคนอื่นถ้านำโมเดลมาทดสอบอาจจะไม่พบข้อผิดพลาดข้อนี้ได้ครับ

ข้อผิดพลาดระหว่างการอิมพอร์ตโมเดลครับ

เราเลยแก้ปัญหาเปลี่ยนไฟล์ JavaScript จากที่โหลดผ่าน CDN เป็นไฟล์ที่ผ่านการคอมไพล์ร่วมกันกับแก้ไข backend ให้รันบน Webasm (Webassembly) แทน ซึ่งก็ทำงานได้ แต่ทำงานช้ามาก (ก หลายตัว) กว่าจะเสร็จก็ไปเติมน้ำรอบนึงงานก็ยังไม่เสร็จอยู่ดี ส่วน WebGL ก็ยังเจอปัญหาเดิมอยู่ดี

ไลบรารีนี้มีแนวโน้มไม่ได้รับการพัฒนาต่อ

ถ้าไปดูในตัวไลบรารีใน Github เราจะพบว่าตัวไลบรารีนี้ไม่ได้มีการพัฒนา แก้ไข ดีบัคอย่างต่อเนื่องเลย ไลบรารีนี้ปล่อยออกมาในเวอร์ชันล่าสุด (เวอร์ชัน 0.18) เมื่อเดือนสิงหาคมปีที่แล้ว ซึ่งคิดว่าทีมงานคงไม่ได้พัฒนาต่อ แต่ถ้าเปลี่ยนไปใช้ Tensorflow.js จะดีกว่า เพราะกูเกิ้ลพัฒนาอยู่ตลอด จนตอนนี้อยู่ที่เวอร์ชัน 3 ไปแล้ว และซัพพอร์ตการทำงาน WebGL ได้ดี เพียงแต่ฟังก์ชันอาจจะไม่ครบครันเท่ากับ Tensorflow ที่ทำงานบนไพทอน

ไลบรารีนี้ Commit ล่าสุดก็ 2 ปีไปแล้ว ดูแนวโน้มน่าจะไม่ได้พัฒนาต่อ

ทีมงานที่ดูแลไม่ได้ซัพพอร์ต

จากที่สังเกตในเว็บ Github ของไลบรารีจะพบคนรายงานใน Issue เยอะ แต่ไม่มีทีมงาน และไม่มีคนอื่นมาตอบเลย เลยคิดว่าไลบรารีนี้ไม่น่าจะได้รับการซัพพอร์ตแล้ว ผิดกับ Tensorflow.js ครับ

ใน Issue เจอปัญหาแบบที่เราเจอเลยหลายคน แต่ไม่มีคนมาตอบ

โดยสรุป

ไลบรารี ONNX.js เป็นไลบรารีที่ได้รับการพัฒนาขึ้นจากไมโครซอฟท์ที่ต้องการให้นำโมเดลที่ผ่านการเรียนรู้มาทำงานบนเว็บบราวเซอร์ เรียกใช้งานได้ง่าย แต่ติดปัญหาที่สำคัญ ได้แก่ ไลบรารีไม่ซัพพอร์ตบาง operation โครงการดูไม่ได้รับการพัฒนาต่อ และทีมงานไม่ได้ซัพพอร์ต

เลยมีความเห็นกับไลบรารีตัวนี้ว่าไม่ควรใช้ฮะ แนะนำให้ไปใช้งาน Tensorflow.js ไปใช้งานจะทำให้ชีวิตผู้อ่านดีกว่ามาก เพราะเป็นไลบรารีที่พัฒนาโดยกูเกิ้ล ที่ได้รับการซัพพอร์ตอย่างต่อเนื่อง และมีการพัฒนาอยู่ตลอด นอกเหนือจากนี้ไลบรารีเป็นไลบรารีที่ได้รับการแนะนำให้ใช้งานในงาน Production ได้เลย

สรุปคือ ไปใช้งาน Tensorflow.js ดีกว่า