.. _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
mxnetpytorchtensorflow
.. 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
mxnetpytorchtensorflow
.. 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
mxnetpytorchtensorflow
.. 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
mxnetpytorchtensorflow
.. 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
mxnetpytorchtensorflow
.. 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
mxnetpytorchtensorflow
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html