2 คะแนน โดย GN⁺ 2024-05-10 | 2 ความคิดเห็น | แชร์ทาง WhatsApp
  • โปรเจกต์ค้นหา แผนที่ และวิเคราะห์ที่รวบรวมไอเท็มมากกว่า 40 ล้านรายการจาก Hacker News public API แล้วแนบ embedding, metadata และเนื้อหา ให้กับความคิดเห็นมากกว่า 30 ล้านรายการและโพสต์ 4 ล้านรายการ
  • แนวทางแรกที่ทำ embedding เฉพาะชื่อเรื่องมีข้อจำกัดจากชื่อเรื่องที่กำกวมและอคติจาก Ask HN/Show HN จึงเปลี่ยนมาใช้เนื้อหาของเว็บเพจที่ลิงก์ ความคิดเห็นยอดนิยม และบริบทของความคิดเห็นบรรพบุรุษร่วมกัน
  • เมื่อสเกลการประมวลผลใหญ่ขึ้น จึงผสาน GPU ประมาณ 150 ตัวของ RunPod, บริการคิวที่เขียนด้วย Rust, HTTP/2 DB proxy, UMAP, การเรนเดอร์ด้วย Canvas และ edge server และหลังเปลี่ยนโมเดล เวลา embedding ต่ออินพุตลดจากประมาณ 600ms เหลือ 6ms
  • การจัดอันดับผลค้นหาไม่ได้ใช้การตรงกันของสตริงแบบง่าย ๆ แต่ใช้ cosine similarity, คะแนน HN และน้ำหนักตามเวลาร่วมกัน เพื่อสะท้อนความเกี่ยวข้องเชิงความหมาย สัญญาณทางสังคม และความใหม่
  • เดโมสาธารณะมีเฉพาะข้อมูลถึงราววันที่ 10 เมษายน 2024 ส่วนข้อมูลทั้งหมดและโค้ดเปิดเผยบน GitHub เพื่อใช้กับการทดลองด้านการค้นหา การแนะนำ การวิเคราะห์ผู้ใช้ และการอัปเดตแบบเรียลไทม์

ขอบเขตโปรเจกต์และข้อมูลที่เปิดเผย

  • สร้างแผนที่ที่วางโพสต์ทั้งหมดของ Hacker News ไว้ใน พื้นที่เชิงความหมาย พร้อมสร้างเครื่องมือค้นหา วิเคราะห์ และแสดงภาพประกอบกัน
  • จุดเริ่มต้นคือการทดลอง text embedding และเลือก HN เป็นชุดข้อมูลที่เหมาะสม เพราะมีคอนเทนต์ที่คัดสรรมาจำนวนมาก และให้เข้าถึงคอนเทนต์ทั้งหมดได้แบบโปรแกรม
  • embedding แทนข้อความเป็นจุดในปริภูมิมิติสูง โดย ระยะห่างสัมพัทธ์ระหว่างจุดต่าง ๆ มีประโยชน์มากกว่าตำแหน่งสัมบูรณ์
  • การใช้งานที่คาดหวังมี 3 อย่าง
    • การค้นหาเชิงความหมายในคอนเทนต์ที่สะสมไว้ของ HN
    • คำแนะนำแบบปรับให้เหมาะกับพื้นที่ความสนใจ
    • การวิเคราะห์อารมณ์ ความนิยม และมุมมองคัดค้านแยกตามหัวข้อในชุมชน
  • ความคิดเห็นมากกว่า 30 ล้านรายการและโพสต์ 4 ล้านรายการถูกเผยแพร่เป็น ชุดข้อมูลรีลีส
    • รวม metadata เช่น ID, คะแนน และผู้เขียน
    • รวม embedding
    • รวมข้อความความคิดเห็นและข้อความเว็บเพจที่ครอลมา
  • โค้ดเปิดเผยใน hackerverse GitHub repository

การรวบรวมข้อมูล Hacker News

  • HN มี public API แบบเรียบง่าย และอ็อบเจกต์ทั้งหมดถูกดึงในรูป item
  • maxitem.json ให้ ID ที่ใหญ่ที่สุด และ ณ เวลาที่เขียน ID สูงสุดเกิน 40 ล้านแล้ว
  • แม้เวลาตอบสนองเฉลี่ยจะอยู่ที่ 10ms แต่หากครอล 40 ล้านรายการตามลำดับจะใช้เวลามากกว่า 4 วัน จึงจำเป็นต้องมี การประมวลผลแบบขนาน
  • สร้างบริการรวบรวมข้อมูลความเร็วสูงด้วย Node.js แต่แนวทาง semaphore และคิว Promise ช้า เพราะเวลาของ CPU ส่วนใหญ่ถูกใช้กับโค้ด JS ใน user space
  • ต่อมาใช้ API worker_threads กระจายงาน fetch ไปยัง CPU ทั้งหมด และปรับปรุงประสิทธิภาพด้วยการทำให้ทุกคอร์ทำงานเต็มที่
  • การรวบรวมแบบขนานทำให้ลำดับสลับกัน ดังนั้นเพื่อไม่ให้มีรายการตกหล่นเมื่อหยุดกลางคัน จึงบันทึก marker ของรายการที่เสร็จแล้วตามลำดับ ID
  • มีคุณลักษณะบางอย่างที่สังเกตได้จาก HN API ด้วย
    • คะแนนดูเหมือนจะไม่ลดต่ำกว่า -1
    • ไม่สามารถดึง downvote ของโพสต์และจำนวนโหวตของความคิดเห็นได้
    • โพสต์และความคิดเห็นบางส่วนไม่มีชื่อเรื่อง ข้อความ หรือ URL แม้จะไม่ได้อยู่ในสถานะถูกลบหรือถูก flag
    • ID ความคิดเห็นอาจน้อยกว่าบรรพบุรุษ ซึ่งอาจเกิดจากการย้าย comment tree
  • HN crawler ยังถูกแยกเป็นโปรเจกต์ TypeScript อีกตัวชื่อ crawler-toolkit-hn

