.. _sec_rmsprop:
RMSProp
=======
Một trong những vấn đề chính trong :numref:`sec_adagrad` là tốc độ học
tập giảm theo lịch trình xác định trước là
:math:`\mathcal{O}(t^{-\frac{1}{2}})` hiệu quả. Mặc dù điều này thường
thích hợp cho các vấn đề lồi, nhưng nó có thể không lý tưởng cho những
vấn đề không lồi, chẳng hạn như những vấn đề gặp phải trong học sâu. Tuy
nhiên, sự thích nghi phối hợp khôn ngoan của Adagrad là rất mong muốn
như một preconditioner.
:cite:`Tieleman.Hinton.2012` đề xuất thuật toán RMSProp như một sửa
chữa đơn giản để tách lập kế hoạch tỷ lệ từ tốc độ học tập thích ứng
phối hợp. Vấn đề là Adagrad tích lũy các ô vuông của gradient
:math:`\mathbf{g}_t` thành một vector trạng thái
:math:`\mathbf{s}_t = \mathbf{s}_{t-1} + \mathbf{g}_t^2`. Kết quả là
:math:`\mathbf{s}_t` tiếp tục phát triển mà không bị ràng buộc do thiếu
bình thường hóa, về cơ bản tuyến tính khi thuật toán hội tụ.
Một cách để khắc phục vấn đề này là sử dụng :math:`\mathbf{s}_t / t`.
Đối với các phân phối hợp lý của :math:`\mathbf{g}_t`, điều này sẽ hội
tụ. Thật không may, nó có thể mất một thời gian rất dài cho đến khi hành
vi giới hạn bắt đầu quan trọng vì thủ tục ghi nhớ quỹ đạo đầy đủ của các
giá trị. Một cách khác là sử dụng trung bình rò rỉ theo cùng một cách
chúng ta đã sử dụng 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 một số tham số :math:`\gamma > 0`. Giữ tất cả các bộ phận khác không
thay đổi năng suất RMSProp.
Các thuật toán
--------------
Hãy để chúng tôi viết ra các phương trình 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}
Hằng số :math:`\epsilon > 0` thường được đặt thành :math:`10^{-6}` để
đảm bảo rằng chúng tôi không bị phân chia bằng 0 hoặc quá lớn kích thước
bước. Với sự mở rộng này, chúng tôi hiện có thể tự do kiểm soát tốc độ
học tập :math:`\eta` độc lập với tỷ lệ được áp dụng trên cơ sở mỗi tọa
độ. Về mặt trung bình rò rỉ, chúng ta có thể áp dụng lý luận tương tự
như được áp dụng trước đây trong trường hợp phương pháp động lượng. Mở
rộng định nghĩa về sản lượng :math:`\mathbf{s}_t`
.. 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}
Như trước đây trong :numref:`sec_momentum` chúng tôi sử dụng
:math:`1 + \gamma + \gamma^2 + \ldots, = \frac{1}{1-\gamma}`. Do đó tổng
trọng lượng được chuẩn hóa thành :math:`1` với thời gian bán hủy của một
quan sát :math:`\gamma^{-1}`. Chúng ta hãy hình dung trọng lượng trong
40 bước thời gian qua cho các lựa chọn khác nhau của :math:`\gamma`.
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import math
from mxnet import np, npx
from d2l import mxnet as d2l
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_251805_3_0.svg
.. raw:: html
.. raw:: html
.. code:: python
import math
import torch
from d2l import torch as d2l
d2l.set_figsize()
gammas = [0.95, 0.9, 0.8, 0.7]
for gamma in gammas:
x = torch.arange(40).detach().numpy()
d2l.plt.plot(x, (1-gamma) * gamma ** x, label=f'gamma = {gamma:.2f}')
d2l.plt.xlabel('time');
.. figure:: output_rmsprop_251805_6_0.svg
.. raw:: html
.. raw:: html
.. code:: python
import math
import tensorflow as tf
from d2l import tensorflow as d2l
d2l.set_figsize()
gammas = [0.95, 0.9, 0.8, 0.7]
for gamma in gammas:
x = tf.range(40).numpy()
d2l.plt.plot(x, (1-gamma) * gamma ** x, label=f'gamma = {gamma:.2f}')
d2l.plt.xlabel('time');
.. figure:: output_rmsprop_251805_9_0.svg
.. raw:: html
.. raw:: html
Thực hiện từ đầu
----------------
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 rằng trong :numref:`sec_adagrad`, khi chúng ta sử dụng Adagrad
với tốc độ học 0.4, các biến chỉ di chuyển rất chậm trong các giai đoạn
sau của thuật toán vì tốc độ học tập giảm quá nhanh. Vì :math:`\eta`
được kiểm soát riêng, điều này không xảy ra với RMSProp.
.. raw:: html
.. raw:: html
.. 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))
.. parsed-literal::
:class: output
epoch 20, x1: -0.010599, x2: 0.000000
.. figure:: output_rmsprop_251805_15_1.svg
.. raw:: html
.. raw:: html
.. 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))
.. parsed-literal::
:class: output
epoch 20, x1: -0.010599, x2: 0.000000
/home/d2l-worker/miniconda3/envs/d2l-vi-release-1/lib/python3.8/site-packages/torch/functional.py:568: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at ../aten/src/ATen/native/TensorShape.cpp:2228.)
return _VF.meshgrid(tensors, **kwargs) # type: ignore[attr-defined]
.. figure:: output_rmsprop_251805_18_1.svg
.. raw:: html
.. raw:: html
.. 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))
.. parsed-literal::
:class: output
epoch 20, x1: -0.010599, x2: 0.000000
.. figure:: output_rmsprop_251805_21_1.svg
.. raw:: html
.. raw:: html
Tiếp theo, chúng tôi triển khai RMSProp để được sử dụng trong một mạng
sâu. Điều này cũng đơn giản như nhau.
.. raw:: html
.. raw:: html
.. 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
.. raw:: html
.. code:: python
def init_rmsprop_states(feature_dim):
s_w = torch.zeros((feature_dim, 1))
s_b = torch.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):
with torch.no_grad():
s[:] = gamma * s + (1 - gamma) * torch.square(p.grad)
p[:] -= hyperparams['lr'] * p.grad / torch.sqrt(s + eps)
p.grad.data.zero_()
.. raw:: html
.. raw:: html
.. code:: python
def init_rmsprop_states(feature_dim):
s_w = tf.Variable(tf.zeros((feature_dim, 1)))
s_b = tf.Variable(tf.zeros(1))
return (s_w, s_b)
def rmsprop(params, grads, states, hyperparams):
gamma, eps = hyperparams['gamma'], 1e-6
for p, s, g in zip(params, states, grads):
s[:].assign(gamma * s + (1 - gamma) * tf.math.square(g))
p[:].assign(p - hyperparams['lr'] * g / tf.math.sqrt(s + eps))
.. raw:: html
.. raw:: html
Chúng tôi đặt tỷ lệ học tập ban đầu là 0,01 và thuật ngữ trọng số
:math:`\gamma` thành 0.9. Đó là, :math:`\mathbf{s}` tổng hợp trung bình
trong quá khứ :math:`1/(1-\gamma) = 10` quan sát của gradient vuông.
.. raw:: html
.. raw:: html
.. 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.244, 0.289 sec/epoch
.. figure:: output_rmsprop_251805_39_1.svg
.. raw:: html
.. raw:: html
.. 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.243, 0.013 sec/epoch
.. figure:: output_rmsprop_251805_42_1.svg
.. raw:: html
.. raw:: html
.. 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.117 sec/epoch
.. figure:: output_rmsprop_251805_45_1.svg
.. raw:: html
.. raw:: html
Thực hiện ngắn gọn
------------------
Vì RMSProp là một thuật toán khá phổ biến, nó cũng có sẵn trong phiên
bản ``Trainer``. Tất cả những gì chúng ta cần làm là khởi tạo nó bằng
cách sử dụng một thuật toán có tên ``rmsprop``, gán :math:`\gamma` cho
tham số ``gamma1``.
.. raw:: html
.. raw:: html
.. code:: python
d2l.train_concise_ch11('rmsprop', {'learning_rate': 0.01, 'gamma1': 0.9},
data_iter)
.. parsed-literal::
:class: output
loss: 0.242, 0.042 sec/epoch
.. figure:: output_rmsprop_251805_51_1.svg
.. raw:: html
.. raw:: html
.. code:: python
trainer = torch.optim.RMSprop
d2l.train_concise_ch11(trainer, {'lr': 0.01, 'alpha': 0.9},
data_iter)
.. parsed-literal::
:class: output
loss: 0.246, 0.012 sec/epoch
.. figure:: output_rmsprop_251805_54_1.svg
.. raw:: html
.. raw:: html
.. code:: python
trainer = tf.keras.optimizers.RMSprop
d2l.train_concise_ch11(trainer, {'learning_rate': 0.01, 'rho': 0.9},
data_iter)
.. parsed-literal::
:class: output
loss: 0.250, 0.146 sec/epoch
.. figure:: output_rmsprop_251805_57_1.svg
.. raw:: html
.. raw:: html
Tóm tắt
-------
- RMSProp rất giống với Adagrad trong chừng mực vì cả hai đều sử dụng
hình vuông của gradient để quy mô các hệ số.
- RMSProp chia sẻ với động lượng trung bình bị rò rỉ. Tuy nhiên,
RMSProp sử dụng kỹ thuật này để điều chỉnh tiền điều hòa hệ số khôn
ngoan.
- Tỷ lệ học tập cần được lên lịch bởi các thí nghiệm trong thực tế.
- Hệ số :math:`\gamma` xác định lịch sử trong bao lâu khi điều chỉnh
thang đo mỗi tọa độ.
Bài tập
-------
1. Điều gì xảy ra bằng thực nghiệm nếu chúng ta đặt :math:`\gamma = 1`?
Tại sao?
2. Xoay vấn đề tối ưu hóa để giảm thiểu
:math:`f(\mathbf{x}) = 0.1 (x_1 + x_2)^2 + 2 (x_1 - x_2)^2`. Điều gì
xảy ra với sự hội tụ?
3. Hãy thử những gì xảy ra với RMSProp về một vấn đề máy học thực sự,
chẳng hạn như đào tạo về Fashion-MNIST. Thử nghiệm với các lựa chọn
khác nhau để điều chỉnh tốc độ học tập.
4. Bạn có muốn điều chỉnh :math:`\gamma` khi tối ưu hóa tiến triển
không? RMSProp nhạy cảm như thế nào đối với điều này?
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html