.. 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