Autoencoder: học biểu diễn bằng cách tái tạo dữ liệu
Bài này trả lời cách một mạng học mã cho dữ liệu khi không có nhãn lớp. Việc then chốt là cổ chai, bottleneck: đoạn giữa của mạng có ít số hơn đầu vào, nên thông tin phải bị chọn lọc mới đi qua được. Mạng không giữ nổi mọi pixel. Nó phải quyết định phần nào của mẫu đáng nằm trong vài chục số ở giữa.
Sau cổ chai, mục tiêu huấn luyện là tái tạo, reconstruction: đầu ra phải gần lại chính đầu vào. Nhãn lớp không cần, vì đích đến lấy từ input. Encoder là khối nén đầu vào thành mã. Decoder là khối đọc mã để dựng lại đầu vào. Bài này chưa phải một cách tốt để sinh mẫu mới. Mã chỉ bị ép hoạt động tốt tại những điểm encoder tạo ra cho dữ liệu đã thấy. Một điểm ngẫu nhiên ở khoảng trống có thể ra thứ vô nghĩa. Cách đặt phân phối lên mã để lấy mẫu thuộc bài sau. Bài này cũng không đi vào GAN hay diffusion.
Đọc nhanh. Đọc vì sao không copy nguyên input, rồi sơ đồ encoder–decoder, rồi mất mát tái tạo, rồi vì sao mã này chưa dùng để sinh mẫu. Các mục Đào sâu không nằm trên đường đó.
Vì sao không copy nguyên input?
Vì sao không copy nguyên input? Nếu mã ở giữa rộng bằng đầu vào và mạng đủ mạnh, decoder có thể nhận gần như đủ thông tin để chép từng số sang đầu ra. Mất mát tái tạo có thể về không, trong khi mã không phải là một bản tóm tắt. Cổ chai làm đường chép đó khó đi: decoder chỉ nhận được ít số hơn đầu vào, nên những số đó phải là phần đáng giữ cho mất mát đang dùng.
Encoder là một hàm, ký hiệu , với bộ trọng số ký hiệu . Decoder là một hàm, ký hiệu , với bộ trọng số ký hiệu . Mã ẩn, latent code, là đầu ra của encoder. Nếu không có ràng buộc, hai hàm ấy có thể chắp thành hàm đồng nhất: mọi đầu vào đi qua rồi trở lại đúng chính nó.
Cổ chai chặn lối thoát đó bằng chiều của mã. Một chuỗi chiều có thể đi từ ảnh 784 số, xuống vài lớp hẹp, tới 16 số, rồi bung trở lại 784 số.
Mười sáu số ở giữa là chỗ mạng phải quyết định giữ gì. Cổ chai là ràng buộc lúc học biểu diễn. Mã phải phục vụ phân phối dữ liệu và mất mát đang dùng. Nén file kiểu ZIP là một việc khác: bản nén giữ đủ thông tin để khôi phục từng bit, còn cổ chai được phép bỏ chi tiết mà mất mát không đòi.