embedding ครั้งแรกและโครงสร้างพื้นฐาน

  • ตอนแรกมองว่าการใช้เฉพาะชื่อเรื่องโพสต์ก็น่าจะเพียงพอสำหรับการแทนความหมาย จึงสร้าง embedding จากส่วนนี้
  • การเปรียบเทียบโมเดลอ้างอิงจาก Massive Text Embedding Benchmark และโมเดลแรกที่เลือกคือ BGE-M3
  • BGE-M3 นอกจากสร้าง dense embedding ทั่วไปแล้ว ยังสร้าง lexical weights ได้ด้วย จึงใช้กับการค้นหาแบบ hybrid ที่ผสมกับแนวทางอย่าง BM25 ได้
  • โครงสร้างพื้นฐานสำหรับสร้าง embedding ไม่ได้เรียบง่าย
    • โมเดลที่ดีอาจมีพารามิเตอร์ตั้งแต่หลายร้อยล้านถึงหลายพันล้านตัว
    • ทำงานบน GPU ได้มีประสิทธิภาพกว่ามาก แต่คลัสเตอร์ GPU มีค่าใช้จ่ายสูง
    • หาก inference ใช้เวลาหลายร้อย ms ต่ออินพุต การประมวลผลอินพุต 40 ล้านรายการด้วย GPU เดี่ยวแทบจะอยู่ในระดับ 1 ปี
    • ข้อมูล/เซิร์ฟเวอร์อยู่ห่างจาก GPU จึงต้องรักษา pipeline ไว้ไม่ให้ GPU ว่างงาน
  • ใช้ RunPod เพื่อ deploy เครื่อง GPU ที่รันใน data center เป็น container และใช้ GPU ที่ค่อนข้างประหยัดอย่าง RTX 4090
  • เมื่อ GPU กระจายอยู่ทั่วโลก latency ของการเชื่อมต่อ DB และ overhead ของ connection กลายเป็นปัญหา จึงสร้าง db-rpc
    • proxy คำสั่ง SQL query ไปยัง DB ในเครื่องผ่าน HTTP/2
    • ใช้ shared connection pool ขนาดใหญ่
    • ประมวลผลหลาย query บนการเชื่อมต่อเดียวด้วย HTTP/2 multiplexing
  • AWS SQS มีข้อจำกัดด้านอัตราความเร็วต่ำและค่าใช้จ่ายต่อข้อความเป็นภาระสำหรับข้อความงานขนาดเล็กหลายล้านรายการ จึงสร้างบริการคิวด้วย Rust บน RocksDB ชื่อ queued
    • ประมวลผลได้ 100K+ op/s บน node เดียว
    • ลดภาระจาก batching, ขนาดข้อความ, rate limit และค่าใช้จ่าย
  • หลังขยายไปถึง GPU ประมาณ 150 ตัว ก็ทำ embedding ให้โพสต์และความคิดเห็น 40 ล้านรายการได้ภายในไม่กี่ชั่วโมง
  • เวลานั้นต้นทุนการทำ embedding ต่ออินพุตอยู่ที่ประมาณ 600ms และอัตราการใช้งาน GPU อยู่ในระดับสูงตลอดช่วงเวลา

เสริมบริบทด้วยการครอลเว็บเพจ

  • แนวทางทำ embedding จากชื่อเรื่องอย่างเดียวไม่เพียงพอ
    • โพสต์จำนวนมากมีชื่อเรื่องแปลก สร้างสรรค์ หรือกำกวม
    • วลี Ask HN และ Show HN กินสัดส่วนมากในชื่อเรื่องทั้งหมด ทำให้มีแนวโน้มถูกจัดคลัสเตอร์ร่วมกันโดยไม่เกี่ยวกับหัวข้อ
  • สำหรับโพสต์แบบข้อความและความคิดเห็นสามารถใช้ข้อความของตัวเองได้ แต่โพสต์แบบลิงก์ส่วนใหญ่ต้องครอลเว็บเพจที่เชื่อมโยงอยู่
  • ใช้บริการ Rust ดึง URL และ parse metadata เช่น ชื่อเรื่อง รูปภาพ ผู้เขียน และข้อความเนื้อหาจาก HTML
  • เวอร์ชัน Node.js แรกช้ากว่าเวอร์ชัน Rust 10 เท่าในงานที่ใช้ CPU หนัก และปรับปรุงประสิทธิภาพด้วยการเขียนใหม่เป็น Rust
  • การสกัดข้อความใช้ scraper parse HTML จากนั้นลบองค์ประกอบ HTML5 ที่ไม่ใช่เนื้อหาหลักตามความหมาย แล้ววนผ่าน tree ที่เหลือ
  • link rot ก็มีมากเช่นกัน
    • URL ประมาณ 200,000 รายการล้มเหลวจาก 404, DNS lookup ล้มเหลว และ connection timeout
    • คิดเป็นน้อยกว่า 5% จาก 4 ล้านหน้า
  • เพื่อลดข้อมูลที่ขาดหาย จึงดึงบทความเก่าบางส่วนด้วย Wayback API ของ Internet Archive
    • rate limit ของ Internet Archive ต่ำมาก อยู่ที่ประมาณ 5 รายการต่อนาที

กลยุทธ์ embedding ครั้งที่สอง

  • เว็บเพจมีความยาว แต่ BGE-M3 รองรับ context window 8192 token
  • อย่างไรก็ตาม BGE-M3 ช้า จึงเปลี่ยนเป็น jina-embeddings-v2-small-en
    • จำนวนพารามิเตอร์น้อยกว่ามาก
    • ประสิทธิภาพตาม MTEB ก็อยู่ในเกณฑ์ดี
    • เวลา inference ลดเหลือประมาณ 6ms เร็วขึ้น 100 เท่า
  • เนื่องจากอินพุตยาว การเพิ่ม batch size ทำให้เกิด OOM จึงไม่สามารถทำให้ GPU ทำงานเต็มที่ได้ทั้งหมด
  • เพื่อชดเชยหน้าที่มีข้อความน้อยหรือดึงไม่ได้ จึงเพิ่มความคิดเห็นยอดนิยมของ HN ต่อท้ายเนื้อหาของโพสต์
    • ใช้ความคิดเห็นระดับบนโดยถือว่า item.kids ถูกจัดอันดับไว้แล้ว
    • ตัดความคิดเห็นที่ถูกลบ dead หรือมีคะแนนติดลบออก
    • จำกัดอินพุตสูงสุดไว้ที่ 64KiB
  • ความคิดเห็นอาจมีความหมายไม่เพียงพอเมื่ออยู่เดี่ยว ๆ จึงสร้างบริบทที่ยาวขึ้นโดยย้อนขึ้นไปถึงความคิดเห็นบรรพบุรุษและชื่อเรื่องของโพสต์
  • ค่าขนาดใหญ่อย่าง embedding และข้อความถูกเก็บไว้ในตาราง kv แยกต่างหาก
    • หากเก็บรวมในแถวเดียวกัน แถวจะอ้วนขึ้น
    • แม้การอัปเดตคอลัมน์เล็ก ๆ ก็จะแพงขึ้น
    • การเปลี่ยน schema ก็จะแพงขึ้น

สร้างแผนที่ความหมายแบบ 2D ด้วย UMAP

  • UMAP เป็นเทคนิคการลดมิติที่พยายามรักษาความสัมพันธ์เชิงความหมายไว้ ขณะลด embedding มิติสูงให้เหลือมิติต่ำ
  • ลดเวกเตอร์ embedding ขนาด 1024 มิติให้เป็นจุด 2D เพื่อใช้กับ scatter plot และการแสดงผลเป็นแผนที่
  • UMAP รับกราฟ PyNNDescent และ embedding ต้นฉบับเป็นอินพุต โดยใช้ metric="cosine", n_components=2
  • การเรียนรู้จากอินพุตมิติสูงจำนวนหลายล้านรายการใช้เวลานาน จึงใช้ VM c7i.metal-48xl บน EC2
    • ใช้โปรเซสเซอร์ 96 คอร์อย่างเต็มที่
    • หลังจากประมาณ 1 ชั่วโมง 30 นาที ก็ได้เมทริกซ์ 2D ออกมา
  • บันทึก embedding 2D ที่สร้างขึ้นและโมเดล UMAP ที่ฝึกแล้วไว้ เพื่อให้สามารถแปลง embedding ใหม่ในภายหลังได้โดยไม่ต้องฝึกใหม่
  • scatter plot แรกมีจุดมากเกินไป จึงลดความหนาแน่นด้วยการเลือกเฉพาะโพสต์คะแนนสูงสุดในแต่ละเซลล์กริด แล้วแสดงชื่อเรื่อง
  • ใน embedding ชุดที่สองซึ่งใส่บริบทมากขึ้น โพสต์ที่จัดวางได้ยากหากดูจากชื่อเรื่องเพียงอย่างเดียว ถูกวางใกล้คอนเทนต์ที่เกี่ยวข้องได้แม่นยำขึ้น

