AI

Matrix Factorization

Khai báo ma trận

$$R \in \mathbb{R}^{m \times n}$$

$$\quad P \in \mathbb{R}^{m \times k}, \quad Q \in \mathbb{R}^{n \times k}$$

Dự đoán rating

$$ \hat{R} = P Q^{\top}$$

Dự đoán rating theo từng dòng

$$\hat r_{ij} = p_i^{\top} q_j$$

Hàm mục tiêu (không regularization)

$$ \min_{P,Q} \left\| M \odot \left(R - P Q^{\top}\right) \right\|_F^2 $$ $$ M_{ij} = \begin{cases} 1, & \text{nếu } r_{ij} \text{ được quan sát} \\ 0, & \text{ngược lại} \end{cases} $$
Hàm mục tiêu theo từng quan sát

$$\min_{P,Q} \sum_{(i,j)\in\Omega} \left(r_{ij} - p_i^{\top} q_j\right)^2$$

Tính sai số

$$E = M \odot (R - P Q^{\top})$$
Sai số theo từng dòng

$$ e_{ij} = r_{ij} - p_i^{\top} q_j$$

Gradient

$$ \frac{\partial \mathcal{L}}{\partial p_i} = -2 e_{ij} q_j $$

$$ \frac{\partial \mathcal{L}}{\partial q_j} = -2 e_{ij} p_i$$

Cập nhật SGD

$$P \leftarrow P + \eta \, E Q$$

$$Q \leftarrow Q + \eta \, E^{\top} P$$

Cập nhật theo từng quan sát

$$p_i \leftarrow p_i + \eta\, e_{ij} q_j$$

$$q_j \leftarrow q_j + \eta\, e_{ij} p_i$$

Example

$$R = \begin{bmatrix} 3 & 5 & 4 & 5\\ 2 & 4 & ? & 5\\ 5 & ? & 3 & 4 \end{bmatrix} $$

Khởi tạo

$$ P= \begin{bmatrix} 0.5\\ 0.1\\ 0.2 \end{bmatrix} \in \mathbb{R}^{3\times 1}, \qquad Q= \begin{bmatrix} 0.1\\ 0.2\\ 0.2\\ 0.3 \end{bmatrix} \in \mathbb{R}^{4\times 1} $$

Learning Rate

$$\eta = 0.1$$

Implement

Cài đặt pytorch

pip install torch torchvision torchaudio

Code chạy mô hình Matrix Factorization
R = torch.tensor([
    [3., 5., 4., 5.],
    [2., 4., 0., 5.],
    [5., 0., 3., 4.]
])
M = torch.tensor([
    [1., 1., 1., 1.],
    [1., 1., 0., 1.],
    [1., 0., 1., 4.]
])
P = torch.tensor([
    [0.5],
    [0.1],
    [0.2]], requires_grad=True)
Q = torch.tensor([
    [0.1],
    [0.2],
    [0.2],
    [0.3]], requires_grad=True)
lr = 0.1
lam = 0.1
def one_step_l2(P, Q):
    Rhat = P @ Q.T
    E = M * (R - Rhat)
    loss = 0.5 * (E**2).sum() + 0.5 * lam * (
        (P**2).sum() + (Q**2).sum()
    )
    loss.backward()
    with torch.no_grad():
        P -= lr * P.grad
        Q -= lr * Q.grad
    P.grad.zero_()
    Q.grad.zero_()
    return P, Q
P, Q = one_step_l2(P, Q)
print("After step 1")
print("P =", P.detach().numpy().ravel())
print("Q =", Q.detach().numpy().ravel())
P, Q = one_step_l2(P, Q)
print("\nAfter step 2")
print("P =", P.detach().numpy().ravel())
print("Q =", Q.detach().numpy().ravel())