.. _sec_linear_scratch:
Thực hiện hồi quy tuyến tính từ đầu
===================================
Bây giờ bạn đã hiểu những ý tưởng quan trọng đằng sau hồi quy tuyến
tính, chúng ta có thể bắt đầu làm việc thông qua việc thực hiện thực
hành trong mã. Trong phần này, chúng tôi sẽ thực hiện toàn bộ phương
pháp từ đầu, bao gồm đường ống dữ liệu, mô hình, chức năng mất mát và
trình tối ưu hóa giảm dần dần ngẫu nhiên minibatch. Trong khi các khuôn
khổ học sâu hiện đại có thể tự động hóa gần như tất cả công việc này,
thực hiện mọi thứ từ đầu là cách duy nhất để đảm bảo rằng bạn thực sự
biết những gì bạn đang làm. Hơn nữa, khi đến lúc tùy chỉnh các mô hình,
xác định các lớp hoặc chức năng mất mát của riêng chúng ta, hiểu cách
mọi thứ hoạt động dưới mui xe sẽ chứng minh tiện dụng. Trong phần này,
chúng tôi sẽ chỉ dựa vào hàng chục và sự khác biệt tự động. Sau đó,
chúng tôi sẽ giới thiệu một triển khai ngắn gọn hơn, tận dụng chuông và
còi của các khuôn khổ học sâu.
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import random
from mxnet import autograd, np, npx
from d2l import mxnet as d2l
npx.set_np()
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import random
import torch
from d2l import torch as d2l
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import random
import tensorflow as tf
from d2l import tensorflow as d2l
.. raw:: html
.. raw:: html
Tạo tập dữ liệu
---------------
Để giữ cho mọi thứ đơn giản, chúng ta sẽ xây dựng một tập dữ liệu nhân
tạo theo một mô hình tuyến tính với tiếng ồn phụ gia. Nhiệm vụ của chúng
ta là khôi phục các tham số của mô hình này bằng cách sử dụng tập hợp
các ví dụ hữu hạn có trong tập dữ liệu của chúng ta. Chúng tôi sẽ giữ dữ
liệu chiều thấp để chúng tôi có thể hình dung nó một cách dễ dàng. Trong
đoạn mã sau, chúng ta tạo ra một tập dữ liệu chứa 1000 ví dụ, mỗi ví dụ
gồm 2 tính năng được lấy mẫu từ một phân phối bình thường chuẩn. Do đó
tập dữ liệu tổng hợp của chúng tôi sẽ là một ma trận
:math:`\mathbf{X}\in \mathbb{R}^{1000 \times 2}`.
Các thông số thực sự tạo ra bộ dữ liệu của chúng tôi sẽ là
:math:`\mathbf{w} = [2, -3.4]^\top` và :math:`b = 4.2` và nhãn tổng hợp
của chúng tôi sẽ được gán theo mô hình tuyến tính sau với thuật ngữ
nhiễu :math:`\epsilon`:
.. math:: \mathbf{y}= \mathbf{X} \mathbf{w} + b + \mathbf\epsilon.
Bạn có thể nghĩ về :math:`\epsilon` là nắm bắt các lỗi đo lường tiềm ẩn
trên các tính năng và nhãn. Chúng tôi sẽ giả định rằng các giả định tiêu
chuẩn giữ và do đó :math:`\epsilon` tuân theo một phân phối bình thường
với trung bình 0. Để làm cho vấn đề của chúng tôi dễ dàng, chúng tôi sẽ
đặt độ lệch chuẩn của nó thành 0,01. Mã sau đây tạo ra tập dữ liệu tổng
hợp của chúng tôi.
.. raw:: html
.. raw:: html
.. code:: python
def synthetic_data(w, b, num_examples): #@save
"""Generate y = Xw + b + noise."""
X = np.random.normal(0, 1, (num_examples, len(w)))
y = np.dot(X, w) + b
y += np.random.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))
true_w = np.array([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
.. raw:: html
.. raw:: html
.. code:: python
def synthetic_data(w, b, num_examples): #@save
"""Generate y = Xw + b + noise."""
X = torch.normal(0, 1, (num_examples, len(w)))
y = torch.matmul(X, w) + b
y += torch.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
.. raw:: html
.. raw:: html
.. code:: python
def synthetic_data(w, b, num_examples): #@save
"""Generate y = Xw + b + noise."""
X = tf.zeros((num_examples, w.shape[0]))
X += tf.random.normal(shape=X.shape)
y = tf.matmul(X, tf.reshape(w, (-1, 1))) + b
y += tf.random.normal(shape=y.shape, stddev=0.01)
y = tf.reshape(y, (-1, 1))
return X, y
true_w = tf.constant([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
.. raw:: html
.. raw:: html
Lưu ý rằng mỗi hàng trong ``features`` bao gồm một ví dụ dữ liệu 2 chiều
và mỗi hàng trong ``labels`` bao gồm một giá trị nhãn 1 chiều (vô hướng)
.
.. raw:: html
.. raw:: html
.. code:: python
print('features:', features[0],'\nlabel:', labels[0])
.. parsed-literal::
:class: output
features: [2.2122064 1.1630787]
label: [4.662078]
.. raw:: html
.. raw:: html
.. code:: python
print('features:', features[0],'\nlabel:', labels[0])
.. parsed-literal::
:class: output
features: tensor([-0.6500, 0.6735])
label: tensor([0.6193])
.. raw:: html
.. raw:: html
.. code:: python
print('features:', features[0],'\nlabel:', labels[0])
.. parsed-literal::
:class: output
features: tf.Tensor([-0.79747343 -0.7921036 ], shape=(2,), dtype=float32)
label: tf.Tensor([5.2827835], shape=(1,), dtype=float32)
.. raw:: html
.. raw:: html
Bằng cách tạo ra một âm mưu phân tán bằng cách sử dụng tính năng thứ hai
``features[:, 1]`` và ``labels``, chúng ta có thể quan sát rõ mối tương
quan tuyến tính giữa hai.
.. raw:: html
.. raw:: html
.. code:: python
d2l.set_figsize()
# The semicolon is for displaying the plot only
d2l.plt.scatter(features[:, (1)].asnumpy(), labels.asnumpy(), 1);
.. figure:: output_linear-regression-scratch_58de05_39_0.svg
.. raw:: html
.. raw:: html
.. code:: python
d2l.set_figsize()
# The semicolon is for displaying the plot only
d2l.plt.scatter(features[:, (1)].detach().numpy(), labels.detach().numpy(), 1);
.. figure:: output_linear-regression-scratch_58de05_42_0.svg
.. raw:: html
.. raw:: html
.. code:: python
d2l.set_figsize()
# The semicolon is for displaying the plot only
d2l.plt.scatter(features[:, (1)].numpy(), labels.numpy(), 1);
.. figure:: output_linear-regression-scratch_58de05_45_0.svg
.. raw:: html
.. raw:: html
Đọc tập dữ liệu
---------------
Nhớ lại rằng các mô hình đào tạo bao gồm thực hiện nhiều lần vượt qua
tập dữ liệu, lấy một minibatch ví dụ tại một thời điểm và sử dụng chúng
để cập nhật mô hình của chúng tôi. Vì quá trình này rất cơ bản để đào
tạo các thuật toán học máy, nên nó đáng để xác định một chức năng tiện
ích để xáo trộn bộ dữ liệu và truy cập nó trong các minibatches.
Trong đoạn code sau, chúng ta [**define the ``data_iter`` function**] để
chứng minh một thực hiện có thể thực hiện chức năng này. Chức năng có
kích thước lô, một ma trận của các tính năng và một vector nhãn, mang
lại minibatches kích thước ``batch_size``. Mỗi minibatch bao gồm một
loạt các tính năng và nhãn.
.. raw:: html
.. raw:: html
.. code:: python
def data_iter(batch_size, features, labels):
num_examples = len(features)
indices = list(range(num_examples))
# The examples are read at random, in no particular order
random.shuffle(indices)
for i in range(0, num_examples, batch_size):
batch_indices = np.array(
indices[i: min(i + batch_size, num_examples)])
yield features[batch_indices], labels[batch_indices]
.. raw:: html
.. raw:: html
.. code:: python
def data_iter(batch_size, features, labels):
num_examples = len(features)
indices = list(range(num_examples))
# The examples are read at random, in no particular order
random.shuffle(indices)
for i in range(0, num_examples, batch_size):
batch_indices = torch.tensor(
indices[i: min(i + batch_size, num_examples)])
yield features[batch_indices], labels[batch_indices]
.. raw:: html
.. raw:: html
.. code:: python
def data_iter(batch_size, features, labels):
num_examples = len(features)
indices = list(range(num_examples))
# The examples are read at random, in no particular order
random.shuffle(indices)
for i in range(0, num_examples, batch_size):
j = tf.constant(indices[i: min(i + batch_size, num_examples)])
yield tf.gather(features, j), tf.gather(labels, j)
.. raw:: html
.. raw:: html
Nói chung, lưu ý rằng chúng tôi muốn sử dụng minibatches có kích thước
hợp lý để tận dụng lợi thế của phần cứng GPU, vượt trội ở các hoạt động
song song. Bởi vì mỗi ví dụ có thể được cung cấp thông qua các mô hình
của chúng tôi song song và gradient của hàm mất cho mỗi ví dụ cũng có
thể được thực hiện song song, GPU cho phép chúng tôi xử lý hàng trăm ví
dụ trong thời gian ít hơn so với việc xử lý chỉ là một ví dụ duy nhất.
Để xây dựng một số trực giác, chúng ta hãy đọc và in hàng loạt ví dụ dữ
liệu nhỏ đầu tiên. Hình dạng của các tính năng trong mỗi minibatch cho
chúng ta biết cả kích thước minibatch và số lượng tính năng đầu vào.
Tương tự như vậy, minibatch nhãn của chúng tôi sẽ có một hình dạng được
đưa ra bởi ``batch_size``.
.. raw:: html
.. raw:: html
.. code:: python
batch_size = 10
for X, y in data_iter(batch_size, features, labels):
print(X, '\n', y)
break
.. parsed-literal::
:class: output
[[ 0.5644832 -0.27778798]
[ 0.0901759 0.27758422]
[-0.55819434 0.33346984]
[ 0.9254156 -1.0446701 ]
[ 0.16704662 0.8423359 ]
[ 0.20792933 -0.02453975]
[ 0.5569871 0.64158773]
[ 0.22596185 0.529344 ]
[-0.5624781 0.72426325]
[ 1.1721171 0.05731938]]
[[6.2593036]
[3.427059 ]
[1.9458812]
[9.606839 ]
[1.6682019]
[4.7006207]
[3.1334352]
[2.8673012]
[0.6194691]
[6.335789 ]]
.. raw:: html
.. raw:: html
.. code:: python
batch_size = 10
for X, y in data_iter(batch_size, features, labels):
print(X, '\n', y)
break
.. parsed-literal::
:class: output
tensor([[-0.6999, 1.1784],
[-0.9279, 1.1579],
[-0.0039, 0.4110],
[-0.5786, -2.2632],
[-0.1232, -0.3288],
[ 1.5607, -0.2430],
[ 0.6993, -0.5202],
[ 0.6211, -0.4483],
[ 1.1416, -1.1832],
[-0.6357, 1.1181]])
tensor([[-1.2099],
[-1.5779],
[ 2.8061],
[10.7431],
[ 5.0564],
[ 8.1567],
[ 7.3705],
[ 6.9707],
[10.5014],
[-0.8699]])
.. raw:: html
.. raw:: html
.. code:: python
batch_size = 10
for X, y in data_iter(batch_size, features, labels):
print(X, '\n', y)
break
.. parsed-literal::
:class: output
tf.Tensor(
[[ 0.3163907 1.0544165 ]
[ 0.04565843 0.76612216]
[ 0.15500692 -0.01428624]
[-0.83107764 -0.00458153]
[-0.67439437 -0.15600796]
[ 0.7293783 -1.2135689 ]
[ 0.45340142 -0.50237995]
[-0.8389561 -0.17799638]
[ 1.2295055 0.49994317]
[-0.9910479 -0.9347741 ]], shape=(10, 2), dtype=float32)
tf.Tensor(
[[1.2605295]
[1.6758626]
[4.553184 ]
[2.5514154]
[3.3955529]
[9.770455 ]
[6.8096895]
[3.1357522]
[4.965126 ]
[5.3838797]], shape=(10, 1), dtype=float32)
.. raw:: html
.. raw:: html
Khi chúng ta chạy lặp lại, chúng ta có được các minibatches riêng biệt
liên tiếp cho đến khi toàn bộ bộ dữ liệu đã cạn kiệt (hãy thử điều này).
Mặc dù việc lặp lại được thực hiện ở trên là tốt cho mục đích giáo khoa,
nhưng nó không hiệu quả theo những cách có thể khiến chúng ta gặp rắc
rối về các vấn đề thực sự. Ví dụ: nó yêu cầu chúng tôi tải tất cả dữ
liệu trong bộ nhớ và chúng tôi thực hiện nhiều truy cập bộ nhớ ngẫu
nhiên. Các bộ lặp tích hợp được triển khai trong một khuôn khổ học sâu
hiệu quả hơn đáng kể và chúng có thể xử lý cả dữ liệu được lưu trữ trong
tệp và dữ liệu được cung cấp thông qua các luồng dữ liệu.
Khởi tạo các tham số mô hình
----------------------------
Trước khi chúng ta có thể bắt đầu tối ưu hóa các tham số của mô hình của
mình bằng cách hạ xuống gradient ngẫu nhiên minibatch, chúng ta cần có
một số tham số ở vị trí đầu tiên. Trong mã sau, chúng ta khởi tạo trọng
lượng bằng cách lấy mẫu các số ngẫu nhiên từ phân phối bình thường với 0
trung bình và độ lệch chuẩn 0,01, và thiết lập sự thiên vị thành 0.
.. raw:: html
.. raw:: html
.. code:: python
w = np.random.normal(0, 0.01, (2, 1))
b = np.zeros(1)
w.attach_grad()
b.attach_grad()
.. raw:: html
.. raw:: html
.. code:: python
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
.. raw:: html
.. raw:: html
.. code:: python
w = tf.Variable(tf.random.normal(shape=(2, 1), mean=0, stddev=0.01),
trainable=True)
b = tf.Variable(tf.zeros(1), trainable=True)
.. raw:: html
.. raw:: html
Sau khi khởi tạo các tham số của chúng tôi, nhiệm vụ tiếp theo của chúng
tôi là cập nhật chúng cho đến khi chúng phù hợp với dữ liệu của chúng
tôi đủ tốt. Mỗi bản cập nhật yêu cầu lấy gradient của hàm mất của chúng
tôi đối với các tham số. Với gradient này, chúng ta có thể cập nhật từng
tham số theo hướng có thể làm giảm tổn thất.
Vì không ai muốn tính toán độ dốc một cách rõ ràng (điều này là tẻ nhạt
và dễ bị lỗi), chúng tôi sử dụng sự khác biệt tự động, như được giới
thiệu trong :numref:`sec_autograd`, để tính toán gradient.
Xác định mô hình
----------------
Tiếp theo, chúng ta phải xác định mô hình của chúng tôi, liên quan đến
các đầu vào và tham số của nó với đầu racủa nó. Nhớ lại rằng để tính
toán đầu ra của mô hình tuyến tính, chúng ta chỉ cần lấy sản phẩm chấm
ma thuật-vector của các tính năng đầu vào :math:`\mathbf{X}` và trọng
lượng mô hình :math:`\mathbf{w}` và thêm :math:`b` bù vào mỗi ví dụ. Lưu
ý rằng dưới :math:`\mathbf{Xw}` là một vectơ và :math:`b` là vô hướng.
Nhớ lại cơ chế phát sóng như được mô tả trong
:numref:`subsec_broadcasting`. Khi chúng ta thêm một vectơ và vô
hướng, vô hướng được thêm vào mỗi thành phần của vectơ.
.. raw:: html
.. raw:: html
.. code:: python
def linreg(X, w, b): #@save
"""The linear regression model."""
return np.dot(X, w) + b
.. raw:: html
.. raw:: html
.. code:: python
def linreg(X, w, b): #@save
"""The linear regression model."""
return torch.matmul(X, w) + b
.. raw:: html
.. raw:: html
.. code:: python
def linreg(X, w, b): #@save
"""The linear regression model."""
return tf.matmul(X, w) + b
.. raw:: html
.. raw:: html
Xác định chức năng mất
----------------------
Vì update model của chúng tôi yêu cầu dùng gradient của hàm mất của
chúng ta, chúng ta nên define the loss function first. Ở đây chúng ta sẽ
sử dụng hàm mất bình phương như mô tả trong
:numref:`sec_linear_regression`. Trong quá trình thực hiện, chúng ta
cần chuyển đổi giá trị thực ``y`` thành hình dạng của giá trị dự đoán
``y_hat``. Kết quả được trả về bởi hàm sau cũng sẽ có hình dạng giống
như ``y_hat``.
.. raw:: html
.. raw:: html
.. code:: python
def squared_loss(y_hat, y): #@save
"""Squared loss."""
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
.. raw:: html
.. raw:: html
.. code:: python
def squared_loss(y_hat, y): #@save
"""Squared loss."""
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2
.. raw:: html
.. raw:: html
.. code:: python
def squared_loss(y_hat, y): #@save
"""Squared loss."""
return (y_hat - tf.reshape(y, y_hat.shape)) ** 2 / 2
.. raw:: html
.. raw:: html
Xác định thuật toán tối ưu hóa
------------------------------
Như chúng ta đã thảo luận trong :numref:`sec_linear_regression`, hồi
quy tuyến tính có một giải pháp dạng kín. Tuy nhiên, đây không phải là
một cuốn sách về hồi quy tuyến tính: nó là một cuốn sách về học sâu. Vì
không có mô hình nào khác mà cuốn sách này giới thiệu có thể được giải
quyết một cách phân tích, chúng tôi sẽ nhân cơ hội này để giới thiệu ví
dụ làm việc đầu tiên của bạn về dòng dốc ngẫu nhiên minibatch.
Ở mỗi bước, sử dụng một minibatch được vẽ ngẫu nhiên từ tập dữ liệu của
chúng tôi, chúng tôi sẽ ước tính độ dốc của sự mất mát đối với các tham
số của chúng tôi. Tiếp theo, chúng tôi sẽ cập nhật các thông số của
chúng tôi theo hướng có thể làm giảm tổn thất. Mã sau áp dụng bản cập
nhật gradient gốc minibatch stochastic, cho một tập hợp các tham số, tốc
độ học tập và kích thước lô. Kích thước của bước cập nhật được xác định
bởi tỷ lệ học tập ``lr``. Bởi vì tổn thất của chúng tôi được tính như
một tổng so với các ví dụ nhỏ, chúng tôi bình thường hóa kích thước bước
của chúng tôi theo kích thước lô (``batch_size``), do đó độ lớn của một
kích thước bước điển hình không phụ thuộc nhiều vào sự lựa chọn của
chúng tôi về kích thước lô.
.. raw:: html
.. raw:: html
.. code:: python
def sgd(params, lr, batch_size): #@save
"""Minibatch stochastic gradient descent."""
for param in params:
param[:] = param - lr * param.grad / batch_size
.. raw:: html
.. raw:: html
.. code:: python
def sgd(params, lr, batch_size): #@save
"""Minibatch stochastic gradient descent."""
with torch.no_grad():
for param in params:
param -= lr * param.grad / batch_size
param.grad.zero_()
.. raw:: html
.. raw:: html
.. code:: python
def sgd(params, grads, lr, batch_size): #@save
"""Minibatch stochastic gradient descent."""
for param, grad in zip(params, grads):
param.assign_sub(lr*grad/batch_size)
.. raw:: html
.. raw:: html
Đào tạo
-------
Bây giờ chúng tôi đã có tất cả các phần tại chỗ, chúng tôi đã sẵn sàng
để thực hiện vòng lặp đào tạo chính Điều quan trọng là bạn phải hiểu mã
này bởi vì bạn sẽ thấy các vòng đào tạo gần giống hệt nhau hơn và hơn
nữa trong suốt sự nghiệp của bạn trong học sâu.
Trong mỗi lần lặp lại, chúng ta sẽ lấy một loạt các ví dụ đào tạo và
chuyển chúng thông qua mô hình của chúng tôi để có được một tập hợp các
dự đoán. Sau khi tính toán tổn thất, chúng tôi bắt đầu đi ngược qua
mạng, lưu trữ các gradient đối với mỗi tham số. Cuối cùng, chúng ta sẽ
gọi thuật toán tối ưu hóa ``sgd`` để cập nhật các tham số mô hình.
Tóm lại, chúng tôi sẽ thực hiện vòng lặp sau:
- Khởi tạo tham số :math:`(\mathbf{w}, b)`
- Lặp lại cho đến khi xong
- Tính gradient
:math:`\mathbf{g} \leftarrow \partial_{(\mathbf{w},b)} \frac{1}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} l(\mathbf{x}^{(i)}, y^{(i)}, \mathbf{w}, b)`
- Cập nhật thông số
:math:`(\mathbf{w}, b) \leftarrow (\mathbf{w}, b) - \eta \mathbf{g}`
Trong mỗi *epoch*, chúng ta sẽ lặp qua toàn bộ tập dữ liệu (sử dụng hàm
``data_iter``) một lần đi qua mọi ví dụ trong tập dữ liệu đào tạo (giả
sử rằng số ví dụ được chia hết cho kích thước lô). Số epochs
``num_epochs`` và tỷ lệ học tập ``lr`` là cả hai siêu tham số, mà chúng
tôi đặt ở đây là 3 và 0,03, tương ứng. Thật không may, việc thiết lập
các siêu tham số là khó khăn và yêu cầu một số điều chỉnh bằng cách dùng
thử và lỗi. Chúng tôi elide những chi tiết này cho bây giờ nhưng sửa đổi
chúng sau này trong :numref:`chap_optimization`.
.. raw:: html
.. raw:: html
.. code:: python
lr = 0.03
num_epochs = 3
net = linreg
loss = squared_loss
for epoch in range(num_epochs):
for X, y in data_iter(batch_size, features, labels):
with autograd.record():
l = loss(net(X, w, b), y) # Minibatch loss in `X` and `y`
# Because `l` has a shape (`batch_size`, 1) and is not a scalar
# variable, the elements in `l` are added together to obtain a new
# variable, on which gradients with respect to [`w`, `b`] are computed
l.backward()
sgd([w, b], lr, batch_size) # Update parameters using their gradient
train_l = loss(net(features, w, b), labels)
print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
.. parsed-literal::
:class: output
[10:47:55] src/base.cc:49: GPU context requested, but no GPUs found.
epoch 1, loss 0.024991
epoch 2, loss 0.000084
epoch 3, loss 0.000051
.. raw:: html
.. raw:: html
.. code:: python
lr = 0.03
num_epochs = 3
net = linreg
loss = squared_loss
for epoch in range(num_epochs):
for X, y in data_iter(batch_size, features, labels):
l = loss(net(X, w, b), y) # Minibatch loss in `X` and `y`
# Compute gradient on `l` with respect to [`w`, `b`]
l.sum().backward()
sgd([w, b], lr, batch_size) # Update parameters using their gradient
with torch.no_grad():
train_l = loss(net(features, w, b), labels)
print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')
.. parsed-literal::
:class: output
epoch 1, loss 0.032702
epoch 2, loss 0.000131
epoch 3, loss 0.000048
.. raw:: html
.. raw:: html
.. code:: python
lr = 0.03
num_epochs = 3
net = linreg
loss = squared_loss
for epoch in range(num_epochs):
for X, y in data_iter(batch_size, features, labels):
with tf.GradientTape() as g:
l = loss(net(X, w, b), y) # Minibatch loss in `X` and `y`
# Compute gradient on l with respect to [`w`, `b`]
dw, db = g.gradient(l, [w, b])
# Update parameters using their gradient
sgd([w, b], [dw, db], lr, batch_size)
train_l = loss(net(features, w, b), labels)
print(f'epoch {epoch + 1}, loss {float(tf.reduce_mean(train_l)):f}')
.. parsed-literal::
:class: output
epoch 1, loss 0.038048
epoch 2, loss 0.000157
epoch 3, loss 0.000055
.. raw:: html
.. raw:: html
Trong trường hợp này, bởi vì chúng tôi tự tổng hợp bộ dữ liệu, chúng tôi
biết chính xác các tham số thực sự là gì. Do đó, chúng ta có thể đánh
giá thành công của mình trong đào tạo bằng cách so sánh các thông số
thực sự với những thông số mà chúng tôi đã học thông qua vòng đào tạo
của chúng tôi. Thật vậy, họ hóa ra rất gần nhau.
.. raw:: html
.. raw:: html
.. code:: python
print(f'error in estimating w: {true_w - w.reshape(true_w.shape)}')
print(f'error in estimating b: {true_b - b}')
.. parsed-literal::
:class: output
error in estimating w: [ 3.7777424e-04 -4.3630600e-05]
error in estimating b: [0.0002017]
.. raw:: html
.. raw:: html
.. code:: python
print(f'error in estimating w: {true_w - w.reshape(true_w.shape)}')
print(f'error in estimating b: {true_b - b}')
.. parsed-literal::
:class: output
error in estimating w: tensor([-0.0004, -0.0004], grad_fn=)
error in estimating b: tensor([0.0008], grad_fn=)
.. raw:: html
.. raw:: html
.. code:: python
print(f'error in estimating w: {true_w - tf.reshape(w, true_w.shape)}')
print(f'error in estimating b: {true_b - b}')
.. parsed-literal::
:class: output
error in estimating w: [ 5.3536892e-04 -1.4305115e-06]
error in estimating b: [0.0011282]
.. raw:: html
.. raw:: html
Lưu ý rằng chúng ta không nên coi là điều hiển nhiên rằng chúng ta có
thể khôi phục các tham số một cách hoàn hảo. Tuy nhiên, trong machine
learning, chúng ta thường ít quan tâm đến việc khôi phục các tham số cơ
bản thực sự và quan tâm nhiều hơn đến các tham số dẫn đến dự đoán chính
xác cao. May mắn thay, ngay cả trên các vấn đề tối ưu hóa khó khăn, gốc
gradient stochastic thường có thể tìm thấy các giải pháp tốt đáng kể,
một phần do thực tế là, đối với các mạng sâu, tồn tại nhiều cấu hình của
các thông số dẫn đến dự đoán chính xác cao.
Tóm tắt
-------
- Chúng tôi đã thấy cách một mạng sâu có thể được triển khai và tối ưu
hóa từ đầu, chỉ sử dụng hàng chục và sự khác biệt tự động, mà không
cần xác định các lớp hoặc tối ưu hóa ưa thích.
- Phần này chỉ làm trầy xước bề mặt của những gì có thể. Trong các phần
sau, chúng tôi sẽ mô tả các mô hình bổ sung dựa trên các khái niệm mà
chúng tôi vừa giới thiệu và tìm hiểu cách thực hiện chúng một cách
chính xác hơn.
Bài tập
-------
1. Điều gì sẽ xảy ra nếu chúng ta khởi tạo trọng lượng bằng không. Liệu
thuật toán vẫn hoạt động?
2. Giả sử rằng bạn đang `Georg Simon
Ohm `__ đang cố gắng đưa ra
một mô hình giữa điện áp và dòng điện. Bạn có thể sử dụng sự khác
biệt tự động để tìm hiểu các thông số của mô hình của bạn?
3. Bạn có thể sử dụng `Định luật
Planck `__ để xác định
nhiệt độ của một vật thể sử dụng mật độ năng lượng quang phổ không?
4. Các vấn đề bạn có thể gặp phải là gì nếu bạn muốn tính toán các dẫn
xuất thứ hai? Bạn sẽ sửa chúng như thế nào?
5. Tại sao chức năng ``reshape`` cần thiết trong hàm ``squared_loss``?
6. Thử nghiệm sử dụng các tỷ lệ học tập khác nhau để tìm hiểu giá trị
hàm mất giảm nhanh như thế nào.
7. Nếu số lượng ví dụ không thể chia cho kích thước lô, điều gì sẽ xảy
ra với hành vi của hàm ``data_iter``?
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html