Hình 1. Sơ đồ Autoencoder. Nguồn: Chervinskii, Wikimedia Commons, CC BY-SA 4.0. Trang giấy phép: https://commons.wikimedia.org/wiki/File:Autoencoder_structure.png
Sơ đồ trên là hình encoder thu hẹp rồi decoder mở rộng. Cùng một luồng viết bằng ký hiệu: đầu vào thành mã , mã thành bản tái tạo .
Điểm khác với học có giám sát quen thuộc là đích đến không phải nhãn lớp. Target được lấy trực tiếp từ input. Mũi tên đứt trên sơ đồ nói điều đó: bản tái tạo bị so với chính đầu vào, không so với một lớp mèo hay chó.
Mất mát tái tạo
Mục tiêu cơ bản là giảm sai khác giữa đầu vào và bản tái tạo. Sai khác đó là mất mát tái tạo, reconstruction loss. Nó là một độ đo khoảng cách giữa hai đối tượng cùng kích thước.
Độ đo chưa bị khóa thành một công thức. Hai lựa chọn dưới đây phủ phần lớn bài nhập môn. Cả hai đều nói cùng một việc: bản dựng lại phải gần mẫu gốc. Chúng khác nhau ở cách phạt từng thành phần.
Với dữ liệu là số thực, một lựa chọn đơn giản là trung bình bình phương sai số, mean squared error. Sai số lớn bị phạt nặng hơn vì có bước bình phương.
Khi mỗi thành phần đầu ra được coi như một biến Bernoulli, tức một lần chọn 0 hoặc 1 với một xác suất, mất mát khớp hơn là cross-entropy nhị phân, binary cross-entropy. Pixel lúc này là xác suất, không phải một độ sáng tự do.
Loss nên khớp phân phối ta giả định cho đầu ra, và khớp cách dữ liệu đã được chuẩn hóa. Ảnh không tự động kéo theo BCE. Nếu pixel đã được co về một khoảng thực và decoder kết thúc bằng một giá trị thực, MSE có thể là giả định đúng hơn. Nếu pixel là xác suất của một biến nhị phân, BCE khớp giả định đó hơn.
Mã ẩn học được điều gì
Khi tái tạo tốt, hai mẫu có cấu trúc giống nhau có thể được encoder đưa tới các vùng gần nhau. Điều này là một kết quả ta hy vọng, không phải hệ quả logic của riêng mất mát tái tạo. Mất mát chỉ thấy từng cặp đầu vào và bản dựng lại. Nó không có một hạng riêng bắt “cùng loại thì mã phải sát nhau”.
Một mã hữu ích thường được mong có vài tính chất cùng lúc. Nó gọn: giữ phần quan trọng với mất mát, bỏ bớt nhiễu. Nó có cấu trúc: mẫu tương tự có mã liên quan. Nó ổn định: đổi đầu vào một chút thì mã không nhảy vô lý. Nó hữu ích cho việc phía sau: phân loại, gom cụm, hoặc tìm kiếm dùng mã tốt hơn dùng dữ liệu thô. Bốn tính chất này là tiêu chí để soi, không phải bốn món mất mát tự xuất hiện.
Với chữ số viết tay, nếu mã chỉ còn hai số, mỗi ảnh là một điểm trên mặt phẳng. Sau huấn luyện, các chữ cùng loại có thể tụ thành cụm. Hình đó rất tốt để nhìn mô hình đang tổ chức dữ liệu ra sao. Mã quá ngắn thì mạng thiếu chỗ để tái tạo. Mã quá dài, và decoder quá mạnh, thì mạng có thể lách cổ chai và học gần như chép. Chiều mã vì vậy là một lựa chọn theo dữ liệu và theo việc cần làm, không phải một số càng nhỏ càng hay.
Mã ngắn hơn đầu vào
Autoencoder undercomplete là dạng cổ chai đúng nghĩa: chiều của mã nhỏ hơn chiều của đầu vào. Từ undercomplete chỉ việc mã không đủ chỗ để chứa nguyên đầu vào.
Theo Deep Learning của Goodfellow, Bengio và Courville, khi encoder và decoder tuyến tính và mất mát là MSE, autoencoder undercomplete học một không gian con liên quan chặt với PCA. PCA, phân tích thành phần chính, là phép tìm các hướng tuyến tính giữ nhiều phương sai của dữ liệu. Với mạng phi tuyến, autoencoder có thể học phép biến đổi phức tạp hơn phép tuyến tính đó.
| PCA | Autoencoder |
|---|---|
| Biến đổi tuyến tính | Có thể phi tuyến |
| Nghiệm có cấu trúc đại số rõ | Huấn luyện bằng gradient descent |
| Các thành phần trực giao | Các chiều mã không bắt buộc trực giao |
| Dễ diễn giải hơn trong trường hợp tuyến tính | Linh hoạt hơn, khó diễn giải hơn |
Với dữ liệu nhỏ, quan hệ gần tuyến tính, hoặc khi cần giải thích rõ các hướng, PCA vẫn là baseline quan trọng. Autoencoder phi tuyến là một mở rộng có ích khi quan hệ trong dữ liệu không nằm trên một không gian con tuyến tính. Nó không thay PCA bằng một kết luận sẵn.
Đây chưa phải cách sinh mẫu mới
Hãy tưởng tượng các mã của dữ liệu huấn luyện như những đảo. Giữa các đảo là vùng decoder ít hoặc chưa bị mất mát ép phải xử lý.
Lấy một điểm ngẫu nhiên rơi vào vùng trống rồi đưa qua decoder, đầu ra có thể vô nghĩa. Mất mát tái tạo chỉ yêu cầu decoder hoạt động tốt tại các mã mà encoder tạo ra cho dữ liệu huấn luyện. Nó không bắt toàn bộ không gian mã phải mượt, và không chỉ một phân phối để rút mã mới. Vì vậy autoencoder cơ bản là một mô hình học biểu diễn và tái tạo. Nó chưa phải một cách tốt để sinh mẫu mới.
Muốn sinh, ta cần một câu trả lời cho việc mã mới lấy từ đâu, và cần decoder xử lý được những mã ấy. Đó là việc bài sau làm bằng một phân phối trên mã, không phải bằng cách thu hẹp thêm cổ chai.
Đào sâu: khi cổ chai không còn là chiều nhỏ
Nếu mã dài bằng hoặc dài hơn đầu vào, hàm đồng nhất lại trở thành một lối thoát dễ. Ta có thể thêm ràng buộc khác, thay vì chỉ thu hẹp chiều.
Mã thưa, sparse autoencoder, cho phép nhiều chiều, nhưng mỗi mẫu chỉ nên làm một ít chiều hoạt động mạnh. Mất mát là tái tạo cộng một hình phạt trên mã. Hệ số chỉnh mức phạt đó.
Một hình phạt đơn giản là chuẩn L1, tổng trị tuyệt đối của các thành phần mã. Mã có nhiều thành phần khác không thì bị phạt.
Kết quả mong muốn là một bộ chiều khá rộng, nhưng mỗi mẫu chỉ dùng một phần nhỏ, giống một túi vài đặc trưng được bật. Mức quá tay thì tái tạo kém. Mức quá nhẹ thì tính thưa không xuất hiện. Không có một đúng cho mọi dữ liệu.
Autoencoder khử nhiễu, denoising autoencoder, đổi đầu vào chứ không nhất thiết đổi chiều mã. Ta cố ý làm hỏng bản sạch, rồi bắt mạng dựng lại bản sạch, không phải dựng lại bản đã hỏng. Bản hỏng ký hiệu là .
Luồng lúc học là từ bản hỏng tới mã, rồi tới bản dựng lại gần bản sạch.
Mạng không thể chỉ nhớ từng pixel, vì pixel đưa vào đã sai hoặc đã bị che. Nó phải dựa vào cấu trúc ổn định của dữ liệu để phục hồi. Đây là một ý quan trọng trong lịch sử autoencoder, và cũng là một bức tranh hữu ích trước diffusion: học phục hồi tín hiệu sạch từ tín hiệu bị nhiễu. Cùng một bức tranh không có nghĩa hai thuật toán là một. Diffusion có lịch nhiễu nhiều bước và mục tiêu riêng. Denoising autoencoder ở đây vẫn là một encoder, một mã, một decoder, với đích là bản sạch.
Với ảnh, encoder và decoder thường dùng tích chập, convolution, thay vì chỉ các lớp kết nối đầy đủ. Encoder giảm kích thước không gian bằng tích chập và downsampling. Decoder bung ảnh trở lại bằng upsampling hoặc tích chập chuyển vị. Decoder không bắt buộc là bản đối xứng từng lớp của encoder. Kiến trúc cần ra đúng kích thước đầu ra, và cần tối ưu được mất mát. Đối xứng là một cách thiết kế dễ nhớ, không phải một điều kiện để mất mát đúng.
Đào sâu: một ví dụ số, việc dùng mã, và lỗi hay gặp
Lấy một đầu vào bốn số để thấy gradient đi đường nào. Đây là một ví dụ tính tay, không phải số liệu từ một tập dữ liệu thật.
Encoder tạo mã hai chiều:
Decoder dựng lại:
Trung bình bình phương sai số của bốn thành phần là:
Trong huấn luyện, gradient đi từ mất mát này qua decoder, qua mã, rồi về encoder. Không có một nhãn dạy mã phải bằng một vector cho trước. Encoder tự tìm mã nào giúp decoder tái tạo tốt với ràng buộc đang có.
Mã ấy dùng được theo vài hướng, mỗi hướng có điều kiện. Vẽ hai chiều nên được soi cùng PCA, vì mỗi phép giữ một kiểu cấu trúc khác nhau. Khử nhiễu là học từ bản hỏng sang bản sạch. Trích đặc trưng là bỏ decoder sau khi học và dùng mã cho phân loại, gom cụm, hoặc tìm kiếm. Autoencoder cũng từng được dùng để khởi tạo mạng sâu. Học tự giám sát hiện nay có thêm mục tiêu khác. Ý giữ lại là học biểu diễn từ chính dữ liệu.
Phát hiện bất thường cần nói riêng, vì nó dễ bị hiểu quá tay. Mạng học chủ yếu trên dữ liệu coi là bình thường. Lúc suy diễn, điểm bất thường là độ sai tái tạo.
Điểm này lớn hơn một ngưỡng thì mẫu bị đánh dấu. Cách làm dễ triển khai, và có giới hạn rõ: một autoencoder quá mạnh đôi khi vẫn tái tạo tốt mẫu lạ. Ngưỡng phải được chọn trên tập kiểm tra có bất thường đại diện. Sai số cao là một tín hiệu cần kiểm, không phải định nghĩa của mọi loại bất thường.
Ba dòng dưới đây là khung huấn luyện, không phải một notebook đủ để chạy. Mọi biến thể trong bài này sửa một trong các chỗ: kiến trúc encoder hoặc decoder, cách tạo đầu vào, ràng buộc trên mã, hoặc mất mát.
z = encoder(x)
x_hat = decoder(z)
loss = reconstruction_loss(x_hat, x)
optimizer.zero_grad()
loss.backward()
optimizer.step()
| Lỗi | Triệu chứng | Cách nghĩ để sửa |
|---|---|---|
| Cổ chai quá nhỏ | Tái tạo rất tệ | Tăng chiều mã hoặc sức chứa của mạng |
| Cổ chai quá lớn | Mất mát tập học rất thấp, mã kém | Giảm chiều hoặc thêm regularization |
| Decoder quá mạnh | Mạng gần như chép | Tăng ràng buộc trên mã |
| Loss không khớp dữ liệu | Ảnh mờ hoặc sai thang đo | Soi chuẩn hóa và phân phối đầu ra |
| Chỉ nhìn mất mát tập học | Tưởng ổn nhưng không tổng quát | Theo dõi tái tạo trên tập kiểm tra và chỉ số việc phía sau |
| Dùng sai số tái tạo làm điểm bất thường mà không kiểm | Báo động sai nhiều | Chọn ngưỡng trên tập có bất thường đại diện |
Regularization trong bảng là các ràng buộc thêm lúc học, như hình phạt L1 ở mục mã thưa, để mã không tự do đến mức chỉ còn việc chép.
Nguồn đã dùng
- Ian Goodfellow, Yoshua Bengio, Aaron Courville, Deep Learning, Chapter 14: https://www.deeplearningbook.org/contents/autoencoders.html
- TensorFlow, Intro to Autoencoders: https://www.tensorflow.org/tutorials/generative/autoencoder
- Pascal Vincent et al., Extracting and Composing Robust Features with Denoising Autoencoders, ICML 2008.
- Hình kiến trúc Autoencoder: Wikimedia Commons, CC BY-SA 4.0: https://commons.wikimedia.org/wiki/File:Autoencoder_structure.png
Nếu chỉ đọc bài này
Autoencoder học mã bằng cách dựng lại chính đầu vào, và chỉ hữu ích khi việc chép nguyên bị chặn. Cổ chai là cách chặn dễ thấy nhất: mã ít chiều hơn đầu vào, nên mạng phải chọn thông tin. Mất mát là khoảng cách giữa bản dựng lại và đầu vào, chọn MSE hay BCE theo phân phối đầu ra chứ không theo tên loại file. Mã ngắn có thể giúp vẽ, khử nhiễu, trích đặc trưng, hoặc góp một tín hiệu bất thường, với điều kiện đã nói: tín hiệu đó cần được kiểm trên dữ liệu có đại diện. Bản dựng lại của một mẫu đã có không phải một mẫu sinh mới. Vùng trống giữa các mã không được mất mát chăm sóc.
Bài kế sửa lỗ mỗi đầu vào chỉ là một điểm, bằng cách đặt một phân phối lên mã ẩn.