Cosine similarity และการจัดอันดับค้นหา

  • แก่นของการใช้ embedding คือการหา ความคล้ายกัน ระหว่าง embedding สองตัว
  • ใน text embedding มักใช้ cosine distance/ similarity มากกว่า Euclidean distance ทั่วไป
  • cosine distance มีประโยชน์ในกรณีที่ทิศทางสำคัญกว่าขนาด
    • การสนทนายาวเกี่ยวกับ X ควรคล้ายกับ X มากกว่าการสนทนายาวเกี่ยวกับ Y
    • หากนำขนาดมาคิดด้วย ความสัมพันธ์เช่นนี้อาจทำให้เข้าใจผิดได้
  • การคำนวณหลักที่ใช้คือ dot product ระหว่างเมทริกซ์ embedding กับ embedding ของคิวรี
  • หากเวกเตอร์เป็น unit vector ก็ไม่จำเป็นต้องหารด้วยขนาดเพิ่มเติม
  • ผลการค้นหาไม่ได้เรียงลำดับด้วยความคล้ายล้วน ๆ
    • cosine similarity เป็นปัจจัยใหญ่ แต่ไม่ใช่ปัจจัยเดียว
    • คะแนน HN ถูกใช้เป็น social proof
    • time weighting ถูกสะท้อนเป็นปัจจัยลบที่แปรผันตาม log(age) เพื่อให้คอนเทนต์เก่าถูกดันลงอย่างรวดเร็วในคิวรีที่ความสดใหม่สำคัญ

แอปแผนที่บนเบราว์เซอร์

  • เป้าหมายคือทำให้พื้นที่ embedding ของ HN เป็น แผนที่แบบโต้ตอบได้ ที่สำรวจได้เหมือน Google Maps
  • พฤติกรรมที่ต้องการนั้นชัดเจน
    • เมื่อซูมเข้าด้วยการ pinch หรือ scroll wheel ของเมาส์ จะมีจุดแสดงมากขึ้น
    • ระยะห่างระหว่างจุดก็ขยายตามไปด้วย
    • บางจุดมี label แต่ไม่ได้ติด label ให้ทุกจุด
    • เมื่อคลิกจุด จะแสดงรายละเอียดโพสต์
    • รองรับทั้ง touch และเมาส์บนมือถือและเดสก์ท็อป
  • การส่งทุกจุดไปยัง client ในครั้งเดียวไม่เหมาะสม เพราะมีจำนวนหลายล้านจุด
  • ใช้โครงสร้างที่แบ่งพื้นที่แผนที่เป็น tile แบบกริด และให้ client ดึงเฉพาะ tile ที่ต้องใช้
    • tile ระบุได้ด้วยพิกัด (x, y)
    • สามารถเก็บใน KV storage เช่น S3 ได้
    • deploy ได้ง่ายโดยไม่ต้องมี logic ฝั่ง server
  • ระดับการซูมจัดการด้วยวิธี LOD
    • ในแต่ละระดับ จะแบ่งเป็นเซลล์กริดตามแกนมากขึ้น 2 เท่า
    • จุดที่ถูกเลือกในระดับก่อนหน้าจะถูกคัดลอกไปยังระดับถัดไปด้วย เพื่อไม่ให้จุดหายไปเมื่อซูมเข้า
  • ตั้งเป้าให้ขนาด tile หลังบีบอัดต่ำกว่า 20KiB
    • จำกัดไว้ที่ประมาณ 1,500 จุด
    • ใช้ (x, y) 8 ไบต์ต่อจุด, ID 4 ไบต์, คะแนน 2 ไบต์
  • ในการเรนเดอร์เว็บแอป วิธีใช้ DOM element หลายพันรายการทำให้ประสิทธิภาพแย่ลงมาก
  • implementation สุดท้ายใช้ Canvas และวาดใหม่ทุกครั้งที่ viewport อัปเดต
    • แม้จะวาดจุดหลายพันจุดใหม่ทุกเฟรม ก็ยังทำงานได้ลื่นและเรียบง่าย
  • การติด label ทำโดยเลือกโพสต์คะแนนสูงสุดซ้ำ ๆ แต่ตัดออกหากทับกับ label ที่มีอยู่
    • การตรวจ collision ใช้ implementation R-tree ของ RBush
    • ความยาว label ประมาณด้วยอาร์เรย์ไบต์ของความยาวชื่อเรื่องและสูตรที่ปรับแล้ว แทนการใช้ measureText() ของเบราว์เซอร์
  • การคำนวณกล่อง label เริ่มต้นและ collision ใช้ CPU หนัก จึงย้ายไปใช้ Web Workers
  • ทดลองใช้ OffscreenCanvas ด้วย แต่ logic การเรนเดอร์มีประสิทธิภาพอยู่แล้ว จึงไม่ได้ผลมากนัก

ภูมิประเทศ ขอบเขต และ label เมือง

  • หากแผนที่มีแต่จุดจะขาดความรู้สึกด้านทิศทางและความน่าสนใจทางภาพ จึงเพิ่มแนวคิดเรื่อง ภูมิประเทศและเมือง
  • เนื่องจากไม่มีภูมิศาสตร์จริงหรือขอบเขตทางการเมือง จึงใช้ภูมิประเทศเป็นอุปมาสำหรับความหนาแน่นของจุด
  • ความหนาแน่นของจุดใช้เป็นสัญญาณที่แสดงพื้นที่ที่มีกิจกรรม ความสนใจ คอนเทนต์ การมีส่วนร่วม ความนิยม และการสนทนามากได้อย่างรวดเร็ว
  • ตอนแรกพิจารณา Kernel Density Estimation แต่การลองใช้ไลบรารีมาตรฐานใช้เวลานานเกินไป
  • จึงเปลี่ยนเป็น mapping แต่ละจุดไปยังเซลล์กริดขนาดใหญ่ นับจำนวนต่อเซลล์ แล้วใช้ Gaussian blur
  • ค่าความหนาแน่นแบบเชิงเส้นส่วนใหญ่ดูใกล้ 0 ทำให้แผนที่ออกมาไม่ดี
  • เมื่อใช้ log(density + 1) ก็ได้ลำดับชั้นที่เป็นธรรมชาติมากขึ้น และบริเวณที่ระดับความหนาแน่นต่างกันมาบรรจบกันดูเหมือนขอบเขตโดยนัย
  • แทนที่จะใช้ภาพขนาดใหญ่ สร้าง SVG path เพื่อให้ client วาดเป็น polygon
    • มีเพียง 4 สี จึงมีประสิทธิภาพ
    • แม้ซูมเข้า ขอบเขตก็ยังคมชัด
    • ใช้ฟังก์ชัน contour ของ OpenCV คำนวณเส้นปิดตามแต่ละระดับ
  • label เมืองแสดงหัวข้อร่วมกันภายในรัศมีหนึ่ง
  • ชื่อเมืองถูกนำไปทำ embedding แล้วใช้โมเดล UMAP ที่บันทึกไว้เพื่อหาตำแหน่ง (x, y)
  • เคยลองสร้างอัตโนมัติด้วย
    • พยายามให้ LLM สร้างชื่อเมือง แต่ยากที่จะทำให้ได้ผลลัพธ์ที่ต้องการอย่างเสถียรด้วย prompt
    • K-means หา cluster ที่มีความหมายในแบบที่มนุษย์น่าจะจัดกลุ่มได้ไม่มากนัก
  • สุดท้ายจึงสำรวจแผนที่เองและจดชื่อเมืองบางส่วนด้วยมือ ซึ่งใช้เวลาประมาณ 1 ชั่วโมง

