.. _sec_mlp_scratch: Thực hiện các Perceptrons đa lớp từ đầu ======================================= Bây giờ chúng ta đã đặc trưng các nhận thức đa lớp (MLPs) về mặt toán học, chúng ta hãy cố gắng thực hiện một chính mình. Để so sánh với các kết quả trước đây của chúng tôi đạt được với hồi quy softmax (:numref:`sec_softmax_scratch`), chúng tôi sẽ tiếp tục làm việc với tập dữ liệu phân loại hình ảnh Fashion-MNIST (:numref:`sec_fashion_mnist`). .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python from mxnet import gluon, np, npx from d2l import mxnet as d2l npx.set_np() batch_size = 256 train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size) .. raw:: html
.. raw:: html
.. code:: python import torch from torch import nn from d2l import torch as d2l batch_size = 256 train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size) .. raw:: html
.. raw:: html
.. code:: python import tensorflow as tf from d2l import tensorflow as d2l batch_size = 256 train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size) .. raw:: html
.. raw:: html
Khởi tạo các tham số mô hình ---------------------------- Nhớ lại rằng Fashion-MNIST chứa 10 lớp, và rằng mỗi hình ảnh bao gồm một :math:`28 \times 28 = 784` lưới giá trị điểm ảnh xám. Một lần nữa, chúng ta sẽ bỏ qua cấu trúc không gian giữa các pixel cho bây giờ, vì vậy chúng ta có thể nghĩ về điều này chỉ đơn giản là một tập dữ liệu phân loại với 784 tính năng đầu vào và 10 lớp. Để bắt đầu, chúng ta sẽ triển khai MLP với một lớp ẩn và 256 đơn vị ẩn. Lưu ý rằng chúng ta có thể coi cả hai đại lượng này là siêu tham số. Thông thường, chúng ta chọn độ rộng lớp trong quyền hạn của 2, mà có xu hướng được tính toán hiệu quả vì cách bộ nhớ được phân bổ và giải quyết trong phần cứng. Một lần nữa, chúng tôi sẽ đại diện cho các thông số của chúng tôi với một số hàng chục. Lưu ý rằng \* cho mỗi lớp\*, chúng ta phải theo dõi một ma trận trọng lượng và một vector thiên vị. Như mọi khi, chúng tôi phân bổ bộ nhớ cho gradient của sự mất mát đối với các tham số này. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python num_inputs, num_outputs, num_hiddens = 784, 10, 256 W1 = np.random.normal(scale=0.01, size=(num_inputs, num_hiddens)) b1 = np.zeros(num_hiddens) W2 = np.random.normal(scale=0.01, size=(num_hiddens, num_outputs)) b2 = np.zeros(num_outputs) params = [W1, b1, W2, b2] for param in params: param.attach_grad() .. raw:: html
.. raw:: html
.. code:: python num_inputs, num_outputs, num_hiddens = 784, 10, 256 W1 = nn.Parameter(torch.randn( num_inputs, num_hiddens, requires_grad=True) * 0.01) b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True)) W2 = nn.Parameter(torch.randn( num_hiddens, num_outputs, requires_grad=True) * 0.01) b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True)) params = [W1, b1, W2, b2] .. raw:: html
.. raw:: html
.. code:: python num_inputs, num_outputs, num_hiddens = 784, 10, 256 W1 = tf.Variable(tf.random.normal( shape=(num_inputs, num_hiddens), mean=0, stddev=0.01)) b1 = tf.Variable(tf.zeros(num_hiddens)) W2 = tf.Variable(tf.random.normal( shape=(num_hiddens, num_outputs), mean=0, stddev=0.01)) b2 = tf.Variable(tf.random.normal([num_outputs], stddev=.01)) params = [W1, b1, W2, b2] .. raw:: html
.. raw:: html
Chức năng kích hoạt ------------------- Để đảm bảo rằng chúng ta biết mọi thứ hoạt động như thế nào, chúng ta sẽ triển khai kích hoạt ReLU bằng cách sử dụng hàm tối đa thay vì gọi trực tiếp hàm ``relu`` tích hợp sẵn. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python def relu(X): return np.maximum(X, 0) .. raw:: html
.. raw:: html
.. code:: python def relu(X): a = torch.zeros_like(X) return torch.max(X, a) .. raw:: html
.. raw:: html
.. code:: python def relu(X): return tf.math.maximum(X, 0) .. raw:: html
.. raw:: html
Mô hình ------- Bởi vì chúng ta đang bỏ qua cấu trúc không gian, chúng ta ``reshape`` mỗi hình ảnh hai chiều thành một vector phẳng có chiều dài ``num_inputs``. Cuối cùng, chúng tôi triển khai mô hình của chúng tôi chỉ với một vài dòng code. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python def net(X): X = X.reshape((-1, num_inputs)) H = relu(np.dot(X, W1) + b1) return np.dot(H, W2) + b2 .. raw:: html
.. raw:: html
.. code:: python def net(X): X = X.reshape((-1, num_inputs)) H = relu(X@W1 + b1) # Here '@' stands for matrix multiplication return (H@W2 + b2) .. raw:: html
.. raw:: html
.. code:: python def net(X): X = tf.reshape(X, (-1, num_inputs)) H = relu(tf.matmul(X, W1) + b1) return tf.matmul(H, W2) + b2 .. raw:: html
.. raw:: html
Chức năng mất ------------- Để đảm bảo tính ổn định số, và bởi vì chúng tôi đã triển khai chức năng softmax từ đầu (:numref:`sec_softmax_scratch`), chúng tôi tận dụng chức năng tích hợp từ các API cấp cao để tính toán sự mất mát softmax và cross-entropy. Nhớ lại cuộc thảo luận trước đó của chúng tôi về những phức tạp này trong :numref:`subsec_softmax-implementation-revisited`. Chúng tôi khuyến khích người đọc quan tâm kiểm tra mã nguồn cho chức năng mất mát để đào sâu kiến thức của họ về chi tiết thực hiện. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python loss = gluon.loss.SoftmaxCrossEntropyLoss() .. raw:: html
.. raw:: html
.. code:: python loss = nn.CrossEntropyLoss(reduction='none') .. raw:: html
.. raw:: html
.. code:: python def loss(y_hat, y): return tf.losses.sparse_categorical_crossentropy( y, y_hat, from_logits=True) .. raw:: html
.. raw:: html
Đào tạo ------- May mắn thay, vòng đào tạo cho MLP hoàn toàn giống như đối với hồi quy softmax. Tận dụng gói ``d2l`` một lần nữa, chúng tôi gọi hàm ``train_ch3`` (xem :numref:`sec_softmax_scratch`), đặt số epochs thành 10 và tỷ lệ học tập là 0.1. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python num_epochs, lr = 10, 0.1 d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, lambda batch_size: d2l.sgd(params, lr, batch_size)) .. figure:: output_mlp-scratch_106d07_63_0.svg .. raw:: html
.. raw:: html
.. code:: python num_epochs, lr = 10, 0.1 updater = torch.optim.SGD(params, lr=lr) d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater) .. figure:: output_mlp-scratch_106d07_66_0.svg .. raw:: html
.. raw:: html
.. code:: python num_epochs, lr = 10, 0.1 updater = d2l.Updater([W1, W2, b1, b2], lr) d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater) .. figure:: output_mlp-scratch_106d07_69_0.svg .. raw:: html
.. raw:: html
Để đánh giá mô hình đã học, chúng tôi áp dụng nó trên một số dữ liệu thử nghiệm. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python d2l.predict_ch3(net, test_iter) .. figure:: output_mlp-scratch_106d07_75_0.svg .. raw:: html
.. raw:: html
.. code:: python d2l.predict_ch3(net, test_iter) .. figure:: output_mlp-scratch_106d07_78_0.svg .. raw:: html
.. raw:: html
.. code:: python d2l.predict_ch3(net, test_iter) .. figure:: output_mlp-scratch_106d07_81_0.svg .. raw:: html
.. raw:: html
Tóm tắt ------- - Chúng tôi thấy rằng việc thực hiện một MLP đơn giản là dễ dàng, ngay cả khi thực hiện thủ công. - Tuy nhiên, với một số lượng lớn các lớp, việc thực hiện MLP từ đầu vẫn có thể trở nên lộn xộn (ví dụ, đặt tên và theo dõi các thông số của mô hình của chúng tôi). Bài tập ------- 1. Thay đổi giá trị của hyperparameters ``num_hiddens`` và xem siêu tham số này ảnh hưởng như thế nào đến kết quả của bạn. Xác định giá trị tốt nhất của siêu tham số này, giữ cho tất cả những người khác không đổi. 2. Hãy thử thêm một layer ẩn bổ sung để xem nó ảnh hưởng đến kết quả như thế nào. 3. Làm thế nào để thay đổi tỷ lệ học tập làm thay đổi kết quả của bạn? Sửa chữa kiến trúc mô hình và các siêu tham số khác (bao gồm số thời đại), tỷ lệ học tập nào mang lại cho bạn kết quả tốt nhất? 4. Kết quả tốt nhất bạn có thể nhận được bằng cách tối ưu hóa tất cả các siêu tham số (tốc độ học tập, số lượng kỷ nguyên, số lớp ẩn, số lượng đơn vị ẩn trên mỗi lớp) cùng nhau? 5. Mô tả lý do tại sao việc đối phó với nhiều siêu tham số khó khăn hơn nhiều. 6. Chiến lược thông minh nhất bạn có thể nghĩ đến để cấu trúc tìm kiếm trên nhiều siêu tham số là gì? .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html