- 01Lý do bắt đầu: “chỉ riêng việc phân loại đã tốn cả khối thời gian”
- 02Bức tranh tổng thể của cơ chế
- 03Chuyển PDF thành hình ảnh theo từng trang
- 04Logic xác định
- 05Thống nhất quy tắc chấm điểm chỉ bằng “ô đánh dấu”
- 06Thay đổi “đơn vị lỗi sai” theo từng môn
- 07Lý do dùng cấu trúc vượt qua nhiều môi trường thực thi
- 08Những gì cảm nhận được khi thực hiện
- 09Phù hợp với những ai
- 10Tổng kết
Chào buổi sáng, mình là まさきん.
Nhà mình có nhiều con. Mỗi bé học bài tập và giáo trình khác nhau. Việc phân loại đống tờ bài bằng tay mỗi lần vốn là một gánh nặng âm thầm.
Mình đã thử tạo một cơ chế: quét gộp lại, còn việc phân loại thì giao cho AI. Lần này mình giới thiệu cụ thể cả đoạn code và quy tắc đang dùng thực tế.
Lý do bắt đầu: “chỉ riêng việc phân loại đã tốn cả khối thời gian”
Bài tập và tờ bài đã làm xong có bao nhiêu loại là có bấy nhiêu con. Môn học và khối lớp cũng khác nhau hết. Nếu để chung một chỗ, cuối cùng sẽ không biết cái nào của ai.
Việc lật từng tờ bằng tay để kiểm tra là một việc đơn giản nhưng tốn thời gian. Vì vậy mình nghĩ liệu có thể tự động hóa riêng phần “phân loại” này không.
Bức tranh tổng thể của cơ chế
Quy trình khá đơn giản. Mình chia làm 3 giai đoạn sau:
- Quét gộp các tờ bài đã làm xong, chuyển thành PDF
- Chuyển từng trang PDF thành hình ảnh, để AI xác định “của ai, môn nào” dựa vào đặc điểm tiêu đề và layout
- Dựa vào kết quả xác định, phản ánh vào công cụ theo từng con, từng môn
Điểm mấu chốt là ở giai đoạn quét, mình không cần nghĩ đến việc phân loại. Cứ đọc gộp hết, rồi để AI đảm nhận việc phán đoán sau đó.
Chuyển PDF thành hình ảnh theo từng trang
Nếu để AI đọc trực tiếp file PDF vừa quét, có lúc sẽ không nhận diện chính xác được. Đặc biệt các file PDF quét có kết quả chấm điểm viết tay thường chỉ là tập hợp hình ảnh, không có lớp văn bản.
Vì vậy đầu tiên mình dùng PyMuPDF (fitz) để chuyển từng trang thành ảnh PNG.
import fitz
doc = fitz.open("scan.pdf")
for i in range(doc.page_count):
pix = doc[i].get_pixmap(matrix=fitz.Matrix(2, 2)) # độ phân giải gấp 2 lần
pix.save(f"page_{i+1}.png")
Khi tăng độ phân giải lên 2 lần bằng Matrix(2, 2) trước khi chuyển thành ảnh, độ chính xác khi AI đọc chữ hay ô chọn sẽ tăng lên. Kết quả chấm điểm viết tay đặc biệt dễ bị bỏ sót nếu độ phân giải thấp.
Cái bẫy dễ mắc phải: đơn vị tọa độ
Khi muốn zoom riêng ô chấm điểm để kiểm tra, có thể chỉ định phạm vi bằng tham số clip trong get_pixmap. Ở đây có một cái bẫy. Tọa độ của clip phải chỉ định theo tọa độ point của PDF, tức kích thước trang gốc, không phải tọa độ pixel sau khi đã phóng to.
# dù zoom 2 lần hay 4 lần, giá trị của clip vẫn giữ theo kích thước thực của trang (khoảng 590×836pt với A4)
pix = doc[i].get_pixmap(matrix=fitz.Matrix(4, 4), clip=fitz.Rect(0, 140, 589, 600))
Nếu tăng tỷ lệ phóng to mà cũng tăng luôn giá trị của clip, phạm vi sẽ vượt ra ngoài ảnh và không lấy được gì. Nếu nhầm lẫn điểm này, sẽ mắc phải hiện tượng “sao ảnh crop lại trắng trơn” — biết trước điều này từ đầu sẽ tiết kiệm được thời gian.
Logic xác định
Mình xin giới thiệu chỉ dẫn đưa cho AI, đã được tổng quát hóa.
Đây là hình ảnh tờ bài học đã quét.
Dựa vào các gợi ý sau, hãy xác định đây là tờ bài của con nào, môn nào.
- Logo hoặc thiết kế tiêu đề ở phần trên trang
- Hình thức đường kẻ hay layout (kích thước ô vuông, khoảng cách dòng, v.v.)
- Tên đơn vị bài học hay dạng bài tập được ghi
- Tên được ghi trong ô tên
Kết quả xác định trả về theo 3 mục: "ID của con", "môn học", "đơn vị bài học".
Nếu không xác định được, hãy trả lời "không rõ", không cố đoán bừa.
Trong thực tế phân loại, mình đã tạo trước một “bảng nhận diện” kết hợp cả 3 yếu tố: nội dung tiêu đề, đặc điểm layout, ô tên, rồi để AI đối chiếu với bảng đó. Ví dụ “bài tập viết chữ Kanji, có ghi tên khối lớp ở góc trên bên phải” và “bài tập tính toán, có in nhỏ ký hiệu loại bài ở góc dưới bên trái mỗi câu” có thể phân biệt gần như chính xác chỉ bằng hình dạng bên ngoài. Nhờ lập thành bảng, kết quả xác định của AI ít bị lệch hơn.
Ý tưởng giảm công sức phân loại bằng cơ chế hóa có thể áp dụng cho nhiều thứ khác ngoài tờ bài. Việc xem lại gói cước điện thoại vốn hay bị bỏ mặc cũng có nét tương tự.
Khi bấm vào, trang đăng nhập Rakuten sẽ mở ra. Đăng nhập xong sẽ thấy nội dung chương trình.
Thống nhất quy tắc chấm điểm chỉ bằng “ô đánh dấu”
Khi xử lý giáo trình của nhiều con, mình còn quyết định thêm một điều nữa. Đó là thống nhất tiêu chí chấm điểm, không phân biệt theo từng con.
Cụ thể, mình chỉ dùng việc ô đánh dấu ở bên trái hoặc góc trên bên trái mỗi câu có được tô đen hay không, làm căn cứ duy nhất để xác định đúng sai.
- Ô đánh dấu được tô đen → sai (cần ôn lại)
- Ô đánh dấu còn trắng → đúng
- Vòng tròn đỏ (◯) gần đáp án là “dấu xác nhận đúng”, không phải dấu báo sai
- Đáp án được sửa lại bằng bút đỏ là do bố mẹ chữa, không phải câu trả lời của con. Không dùng sự có mặt của chữ đỏ để phán đoán đúng sai
Mình không đưa độ nắn nót của chữ viết hay vết tẩy xóa vào tiêu chí phán đoán. Lý do đơn giản. Việc có ô đánh dấu hay không có thể đọc một cách máy móc, nhưng nếu trộn cả đánh giá độ nắn nót chữ viết vào, tiêu chí sẽ lập tức bị lệch.
Vì vậy mình đã ghi rõ ngay từ đầu trong chỉ dẫn cho AI quy tắc: “chỉ dùng việc tô đen ô đánh dấu để phán đoán đúng sai, không đưa chữ đẹp xấu hay chỗ sửa bằng bút đỏ vào làm căn cứ”. Có câu này hay không đã làm thay đổi khá nhiều mức độ lệch của kết quả xác định.
Quy trình phóng to để tránh bỏ sót ô đánh dấu
Nếu chỉ xem ảnh quét toàn trang đã thu nhỏ, có lúc ô đánh dấu bị tô đen sẽ trông không rõ. Để tránh vội kết luận “đã viết hết nên đúng hết toàn bộ”, mình luôn thực hiện các bước sau:
- Xem toàn trang, nắm được layout tổng quát
- Cắt riêng cột ô đánh dấu rồi phóng to (dùng
clipnhư đã nói ở trên) - Kiểm tra từng câu trên ảnh đã phóng to, xem có bị tô đen không
- Những ô đánh dấu khó xác định, hoặc chỗ không đọc được chữ, thì không đoán bừa mà nhờ người kiểm tra lại
Mình cảm nhận rõ rằng nếu chỉ phán đoán bằng ảnh thu nhỏ cỡ thumbnail, rất dễ bỏ sót việc tô đen.
Thay đổi “đơn vị lỗi sai” theo từng môn
Có một điểm nữa mình đã tinh chỉnh. Đó là thay đổi đơn vị ghi nhận lỗi sai theo từng môn học.
| Môn học | Đơn vị ghi nhận | Ví dụ cụ thể |
|---|---|---|
| Luyện viết Kanji, Hiragana | Đơn vị từng chữ | Dùng chính chữ đó làm khóa, ví dụ “校”, “ぬ” |
| Toán | Đơn vị dạng bài | Dùng dạng bài làm khóa, ví dụ “đổi đơn vị”, “chia có dư”, “giá trị hàng số” |
| Khoa học, Xã hội | Đơn vị chủ đề + mục nhỏ | Dùng khóa phân cấp kiểu “tên chủ đề : phần : số thứ tự” |
Cùng là “câu sai” nhưng độ chi tiết cần xem lại khác nhau tùy môn. Nếu gộp chữ Kanji theo đơn vị bài học, độ chính xác của lần ôn tập sau sẽ giảm. Ngược lại, nếu chia “dạng bài” của Toán quá nhỏ đến từng câu, sẽ khó thu hẹp đối tượng cần ôn tập.
Với Toán, mình cho in sẵn một ký hiệu nhỏ biểu thị dạng bài ở góc mỗi câu, khi đọc kết quả chấm điểm sẽ tổng hợp lỗi sai theo đơn vị ký hiệu đó. Quy tắc đơn giản là nếu có nhiều câu cùng dạng và chỉ cần sai một câu, toàn bộ dạng đó sẽ được coi là “cần ôn lại”.
Với Khoa học và Xã hội, vì phần ôn tập ở cuối tờ bài có khi ra đề từ một đơn vị khác với chủ đề chính của ngày đó, mình luôn đối chiếu nội dung câu hỏi với danh sách chủ đề trước, rồi mới xác định đây là ôn tập của chủ đề nào. Đây là phần mình không quyết định bừa mà luôn đối chiếu trước khi ghi nhận.
Cơ chế này thực ra được chuyển thể từ một cơ chế “ghi nhận mục đã sai để ra đề lại nhiều lần” mà mình từng tạo cho mục đích khác. Dù mục đích thay đổi, logic nền tảng vẫn dùng được nguyên vẹn.
Lý do dùng cấu trúc vượt qua nhiều môi trường thực thi
Cơ chế này có cấu trúc 2 tầng: phần trao đổi với AI diễn ra trên môi trường sandbox trên cloud, còn việc thao tác file thực tế và quản lý trạng thái được giao cho một tiến trình chạy thường trực trên máy tính ở nhà.
Lý do rất đơn giản: cơ sở dữ liệu lưu kết quả chấm điểm và script tạo bài tập chỉ đặt trên máy tính ở nhà. Từ phía cloud truy cập vào phía nhà thông qua một script client nhẹ, chỉ để gửi lệnh đơn giản.
# ví dụ: dựa vào kết quả xác định, phản ánh khóa của câu sai
python3 tools/kanji_drill/kanji_bridge_client.py mark-miss 校庭 音楽
python3 tools/kanji_drill/kanji_bridge_client.py mark-correct 教室
# trước khi phản ánh, kiểm tra tiến trình thường trực ở nhà còn sống không
python3 tools/kanji_drill/kanji_bridge_client.py health
Mình luôn chèn lệnh health này ngay trước khi phản ánh. Nếu không nhận ra tiến trình ở nhà đã bị dừng mà vẫn tiếp tục gửi mark-miss, lệnh sẽ trông như thành công nhưng thực ra chẳng phản ánh được gì cả — đây là sự cố mình muốn tránh.
Những gì cảm nhận được khi thực hiện
Điều giúp ích nhất là việc kiểm tra “của ai, môn nào” đã biến mất. Chỉ cần quét gộp, sau đó xem kết quả là xong.
Nhưng mình không hoàn toàn tin tưởng tuyệt đối vào kết quả xác định của AI. Những phần được đánh giá là “không rõ”, hay những ô đánh dấu khó xác định, mình luôn tự mắt kiểm tra lại. Mình cảm thấy việc để AI thẳng thắn nói “không biết” khi không chắc, thay vì ép nó phân loại bừa, cuối cùng lại tạo ra một cơ chế đáng tin cậy hơn.
Phù hợp với những ai
- Người có tờ bài, bài tập của nhiều con lẫn vào nhau, mất thời gian phân loại
- Người muốn thống nhất tiêu chí chấm điểm bằng quy tắc máy móc, thay vì dựa vào “độ nắn nót bề ngoài”
- Người không ngại việc lập trình ở mức PyMuPDF hay một script bridge nhỏ
Tổng kết
Giáo trình của nhiều con, số lượng càng nhiều thì gánh nặng phân loại càng lớn. Bằng cách kết hợp quét và phân loại bằng AI, mình đã tự động hóa được riêng phần đó.
Những chi tiết nhỏ nhặt như thống nhất đơn vị tọa độ hay minh bạch hóa tiêu chí chấm điểm, thực ra lại là yếu tố quyết định độ ổn định của độ chính xác. Khi nghĩ đến việc cơ chế hóa, có lẽ chính công việc “quyết định rõ tiêu chí phán đoán” này mới là điều quan trọng bất ngờ.
Gánh nặng có thể giảm bằng cơ chế hóa không chỉ có việc phân loại tờ bài. Tiếp theo mình định xem lại gói cước điện thoại theo cách tương tự.
Khi bấm vào, trang đăng nhập Rakuten sẽ mở ra. Đăng nhập xong sẽ thấy nội dung chương trình.
Bài viết này có chứa quảng cáo liên kết. Nếu bạn đăng ký sản phẩm hoặc dịch vụ qua liên kết trên trang này, chúng tôi có thể nhận được hoa hồng từ đối tác. Ngoài ra, người vận hành trang là nhân viên của Rakuten Group và có thể nhận thù lao qua chương trình giới thiệu nhân viên. Nội dung và đánh giá trong bài được viết dựa trên trải nghiệm thực tế và tìm hiểu của người vận hành, không phụ thuộc vào việc có quảng cáo hay không, nhưng mong bạn đọc với sự hiểu biết về mối quan hệ trên. Chi tiết xem tại phần Miễn trừ trách nhiệm & Tiết lộ liên kết. Miễn trừ trách nhiệm & Tiết lộ liên kết
Bài viết này có sử dụng dịch máy. Vui lòng tham khảo trang đa ngôn ngữ trên website chính thức của Rakuten Mobile để biết điều kiện chính xác.
Nếu bạn có thắc mắc về khu vực phủ sóng hoặc chất lượng tín hiệu của Rakuten Mobile, có thể liên hệ qua mẫu đề nghị khảo sát và cải thiện sóng chính thức.