Trải nghiệm AI hoàn tất giai điệu piano ngay trên iPhone: Mô hình 125M chạy hoàn toàn trên thiết bị

20 tháng 8, 2026·5 phút đọc

Một nhà phát triển đã huấn luyện thành công mô hình transformer 125M tham số có khả năng tự động hoàn tất (autocomplete) bản nhạc piano theo thời gian thực, đạt tốc độ khoảng 108 nốt/giây trên iPhone 15. Mô hình hoạt động như 'GitHub Copilot cho piano', cho phép người dùng chơi vài nốt nhạc qua MIDI và AI sẽ tiếp tục sáng tác phần còn lại ngay trên thiết bị, không cần kết nối internet.

Trải nghiệm AI hoàn tất giai điệu piano ngay trên iPhone: Mô hình 125M chạy hoàn toàn trên thiết bị

Gần một năm trước, tôi bắt đầu mày mò với một ý tưởng: kết nối đàn piano MIDI của mình với chiếc điện thoại, chơi một đoạn nhạc và để AI tự động hoàn tất bản nhạc đó. Hãy tưởng tượng GitHub Copilot, nhưng dành cho piano.

Hóa ra, đây là một cái hố thỏ sâu hơn tôi tưởng. Trải qua 14 thí nghiệm khác nhau, cuối cùng dự án cũng đã đạt đến mức tôi cảm thấy hài lòng và muốn chia sẻ. Kết quả là một ứng dụng tên RollTab, hoàn toàn miễn phí cho người dùng iPhone/iPad sở hữu bàn phím MIDI.

Kiến trúc MIDI: Khác biệt so với âm thanh thông thường

Khác với MP3 hay các định dạng âm thanh khác lưu trữ âm thanh đã thu sẵn, file MIDI lưu trữ âm nhạc dưới dạng một chuỗi các sự kiện: phím được nhấn ở cao độ (pitch) và lực nhấn (velocity) nào, phím được nhả ra khi nào, bàn đạp sustain thay đổi ra sao...

Vấn đề quan trọng nhất là tokenization (chuyển đổi dữ liệu thành token cho AI đọc). Cách biểu diễn ngây thơ nhất là tạo token cho từng sự kiện như NOTE_ON_60_80, NOTE_OFF_60, dẫn đến bộ từ vựng khổng lồ lên đến 16.512 token. Cách này khiến mô hình khó học và dễ bị lệch lạc.

Tôi đã thử nghiệm nhiều cách tiếp cận, từ việc tách cấu trúc gramma (tách riêng NOTE_ON, PITCH, VELOCITY thành các token riêng biệt) đến việc dùng [NOTE, PITCH, VELOCITY, DURATION]. Tuy nhiên, cách đầu tiên khiến mô hình "quên" phát ra lệnh NOTE_OFF, tạo ra các nốt kéo dài vô tận. Cách thứ hai hoạt động tốt về mặt âm nhạc nhưng quá chậm vì tốn nhiều bước tính toán.

Giải pháp đột phá: Biểu diễn nốt nhạc trọn vẹn

Biểu diễn cuối cùng tôi chọn là một sự kiện nốt nhạc duy nhất với 5 trường thông tin:

NOTE(pitch, delta_onset, duration, velocity)

Trong đó, delta_onset đại diện cho khoảng lặng (silence) trước khi nốt tiếp theo vang lên, thay thế cho token TIME_SHIFT riêng biệt. Các hợp âm (chord) được biểu diễn là nhiều nốt có delta_onset = 0, được sắp xếp theo cao độ tăng dần.

Điểm mấu chốt là mô hình xử lý cả nốt nhạc trong một bước duy nhất, thay vì phải chạy 4 bước cho từng thuộc tính. Điều này giúp mô hình đạt tốc độ khoảng 108 nốt/giây trên iPhone, quá đủ cho việc chơi nhạc trực tiếp.

Huấn luyện và tối ưu hóa dữ liệu

Tôi thu thập và xử lý một bộ dữ liệu khổng lồ với vài trăm nghìn file MIDI, tương đương khoảng 300 triệu sự kiện nốt nhạc. Điều đáng ngạc nhiên là việc làm sạch dữ liệu đóng vai trò quan trọng hơn nhiều so với việc chỉ tăng dung lượng dữ liệu. Khi tăng dataset lên 5 lần, các mô hình lại hoạt động tệ hơn.

Quá trình tiền xử lý dữ liệu rất kỹ lưỡng:

  • Chọn lọc các bản nhạc tập trung vào piano
  • Loại bỏ các track trộn lẫn nhiều nhạc cụ
  • Lọc theo mật độ và độ phủ của cao độ/thời gian
  • Khử trùng lặp bằng vân tay (fingerprints) bỏ qua transposition và tempo

DPO: Bí quyết tạo nên sự khác biệt lớn nhất

DPO (Direct Preference Optimization) — tối ưu hóa sở thích trực tiếp — mang lại sự cải thiện lớn nhất sau giai đoạn tiền huấn luyện. Thay vì chỉ huấn luyện để dự đoán nốt nhạc "đúng" duy nhất, tôi dùng Gemini 3.5 Flash để đánh giá cặp đôi (pairwise) các đoạn continuation khác nhau.

Cách đánh giá này hiệu quả hơn nhiều so với việc cho điểm tuyệt đối. Tôi chia thành hai tiêu chí:

  • Điểm continuation: đo độ bám sát với đoạn nhạc đệm (prompt)
  • Điểm sounds-good: đo chất lượng âm nhạc độc lập

Sau khi áp dụng DPO với β=0.03 và dùng bộ dữ liệu consensus (chỉ giữ những cặp đánh giá nhất quán), mô hình đạt tỷ lệ thắng 69.05% so với mô hình gốc, thay vì chỉ 24.55% như trước.

Những thất bại và bài học kinh nghiệm

Không phải mọi thứ đều suôn sẻ. Tôi đã thử rất nhiều phương pháp thất bại:

  • Mô hình note-on/note-off: dễ bị lệch lạc ở các mô hình nhỏ chạy thời gian thực
  • Token stream có grammar: hợp lệ về cú pháp nhưng quá chậm
  • Mirostat (kỹ thuật giảm lặp): làm output trở nên rời rạc
  • Born-again networks: tái huấn luyện trên dự đoán mềm của chính nó, không cải thiện chất lượng

Từ PyTorch đến ứng dụng iOS

Tôi export mô hình từ PyTorch sang Core ML và lượng tử hóa (quantize) trọng số xuống INT8. Vì mô hình chỉ được huấn luyện với context tối đa 512 nốt, tôi xử lý các phiên chơi dài hơn bằng cách giữ lại 384 nốt gần nhất và xây dựng lại context khi cần.

Kết luận

Dự án này mang lại cho tôi rất nhiều niềm vui. Tôi cố tình không đọc quá sâu các nghiên cứu về tạo nhạc để tự mình trải nghiệm quá trình giải quyết vấn đề. Kết quả vẫn chưa hoàn hảo — mô hình vẫn lặp lại đôi chỗ, lời nhắc ngắn vẫn khó xử lý — nhưng đủ để tôi thực sự thích thú ngồi xuống bên cây đàn, chơi vài nốt nhạc và xem chúng tôi có thể cùng nhau tạo ra điều gì.

Hãy nghĩ về nó như một GPT-2 dành cho piano — một mô hình nhỏ gọn, hoạt động mượt mà ngay trên thiết bị di động, ngay bên cạnh người chơi.

Chia sẻ:FacebookX
Nội dung tổng hợp bằng AI, mang tính tham khảo. Xem bài gốc ↗