- Shape Assist ของ Canva คือฟีเจอร์ใน Draw tool ที่ตรวจจับรูปทรงเส้นเดียวซึ่งผู้ใช้วาดแบบสั่น ๆ ภายในเบราว์เซอร์ แล้วแปลงเป็นกราฟิกเวกเตอร์ที่เรียบร้อย
- computer vision heuristic ที่อาศัยกฎและค่า threshold ใช้งานได้กับสี่เหลี่ยม วงกลม และสามเหลี่ยม แต่มีข้อจำกัดเมื่อเจอกับรูปทรงซับซ้อนอย่างก้อนเมฆ ดาว หรือหัวใจ รวมถึงการเพิ่มรูปทรงใหม่
- โมเดลนี้จัดการ stroke ในรูปแบบ ลำดับพิกัด x·y แทนภาพ และเลือกสถาปัตยกรรมแบบ RNN/LSTM กับโค้ด inference แบบคัสตอมแทน CNN เพื่อให้รันบนไคลเอนต์ได้
- โมเดลสุดท้ายประกอบด้วยเลเยอร์ LSTM เดี่ยวและเลเยอร์ Gemm โดยตั้งค่า
P = 25,H = 100,N = 9มีพารามิเตอร์64,109ตัว ขนาดประมาณ 250KB และรันได้ในเวลาไม่ถึง 10ms บนโน้ตบุ๊กรุ่นใหม่ - ระบบทำงานได้โดยไม่ต้องส่งข้อมูลไปกลับกับเซิร์ฟเวอร์ และถูกออกแบบให้แทนที่อัตโนมัติก็ต่อเมื่อผู้ใช้วาดรูปทรงเสร็จแล้วค้างเคอร์เซอร์ไว้นานเกิน 1 วินาที และรูปนั้นตรงกับรูปทรงที่กำหนดไว้มากพอ
บทบาทของ Draw tool และ Shape Assist
- Draw tool ของ Canva ช่วยให้ผู้ใช้เพิ่มภาพวาดที่วาดเองลงในดีไซน์ได้โดยตรง
- Shape Assist ถูกสร้างขึ้นมาเพื่อเปลี่ยนลายเส้นสเก็ตช์ที่มือสั่นให้เป็นกราฟิกเวกเตอร์ที่ลื่นและเรียบร้อยกว่าเดิม
- เนื่องจากเวลาแฝงของการจำแนกเป็นเงื่อนไขสำคัญ จึงเลือกให้ทำงาน ภายในเบราว์เซอร์ แทนการประมวลผลบนเซิร์ฟเวอร์
- ผู้ใช้ได้รับ feedback ทันทีเมื่อวาดรูปทรง
- หลีกเลี่ยงความหน่วงจากการประมวลผลบนเซิร์ฟเวอร์
- ใช้งานแบบออฟไลน์ได้โดยไม่ต้องมีการเชื่อมต่ออินเทอร์เน็ตตลอดเวลา
เหตุผลที่เปลี่ยนจาก heuristic ไปเป็นโมเดล ML
- Shape Assist รุ่นแรกใช้ computer vision heuristic ที่วิเคราะห์คุณสมบัติทางเรขาคณิตของพิกัดที่ผู้ใช้วาด
- ตรวจจับรูปทรงอย่างสี่เหลี่ยม วงกลม และสามเหลี่ยมด้วยกฎและค่า threshold
- พิกัดถูกวิเคราะห์เป็นจุดในระบบพิกัดคาร์ทีเซียน
- แม้จะใช้ได้กับการรู้จำรูปทรงพื้นฐาน แต่ก็ยากที่จะเพิ่มรูปทรงใหม่หรือรองรับรูปทรงที่ซับซ้อนกว่า
- เวอร์ชันแรกจำกัดอยู่ที่รูปทรงที่วาดได้ด้วย single stroke
- รายการรูปทรงที่เสนอมีทั้งก้อนเมฆ ดาว และหัวใจ ซึ่งจัดการด้วย heuristic ได้ยาก
- โมเดล ML สามารถเรียนรู้สไตล์และความแปรผันที่หลากหลายจากชุดข้อมูลภาพวาดมือของผู้ใช้ จึงช่วยขยายความสามารถของ Shape Assist ไปไกลกว่ารูปทรงเรขาคณิตแบบง่าย
ข้อมูลภาพวาดมือและการแทนค่าแบบพิกัด
- Canva รวบรวมข้อมูลภาพวาดมือของผู้ใช้ด้วย UI แบบง่ายสำหรับวาดรูปทรง single stroke
- แต่ละ stroke ถูกบันทึกเป็น ลำดับพิกัด x·y
- วิธีนี้ยืดหยุ่นกว่าในการทำ preprocessing และ data augmentation เมื่อเทียบกับการเก็บรูปทรงเป็นภาพไบนารี
- ถ้าเป็นแบบภาพ จะทำ spatial augmentation อย่างการพลิก หมุน และ shear ได้
- ถ้าเป็นแบบพิกัด จะทำ augmentation อย่างการลบพิกัดแบบสุ่ม การเพิ่มความสั่นให้ตำแหน่งจุดแบบสุ่ม หรือการกลับลำดับจุดได้ด้วย
- แม้จะรวบรวมชุดข้อมูลได้มากพอจากอาสาสมัคร แต่ภาพวาดของวิศวกรและดีไซเนอร์ก็ไม่ได้สะท้อนผู้ใช้ Canva โดยเฉลี่ยได้ดีนัก
- วิศวกร ML มักให้ข้อมูลเชิง adversarial
- ภาพวาดของดีไซเนอร์สวยเกินไป จนบางคนถูกขอให้วาดด้วยมือข้างที่ไม่ถนัด
- หลังให้แนวทางและความคาดหวังที่เข้มงวดขึ้น ก็สามารถรวบรวมชุดข้อมูลขนาดใหญ่ได้
การออกแบบโมเดลและวิธีการฝึก
- โมเดลต้องรันบนไคลเอนต์และต้องไม่กระทบเวลาโหลดหน้า จึงจำเป็นต้องทำให้ขนาดเล็กที่สุด
- Canva ทดลองใช้ RNN ที่ใช้พิกัด x·y ของ stroke โดยตรง แทน CNN ที่ต้องแปลงจุดให้เป็นพิกเซลก่อน
- มีการทำ hyperparameter search เพื่อหาเซ็ตคุณสมบัติของโมเดลที่เหมาะที่สุด
- ปรับพารามิเตอร์อย่างขนาดอินพุต จำนวนเลเยอร์ และจำนวนฟีเจอร์ของ hidden state
- ผู้ใช้แต่ละคนวาดด้วยความเร็วต่างกัน ทำให้แม้เป็นรูปทรงเดียวกัน ความยาวของรายการจุดก็ไม่เท่ากัน
- คนวาดช้าจะทิ้งจุดไว้มากกว่า
- คนวาดเร็วจะทิ้งจุดไว้น้อยกว่า
- แม้จะตรึงจำนวนจุดให้คงที่ด้วย linear interpolation ตามช่วงที่กระจายเท่า ๆ กันได้ แต่ก็ทำให้จุดสำคัญบางจุดหายไปและสูญเสียรายละเอียด
- แทนที่จะทำเช่นนั้น Canva ได้พัฒนาวิธีดัดแปลงจาก อัลกอริทึม Ramer-Douglas-Peucker
- RDP เป็นอัลกอริทึมทำให้เส้นโค้งง่ายขึ้นโดยลดจำนวนจุดลง แต่ยังคงรายละเอียดสำคัญของเส้นโค้งไว้
- มันลบจุดที่ไม่ได้เบี่ยงเบนจากเส้นโค้งที่ถูกทำให้ง่ายลงอย่างมีนัยสำคัญออกแบบ recursive
วิธีจำแนกเพื่อลดการแทนที่อัตโนมัติผิดพลาด
- Shape Assist ต้องไม่แทนที่อัตโนมัติหากภาพวาดมือไม่ได้คล้ายกับคลาสที่กำหนดไว้ล่วงหน้าคลาสใดมากพอ
- เนื่องจากมีได้เพียงรูปทรงเดียวที่เป็นคำตอบถูกต้อง การใช้ softmax activation กับ cross-entropy loss จึงดูเป็นตัวเลือกที่เหมาะสม
- ถ้าความเชื่อมั่นของคลาสที่มีความน่าจะเป็นสูงสุดต่ำกว่าค่า threshold ก็ปฏิเสธการทำนาย
- แต่แนวทางนี้มีปัญหาที่โมเดลยังแสดงความเชื่อมั่นสูงแม้จะทำนายผิด
- สุดท้ายจึงฝึกให้เป็นตัวจำแนกแบบ multi-class, multi-label ที่ใช้ sigmoid activation สำหรับแต่ละคลาสเอาต์พุต
- หากไม่มีคลาสใดเกิน threshold ก็จะปฏิเสธการทำนาย
สถาปัตยกรรม inference ฝั่งไคลเอนต์
- ปกติโมเดล ML มักมีขนาดใหญ่และใช้การคำนวณมาก จึงมักรันบนคอมพิวเตอร์ประสิทธิภาพสูงในคลาวด์
- แต่โมเดล Shape Assist มีขนาดเล็กและใช้การคำนวณทางคณิตศาสตร์ไม่มาก จึงสามารถรันกระบวนการทั้งหมดภายในแอปพลิเคชันฝั่งไคลเอนต์ได้
- วิธีนี้ทำให้ไม่ต้องพึ่งการเชื่อมต่อกับเซิร์ฟเวอร์ และตัดเวลาไปกลับกับเซิร์ฟเวอร์ออก จึงรู้จำรูปทรงได้แทบจะทันที
สถาปัตยกรรมโมเดลและขนาด
- โมเดลสุดท้ายใช้โครงสร้างที่มีเลเยอร์ LSTM เดี่ยวตามด้วยเลเยอร์ Gemm
- Gemm เรียกได้อีกอย่างว่าเลเยอร์ Dense หรือ Fully Connected
- ค่าตั้งต้นหลักมีดังนี้
- จำนวนจุดหลัง interpolation:
P = 25 - hidden size:
H = 100 - จำนวนรูปทรงที่กำหนดไว้ล่วงหน้า:
N = 9
- จำนวนจุดหลัง interpolation:
- จำนวนพารามิเตอร์คำนวณได้ดังนี้
- LSTM:
4H * 2 + 4H * H + 8H = 41,600 - Gemm:
P * H * N + N = 22,509 - รวม:
64,109
- LSTM:
- หากคิดตามมาตรฐาน IEEE754 แบบ floating point 32 บิตที่ใช้ 4 ไบต์ต่อพารามิเตอร์ โมเดลจะมีขนาดประมาณ 250KB
- ใกล้เคียงกับภาพ 360p 16:9 แบบไม่บีบอัด 1 ภาพ
- หากเก็บพารามิเตอร์ด้วยความละเอียดต่ำกว่านี้ก็อาจลดขนาดลงได้อีก
- Canva เลือก implement การคำนวณ LSTM และ Gemm ด้วย TypeScript โดยตรง แทนการใช้ ML engine แบบทั่วไป
- เป็นแนวทางที่อาจไม่ generalize ได้ดีกับโมเดลที่ซับซ้อนกว่านี้
- โค้ดมีน้อยกว่า 300 บรรทัด
- รันได้ในเวลาไม่ถึง 10ms บนโน้ตบุ๊กรุ่นใหม่
การแทนที่รูปทรงและการจัดแนว
- หลังจากโมเดลตัดสินรูปทรงที่วาดด้วยมือแล้ว Canva ใช้วิธี template matching เพื่อจัดแนว path ของภาพวาดมือให้ตรงกับการแสดงผลแบบเวกเตอร์กราฟิก
- กระบวนการจัดแนวทำหลังจาก normalize รูปทรงอินพุตและรูปทรงเทมเพลตแล้ว
- หมุนรูปทรงเทมเพลตทีละ 15° เพื่อทดสอบ
- คำนวณโมเมนต์อันดับหนึ่งและอันดับสองของจุดอินพุตในปริภูมิพิกัดที่หมุนแล้ว
- คำนวณค่าความไม่คล้ายกันระหว่างจุดอินพุตกับรูปทรงเทมเพลต
- เลือกมุมหมุนที่มีค่าความไม่คล้ายกันต่ำที่สุดเป็นมุมที่เหมาะสมที่สุด
- เมื่อผู้ใช้วาดรูปทรงเสร็จและค้างเคอร์เซอร์ไว้กับที่อย่างน้อย 1 วินาที หากรูปนั้นตรงกับรูปทรงที่กำหนดไว้ล่วงหน้ามากพอ Shape Assist ก็จะเปลี่ยนรูปทรงให้อัตโนมัติ
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
สำหรับปัญหานี้ เครือข่ายประสาทแบบวนกลับ (RNN) ดูจะเกินความจำเป็น และ $1 unistroke recognizer ที่เรียบง่ายและงดงามน่าจะเหมาะกว่า
แค่ฝึกด้วยตัวอย่างหนึ่งตัวอย่างต่อเจสเจอร์ก็ทำงานได้ค่อนข้างดี และไม่ว่าโปรเจกต์ไหนก็สามารถเอาไปใส่เพิ่มการรู้จำเจสเจอร์เพื่อทำให้ UI เป็นมิตรขึ้นได้ภายในบ่ายเดียว
ถ้าตัวอักษรแต่ละตัวเป็นเส้นเดียว ก็ทำงานได้ค่อนข้างเสถียรกับการป้อนข้อความแบบ Graffiti สไตล์ Palm ด้วย และบทความต้นฉบับก็เขียนให้อ่านง่ายและเข้าใจได้ดี
https://depts.washington.edu/acelab/proj/dollar/index.html
เช่น เวลาวาดวงกลมต้องวาดทวนเข็มนาฬิกา และถ้าวาดตามเข็มนาฬิกาซึ่งรู้สึกเป็นธรรมชาติกว่า ก็จะถูกมองว่าเป็นเครื่องหมาย caret
ในบริบทของการวาดอิสระที่ผู้ใช้ไม่รู้รายละเอียดการทำงานภายใน จึงใช้งานจริงได้ยาก
เปเปอร์ที่ลิงก์ไว้[0] พูดถึงอัตราข้อผิดพลาด และแค่เพิ่มตัวอย่างอีกไม่กี่ตัวอย่างก็ปรับปรุงได้ค่อนข้างเร็ว
[0]https://faculty.washington.edu/wobbrock/pubs/uist-07.01.pdf , หน้า 8
สี่เหลี่ยมที่ฉันวาดถูกจำเป็น caret ส่วนเส้นซิกแซกถูกจำเป็นวงเล็บปีกกา
และไม่รองรับ รูปทรงที่วาดด้วยสองเส้น อย่างลูกศรด้วย
ลองเทียบรูปตัวอย่าง “delete” กับ “x” จะเห็นได้ดีว่าประสิทธิภาพแย่แค่ไหน
อาจพอใช้เป็นจุดเริ่มต้นของอินเทอร์เฟซแบบเจสเจอร์ที่คาดหวังให้วาดรูปทรงแบบเดียวกันทุกครั้ง แต่ไม่ค่อยเหมาะกับกรณี การทำไดอะแกรม ที่พูดถึงในที่นี้
เคยทำ ES6 implementation เป็นโปรเจกต์มหาวิทยาลัย ถ้าสนใจก็อยู่ที่นี่: https://github.com/gurgunday/onedollar-unistroke-es6
เข้าใจคำอธิบายที่ว่า “แม้แต่เส้นตรงธรรมดาที่ลากด้วยเมาส์หรือแทร็กแพดก็อาจดูเหมือนเส้นทางที่กระรอกเมาเดินผ่าน” แต่ไม่แน่ใจว่าใน Canva ใครบ้างที่ต้องวาดรูปทรงเองด้วยเมาส์
เมื่อก่อน Miro เคยมีฟีเจอร์ที่ถ้าวาดดาวแบบคร่าว ๆ ด้วยเมาส์ มันจะเปลี่ยนเป็นดาว วงกลม สามเหลี่ยม ฯลฯ ที่ถูกต้องตามเรขาคณิต ซึ่งผมคิดว่าเจ๋งดี แต่ในทางปฏิบัติไม่เคยต้องใช้เลยสักครั้ง
เวลาทำไดอะแกรม การใช้รูปทรงที่เตรียมไว้ล่วงหน้ามักเร็วกว่า ส่วนเวลาทำไอคอนก็จะใช้เวิร์กโฟลว์แยกที่เน้น Boolean operation การย้ายจุด และเครื่องมือ Pen โดยปกติใช้โปรแกรมเฉพาะทางอย่าง Illustrator
เวลาวาดภาพประกอบจริง ๆ ก็หยิบแท็บเล็ตมาใช้ ดังนั้นแม้เทคโนโลยีจะเจ๋ง แต่ก็สงสัยว่า use case คืออะไร
มีไลบรารีแอสเซ็ตขนาดใหญ่มาก และมีภาพนับล้าน หรืออาจถึงหลักสิบล้าน ทั้งภาพถ่ายและกราฟิกเวกเตอร์
จากประสบการณ์ที่เคยใช้แบบจำกัด สิ่งที่น่ารำคาญเป็นพิเศษคือแม้จะรู้แน่ชัดอยู่แล้วว่าต้องการรูปทรงเรียบง่ายแบบไหน ก็ยังต้องค้นหาในไลบรารีที่ไม่มีที่สิ้นสุด เครื่องมือนี้จึงน่าจะตั้งใจลดความเจ็บปวดนั้น
เคยทำงานที่ Canva เมื่อไม่กี่ปีก่อน
ไม่มีข้อมูลภายในเลย แต่ Canva อยากเป็นเครื่องมือทำไดอะแกรมที่แข่งขันได้ด้วย ดังนั้น use case นี้อาจสำคัญ อย่างไรก็ตามน่าจะมีข้อจำกัดว่าไม่สามารถเปลี่ยนประสบการณ์ออกแบบของผู้ใช้ปัจจุบัน 99% ได้อย่างสิ้นเชิง
แม้รูปทรงจะอยู่ตรงหน้าโดยไม่ต้องผ่านเมนู การใช้เคอร์เซอร์เดียววาดทั้งหมดก็อาจเร็วกว่าการวางและปรับขนาดไอคอนหลายอัน จากนั้นสลับไปฟังก์ชันลูกศรเพื่อเพิ่มลูกศร
ไลบรารีที่ Canva ใช้สำหรับการวาดเส้นก็น่าสนใจเช่นกัน: https://github.com/steveruizok/perfect-freehand
ตรงส่วนที่บอกว่า “ได้พัฒนาเวอร์ชันดัดแปลงของอัลกอริทึม Ramer-Douglas-Peucker (RDP)” ทำให้นึกถึงไซด์โปรเจกต์เก่า
ในการบรรยาย Strange Loop ปี 2018 เคยนำ Douglas-Peucker ไปใช้กับ Picasso
Picasso's Bulls: Deconstructing his design process with Python
https://rrherr.github.io/picasso/
ชวนสงสัยว่าเมื่อกว่า 20 ปีก่อน Macromedia Flash ทำสิ่งที่คล้ายกันได้อย่างไร
ตอนนั้นประสิทธิภาพ CPU จำกัดกว่าตอนนี้มาก แต่ยังจำได้ชัดว่าเคยทึ่งตอนเห็นมันปรับเส้นโค้งให้เนียนขึ้นเวลาวาดเส้นโค้งอิสระ
ถึงอย่างนั้น การทำให้มันทำงานได้เบาและเร็วในเบราว์เซอร์ก็ยังถือเป็นความสำเร็จอยู่ดี สุดท้ายสิ่งสำคัญก็ยังเป็นประสบการณ์ผู้ใช้เสมอ
https://en.wikipedia.org/wiki/MessagePad#User_interface
เช่น ถ้าวาดเส้นเกือบตรงแล้วเกิดจุดควบคุม 100 จุด ซอฟต์แวร์ก็จะลดมันลงเหลือประมาณ 4 จุด
พอวาดเสร็จแล้วก็น่าจะเอาจุดชุดเดิมมาเป็นอินพุต แล้ววาดเส้นใหม่ด้วย อัลกอริทึมเส้นโค้งสไพลน์
การคำนวณเพื่อวาดสไพลน์เองไม่ได้ยากกว่ามากนัก แต่ประเด็นสำคัญคือเมื่อเพิ่มจุดหนึ่งจุดที่ปลายเส้น บางส่วนของเส้นที่วาดไปแล้วจะเปลี่ยนไป
แบบนั้นก็ต้องวาดทุกอย่างที่อยู่หลังเส้นนั้นใหม่ทั้งหมด ทำให้มีต้นทุนการคำนวณสูง และยากจะรับประกันได้ว่าจะประมวลผลที่ 60fps ได้แน่นอน
เป็นบทความที่ดี และงานก็น่าสนใจมาก
อาจเป็นรสนิยมเฉพาะกลุ่ม แต่แปลกที่ผมรู้สึกชอบ อารมณ์เส้นขยุกขยิกสั่น ๆ แบบวาดมือ มากกว่ากราฟิกเวกเตอร์ที่เนียนกริบ
แน่นอนว่าความชอบอาจเปลี่ยนไปตามบริบท ดังนั้นตัวฟีเจอร์เองก็ยังเจ๋งอยู่ดี ในโลกที่เต็มไปด้วยความสมบูรณ์แบบแบบประดิษฐ์ มีบางอย่างที่ดึงดูดเราโดยเนื้อแท้ในผลงานวาดมือจริง ๆ
ถ้าจะทำฟีเจอร์แบบนี้ ก็อยากให้ทำให้ เลือกเปิดปิดได้ และเมื่อเปิดอยู่ก็ให้เห็นชัดเจน
ถ้าเครื่องมือทำตัวเหมือนฉลาดเกินไปแต่ทายไม่ถูกเป๊ะ ๆ มันน่าหงุดหงิดมาก ผมเองก็เคยทำพลาดแบบนั้นมาแล้ว
ก่อนกระแส machine learning/AI ช่วงหลัง ๆ อยู่หลายปี มีเกมชื่อ Scribblenauts ที่เด็ก ๆ ชอบ ซึ่งเปลี่ยนภาพขีดเขียนหยาบ ๆ ให้กลายเป็นวัตถุหลากหลายอย่างน่าทึ่ง
ไม่รู้ว่าทำได้อย่างไร แต่ผมเองก็ทึ่ง และเด็ก ๆ ก็มองว่ามันเหมือนเวทมนตร์
https://store.steampowered.com/app/218680/Scribblenauts_Unli...
อยากให้สิ่งนี้เป็น โอเพนซอร์ส
ช่วงหลังมีโมเดลขนาดเล็กออกมาหลายตัว โมเดลนี้มีขนาด 250KB และในงานง่าย ๆ อย่างการ fine-tune โมเดลขนาดใหญ่ ก็เคยมีโมเดลประมาณ 50KB ด้วย
ตั้งตารอช่วงเวลาที่เราจะสามารถนำโมเดลเล็ก ๆ กลับมาใช้จริงในแอปพลิเคชันที่มีประโยชน์ได้อีกครั้ง
ดาวห้าแฉกแบบ pentagram กับดาวประกายแวววาวไม่ใช่สิ่งเดียวกัน นี่เป็นตัวอย่างของ underfitting หรือเปล่า?