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