Layers tùy chỉnh ================ Một yếu tố đằng sau sự thành công của deep learning là sự sẵn có của một loạt các lớp có thể được sáng tác theo những cách sáng tạo để thiết kế kiến trúc phù hợp với nhiều nhiệm vụ khác nhau. Ví dụ, các nhà nghiên cứu đã phát minh ra các lớp đặc biệt để xử lý hình ảnh, văn bản, lặp lại dữ liệu tuần tự và thực hiện lập trình động. Sớm hay muộn, bạn sẽ gặp hoặc phát minh ra một lớp chưa tồn tại trong khuôn khổ học sâu. Trong những trường hợp này, bạn phải xây dựng một lớp tùy chỉnh. Trong phần này, chúng tôi chỉ cho bạn như thế nào. Các lớp không có tham số ------------------------ Để bắt đầu, chúng tôi xây dựng một lớp tùy chỉnh không có bất kỳ tham số nào của riêng nó. Điều này sẽ trông quen thuộc nếu bạn nhớ lại giới thiệu của chúng tôi để chặn trong :numref:`sec_model_construction`. Lớp ``CenteredLayer`` sau chỉ đơn giản là trừ trung bình từ đầu vào của nó. Để xây dựng nó, chúng ta chỉ cần kế thừa từ lớp lớp cơ sở và thực hiện hàm tuyên truyền chuyển tiếp. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python from mxnet import np, npx from mxnet.gluon import nn npx.set_np() class CenteredLayer(nn.Block): def __init__(self, **kwargs): super().__init__(**kwargs) def forward(self, X): return X - X.mean() .. raw:: html
.. raw:: html
.. code:: python import torch from torch import nn from torch.nn import functional as F class CenteredLayer(nn.Module): def __init__(self): super().__init__() def forward(self, X): return X - X.mean() .. raw:: html
.. raw:: html
.. code:: python import tensorflow as tf class CenteredLayer(tf.keras.Model): def __init__(self): super().__init__() def call(self, inputs): return inputs - tf.reduce_mean(inputs) .. raw:: html
.. raw:: html
Hãy để chúng tôi xác minh rằng lớp của chúng tôi hoạt động như dự định bằng cách cung cấp một số dữ liệu thông qua nó. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python layer = CenteredLayer() layer(np.array([1, 2, 3, 4, 5])) .. parsed-literal:: :class: output array([-2., -1., 0., 1., 2.]) .. raw:: html
.. raw:: html
.. code:: python layer = CenteredLayer() layer(torch.FloatTensor([1, 2, 3, 4, 5])) .. parsed-literal:: :class: output tensor([-2., -1., 0., 1., 2.]) .. raw:: html
.. raw:: html
.. code:: python layer = CenteredLayer() layer(tf.constant([1, 2, 3, 4, 5])) .. parsed-literal:: :class: output .. raw:: html
.. raw:: html
Bây giờ chúng ta có thể kết hợp layer của chúng ta như một component trong việc xây dựng các mô hình phức tạp hơn. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python net = nn.Sequential() net.add(nn.Dense(128), CenteredLayer()) net.initialize() .. raw:: html
.. raw:: html
.. code:: python net = nn.Sequential(nn.Linear(8, 128), CenteredLayer()) .. raw:: html
.. raw:: html
.. code:: python net = tf.keras.Sequential([tf.keras.layers.Dense(128), CenteredLayer()]) .. raw:: html
.. raw:: html
Là một kiểm tra thêm sự tỉnh táo, chúng tôi có thể gửi dữ liệu ngẫu nhiên thông qua mạng và kiểm tra xem trung bình có thực tế 0 không. Bởi vì chúng ta đang xử lý các số điểm nổi, chúng ta vẫn có thể thấy một số nonzero rất nhỏ do lượng tử hóa. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python Y = net(np.random.uniform(size=(4, 8))) Y.mean() .. parsed-literal:: :class: output array(3.783498e-10) .. raw:: html
.. raw:: html
.. code:: python Y = net(torch.rand(4, 8)) Y.mean() .. parsed-literal:: :class: output tensor(-4.6566e-09, grad_fn=) .. raw:: html
.. raw:: html
.. code:: python Y = net(tf.random.uniform((4, 8))) tf.reduce_mean(Y) .. parsed-literal:: :class: output .. raw:: html
.. raw:: html
Các lớp có tham số ------------------ Bây giờ chúng ta đã biết cách xác định các lớp đơn giản, chúng ta hãy chuyển sang xác định các lớp với các tham số có thể được điều chỉnh thông qua đào tạo. Chúng ta có thể sử dụng các chức năng tích hợp để tạo các tham số, cung cấp một số chức năng dọn phòng cơ bản. Đặc biệt, họ chi phối quyền truy cập, khởi tạo, chia sẻ, lưu và tải các tham số mô hình. Bằng cách này, trong số các lợi ích khác, chúng tôi sẽ không cần phải viết các thói quen serialization tùy chỉnh cho mọi lớp tùy chỉnh. Bây giờ chúng ta hãy thực hiện phiên bản riêng của chúng ta của lớp được kết nối hoàn toàn. Nhớ lại rằng lớp này yêu cầu hai tham số, một để đại diện cho trọng lượng và một cho sự thiên vị. Trong triển khai này, chúng tôi nướng trong kích hoạt ReLU dưới dạng mặc định. Lớp này yêu cầu nhập đối số: ``in_units`` và ``units``, biểu thị số lượng đầu vào và đầu ra, tương ứng. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python class MyDense(nn.Block): def __init__(self, units, in_units, **kwargs): super().__init__(**kwargs) self.weight = self.params.get('weight', shape=(in_units, units)) self.bias = self.params.get('bias', shape=(units,)) def forward(self, x): linear = np.dot(x, self.weight.data(ctx=x.ctx)) + self.bias.data( ctx=x.ctx) return npx.relu(linear) Tiếp theo, chúng tôi khởi tạo lớp ``MyDense`` và truy cập các tham số mô hình của nó. .. code:: python dense = MyDense(units=3, in_units=5) dense.params .. parsed-literal:: :class: output mydense0_ ( Parameter mydense0_weight (shape=(5, 3), dtype=) Parameter mydense0_bias (shape=(3,), dtype=) ) .. raw:: html
.. raw:: html
.. code:: python class MyLinear(nn.Module): def __init__(self, in_units, units): super().__init__() self.weight = nn.Parameter(torch.randn(in_units, units)) self.bias = nn.Parameter(torch.randn(units,)) def forward(self, X): linear = torch.matmul(X, self.weight.data) + self.bias.data return F.relu(linear) Tiếp theo, chúng tôi khởi tạo lớp ``MyLinear`` và truy cập các tham số mô hình của nó. .. code:: python linear = MyLinear(5, 3) linear.weight .. parsed-literal:: :class: output Parameter containing: tensor([[-0.5447, -0.4223, -0.7320], [-0.3532, 1.4021, 0.3656], [ 0.4039, 0.0149, -1.7429], [-0.9663, -2.5671, -1.0107], [ 0.4001, -0.4510, 0.6005]], requires_grad=True) .. raw:: html
.. raw:: html
.. code:: python class MyDense(tf.keras.Model): def __init__(self, units): super().__init__() self.units = units def build(self, X_shape): self.weight = self.add_weight(name='weight', shape=[X_shape[-1], self.units], initializer=tf.random_normal_initializer()) self.bias = self.add_weight( name='bias', shape=[self.units], initializer=tf.zeros_initializer()) def call(self, X): linear = tf.matmul(X, self.weight) + self.bias return tf.nn.relu(linear) Tiếp theo, chúng tôi khởi tạo lớp ``MyDense`` và truy cập các tham số mô hình của nó. .. code:: python dense = MyDense(3) dense(tf.random.uniform((2, 5))) dense.get_weights() .. parsed-literal:: :class: output [array([[ 0.09981945, -0.04308238, -0.06013313], [-0.04979542, -0.02897512, 0.02753923], [ 0.06066662, 0.09469151, -0.00839288], [-0.00426127, -0.03299933, 0.01423264], [-0.00832251, 0.03117967, 0.02648194]], dtype=float32), array([0., 0., 0.], dtype=float32)] .. raw:: html
.. raw:: html
Chúng ta có thể trực tiếp thực hiện các phép tính tuyên truyền chuyển tiếp bằng cách sử dụng các lớp tùy chỉnh .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python dense.initialize() dense(np.random.uniform(size=(2, 5))) .. parsed-literal:: :class: output array([[0. , 0.01633355, 0. ], [0. , 0.01581812, 0. ]]) .. raw:: html
.. raw:: html
.. code:: python linear(torch.rand(2, 5)) .. parsed-literal:: :class: output tensor([[1.8603, 0.0000, 0.0000], [1.9760, 0.0000, 0.0000]]) .. raw:: html
.. raw:: html
.. code:: python dense(tf.random.uniform((2, 5))) .. parsed-literal:: :class: output .. raw:: html
.. raw:: html
Chúng ta cũng có thể xây dựng các mô hình bằng cách sử dụng lớp tùy chỉnh Khi chúng ta có rằng chúng ta có thể sử dụng nó giống như lớp được kết nối hoàn toàn tích hợp. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python net = nn.Sequential() net.add(MyDense(8, in_units=64), MyDense(1, in_units=8)) net.initialize() net(np.random.uniform(size=(2, 64))) .. parsed-literal:: :class: output array([[0.06508517], [0.0615553 ]]) .. raw:: html
.. raw:: html
.. code:: python net = nn.Sequential(MyLinear(64, 8), MyLinear(8, 1)) net(torch.rand(2, 64)) .. parsed-literal:: :class: output tensor([[0.], [0.]]) .. raw:: html
.. raw:: html
.. code:: python net = tf.keras.models.Sequential([MyDense(8), MyDense(1)]) net(tf.random.uniform((2, 64))) .. parsed-literal:: :class: output .. raw:: html
.. raw:: html
Tóm tắt ------- - Chúng ta có thể thiết kế các lớp tùy chỉnh thông qua lớp lớp cơ bản. Điều này cho phép chúng ta xác định các lớp mới linh hoạt hoạt hoạt khác với bất kỳ lớp hiện có nào trong thư viện. - Sau khi được xác định, các lớp tùy chỉnh có thể được gọi trong bối cảnh và kiến trúc tùy ý. - Các lớp có thể có các tham số cục bộ, có thể được tạo thông qua các chức năng tích hợp. Bài tập ------- 1. Thiết kế một lớp lấy đầu vào và tính toán giảm tensor, tức là nó trả về :math:`y_k = \sum_{i, j} W_{ijk} x_i x_j`. 2. Thiết kế một lớp trả về một nửa hàng đầu của hệ số Fourier của dữ liệu. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html