.. raw:: html
.. _sec_rmsprop:
RMSProp
=======
.. raw:: html
Một trong những vấn đề then chốt trong :numref:`sec_adagrad` là tốc độ
học thực tế được giảm theo một thời điểm được định nghĩa sẵn
:math:`\mathcal{O}(t^{-\frac{1}{2}})`. Nhìn chung, cách này thích hợp
với các bài toán lồi nhưng có thể không phải giải pháp lý tưởng cho
những bài toán không lồi, chẳng hạn những bài toán gặp phải trong học
sâu. Tuy vậy, khả năng thích ứng theo tọa độ của Adagrad là rất tuyệt
vời cho một bộ tiền điều kiện (*preconditioner*).
.. raw:: html
:cite:`Tieleman.Hinton.2012` đề xuất thuật toán RMSProp như một bản vá
đơn giản để tách rời tốc độ định thời ra khỏi tốc độ học thay đổi theo
tọa độ (*coordinate-adaptive*). Vấn đề ở đây là Adagrad cộng dồn tổng
bình phương của gradient :math:`\mathbf{g}_t` vào vector trạng thái
:math:`\mathbf{s}_t = \mathbf{s}_{t-1} + \mathbf{g}_t^2`. Kết quả là, do
không có phép chuẩn hóa, :math:`\mathbf{s}_t` vẫn tiếp tục tăng tuyến
tính không ngừng trong quá trình hội tụ của thuật toán.
.. raw:: html
Vấn đề này có thể được giải quyết bằng cách sử dụng
:math:`\mathbf{s}_t / t`. Với phân phối :math:`\mathbf{g}_t` hợp lý,
thuật toán sẽ hội tụ. Đáng tiếc là có thể mất rất nhiều thời gian cho
đến khi các tính chất tại giới hạn bắt đầu có ảnh hưởng, bởi thuật toán
này ghi nhớ toàn bộ quỹ đạo của các giá trị. Một cách khác là sử dụng
trung bình rò rỉ tương tự như trong phương pháp động lượng, tức là
:math:`\mathbf{s}_t \leftarrow \gamma \mathbf{s}_{t-1} + (1-\gamma) \mathbf{g}_t^2`
cho các tham số :math:`\gamma > 0`. Giữ nguyên tất cả các phần khác và
ta có thuật toán RMSProp.
.. raw:: html
Thuật toán
----------
.. raw:: html
Chúng ta hãy viết các phương trình ra một cách chi tiết.
.. math::
\begin{aligned}
\mathbf{s}_t & \leftarrow \gamma \mathbf{s}_{t-1} + (1 - \gamma) \mathbf{g}_t^2, \\
\mathbf{x}_t & \leftarrow \mathbf{x}_{t-1} - \frac{\eta}{\sqrt{\mathbf{s}_t + \epsilon}} \odot \mathbf{g}_t.
\end{aligned}
.. raw:: html
Hằng số :math:`\epsilon > 0` thường được đặt bằng :math:`10^{-6}` để đảm
bảo rằng chúng ta sẽ không gặp vấn đề khi chia cho 0 hoặc kích thước
bước quá lớn. Với khai triển này, bây giờ chúng ta có thể tự do kiểm
soát tốc độ học :math:`\eta` độc lập với phép biến đổi tỉ lệ được áp
dụng cho từng tọa độ. Về mặt trung bình rò rỉ, chúng ta có thể áp dụng
các lập luận tương tự như trước trong phương pháp động lượng. Khai triển
định nghĩa :math:`\mathbf{s}_t` ta có
.. math::
\begin{aligned}
\mathbf{s}_t & = (1 - \gamma) \mathbf{g}_t^2 + \gamma \mathbf{s}_{t-1} \\
& = (1 - \gamma) \left(\mathbf{g}_t^2 + \gamma \mathbf{g}_{t-1}^2 + \gamma^2 \mathbf{g}_{t-2} + \ldots, \right).
\end{aligned}
.. raw:: html
Tương tự như :numref:`sec_momentum`, ta có
:math:`1 + \gamma + \gamma^2 + \ldots, = \frac{1}{1-\gamma}`. Do đó,
tổng trọng số được chuẩn hóa bằng :math:`1` và chu kỳ bán rã của một
quan sát là :math:`\gamma^{-1}`. Hãy cùng minh họa trực quan các trọng
số này trong vòng 40 bước thời gian trước đó với các giá trị
:math:`\gamma` khác nhau.
.. code:: python
%matplotlib inline
from d2l import mxnet as d2l
import math
from mxnet import np, npx
npx.set_np()
d2l.set_figsize()
gammas = [0.95, 0.9, 0.8, 0.7]
for gamma in gammas:
x = np.arange(40).asnumpy()
d2l.plt.plot(x, (1-gamma) * gamma ** x, label=f'gamma = {gamma:.2f}')
d2l.plt.xlabel('time');
.. figure:: output_rmsprop_vn_5d44fd_1_0.svg
.. raw:: html
Lập trình Từ đầu
----------------
.. raw:: html
Như trước đây, chúng ta sử dụng hàm bậc hai
:math:`f(\mathbf{x})=0.1x_1^2+2x_2^2` để quan sát quỹ đạo của RMSProp.
Nhớ lại trong :numref:`sec_adagrad`, khi chúng ta sử dụng Adagrad với
tốc độ học bằng 0.4, các biến di chuyển rất chậm trong các giai đoạn sau
của thuật toán do tốc độ học giảm quá nhanh. Do :math:`\eta` được kiểm
soát riêng biệt, nên điều này không xảy ra với RMSProp.
.. code:: python
def rmsprop_2d(x1, x2, s1, s2):
g1, g2, eps = 0.2 * x1, 4 * x2, 1e-6
s1 = gamma * s1 + (1 - gamma) * g1 ** 2
s2 = gamma * s2 + (1 - gamma) * g2 ** 2
x1 -= eta / math.sqrt(s1 + eps) * g1
x2 -= eta / math.sqrt(s2 + eps) * g2
return x1, x2, s1, s2
def f_2d(x1, x2):
return 0.1 * x1 ** 2 + 2 * x2 ** 2
eta, gamma = 0.4, 0.9
d2l.show_trace_2d(f_2d, d2l.train_2d(rmsprop_2d))
.. figure:: output_rmsprop_vn_5d44fd_3_0.svg
.. raw:: html
Tiếp theo, chúng ta hãy lập trình thuật toán RMSProp để sử dụng trong
một mạng nơ-ron sâu. Cách lập trình không quá phức tạp.
.. code:: python
def init_rmsprop_states(feature_dim):
s_w = np.zeros((feature_dim, 1))
s_b = np.zeros(1)
return (s_w, s_b)
def rmsprop(params, states, hyperparams):
gamma, eps = hyperparams['gamma'], 1e-6
for p, s in zip(params, states):
s[:] = gamma * s + (1 - gamma) * np.square(p.grad)
p[:] -= hyperparams['lr'] * p.grad / np.sqrt(s + eps)
.. raw:: html
Chúng ta khởi tạo tốc độ học ban đầu bằng 0.01 và trọng số
:math:`\gamma` bằng 0.9. Nghĩa là, :math:`\mathbf{s}` là tổng trung bình
của :math:`1/(1-\gamma) = 10` quan sát bình phương gradient trong quá
khứ.
.. code:: python
data_iter, feature_dim = d2l.get_data_ch11(batch_size=10)
d2l.train_ch11(rmsprop, init_rmsprop_states(feature_dim),
{'lr': 0.01, 'gamma': 0.9}, data_iter, feature_dim);
.. parsed-literal::
:class: output
loss: 0.245, 0.049 sec/epoch
.. figure:: output_rmsprop_vn_5d44fd_7_1.svg
.. raw:: html
Lập trình Súc tích
------------------
.. raw:: html
Do RMSProp là thuật toán khá phổ biến, nó cũng được tích hợp sẵn trong
thực thể ``Trainer``. Những gì ta cần phải làm là khởi tạo thuật toán có
tên là ``rmsprop``, với :math:`\gamma` được gán cho tham số ``gamma1``.
.. code:: python
d2l.train_concise_ch11('rmsprop', {'learning_rate': 0.01, 'gamma1': 0.9},
data_iter)
.. parsed-literal::
:class: output
loss: 0.243, 0.028 sec/epoch
.. figure:: output_rmsprop_vn_5d44fd_9_1.svg
.. raw:: html
Tóm tắt
-------
.. raw:: html
- Thuật toán RMSProp rất giống với Adagrad ở chỗ cả hai đều sử dụng
bình phương của gradient để thay đổi tỉ lệ hệ số.
- RMSProp có điểm chung với phương pháp động lượng là chúng đều sử dụng
trung bình rò rỉ. Tuy nhiên, RMSProp sử dụng kỹ thuật này để điều
chỉnh tiền điều kiện theo hệ số.
- Trong thực tế, tốc độ học cần được định thời bởi người lập trình.
- Hệ số :math:`\gamma` xác định độ dài thông tin quá khứ được sử dụng
khi điều chỉnh tỉ lệ theo từng tọa độ.
.. raw:: html
Bài tập
-------
.. raw:: html
1. Điều gì sẽ xảy ra nếu ta đặt :math:`\gamma = 1`? Giải thích tại sao?
2. Biến đổi bài toán tối ưu thành cực tiểu hóa
:math:`f(\mathbf{x}) = 0.1 (x_1 + x_2)^2 + 2 (x_1 - x_2)^2`. Sự hội
tụ sẽ diễn ra như thế nào?
3. Hãy thử áp dụng RMSProp cho một bài toán học máy cụ thể, chẳng hạn
như huấn luyện trên tập Fashion-MNIST. Hãy thí nghiệm với các tốc độ
học khác nhau.
4. Bạn có muốn điều chỉnh :math:`\gamma` khi việc tối ưu đang tiến triển
không? Hãy cho biết độ nhạy của RMSProp với việc điều chỉnh này?
Thảo luận
---------
- `Tiếng Anh - MXNet `__
- `Tiếng Việt `__
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
- Nguyễn Văn Quang
- Nguyễn Lê Quang Nhật
- Phạm Minh Đức
- Nguyễn Văn Cường
- Lê Khắc Hồng Phúc
- Phạm Hồng Vinh