Edge deployment และการตอบสนอง

  • การสำรวจแผนที่ต้องเร็วและตอบสนองดี ดังนั้นการลด latency ในการ fetch ข้อมูลจึงสำคัญ
  • ตอนแรกเก็บข้อมูลแผนที่ทั้งหมดไว้ใน region ENAM ของ Cloudflare R2 แต่ latency อยู่ที่ 600ms ไปจนถึงหลายวินาที
  • แม้ latency ทางกายภาพจะประมาณ 200ms ก็ยังไม่ดีพอ เพราะ 100ms คือ threshold ที่ให้ความรู้สึกเหมือนตอบสนองทันที
  • เพื่อลด latency จึงย้ายข้อมูลไปใกล้ผู้ใช้มากขึ้น
  • วาง server ขนาดเล็กไว้ที่ Virginia, San Jose, London, Sydney และให้บริการข้อมูลด้วย server ที่เขียนด้วย Rust
  • client เรียก /healthz ของ edge หลายแห่งไม่กี่ครั้ง แล้วเลือก server ที่ตอบกลับก่อน
  • วิธีอย่าง Anycast หรือ CDN ก็เป็นไปได้ แต่ไม่ใช้เพราะต้นทุนและความซับซ้อนเกินจำเป็น
  • การใช้หน่วยความจำของ process บน edge server มากกว่าข้อมูลต้นฉบับ 2–4 เท่า จึงยังเป็นข้อสงสัย
    • อาจใช้ type ผิด
    • struct padding
    • การ over-allocation ของ Vec, HashMap
    • ความเป็นไปได้ของ fragmentation หรือความไม่มีประสิทธิภาพของ memory allocator

ผลลัพธ์และข้อจำกัดของ semantic search

  • ในคิวรีง่าย ๆ อย่าง “entering the tech industry” พบทั้งผลลัพธ์ที่มี upvote มากและผลลัพธ์ที่ไม่ได้รับความสนใจมากนัก ซึ่งดูมีความเกี่ยวข้องและมีประโยชน์ดี
  • เมื่อเทียบกับบริการค้นหาเดิมของ HN การค้นหาด้วย semantic embedding สามารถหาผลลัพธ์ได้แม้ข้อความจะไม่ได้ตรงกันตามตัวอักษร
  • คิวรีแบบคำถามอย่าง “what happened to wework” ก็แสดงผลลัพธ์ที่ครอบคลุมหลายปี เช่น การปลดพนักงาน ราคาหุ้นตก และการล้มละลายของ WeWork
  • แม้ผลการค้นหาจะไม่ได้มีคำว่า “what happened” จริง ๆ หรือไม่ได้อยู่ในรูปคำถาม ก็ยัง match ได้
  • ปัญหาหนึ่งคือไม่ได้กรองผลลัพธ์ที่ไม่คล้ายกันพอ ทำให้มีผลลัพธ์ลำดับล่างที่ไม่เกี่ยวข้องโดยสิ้นเชิงปะปนเข้ามา
    • เรื่องนี้ถูกมองว่าเป็นปัญหาที่แก้ได้ง่าย
  • ในการค้นหา “career growth” มีเอสเซย์ที่สร้างสรรค์และหลากหลายซึ่งไม่ได้มีคำนั้นตรง ๆ ปรากฏขึ้น
  • คุณภาพการคัดสรรและคะแนนของ HN ช่วยยกระดับคุณภาพการค้นหา
  • ในแอปมี query suggestion แบบ hardcoded เช่น “linus rants”, “self bootstrapping”, “cool things with css”

ชุมชนเสมือนและการวิเคราะห์ความคิดเห็น

  • สามารถใช้ embedding เพื่อสร้างฟีเจอร์ ซับคอมมูนิตี้เสมือน ได้
  • เมื่อผู้ใช้ป้อนชื่อหรือคำอธิบายของชุมชน โพสต์ที่มีความคล้ายกันเกินค่า threshold ที่กำหนดจะถูกจัดกลุ่มขึ้นมาทันที
  • เนื่องจาก HN ไม่มีฟีเจอร์สำหรับแบ่งย่อยโพสต์ให้ละเอียดกว่านี้ จึงเป็นวิธีสร้างการคัดสรรเนื้อหาตามความสนใจเฉพาะได้ทันที
  • snippet และรูปภาพในการ์ดผลลัพธ์นำมาจาก metadata ของหน้าเว็บที่เว็บครอว์เลอร์บันทึกไว้
  • ไอคอนของเว็บไซต์ถูกทำให้ง่ายขึ้น โดยให้ฝั่งไคลเอนต์ดึง /favicon.ico ของโดเมน แทนการ parse metadata ที่ซับซ้อน
  • เธรดความคิดเห็นก็สามารถแสดงด้วยวิธีเดียวกันได้
  • HN API ไม่ได้ให้คะแนนความคิดเห็น จึงทำได้เพียงเรียงตามเวลา
  • มองว่าวิธีจัดอันดับโดยไม่มีคะแนนความคิดเห็นสามารถใช้ข้อมูลอย่างประวัติการคอมเมนต์ของผู้ใช้ การมีส่วนร่วมรอบความคิดเห็นนั้น โพสต์ หัวข้อ และเนื้อหาได้
  • ยังสามารถค้นหาผู้ใช้ที่มีอิทธิพลหรือมีความเคลื่อนไหวสูงในหัวข้อเฉพาะได้ด้วย
    • ในคิวรี “cloudflare” มี jgrahamc และ eastdakota ปรากฏอยู่ในอันดับต้น ๆ
    • ผู้ใช้ทั้งสองเป็น CTO และ CEO ของ Cloudflare ตามลำดับ
  • งานนี้ประมวลผลด้วยการคำนวณเมทริกซ์ โดยไม่ต้องแยกประเภทความคิดเห็นต่างหากหรือใช้การค้นหาด้วยคีย์เวิร์ด
  • โดยทั่วไปการกรองหลังประมวลผลมักเร็วกว่าและเพียงพอกว่าการกรองก่อนประมวลผล
    • การกรองก่อนต้องลบแถวที่สอดคล้องกันออกจากเมทริกซ์ embedding ซึ่งอาจต้องคัดลอกหน่วยความจำขนาดใหญ่มาก หรือคำนวณแบบ vectorization บางส่วนที่ช้า
    • มองว่าควรหาแถวที่คล้ายกันก่อน แล้วค่อยกรองผลลัพธ์
  • ค่า threshold ขั้นต่ำเป็นสิ่งสำคัญ
    • รายการที่ไม่เกี่ยวข้องก็อาจมีค่าความคล้ายกันระดับ 0.6 ได้
    • หากไม่มี threshold ผู้ใช้ที่มีจำนวนความคิดเห็นมากมากอาจครองอันดับได้เพียงเพราะปริมาณที่มาก

