.. raw:: html
AutoRec: Dự đoán Đánh giá với Bộ tự Mã hóa
==========================================
.. raw:: html
Mặc dù mô hình phân rã ma trận đạt hiệu năng tương đối ổn với bài toán
dự đoán đánh giá, nhưng về căn bản nó là một mô hình tuyến tính. Do đó,
mô hình dạng này không có khả năng nắm bắt được mối quan hệ phi tuyến
phức tạp và rắc rối, mà có thể có khả năng dự đoán sở thích người dùng.
Trong phần này, chúng tôi sẽ giới thiệu một mô hình mạng nơ-ron lọc cộng
tác phi tuyến, gọi là AutoRec :cite:`Sedhain.Menon.Sanner.ea.2015`. Nó
áp dụng lọc cộng tác (*collaborative filtering - CF*) với kiến trúc của
một bộ tự mã hóa (*autoencoder*), nhằm mục đích tích hợp biến đổi phi
tuyến vào CF dựa trên cơ sở các phản hồi trực tiếp. Mạng nơ-ron đã được
chứng minh là có khả năng xấp xỉ bất kì hàm liên tục nào, điều này khiến
nó phù hợp để khắc phục các hạn chế và tăng cường khả năng biểu diễn của
mô hình phân rã ma trận.
.. raw:: html
Một mặt, AutoRec có cùng cấu trúc với một bộ tự mã hóa gồm một tầng đầu
vào, một tầng ẩn và một tầng khôi phục (đầu ra). Bộ tự mã hóa là một
mạng nơ-ron học cách sao chép đầu vào sang đầu ra nhằm mã hóa đầu vào
thành dạng biểu diễn ẩn (và thường có kích thước nhỏ). Trong AutoRec,
thay vì trực tiếp tạo embedding của người dùng/sản phẩm trong không gian
kích thước nhỏ hơn, ta sử dụng các cột/hàng của ma trận tương tác làm
đầu vào, sau đó khôi phục lại ma trận tương tác ở tầng đầu ra.
.. raw:: html
Mặt khác, AutoRec khác với bộ tự mã hóa truyền thống ở chỗ: thay vì học
dạng biểu diễn ẩn, AutoRec tập trung vào học/khôi phục tầng đầu ra. Nó
sử dụng phần đã biết của ma trận tương tác làm đầu vào, nhằm khôi phục
lại ma trận đánh giá hoàn chỉnh. Trong khi đó, các phần tử còn thiếu
trong đầu vào được điền vào tầng đầu ra thông qua quá trình khôi phục
cho mục đích đề xuất.
.. raw:: html
Có hai dạng AutoRec: dựa trên người dùng (*user-based*) và dựa trên sản
phẩm (*item-based*). Để ngắn gọn, ở đây chúng tôi chỉ giới thiệu AutoRec
dựa trên sản phẩm. AutoRec dựa trên người dùng có thể được suy ra một
cách tương tự.
.. raw:: html
Mô hình
-------
.. raw:: html
Gọi :math:`\mathbf{R}_{*i}` ký hiệu cột thứ :math:`i` của ma trận đánh
giá. Những đánh giá chưa biết được gán mặc định bằng không. Kiến trúc
nơ-ron được định nghĩa như sau:
.. math::
h(\mathbf{R}_{*i}) = f(\mathbf{W} \cdot g(\mathbf{V} \mathbf{R}_{*i} + \mu) + b)
.. raw:: html
trong đó :math:`f(\cdot)` và :math:`g(\cdot)` biểu diễn hàm kích hoạt,
:math:`\mathbf{W}` và :math:`\mathbf{V}` là các ma trận trọng số,
:math:`\mu` và :math:`b` là hệ số điều chỉnh. Gọi :math:`h( \cdot )` ký
hiệu cho toàn bộ mạng AutoRec. Đầu ra :math:`h(\mathbf{R}_{*i})` chính
là bản khôi phục của cột thứ :math:`i` của ma trận đánh giá.
.. raw:: html
Hàm mục tiêu sau hướng tới việc cực tiểu hóa sai số khôi phục:
.. math::
\underset{\mathbf{W},\mathbf{V},\mu, b}{\mathrm{argmin}} \sum_{i=1}^M{\parallel \mathbf{R}_{*i} - h(\mathbf{R}_{*i})\parallel_{\mathcal{O}}^2} +\lambda(\| \mathbf{W} \|_F^2 + \| \mathbf{V}\|_F^2)
.. raw:: html
trong đó :math:`\| \cdot \|_{\mathcal{O}}` nghĩa là chỉ có phần đánh giá
đã biết là được xét, tức chỉ các trọng số tương ứng với những đầu vào đã
biết mới được cập nhật trong lan truyền ngược.
.. code:: python
from d2l import mxnet as d2l
from mxnet import autograd, gluon, np, npx
from mxnet.gluon import nn
import mxnet as mx
import sys
npx.set_np()
.. raw:: html
Lập trình Mô hình
-----------------
.. raw:: html
Một bộ tự mã hóa điển hình bao gồm một bộ mã hóa và một bộ giải mã. Bộ
mã hóa chiếu đầu vào thành dạng biểu diễn ẩn và bộ giải mã ánh xạ tầng
ẩn tới tầng khôi phục. Ta tuân theo cấu trúc này và tạo bộ mã hóa cùng
bộ giải mã với các tầng kết nối dày đặc. Hàm kích hoạt của bộ mã hóa
được đặt mặc định bằng ``sigmoid`` và ta sẽ không áp dụng hàm kích hoạt
nào lên tầng giải mã. Dropout được thêm vào sau khi mã hóa nhằm giảm
hiện tượng quá khớp. Gradient của các đầu vào chưa biết được che lại để
đảm bảo rằng chỉ có các đánh giá đã biết tham gia vào quá trình học của
mô hình.
.. code:: python
class AutoRec(nn.Block):
def __init__(self, num_hidden, num_users, dropout=0.05):
super(AutoRec, self).__init__()
self.encoder = nn.Dense(num_hidden, activation='sigmoid',
use_bias=True)
self.decoder = nn.Dense(num_users, use_bias=True)
self.dropout = nn.Dropout(dropout)
def forward(self, input):
hidden = self.dropout(self.encoder(input))
pred = self.decoder(hidden)
if autograd.is_training(): # Mask the gradient during training
return pred * np.sign(input)
else:
return pred
.. raw:: html
Lập trình lại Bộ Đánh giá
-------------------------
.. raw:: html
Do đầu vào và đầu ra thay đổi nên ta cần phải lập trình lại hàm đánh
giá, nhưng vẫn sử dụng RMSE làm phép đo độ chính xác.
.. code:: python
def evaluator(network, inter_matrix, test_data, devices):
scores = []
for values in inter_matrix:
feat = gluon.utils.split_and_load(values, devices, even_split=False)
scores.extend([network(i).asnumpy() for i in feat])
recons = np.array([item for sublist in scores for item in sublist])
# Calculate the test RMSE
rmse = np.sqrt(np.sum(np.square(test_data - np.sign(test_data) * recons))
/ np.sum(np.sign(test_data)))
return float(rmse)
.. raw:: html
Huấn luyện và Đánh giá Mô hình
------------------------------
.. raw:: html
Giờ hãy cùng huấn luyện và đánh giá AutoRec trên tập dữ liệu MovieLens.
Ta có thể thấy rõ ràng rằng RMSE kiểm tra thấp hơn so với mô hình phân
rã ma trận, điều này xác thực độ hiệu quả của mạng nơ-ron trong nhiệm vụ
dự đoán đánh giá.
.. code:: python
devices = d2l.try_all_gpus()
# Load the MovieLens 100K dataset
df, num_users, num_items = d2l.read_data_ml100k()
train_data, test_data = d2l.split_data_ml100k(df, num_users, num_items)
_, _, _, train_inter_mat = d2l.load_data_ml100k(train_data, num_users,
num_items)
_, _, _, test_inter_mat = d2l.load_data_ml100k(test_data, num_users,
num_items)
train_iter = gluon.data.DataLoader(train_inter_mat, shuffle=True,
last_batch="rollover", batch_size=256,
num_workers=d2l.get_dataloader_workers())
test_iter = gluon.data.DataLoader(np.array(train_inter_mat), shuffle=False,
last_batch="keep", batch_size=1024,
num_workers=d2l.get_dataloader_workers())
# Model initialization, training, and evaluation
net = AutoRec(500, num_users)
net.initialize(ctx=devices, force_reinit=True, init=mx.init.Normal(0.01))
lr, num_epochs, wd, optimizer = 0.002, 25, 1e-5, 'adam'
loss = gluon.loss.L2Loss()
trainer = gluon.Trainer(net.collect_params(), optimizer,
{"learning_rate": lr, 'wd': wd})
d2l.train_recsys_rating(net, train_iter, test_iter, loss, trainer, num_epochs,
devices, evaluator, inter_mat=test_inter_mat)
.. parsed-literal::
:class: output
train loss 0.000, test RMSE 0.900
141998383.2 examples/sec on [gpu(0)]
.. figure:: output_autorec_vn_abddf5_7_1.svg
Tóm tắt
-------
.. raw:: html
- Ta có thể thiết kế thuật toán phân rã ma trận với bộ tự giải mã, cùng
lúc tích hợp các tầng phi tuyến và điều chuẩn dropout.
- Thí nghiệm trên tập dữ liệu MovieLens 100K cho thấy AutoRec đạt hiệu
năng vượt trội so với phân rã ma trận.
Bài tập
-------
.. raw:: html
- Thay đổi kích thước ẩn của AutoRec để quan sát ảnh hưởng của việc này
lên hiệu năng mô hình.
- Hãy thử thêm vào nhiều tầng ẩn. Việc này có giúp cải thiện hiệu năng
mô hình không?
- Liệu bạn có thể tìm một bộ hàm kích hoạt nào khác tốt hơn cho bộ giải
mã và bộ mã hóa?
Thảo luận
---------
- Tiếng Anh: `MXNet `__
- Tiếng Việt: `Diễn đàn Machine Learning Cơ
Bản `__
Những người thực hiện
---------------------
Bản dịch trong trang này được thực hiện bởi:
- Đoàn Võ Duy Thanh
- Đỗ Trường Giang
- Nguyễn Văn Cường
- Nguyễn Thái Bình
- Nguyễn Lê Quang Nhật
- Phạm Hồng Vinh
- Lê Khắc Hồng Phúc
*Cập nhật lần cuối: 05/10/2020. (Cập nhật lần cuối từ nội dung gốc:
21/07/2020)*