.. _sec_sgd:
Stochastic Gradient Descent
===========================
Tuy nhiên, trong các chương trước, chúng tôi tiếp tục sử dụng gốc
gradient ngẫu nhiên trong quy trình đào tạo của chúng tôi, tuy nhiên, mà
không giải thích lý do tại sao nó hoạt động. Để làm sáng tỏ nó, chúng
tôi chỉ mô tả các nguyên tắc cơ bản của gradient gốc trong
:numref:`sec_gd`. Trong phần này, chúng tôi tiếp tục thảo luận *xuống
dốc ngẫu nhiên* chi tiết hơn.
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import math
from mxnet import np, npx
from d2l import mxnet as d2l
npx.set_np()
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import math
import torch
from d2l import torch as d2l
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import math
import tensorflow as tf
from d2l import tensorflow as d2l
.. raw:: html
.. raw:: html
Stochastic Gradient Những Thông Tin Cập Nhập
--------------------------------------------
Trong học sâu, chức năng khách quan thường là trung bình của các hàm mất
cho mỗi ví dụ trong tập dữ liệu đào tạo. Với một tập dữ liệu đào tạo
:math:`n` ví dụ, chúng tôi giả định rằng :math:`f_i(\mathbf{x})` là hàm
mất liên quan đến ví dụ đào tạo của chỉ số :math:`i`, trong đó
:math:`\mathbf{x}` là vectơ tham số. Sau đó, chúng tôi đến chức năng mục
tiêu
.. math:: f(\mathbf{x}) = \frac{1}{n} \sum_{i = 1}^n f_i(\mathbf{x}).
Gradient của hàm khách quan tại :math:`\mathbf{x}` được tính là
.. math:: \nabla f(\mathbf{x}) = \frac{1}{n} \sum_{i = 1}^n \nabla f_i(\mathbf{x}).
Nếu sử dụng gradient descent, chi phí tính toán cho mỗi lần lặp biến độc
lập là :math:`\mathcal{O}(n)`, phát triển tuyến tính với :math:`n`. Do
đó, khi tập dữ liệu đào tạo lớn hơn, chi phí của gradient descent cho
mỗi lần lặp sẽ cao hơn.
Stochastic gradient descent (SGD) giảm chi phí tính toán tại mỗi lần lặp
lại. Tại mỗi lần lặp lại của dòng dốc ngẫu nhiên, chúng tôi lấy mẫu
thống nhất một chỉ số :math:`i\in\{1,\ldots, n\}` cho các ví dụ dữ liệu
một cách ngẫu nhiên và tính toán gradient :math:`\nabla f_i(\mathbf{x})`
để cập nhật :math:`\mathbf{x}`:
.. math:: \mathbf{x} \leftarrow \mathbf{x} - \eta \nabla f_i(\mathbf{x}),
trong đó :math:`\eta` là tỷ lệ học tập. Chúng ta có thể thấy rằng chi
phí tính toán cho mỗi lần lặp giảm từ :math:`\mathcal{O}(n)` của
gradient gốc xuống hằng số :math:`\mathcal{O}(1)`. Hơn nữa, chúng tôi
muốn nhấn mạnh rằng gradient ngẫu nhiên :math:`\nabla f_i(\mathbf{x})`
là một ước tính không thiên vị của gradient đầy đủ
:math:`\nabla f(\mathbf{x})` bởi vì
.. math:: \mathbb{E}_i \nabla f_i(\mathbf{x}) = \frac{1}{n} \sum_{i = 1}^n \nabla f_i(\mathbf{x}) = \nabla f(\mathbf{x}).
Điều này có nghĩa là, trung bình, gradient stochastic là một ước tính
tốt của gradient.
Bây giờ, chúng ta sẽ so sánh nó với gradient descent bằng cách thêm
nhiễu ngẫu nhiên với trung bình 0 và phương sai 1 với gradient để mô
phỏng một gradient gốc ngẫu nhiên.
.. raw:: html
.. raw:: html
.. code:: python
def f(x1, x2): # Objective function
return x1 ** 2 + 2 * x2 ** 2
def f_grad(x1, x2): # Gradient of the objective function
return 2 * x1, 4 * x2
def sgd(x1, x2, s1, s2, f_grad):
g1, g2 = f_grad(x1, x2)
# Simulate noisy gradient
g1 += np.random.normal(0.0, 1, (1,))
g2 += np.random.normal(0.0, 1, (1,))
eta_t = eta * lr()
return (x1 - eta_t * g1, x2 - eta_t * g2, 0, 0)
def constant_lr():
return 1
eta = 0.1
lr = constant_lr # Constant learning rate
d2l.show_trace_2d(f, d2l.train_2d(sgd, steps=50, f_grad=f_grad))
.. parsed-literal::
:class: output
epoch 50, x1: -0.472513, x2: 0.110780
/home/d2l-worker/miniconda3/envs/d2l-vi-release-1/lib/python3.8/site-packages/numpy/core/shape_base.py:65: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
ary = asanyarray(ary)
.. figure:: output_sgd_baca77_15_1.svg
.. raw:: html
.. raw:: html
.. code:: python
def f(x1, x2): # Objective function
return x1 ** 2 + 2 * x2 ** 2
def f_grad(x1, x2): # Gradient of the objective function
return 2 * x1, 4 * x2
def sgd(x1, x2, s1, s2, f_grad):
g1, g2 = f_grad(x1, x2)
# Simulate noisy gradient
g1 += torch.normal(0.0, 1, (1,))
g2 += torch.normal(0.0, 1, (1,))
eta_t = eta * lr()
return (x1 - eta_t * g1, x2 - eta_t * g2, 0, 0)
def constant_lr():
return 1
eta = 0.1
lr = constant_lr # Constant learning rate
d2l.show_trace_2d(f, d2l.train_2d(sgd, steps=50, f_grad=f_grad))
.. parsed-literal::
:class: output
epoch 50, x1: 0.100386, x2: 0.117807
/home/d2l-worker/miniconda3/envs/d2l-vi-release-1/lib/python3.8/site-packages/numpy/core/shape_base.py:65: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
ary = asanyarray(ary)
/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_sgd_baca77_18_1.svg
.. raw:: html
.. raw:: html
.. code:: python
def f(x1, x2): # Objective function
return x1 ** 2 + 2 * x2 ** 2
def f_grad(x1, x2): # Gradient of the objective function
return 2 * x1, 4 * x2
def sgd(x1, x2, s1, s2, f_grad):
g1, g2 = f_grad(x1, x2)
# Simulate noisy gradient
g1 += tf.random.normal([1], 0.0, 1)
g2 += tf.random.normal([1], 0.0, 1)
eta_t = eta * lr()
return (x1 - eta_t * g1, x2 - eta_t * g2, 0, 0)
def constant_lr():
return 1
eta = 0.1
lr = constant_lr # Constant learning rate
d2l.show_trace_2d(f, d2l.train_2d(sgd, steps=50, f_grad=f_grad))
.. parsed-literal::
:class: output
epoch 50, x1: 0.065599, x2: -0.002330
/home/d2l-worker/miniconda3/envs/d2l-vi-release-1/lib/python3.8/site-packages/numpy/core/shape_base.py:65: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
ary = asanyarray(ary)
.. figure:: output_sgd_baca77_21_1.svg
.. raw:: html
.. raw:: html
Như chúng ta có thể thấy, quỹ đạo của các biến trong gốc gradient ngẫu
nhiên ồn hơn nhiều so với quỹ đạo mà chúng ta quan sát thấy trong
gradient gốc trong :numref:`sec_gd`. Điều này là do tính chất ngẫu
nhiên của gradient. Đó là, ngay cả khi chúng tôi đến gần mức tối thiểu,
chúng tôi vẫn phải chịu sự không chắc chắn được tiêm bởi gradient tức
thời qua :math:`\eta \nabla f_i(\mathbf{x})`. Ngay cả sau 50 bước chất
lượng vẫn không tốt như vậy. Thậm chí tệ hơn, nó sẽ không cải thiện sau
các bước bổ sung (chúng tôi khuyến khích bạn thử nghiệm với một số lượng
lớn hơn các bước để xác nhận điều này). Điều này để lại cho chúng ta sự
thay thế duy nhất: thay đổi tỷ lệ học tập :math:`\eta`. Tuy nhiên, nếu
chúng ta chọn điều này quá nhỏ, ban đầu chúng ta sẽ không đạt được bất
kỳ tiến bộ có ý nghĩa nào. Mặt khác, nếu chúng ta chọn nó quá lớn, chúng
ta sẽ không nhận được một giải pháp tốt, như đã thấy ở trên. Cách duy
nhất để giải quyết các mục tiêu mâu thuẫn này là giảm tỷ lệ học tập \*
năng lượng\* khi tối ưu hóa tiến triển.
Đây cũng là lý do để thêm một hàm tốc độ học tập ``lr`` vào hàm bước
``sgd``. Trong ví dụ trên bất kỳ chức năng nào để lập kế hoạch tỷ lệ học
tập nằm không hoạt động khi chúng ta đặt hàm ``lr`` liên quan là hằng
số.
Tốc độ học động
---------------
Thay thế :math:`\eta` bằng tốc độ học tập phụ thuộc vào thời gian
:math:`\eta(t)` thêm vào sự phức tạp của việc kiểm soát sự hội tụ của
một thuật toán tối ưu hóa. Đặc biệt, chúng ta cần tìm ra cách nhanh
chóng :math:`\eta` sẽ phân rã. Nếu quá nhanh, chúng tôi sẽ ngừng tối ưu
hóa sớm. Nếu chúng ta giảm nó quá chậm, chúng ta lãng phí quá nhiều thời
gian để tối ưu hóa. Sau đây là một vài chiến lược cơ bản được sử dụng để
điều chỉnh :math:`\eta` theo thời gian (chúng tôi sẽ thảo luận về các
chiến lược nâng cao hơn sau):
.. math::
\begin{aligned}
\eta(t) & = \eta_i \text{ if } t_i \leq t \leq t_{i+1} && \text{piecewise constant} \\
\eta(t) & = \eta_0 \cdot e^{-\lambda t} && \text{exponential decay} \\
\eta(t) & = \eta_0 \cdot (\beta t + 1)^{-\alpha} && \text{polynomial decay}
\end{aligned}
Trong kịch bản *piecewise constant* đầu tiên, chúng tôi giảm tỷ lệ học
tập, ví dụ, bất cứ khi nào tiến bộ trong các quầy hàng tối ưu hóa. Đây
là một chiến lược phổ biến để đào tạo các mạng sâu. Ngoài ra, chúng ta
có thể giảm nó mạnh mẽ hơn nhiều bởi sự phân rã theo cấp số nhân *. Thật
không may điều này thường dẫn đến dừng sớm trước khi thuật toán đã hội
tụ. Một lựa chọn phổ biến là * phân rã đa thứ\* với
:math:`\alpha = 0.5`. Trong trường hợp tối ưu hóa lồi, có một số bằng
chứng cho thấy tỷ lệ này được cư xử tốt.
Chúng ta hãy xem sự phân rã theo cấp số nhân trông như thế nào trong
thực tế.
.. raw:: html
.. raw:: html
.. code:: python
def exponential_lr():
# Global variable that is defined outside this function and updated inside
global t
t += 1
return math.exp(-0.1 * t)
t = 1
lr = exponential_lr
d2l.show_trace_2d(f, d2l.train_2d(sgd, steps=1000, f_grad=f_grad))
.. parsed-literal::
:class: output
epoch 1000, x1: -0.820458, x2: 0.004701
.. figure:: output_sgd_baca77_27_1.svg
.. raw:: html
.. raw:: html
.. code:: python
def exponential_lr():
# Global variable that is defined outside this function and updated inside
global t
t += 1
return math.exp(-0.1 * t)
t = 1
lr = exponential_lr
d2l.show_trace_2d(f, d2l.train_2d(sgd, steps=1000, f_grad=f_grad))
.. parsed-literal::
:class: output
epoch 1000, x1: -0.866443, x2: -0.070251
.. figure:: output_sgd_baca77_30_1.svg
.. raw:: html
.. raw:: html
.. code:: python
def exponential_lr():
# Global variable that is defined outside this function and updated inside
global t
t += 1
return math.exp(-0.1 * t)
t = 1
lr = exponential_lr
d2l.show_trace_2d(f, d2l.train_2d(sgd, steps=1000, f_grad=f_grad))
.. parsed-literal::
:class: output
epoch 1000, x1: -0.950308, x2: 0.075469
.. figure:: output_sgd_baca77_33_1.svg
.. raw:: html
.. raw:: html
Đúng như dự đoán, phương sai trong các thông số được giảm đáng kể. Tuy
nhiên, điều này đến với chi phí không hội tụ với giải pháp tối ưu
:math:`\mathbf{x} = (0, 0)`. Ngay cả sau 1000 bước lặp lại chúng ta vẫn
còn rất xa giải pháp tối ưu. Thật vậy, thuật toán không hội tụ ở tất cả.
Mặt khác, nếu chúng ta sử dụng phân rã đa thức trong đó tốc độ học tập
phân rã với căn bậc hai nghịch đảo của số bước, sự hội tụ sẽ tốt hơn chỉ
sau 50 bước.
.. raw:: html
.. raw:: html
.. code:: python
def polynomial_lr():
# Global variable that is defined outside this function and updated inside
global t
t += 1
return (1 + 0.1 * t) ** (-0.5)
t = 1
lr = polynomial_lr
d2l.show_trace_2d(f, d2l.train_2d(sgd, steps=50, f_grad=f_grad))
.. parsed-literal::
:class: output
epoch 50, x1: 0.025029, x2: 0.115820
.. figure:: output_sgd_baca77_39_1.svg
.. raw:: html
.. raw:: html
.. code:: python
def polynomial_lr():
# Global variable that is defined outside this function and updated inside
global t
t += 1
return (1 + 0.1 * t) ** (-0.5)
t = 1
lr = polynomial_lr
d2l.show_trace_2d(f, d2l.train_2d(sgd, steps=50, f_grad=f_grad))
.. parsed-literal::
:class: output
epoch 50, x1: -0.011478, x2: 0.051227
.. figure:: output_sgd_baca77_42_1.svg
.. raw:: html
.. raw:: html
.. code:: python
def polynomial_lr():
# Global variable that is defined outside this function and updated inside
global t
t += 1
return (1 + 0.1 * t) ** (-0.5)
t = 1
lr = polynomial_lr
d2l.show_trace_2d(f, d2l.train_2d(sgd, steps=50, f_grad=f_grad))
.. parsed-literal::
:class: output
epoch 50, x1: 0.118743, x2: -0.097886
.. figure:: output_sgd_baca77_45_1.svg
.. raw:: html
.. raw:: html
Tồn tại nhiều lựa chọn hơn cho cách thiết lập tỷ lệ học tập. Ví dụ,
chúng ta có thể bắt đầu với một tốc độ nhỏ, sau đó nhanh chóng tăng lên
và sau đó giảm nó một lần nữa, mặc dù chậm hơn. Chúng tôi thậm chí có
thể thay thế giữa tỷ lệ học tập nhỏ hơn và lớn hơn. Có tồn tại một loạt
các lịch trình như vậy. Bây giờ chúng ta hãy tập trung vào lịch trình
học tập mà có thể phân tích lý thuyết toàn diện, tức là về tốc độ học
tập trong một môi trường lồi. Đối với các bài toán phi lồi nói chung,
rất khó để có được những đảm bảo hội tụ có ý nghĩa, vì nói chung giảm
thiểu các bài toán phi lồi phi tuyến là NP cứng. Đối với một cuộc khảo
sát xem ví dụ, xuất sắc `bài giảng ghi
chú `__
của Tibshirani 2015.
Phân tích hội tụ cho mục tiêu lồi
---------------------------------
Phân tích hội tụ sau đây của gốc gradient ngẫu nhiên cho các chức năng
mục tiêu lồi là tùy chọn và chủ yếu phục vụ để truyền đạt nhiều trực
giác hơn về vấn đề. Chúng tôi giới hạn bản thân mình với một trong những
bằng chứng đơn giản nhất :cite:`Nesterov.Vial.2000`. Các kỹ thuật
chứng minh tiên tiến hơn đáng kể tồn tại, ví dụ, bất cứ khi nào chức
năng mục tiêu được cư xử đặc biệt tốt.
Giả sử hàm khách quan :math:`f(\boldsymbol{\xi}, \mathbf{x})` là lồi
trong :math:`\mathbf{x}` cho tất cả :math:`\boldsymbol{\xi}`. Cụ thể
hơn, chúng tôi xem xét bản cập nhật gradient gốc stochastic:
.. math:: \mathbf{x}_{t+1} = \mathbf{x}_{t} - \eta_t \partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x}),
trong đó :math:`f(\boldsymbol{\xi}_t, \mathbf{x})` là chức năng khách
quan đối với ví dụ đào tạo :math:`\boldsymbol{\xi}_t` rút ra từ một số
phân phối ở bước :math:`t` và :math:`\mathbf{x}` là tham số mô hình.
Biểu thị bởi
.. math:: R(\mathbf{x}) = E_{\boldsymbol{\xi}}[f(\boldsymbol{\xi}, \mathbf{x})]
rủi ro dự kiến và đến :math:`R^*` mức tối thiểu của nó đối với
:math:`\mathbf{x}`. Cuối cùng cho phép :math:`\mathbf{x}^*` là minimizer
(chúng tôi giả định rằng nó tồn tại trong miền nơi :math:`\mathbf{x}`
được xác định). Trong trường hợp này, chúng ta có thể theo dõi khoảng
cách giữa tham số hiện tại :math:`\mathbf{x}_t` tại thời điểm :math:`t`
và bộ giảm thiểu rủi ro :math:`\mathbf{x}^*` và xem liệu nó có cải thiện
theo thời gian hay không:
.. math:: \begin{aligned} &\|\mathbf{x}_{t+1} - \mathbf{x}^*\|^2 \\ =& \|\mathbf{x}_{t} - \eta_t \partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x}) - \mathbf{x}^*\|^2 \\ =& \|\mathbf{x}_{t} - \mathbf{x}^*\|^2 + \eta_t^2 \|\partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x})\|^2 - 2 \eta_t \left\langle \mathbf{x}_t - \mathbf{x}^*, \partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x})\right\rangle. \end{aligned}
:label: eq_sgd-xt+1-xstar
Chúng tôi giả định rằng định mức :math:`L_2` của gradient ngẫu nhiên
:math:`\partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x})` được giới
hạn bởi một số hằng số :math:`L`, do đó chúng tôi có
.. math:: \eta_t^2 \|\partial_\mathbf{x} f(\boldsymbol{\xi}_t, \mathbf{x})\|^2 \leq \eta_t^2 L^2.
:label: eq_sgd-L
Chúng tôi chủ yếu quan tâm đến khoảng cách giữa :math:`\mathbf{x}_t` và
:math:`\mathbf{x}^*` thay đổi như thế nào *theo mong đợ*. Trên thực tế,
đối với bất kỳ trình tự cụ thể nào của các bước, khoảng cách có thể tăng
lên, tùy thuộc vào bất kỳ :math:`\boldsymbol{\xi}_t` nào chúng ta gặp
phải. Do đó chúng ta cần phải ràng buộc các sản phẩm dot. Kể từ khi đối
với bất kỳ chức năng lồi :math:`f` nó giữ rằng
:math:`f(\mathbf{y}) \geq f(\mathbf{x}) + \langle f'(\mathbf{x}), \mathbf{y} - \mathbf{x} \rangle`
cho tất cả :math:`\mathbf{x}` và :math:`\mathbf{y}`, bởi lồi chúng tôi
có
.. math:: f(\boldsymbol{\xi}_t, \mathbf{x}^*) \geq f(\boldsymbol{\xi}_t, \mathbf{x}_t) + \left\langle \mathbf{x}^* - \mathbf{x}_t, \partial_{\mathbf{x}} f(\boldsymbol{\xi}_t, \mathbf{x}_t) \right\rangle.
:label: eq_sgd-f-xi-xstar
Cắm cả hai bất đẳng thức :eq:`eq_sgd-L` và
:eq:`eq_sgd-f-xi-xstar` vào :eq:`eq_sgd-xt+1-xstar` chúng tôi
có được một ràng buộc về khoảng cách giữa các tham số tại thời điểm
:math:`t+1` như sau:
.. math:: \|\mathbf{x}_{t} - \mathbf{x}^*\|^2 - \|\mathbf{x}_{t+1} - \mathbf{x}^*\|^2 \geq 2 \eta_t (f(\boldsymbol{\xi}_t, \mathbf{x}_t) - f(\boldsymbol{\xi}_t, \mathbf{x}^*)) - \eta_t^2 L^2.
:label: eqref_sgd-xt-diff
Điều này có nghĩa là chúng tôi đạt được tiến bộ miễn là sự khác biệt
giữa tổn thất hiện tại và tổn thất tối ưu lớn hơn :math:`\eta_t L^2/2`.
Vì sự khác biệt này được ràng buộc để hội tụ với 0 nên sau đó tỷ lệ học
tập :math:`\eta_t` cũng cần phải \* biến mất \*.
Tiếp theo, chúng tôi có kỳ vọng hơn :eq:`eqref_sgd-xt-diff`. This
yields năng suất
.. math:: E\left[\|\mathbf{x}_{t} - \mathbf{x}^*\|^2\right] - E\left[\|\mathbf{x}_{t+1} - \mathbf{x}^*\|^2\right] \geq 2 \eta_t [E[R(\mathbf{x}_t)] - R^*] - \eta_t^2 L^2.
Bước cuối cùng liên quan đến việc tổng hợp các bất bình đẳng cho
:math:`t \in \{1, \ldots, T\}`. Kể từ khi tổng kính thiên văn và bằng
cách giảm thuật ngữ thấp hơn, chúng tôi thu được
.. math:: \|\mathbf{x}_1 - \mathbf{x}^*\|^2 \geq 2 \left (\sum_{t=1}^T \eta_t \right) [E[R(\mathbf{x}_t)] - R^*] - L^2 \sum_{t=1}^T \eta_t^2.
:label: eq_sgd-x1-xstar
Lưu ý rằng chúng tôi đã khai thác rằng :math:`\mathbf{x}_1` được đưa ra
và do đó kỳ vọng có thể được giảm xuống. Định nghĩa cuối
.. math:: \bar{\mathbf{x}} \stackrel{\mathrm{def}}{=} \frac{\sum_{t=1}^T \eta_t \mathbf{x}_t}{\sum_{t=1}^T \eta_t}.
Kể từ
.. math:: E\left(\frac{\sum_{t=1}^T \eta_t R(\mathbf{x}_t)}{\sum_{t=1}^T \eta_t}\right) = \frac{\sum_{t=1}^T \eta_t E[R(\mathbf{x}_t)]}{\sum_{t=1}^T \eta_t} = E[R(\mathbf{x}_t)],
bởi sự bất bình đẳng của Jensen (thiết lập :math:`i=t`,
:math:`\alpha_i = \eta_t/\sum_{t=1}^T \eta_t` trong
:eq:`eq_jensens-inequality`) và độ lồi của :math:`R` nó theo sau đó
:math:`E[R(\mathbf{x}_t)] \geq E[R(\bar{\mathbf{x}})]`, do đó
.. math:: \sum_{t=1}^T \eta_t E[R(\mathbf{x}_t)] \geq \sum_{t=1}^T \eta_t E\left[R(\bar{\mathbf{x}})\right].
Cắm này vào bất bình đẳng :eq:`eq_sgd-x1-xstar` mang lại sự ràng
buộc
.. math::
\left[E[\bar{\mathbf{x}}]\right] - R^* \leq \frac{r^2 + L^2 \sum_{t=1}^T \eta_t^2}{2 \sum_{t=1}^T \eta_t},
trong đó
:math:`r^2 \stackrel{\mathrm{def}}{=} \|\mathbf{x}_1 - \mathbf{x}^*\|^2`
là một ràng buộc về khoảng cách giữa sự lựa chọn ban đầu của các tham số
và kết quả cuối cùng. Nói tóm lại, tốc độ hội tụ phụ thuộc vào cách định
mức của gradient ngẫu nhiên được giới hạn (:math:`L`) và cách tối ưu giá
trị tham số ban đầu là bao xa (:math:`r`). Lưu ý rằng sự ràng buộc là về
:math:`\bar{\mathbf{x}}` chứ không phải là :math:`\mathbf{x}_T`. Đây là
trường hợp vì :math:`\bar{\mathbf{x}}` là một phiên bản được làm mịn của
đường dẫn tối ưu hóa. Bất cứ khi nào :math:`r, L`, và :math:`T` được
biết đến, chúng tôi có thể chọn tỷ lệ học tập
:math:`\eta = r/(L \sqrt{T})`. Điều này mang lại như trên ràng buộc
:math:`rL/\sqrt{T}`. Đó là, chúng tôi hội tụ với tỷ lệ
:math:`\mathcal{O}(1/\sqrt{T})` đến giải pháp tối ưu.
Gradient Stochastic và mẫu hữu hạn
----------------------------------
Cho đến nay chúng tôi đã chơi một chút nhanh và lỏng lẻo khi nói về gốc
gradient ngẫu nhiên. Chúng tôi xác định rằng chúng tôi vẽ các trường hợp
:math:`x_i`, thường với nhãn :math:`y_i` từ một số phân phối
:math:`p(x, y)` và chúng tôi sử dụng điều này để cập nhật các tham số mô
hình theo một cách nào đó. Đặc biệt, đối với một kích thước mẫu hữu hạn,
chúng tôi chỉ đơn giản lập luận rằng phân phối rời rạc
:math:`p(x, y) = \frac{1}{n} \sum_{i=1}^n \delta_{x_i}(x) \delta_{y_i}(y)`
cho một số chức năng :math:`\delta_{x_i}` và :math:`\delta_{y_i}` cho
phép chúng tôi thực hiện chuyển đổi gradient ngẫu nhiên trên nó.
Tuy nhiên, đây không thực sự là những gì chúng tôi đã làm. Trong các ví
dụ đồ chơi trong phần hiện tại, chúng tôi chỉ cần thêm tiếng ồn vào một
gradient không ngẫu nhiên khác, tức là, chúng tôi giả vờ có cặp
:math:`(x_i, y_i)`. Nó chỉ ra rằng điều này là hợp lý ở đây (xem các bài
tập để thảo luận chi tiết). Rắc rối hơn là trong tất cả các cuộc thảo
luận trước đó, chúng tôi rõ ràng đã không làm điều này. Thay vào đó,
chúng tôi lặp lại tất cả các phiên bản \* chính xác một lầu\ *. Để xem
lý do tại sao điều này là thích hợp hơn, hãy xem xét cuộc trò chuyện, cụ
thể là chúng tôi đang lấy mẫu :math:`n` quan sát từ phân phối rời rạc *
với thay thế\ *. Xác suất chọn một phần tử :math:`i` ngẫu nhiên là
:math:`1/n`. Do đó để chọn nó * ít nhất\* một lần là
.. math:: P(\mathrm{choose~} i) = 1 - P(\mathrm{omit~} i) = 1 - (1-1/n)^n \approx 1-e^{-1} \approx 0.63.
Một lý do tương tự cho thấy xác suất chọn một số mẫu (tức là ví dụ đào
tạo) \* chính xác một lầu\* được đưa ra bởi
.. math:: {n \choose 1} \frac{1}{n} \left(1-\frac{1}{n}\right)^{n-1} = \frac{n}{n-1} \left(1-\frac{1}{n}\right)^{n} \approx e^{-1} \approx 0.37.
Điều này dẫn đến sự gia tăng phương sai và giảm hiệu quả dữ liệu so với
lấy mẫu \* mà không thay thế\ *. Do đó, trong thực tế, chúng tôi thực
hiện sau này (và đây là lựa chọn mặc định trong suốt cuốn sách này). Lưu
ý cuối cùng rằng lặp đi lặp lại qua tập dữ liệu đào tạo đi qua nó theo
thứ tự ngẫu nhiên *\ khác nhau\*.
Tóm tắt
-------
- Đối với các vấn đề lồi, chúng ta có thể chứng minh rằng đối với một
sự lựa chọn rộng của tỷ lệ học tập stochastic gradient gốc sẽ hội tụ
với giải pháp tối ưu.
- Đối với học sâu, điều này thường không phải là trường hợp. Tuy nhiên,
việc phân tích các bài toán lồi cho chúng ta cái nhìn sâu sắc hữu ích
về cách tiếp cận tối ưu hóa, cụ thể là giảm tốc độ học tập dần dần,
mặc dù không quá nhanh.
- Vấn đề xảy ra khi tỷ lệ học tập quá nhỏ hoặc quá lớn. Trong thực tế,
một tỷ lệ học tập phù hợp thường chỉ được tìm thấy sau nhiều thí
nghiệm.
- Khi có nhiều ví dụ hơn trong tập dữ liệu đào tạo, chi phí nhiều hơn
để tính toán mỗi lần lặp cho gradient descent, do đó, stochastic
gradient descent được ưa thích trong những trường hợp này.
- Đảm bảo tối ưu cho dòng dốc ngẫu nhiên nói chung không có sẵn trong
các trường hợp không lồi vì số lượng minima cục bộ yêu cầu kiểm tra
cũng có thể là cấp số nhân.
Bài tập
-------
1. Thử nghiệm với các lịch trình tỷ lệ học tập khác nhau cho gốc
gradient ngẫu nhiên và với các số lần lặp khác nhau. Đặc biệt, vẽ
khoảng cách từ giải pháp tối ưu :math:`(0, 0)` như một hàm của số lần
lặp lại.
2. Chứng minh rằng đối với hàm :math:`f(x_1, x_2) = x_1^2 + 2 x_2^2`
thêm nhiễu bình thường vào gradient tương đương với việc giảm thiểu
hàm mất
:math:`f(\mathbf{x}, \mathbf{w}) = (x_1 - w_1)^2 + 2 (x_2 - w_2)^2`
trong đó :math:`\mathbf{x}` được rút ra từ một phân phối bình thường.
3. So sánh sự hội tụ của gốc gradient ngẫu nhiên khi bạn lấy mẫu từ
:math:`\{(x_1, y_1), \ldots, (x_n, y_n)\}` với sự thay thế và khi bạn
lấy mẫu mà không cần thay thế.
4. Làm thế nào bạn sẽ thay đổi các stochastic gradient descent solver
nếu một số gradient (hoặc đúng hơn là một số phối hợp liên quan đến
nó) đã luôn lớn hơn tất cả các gradient khác?
5. Giả sử rằng :math:`f(x) = x^2 (1 + \sin x)`. :math:`f` có bao nhiêu
minima địa phương? Bạn có thể thay đổi :math:`f` theo cách để giảm
thiểu nó, người ta cần đánh giá tất cả các minima địa phương không?
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html