การวิเคราะห์อารมณ์และความนิยมจากข้อมูลความคิดเห็นทั้งหมด

  • การวิเคราะห์ขนาดใหญ่ที่อยากลองทำกับความคิดเห็น 30 ล้านรายการคือ ความนิยมและอารมณ์
  • เป้าหมายคือดูว่า HN รู้สึกอย่างไรต่อหัวข้อหนึ่ง ๆ เมื่อเวลาผ่านไป เหตุการณ์สำคัญส่งผลต่ออารมณ์อย่างไร และหัวข้อที่ผู้คนสนใจเติบโตหรือเสื่อมความนิยมอย่างไร
  • เนื่องจากไม่มีข้อมูลอารมณ์ จึงใช้โมเดลจำแนกอารมณ์โอเพนซอร์สของ Hugging Face
  • โมเดลที่เลือกคือ TweetEval ซึ่งเป็นโมเดลที่ฝึกกับคอนเทนต์บนโซเชียลมีเดีย
  • เนื่องจาก TweetEval เป็นโมเดลสำหรับทวีตสั้น ๆ จึงใช้เฉพาะตัวความคิดเห็นเองเป็นอินพุต โดยไม่แนบบริบทของบรรพบุรุษเหมือนตอนทำ embedding
  • นำความคิดเห็นเข้า queue แล้วประมวลผลงานบนคลัสเตอร์ GPU จากนั้นบันทึกผลลัพธ์
  • เนื่องจากโมเดลมีขนาดเล็ก จึงเพิ่ม batch size เพื่อเพิ่มประสิทธิภาพการใช้ GPU
  • การเพิ่ม batch size ใช้ VRAM มากขึ้น แต่ช่วยลดการถ่ายโอนหน่วยความจำระหว่างโฮสต์กับ GPU และเพิ่มความขนานได้
  • ในโมเดล Transformer อินพุตแบบ batch ต้องเป็นรูปสี่เหลี่ยมผืนผ้า จึงถูก padding ให้ตรงกับความยาวอินพุตที่ยาวที่สุด
    • หากมีอินพุตยาวหนึ่งรายการปะปนกับอินพุตสั้น ๆ ไม่กี่รายการ ขนาดอินพุตทั้งหมดและสถานะภายในอาจเพิ่มขึ้นอย่างมาก
    • ด้วยเหตุนี้จึงอาจเกิด memory spike และ OOM ได้
  • ในตัวอย่างการวิเคราะห์อารมณ์เกี่ยวกับ Rust พบว่าโดยรวมมีอารมณ์เชิงบวกต่อ Rust ค่อนข้างมาก
    • มี spike เชิงบวกในช่วงที่ประกาศ Rust 1.0
    • โพสต์ที่เป็นลบมากกว่าสัมพันธ์กับความคิดเห็นเชิงลบจำนวนมากตามเกณฑ์ของโมเดล
  • ยังประเมินความนิยมตามภาษาโดยถ่วงน้ำหนักคะแนนกับค่าความคล้ายกันด้วย
    • HN ไม่ให้คะแนนความคิดเห็น จึงใช้คะแนนความคิดเห็นไม่ได้
    • Rust ทำได้ดี แต่ดูเหมือนจะยังไม่เป็นที่นิยมเท่าภาษาอื่น ๆ
    • ค่า threshold ของความคล้ายกันอาจต้องปรับ ดังนั้นผลลัพธ์อาจผิดได้

เร่งความเร็วการคำนวณเชิงตัวเลขขนาดใหญ่ด้วย GPU

  • คิวรีวิเคราะห์ใช้เวลา 10–30 วินาทีแม้บนเครื่อง 32 คอร์ จึงช้าเกินไปสำหรับการทดลองแบบโต้ตอบ
  • หลังจากพิจารณาเรื่อง index และ preprocessing จึงเปลี่ยนมาใช้ GPU สำหรับการคำนวณเชิงตัวเลขแบบ vectorization
  • CuPy และ cuDF ให้ API ที่คล้ายกับ NumPy และ pandas ตามลำดับ แต่รันบน GPU
  • การพอร์ตค่อนข้างง่าย และเวลาคิวรีลดลงเหลือระดับไม่กี่ร้อยมิลลิวินาที
  • เนื่องจากความเร็วเพียงพอแล้ว จึงไม่ได้ใช้กราฟ ANN
  • ส่วนที่ยากคือการนำเมทริกซ์ embedding ขนาดใหญ่ขึ้นไปไว้บน GPU
    • เมทริกซ์ embedding ของความคิดเห็นมีขนาด 30M x 512
    • เป็นเรื่องยากที่จะเก็บเมทริกซ์มากกว่า 1 เท่าไว้ในหน่วยความจำระบบหรือหน่วยความจำวิดีโอ
  • วิธีโหลดแบบง่ายอาจสร้างสำเนาหลายชุด
    • อ่านไบต์จากดิสก์
    • โหลดเป็นอาร์เรย์ NumPy
    • แปลงเป็นอาร์เรย์ CuPy
    • คัดลอกไปยัง GPU
    • กระบวนการนี้อาจสร้างสำเนารวม 4 ชุด และในนั้น 3 ชุดอยู่ในหน่วยความจำ
  • วิธีสุดท้ายคือทำ memory mapping เมทริกซ์บนดิสก์ จัดสรรเมทริกซ์ที่ยังไม่ถูก initialize ขนาดเท่ากันบน GPU ไว้ล่วงหน้า แล้วคัดลอกเป็น chunk
  • วิธีนี้หลีกเลี่ยงการอ่านเข้าไปในหน่วยความจำของ Python ก่อน และใช้ system RAM กับ VRAM อย่างละพอดี 1 เท่า

เดโมและขั้นตอนถัดไป

  • แอปเดโมให้บริการที่ hn.wilsonl.in
  • หน้าหลักคือแผนที่และการค้นหา และสามารถเข้าถึงเครื่องมือชุมชนและวิเคราะห์ได้จากปุ่มมุมขวาบน
  • URL ของชุมชนหรือผลการวิเคราะห์สามารถแชร์กับผู้อื่นได้ เพราะเก็บคิวรีไว้ใน URL
  • ชุดข้อมูลเดโมสิ้นสุดอยู่ราววันที่ 10 เมษายน 2024 และไม่รวมโพสต์กับความคิดเห็นสดล่าสุด
  • มีหลายไอเดียที่อยากสำรวจต่อไป
    • ข้อมูลสดที่อัปเดตให้เป็นปัจจุบันอยู่เสมอ
    • ระบบแนะนำที่ใช้ deep learning ซึ่งทำงานบนเว็บที่ HN คัดสรรไว้
    • การปรับปรุงผลการค้นหาผ่านการฝึก reranker
    • เส้นทางและการเดินทางที่น่าสนใจบนแผนที่
    • การวิเคราะห์ความสัมพันธ์ที่คล้ายหรือขัดแย้งกันระหว่างผู้ใช้
    • การวิเคราะห์ผู้ใช้ที่เชี่ยวชาญที่สุดใน niche เฉพาะ
  • สามารถดู ข้อมูล และ โค้ด ทั้งหมดได้บน GitHub

2 ความคิดเห็น

 
GN⁺ 2024-05-10
ความเห็นบน Hacker News
  • ถือว่าน่าประทับใจมาก โดยเฉพาะเมื่อเป็นโปรเจ็กต์ที่ทำคนเดียว
    กราฟวิเคราะห์อารมณ์ความรู้สึก ตามช่วงเวลาเด่นสะดุดตา และก็น่าสนใจเพราะนี่เป็นครั้งแรกที่ได้เห็น Rust ในมุมแบบนี้ เลยอยากรู้ว่าหัวข้อไหนเป็นบวกมากที่สุดเมื่อเวลาผ่านไป และมีหัวข้อไหนที่ร่วงลงแรงแบบฉับพลันบ้างไหม
    ประโยคที่ว่า “ดูเหมือนว่า HN โดยรวมจะมีอารมณ์เชิงลบเยอะ” ก็ฟังดูตรงกับความรู้สึกที่มีต่อโซเชียลมีเดียเหมือนกัน ถ้าได้เห็นการเปรียบเทียบอารมณ์ความรู้สึกระหว่างแพลตฟอร์มโซเชียลมีเดียต่าง ๆ และแต่ละช่วงเวลาก็น่าจะน่าสนุก

    • อยากขุดเรื่อง sentiment ให้ลึกกว่านี้ อย่างที่พูดไว้ การดูภาพรวมทั้งหมดแทนที่จะเป็น query เฉพาะก็น่าจะน่าสนใจ
      ที่สังเกตเห็นอารมณ์เชิงลบเด่นชัด เป็นเพราะเดิมคาดหวังว่าจะได้เห็น กราฟอารมณ์ความรู้สึกที่ชัดเจนกว่าเดิม โดยทั่วไปคิดว่าน่าจะออกมากลาง ๆ ถึงเชิงบวก และกระโดดไปทางบวกใกล้โพสต์เชิงบวก หรือไปทางลบใกล้โพสต์เชิงลบ แต่กลับพบว่าแทบทุก query ให้อารมณ์ออกมาเป็นลบเกือบตลอดเวลา แม้แต่โพสต์เชิงบวกก็ดูเหมือนจะดึงความเป็นลบออกมาเยอะตามเกณฑ์ของโมเดลและวิธีการที่ใช้ ซึ่งก็อาจเป็นไปได้ว่าทั้งสองอย่างผิด เลยอยากไปขุดต่อในบล็อกโพสต์ถัดไป
    • นอกจากอารมณ์ความรู้สึกแยกตามแพลตฟอร์มโซเชียลมีเดียและช่วงเวลาแล้ว น่าจะดีถ้าได้ดู ช่วงเวลาของวัน และวันธรรมดา/วันหยุดสุดสัปดาห์ด้วย
    • เมื่อไม่กี่เดือนก่อนฉันเขียนบล็อกโพสต์วิเคราะห์ อารมณ์ความรู้สึกในคอมเมนต์ HN เกี่ยวกับ AI, blockchain, remote work และ Rust ไว้ กราฟสุดท้ายท้ายบทความเกี่ยวข้องกับหัวข้อนี้โดยตรง
      https://openpipe.ai/blog/hn-ai-crypto
    • น่าเสียดายจริง ๆ ที่ HN API ไม่ให้ จำนวนโหวต ของคอมเมนต์ อยากรู้ว่าถ้าให้น้ำหนักด้วย upvote/downvote แล้วผลวิเคราะห์อารมณ์ความรู้สึกจะเปลี่ยนไปอย่างไร
      ไม่มีหลักฐานอะไร แต่รู้สึกว่าวิศวกรมักจะมีมุมวิจารณ์มากกว่า และเวลามีฟีดแบ็กเชิงบวกก็มักกด +1 มากกว่าจะพิมพ์ซ้ำ ๆ ส่วนคำวิจารณ์มักจะเขียนตรง ๆ มากกว่า :)
    • Crypto ก็น่าจะอยู่ในหมวดนั้นเหมือนกัน
  • เป็นตัวอย่างที่ดีสำหรับคนที่ไม่คุ้นกับ data engineering/MLOps
    ขอเสนอให้ใช้ HDBSCAN สร้างคลัสเตอร์แบบลำดับชั้นจากจุดต่าง ๆ แล้วใช้โมเดลสร้างชื่อคลัสเตอร์ย่อยภายใน แบบนี้จะช่วยให้สำรวจหัวข้อไปจนถึงระดับใบไม้ได้ง่ายขึ้น โดยค่อย ๆ แสดงหัวข้อย่อยตามความเชื่อมโยงกับโหนดปัจจุบัน
    สีของกลุ่มควรชัดกว่านี้ และถ้ามีคลัสเตอร์ก็น่าจะช่วยได้ ขนาดตัวอักษรของแต่ละโพสต์ก็ควรเปลี่ยนตามความสำคัญ/ความเกี่ยวข้องเมื่อเทียบกับทั้งระบบหรือผลค้นหาปัจจุบัน ถ้ามีสรุปคลัสเตอร์ย่อยภายในมากขึ้น ก็อาจแทนหลายโพสต์ด้วยสรุปกลุ่มไปก่อนจนกว่าจะซูมเข้า เพื่อลดความแน่นของข้อความ

    • ถ้าใครมี GPU ก็น่าจะเป็นประโยชน์ที่รู้ว่า HDBSCAN ถูก optimize ไว้ดีมากใน cuML
      https://docs.rapids.ai/api/cuml/stable/api/#clustering / https://developer.nvidia.com/blog/faster-hdbscan-soft-cluste...
    • ขอบคุณสำหรับข้อมูลดี ๆ น่าเสียดายที่ยังไม่มีเวลาลองดู hierarchical clustering แต่ใส่ไว้ในรายการสิ่งที่ต้องทำแล้ว
      ข้อสังเกตเรื่องการทำให้แผนที่ชัดขึ้นก็ดีมาก และคิดว่ายังมีวิธีปรับปรุงง่าย ๆ ได้อีกหลายอย่าง อันนี้ก็เพิ่มเข้าไปในรายการสิ่งที่ต้องทำเหมือนกัน :)
  • ขอบเขตของโปรเจ็กต์ใหญ่จนน่าทึ่ง
    แต่ดูเหมือนว่าไม่ว่าจะเป็น jina หรือ bge-3/flag ทั้ง embedding และ tokenizer จะยังไม่ค่อยเหมาะกับหัวข้อสายเทคนิคนัก คำธรรมดาในภาษาธรรมชาติพอใช้ได้ แต่พอค้นหาแนวคิดทางเทคนิคอย่าง “xaml” หรือ “simd” ระบบจะโน้มเอียงไปทางจับคำที่ฟังคล้ายกันหลังจาก tokenize อินพุตแล้ว
    ในเชิงฟีดแบ็กแบบสร้างสรรค์ อยากให้มีวิธีไม่แสดงผล “อันดับ HN” แบบเดิมซ้ำ ๆ ตอนที่หัวข้อเฉพาะทางเกินไปจนไม่มีผลลัพธ์ เวลาค้นหาคำที่ embedding ไม่คุ้นเคยก็มักจะเจอ “Stephen Hawking has died” โผล่มาบ่อยมาก
    ส่วนการวิเคราะห์อารมณ์ความรู้สึกก็ยังไม่แน่ใจว่าทำงานได้ดีแค่ไหน เพราะดูมีอารมณ์เชิงลบมากเกินจริง เช่นลองค้นหา “Mr Rogers” ซึ่ง HN น่าจะมองในแง่บวกอย่างท่วมท้น ก็ยังได้พีคเชิงลบรุนแรง หรือค้น “Carter” ก็มีพีคเชิงลบใหญ่มากที่เกี่ยวกับการเสียชีวิตของ Rosalynn Carter ทั้งที่โพสต์จริงเป็นการส่งลิงก์ที่พูดถึงสิ่งดี ๆ มากมายที่คู่สามีภรรยา Carter ทำไว้
    ส่วน “ความนิยมตามเวลา” น่าจะต้องปรับด้วยคะแนนโหวตมัธยฐานของโพสต์ในเดือน/ปีนั้น ถ้าแค่พล็อตจำนวนโพสต์ เส้นแนวโน้มก็จะสูงขึ้นเรื่อย ๆ ดูคำว่า “diesel” แล้วจะเห็นว่าหมายถึงอะไร เพราะคำนี้พีคไปตั้งแต่ 10 ปีก่อนแล้ว หรืออีกทางอาจไม่ควรใช้คะแนนโพสต์ แต่ใช้ความถี่การเกิดของคีย์เวิร์ด หรือจำนวนรายการที่มีดัชนี cosine similarity กับ query ต่ำกว่า x แทนก็ได้
    ฟีเจอร์ไดนามิกที่คลิกโพสต์เพื่อตัดออกแล้วคำนวณ ค่า threshold ของ similarity ใหม่ถือว่ายอดเยี่ยมมาก

    • จะตัดสินแบบ เป็นโปรแกรม ได้อย่างไรว่า embedding model ไหนไม่รู้จักคำหรือศัพท์บางคำ?
  • มีเครื่องมือที่ยอดเยี่ยมซึ่งทำสิ่งเกือบเหมือนกันนี้ให้กับ dataset แบบไหนก็ได้: https://github.com/enjalot/latent-scope
    แน่นอนว่าเพราะโปรเจ็กต์ต้นฉบับมีขนาดใหญ่มาก จึงมีความซับซ้อนที่น่าสนใจเพิ่มเข้ามาเยอะ และเครื่องมือนี้อาจจัดการกับสเกลขนาดนั้นไม่ได้ แต่สำหรับ dataset ขนาดกลางถือว่าเหมาะมาก

  • อยากลองวิเคราะห์ว่าบน HN มีการโปรโมตตัวเองเพิ่มขึ้นหรือไม่
    ในที่นี้นิยามการโปรโมตตัวเองว่าเป็นโพสต์รูปแบบ “Show HN: I ...” ไม่ใช่ “Show HN: Something ...”
    ตอนนี้ใน 100 อันดับบนสุด ตัวอย่างเช่น “Show HN: Exploring HN by mapping and analyzing 40M posts and comments for fun”, “Show HN: Browser-based knitting (pattern) software” ไม่ใช่หัวข้อโปรโมตตัวเอง เพราะประธานของแต่ละประโยคคือการสำรวจและซอฟต์แวร์
    ในทางกลับกัน “Show HN: I built a non-linear UI for ChatGPT”, “Show HN: I created 3,800+ Open Source React Icons” เป็นหัวข้อโปรโมตตัวเอง เพราะประธานคือ “I”
    ถ้าตรวจอย่างง่ายจากผลค้นหาของ Algolia โดยดูหัวข้อที่ขึ้นต้นด้วย “Show HN: I” แยกตามแต่ละปีที่เริ่มนับตั้งแต่ 1 เมษายน แล้วหารด้วยจำนวนผลลัพธ์ทั้งหมดของปีนั้น จากนั้นพล็อตเป็นกราฟ จะได้ดังนี้
    2023 ****************************************
    2022 ***********************************
    2021 ***************************
    2020 **************************************
    2019 *************************
    2018 *************
    2017 *******
    2016 **********
    2015 ********
    2014 ************
    2013 *********************
    2012 *****************
    2011 *********
    2010 ***
    ตอนที่ฉันโตมา โดยทั่วไปเหมือนการโปรโมตตัวเองจะถูกมองว่าเป็นลักษณะนิสัยที่ไม่ดี เราถูกสอนว่าการกระทำควรเป็นตัวโปรโมตตัวเอง ไม่ใช่การเรียกร้องความสนใจโดยตรง แต่รู้สึกว่าวัฒนธรรมนั้นกำลังเปลี่ยนไป
    ถ้าการโปรโมตตัวเองเพิ่มขึ้นจริง ก็สงสัยว่าเป็นผลจากโซเชียลมีเดียหรืออย่างอื่นหรือไม่ บน YouTube ก็รู้สึกว่ามีแนวโน้มคล้ายกัน แต่มีแค่ความรู้สึกว่ามีวิดีโอแนะนำที่ขึ้นต้นด้วย “I.....” เยอะขึ้น ยังไม่มีข้อมูลยืนยัน

    • นิยามของการโปรโมตตัวเองต่างจากที่ฉันเข้าใจอยู่พอสมควร ปกติถ้าใครสักคนโปรโมตสิ่งที่ตัวเองสร้าง ฉันก็ถือว่านั่นคือการโปรโมตตัวเอง ดังนั้นสองตัวอย่างที่ยกว่าไม่ใช่การโปรโมตตัวเอง สำหรับนิยามของฉันก็ยังเป็นการโปรโมตตัวเองอยู่
      พูดอีกอย่างคือ สิ่งที่คุณแบ่งเป็นโปรโมตตัวเองกับไม่โปรโมตตัวเอง สำหรับฉันคือกรณีที่หัวข้อแสดงชัดมากว่าเป็นการโปรโมตตัวเอง กับกรณีที่แสดงชัดน้อยกว่าเท่านั้น แต่เพราะวลี “Show HN” เองดูเหมือนจะใช้เฉพาะกับการโปรโมตตัวเองอยู่แล้ว คนที่รู้ธรรมเนียมนี้ก็น่าจะรู้ได้ว่าเป็นการโปรโมตตัวเองแม้ไม่มี “I”
    • Show HN ทุกอันควรเป็นสิ่งที่ผู้เขียนสร้างขึ้นอยู่แล้ว ดังนั้นการทำให้สิ่งที่เป็นนัยอยู่แล้วกลายเป็นคำพูดตรง ๆ ไม่ได้ทำให้เห็นชัดว่ามันโปรโมตตัวเองมากขึ้นตรงไหน
      ทั้งหมดก็มีความหมายประมาณว่า “ดูสิ ฉันสร้างของเจ๋ง ๆ มา คุณคิดว่าไง?”
    • เรื่องนี้ถูกพูดถึงเยอะมากในชีวประวัติ Einstein ของ Walter Isaacson ด้วย ดังนั้นผู้คนสังเกตแนวโน้มนี้กันมานานแล้ว
      เช่น มีการพูดว่าชาวเยอรมันตำหนิ Einstein ว่าโปรโมตตัวเอง ขณะที่อเมริกามีวัฒนธรรมคนดังอยู่แล้ว อาจเป็นปรากฏการณ์ที่เกิดเป็นวัฏจักรก็ได้
  • นี่น่าจะเป็นโพสต์ที่เจ๋งที่สุดที่ฉันเห็นบน HN ในปีนี้แบบทิ้งห่าง

  • ตอนแรกที่ดูยังไม่ชัด แต่ตัวแอปจริงอยู่ที่นี่: https://hn.wilsonl.in/

    • สงสัยว่าจงใจวางลิงก์หน้า landing page ไว้เกือบท้ายสุดหรือเปล่า แบบนี้จะมีแต่คนที่อ่านโพสต์จริง ๆ เท่านั้นถึงจะเข้าเว็บ
      ไม่ได้ประชดนะ คิดว่าเป็นไอเดียที่ดี
    • ดูเหมือนว่าลิงก์ค้นหาจะไม่สามารถแชร์ได้ หรือไม่ก็ไม่ได้ใส่คำค้นไว้ในนั้น
      เลยสงสัยว่าฝังความหมายของข้อความค้นหาแบบแยกเป็นรายคำหรือเปล่า และใช้โมเดลเดียวกับที่ใช้กับเอกสารไหม ฉันลองค้น “lead generation” ซึ่งถ้าเป็น embedding ของหลายคำที่ทำงานถูกต้องก็น่าจะเข้าใจได้ แต่กลับได้ผลลัพธ์เรื่องพิษตะกั่ว
    • ฉันเจอตัวเองกับโพสต์ของตัวเองในนั้นด้วย! เยี่ยมเลย
  • คำแนะนำสมัยใหม่ของ UMAP คือ Parametric UMAP: https://umap-learn.readthedocs.io/en/latest/parametric_umap....
    มันฝึก Keras MLP ขนาดเล็กเพื่อย่อมิติลงมาเป็น 2 มิติ โดยทำให้ UMAP loss ต่ำที่สุด ข้อดีคือโมเดลนี้มีขนาดเล็ก จึงบันทึกและนำกลับมาใช้ซ้ำเพื่อทำนายกับข้อมูลใหม่ที่ไม่เคยเห็นมาก่อนได้ ขณะที่โมเดล UMAP แบบดั้งเดิมที่ฝึกแล้วมีขนาดใหญ่ นอกจากนี้ยังใช้ GPU จึงในทางทฤษฎีแล้วฝึกได้เร็วกว่าเยอะ
    ข้อเสียคือ implementation ใน Python UMAP package ยังไม่ค่อยดีนัก และมันสร้างชุดข้อมูลโหนด/ขอบแบบขยายทั้งหมดแล้วส่งเข้า GPU เลย ทำให้ฝึกได้เพียงราว 100,000 embedding ก่อนจะเจอปัญหา out-of-memory
    pipeline แบบไม่มีผู้สอนทั้งหมดที่ต่อกันเป็น UMAP → HDBSCAN → AI cluster labeling มีประโยชน์มากจนทำให้อยากลองสร้าง Parametric UMAP implementation ที่ขยายได้ดีกว่านี้

    • มี implementation บน GPU ที่เร็วใน cuML อยู่แล้ว ไม่ค่อยเข้าใจเหมือนกันว่าทำไม cuML ถึงไม่เป็นที่รู้จักมากกว่านี้
    • มองเผิน ๆ เหมือนว่าปัญหาเกิดจาก implementation ส่งทั้งกราฟทั้งหมด หรือก็คือทุกขอบ เข้า GPU ทีเดียว ถ้าทำedge sampling ระหว่างฝึกก็น่าจะช่วยบรรเทาได้
  • สำหรับสิ่งที่ดูเหมือนโปรเจ็กต์งานอดิเรกเชิงสำรวจ นี่เป็นงานที่ใหญ่อย่างน่าประหลาดใจ
    ไม่ได้จะลดทอนความสำเร็จนะ มันเจ๋งมากจริง ๆ แต่ก็แปลกใจที่ต้องลงแรงกันขนาดนี้
    แค่การคำนวณ embedding ก็ใช้ GPU 150 ตัว แล้ว และยังพัฒนาระบบคัสตอมสองตัวคือ db-rpc และ queued สำหรับการสื่อสารระหว่างเซิร์ฟเวอร์ด้วย
    นอกจากนี้ยังมีงานประกอบและการคำนวณอีกมากมาย
    เลยสงสัยถึงบริบทของโปรเจ็กต์นี้ รวมถึงอยากรู้ว่าหาเงินทุนและเวลาเพื่อทำงานวิจัยแบบนี้ได้อย่างไร
    จากมุมของคนที่เคยทำงานลักษณะคล้าย ๆ กันในเชิงอาชีพมาเยอะ ผมเคยทำแผนที่ภูมิทัศน์ของงานวิชาการและสิทธิบัตรมาก่อน แต่ก็ไม่แน่ใจว่า GPU 150 ตัว จำเป็นจริงไหม
    ถ้าสุดท้ายคือการฉายลง 2 มิติและการทำคลัสเตอร์ วิธีแบบดั้งเดิมอย่าง bag-of-words หรือ topic modeling น่าจะง่ายกว่า ถูกกว่า และแทบไม่รู้สึกถึงความต่างด้านคุณภาพ
    แม้จะใช้กราฟของผู้เขียนและเธรดความคิดเห็น ก็อาจได้ผลลัพธ์คล้ายกัน

    • เรื่องค่าใช้จ่าย แม้จะไม่ได้พูดไว้ในบทความ แต่ก็อยู่แค่ระดับหลายร้อยดอลลาร์ จึงถือว่าเข้าถึงได้พอสมควรแม้จะเป็นโปรเจ็กต์งานอดิเรก
      GPU ถูกอย่างน่าประหลาดใจ และส่วนใหญ่ที่ขยายสเกลก็เพราะผมใจร้อนไม่ค่อยอยากรอ :) ทั้งคลัสเตอร์ก็รันอยู่แค่ไม่กี่ชั่วโมง
      ถ้ามีลิงก์ไปยังงานที่คุณเคยทำ อยากดูมากเลย น่าสนใจจนอยากอ่านต่อ
    • เห็นได้ชัดว่าผู้เขียนมีฝีมือมาก อีกจุดที่น่าสนใจคือเขาโพสต์บน HN แต่ไม่ได้คอมเมนต์เลยตั้งแต่ปี 2018 แล้วจากนั้นก็เริ่มโปรเจ็กต์นี้
      ในแง่เงินทุนและเวลา เป็นไปได้ว่าเขาอยู่ในช่วงคั่นระหว่างงานถัดไปหรือระหว่างงานประจำ และประสบความสำเร็จทางการเงินจากอาชีพหรือธุรกิจก่อนหน้านี้ จึง ออกทุนเอง ทำโปรเจ็กต์นี้
      การใช้ GPU ก็ดูมีประสิทธิภาพมาก ค่าใช้จ่ายจึงน่าจะไม่ได้สูงมากนัก
    • แม้ใช้ embedding ที่ถูกกว่านี้ ก็ยังได้ผลลัพธ์ที่ดีพอสมควร
      สามารถนำ แมชชีนเลิร์นนิงแบบคลาสสิก อย่าง SVM ที่ทำ probability calibration มาใช้กับ embedding ลักษณะนี้ เพื่อให้ได้ผลดีทั้งในการจำแนกและการทำคลัสเตอร์ และยังเร็วกว่า fine-tuning LLM มากกว่า 100 เท่า
  • ปกติแล้วจะไม่ทำแบบเดโมนี้ แต่จะ normalize เวกเตอร์แทน
    เมื่อใช้เวกเตอร์ที่ normalize แล้ว ระยะทางแบบ Euclidean จะวัดระยะระหว่างปลายของเวกเตอร์สองตัว ขณะที่ระยะทางแบบ cosine จะวัดความยาวของการฉายเวกเตอร์หนึ่งลงบนอีกเวกเตอร์หนึ่ง

    • ปัญหาของการ normalize คือจะเสียหนึ่งองศาอิสระไป สำหรับการทำภาพข้อมูลแล้ว มันแทบจะเท่ากับ เสียไปหนึ่งมิติ
      เวกเตอร์ 2 มิติที่ normalize แล้ว ในความเป็นจริงเทียบได้กับเวกเตอร์ 1 มิติเท่านั้น ถ้าต้องการแสดงความสัมพันธ์แบบ 2 มิติ ก็ต้องใช้เวกเตอร์ 3 มิติแทนเพื่อให้กลับมามีอิสระ 2 องศา
 
ggg213 2024-05-10

ดูเหมือนว่าชื่อเรื่องจะหายไปนะ