Các lớp tùy chỉnh

Xem trên TensorFlow.org Chạy trong Google Colab Xem nguồn trên GitHub Tải xuống sổ ghi chép

Chúng tôi khuyên bạn nên sử dụng tf.keras làm API cấp cao để xây dựng mạng thần kinh. Điều đó nói rằng, hầu hết các API TensorFlow đều có thể sử dụng được với khả năng thực thi nhanh chóng.

import tensorflow as tf
print(tf.config.list_physical_devices('GPU'))
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]

Lớp: tập hợp phổ biến của các hoạt động hữu ích

Hầu hết thời gian khi viết mã cho các mô hình học máy, bạn muốn hoạt động ở mức độ trừu tượng cao hơn các hoạt động riêng lẻ và thao tác với các biến riêng lẻ.

Nhiều mô hình học máy có thể biểu đạt được như thành phần và xếp chồng của các lớp tương đối đơn giản và TensorFlow cung cấp cả một tập hợp nhiều lớp chung cũng như cách dễ dàng để bạn viết các lớp dành riêng cho ứng dụng của mình ngay từ đầu hoặc thành phần của các lớp hiện có.

TensorFlow bao gồm API Keras đầy đủ trong gói tf.keras và các lớp Keras rất hữu ích khi xây dựng các mô hình của riêng bạn.

# In the tf.keras.layers package, layers are objects. To construct a layer,
# simply construct the object. Most layers take as a first argument the number
# of output dimensions / channels.
layer = tf.keras.layers.Dense(100)
# The number of input dimensions is often unnecessary, as it can be inferred
# the first time the layer is used, but it can be provided if you want to
# specify it manually, which is useful in some complex models.
layer = tf.keras.layers.Dense(10, input_shape=(None, 5))

Danh sách đầy đủ các lớp đã tồn tại trước có thể được xem trong tài liệu . Nó bao gồm Dense (một lớp được kết nối đầy đủ), Conv2D, LSTM, BatchNormalization, Dropout và nhiều lớp khác.

# To use a layer, simply call it.
layer(tf.zeros([10, 5]))
<tf.Tensor: shape=(10, 10), dtype=float32, numpy=
array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)>
# Layers have many useful methods. For example, you can inspect all variables
# in a layer using `layer.variables` and trainable variables using
# `layer.trainable_variables`. In this case a fully-connected layer
# will have variables for weights and biases.
layer.variables
[<tf.Variable 'dense_1/kernel:0' shape=(5, 10) dtype=float32, numpy=
 array([[-0.4370762 ,  0.6231566 , -0.44082257, -0.48535   ,  0.17860883,
         -0.521853  , -0.45774594, -0.5409817 ,  0.29194772, -0.18690601],
        [ 0.3304953 , -0.27142242, -0.48322448, -0.19328138, -0.14415592,
          0.05973059,  0.56227285,  0.5323917 , -0.4914217 ,  0.62182254],
        [-0.5313885 ,  0.54680306,  0.1632638 , -0.10741419, -0.04727739,
         -0.35414204,  0.07529551, -0.06515282, -0.19732419,  0.25217015],
        [ 0.49743277,  0.31172627,  0.04989761,  0.1200847 ,  0.42642146,
          0.5887727 ,  0.5771937 ,  0.08720696,  0.43024355, -0.17298424],
        [-0.07610255,  0.04131562,  0.3136508 , -0.6197298 ,  0.2331146 ,
          0.04888463, -0.54215366,  0.41208786,  0.27439958,  0.08524591]],
       dtype=float32)>,
 <tf.Variable 'dense_1/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>]
# The variables are also accessible through nice accessors
layer.kernel, layer.bias
(<tf.Variable 'dense_1/kernel:0' shape=(5, 10) dtype=float32, numpy=
 array([[-0.4370762 ,  0.6231566 , -0.44082257, -0.48535   ,  0.17860883,
         -0.521853  , -0.45774594, -0.5409817 ,  0.29194772, -0.18690601],
        [ 0.3304953 , -0.27142242, -0.48322448, -0.19328138, -0.14415592,
          0.05973059,  0.56227285,  0.5323917 , -0.4914217 ,  0.62182254],
        [-0.5313885 ,  0.54680306,  0.1632638 , -0.10741419, -0.04727739,
         -0.35414204,  0.07529551, -0.06515282, -0.19732419,  0.25217015],
        [ 0.49743277,  0.31172627,  0.04989761,  0.1200847 ,  0.42642146,
          0.5887727 ,  0.5771937 ,  0.08720696,  0.43024355, -0.17298424],
        [-0.07610255,  0.04131562,  0.3136508 , -0.6197298 ,  0.2331146 ,
          0.04888463, -0.54215366,  0.41208786,  0.27439958,  0.08524591]],
       dtype=float32)>,
 <tf.Variable 'dense_1/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>)

Triển khai các lớp tùy chỉnh

Cách tốt nhất để triển khai lớp của riêng bạn là mở rộng lớp tf.keras.Layer và triển khai:

  1. __init__ , nơi bạn có thể thực hiện tất cả quá trình khởi tạo không phụ thuộc vào đầu vào
  2. build , nơi bạn biết hình dạng của bộ căng đầu vào và có thể thực hiện phần còn lại của quá trình khởi tạo
  3. call , nơi bạn thực hiện tính toán chuyển tiếp

Lưu ý rằng bạn không phải đợi cho đến khi bản build được gọi để tạo các biến của mình, bạn cũng có thể tạo chúng trong __init__ . Tuy nhiên, ưu điểm của việc tạo chúng trong bản build là nó cho phép tạo biến trễ dựa trên hình dạng của các đầu vào mà lớp sẽ hoạt động. Mặt khác, việc tạo các biến trong __init__ có nghĩa là các hình dạng cần thiết để tạo các biến sẽ cần được chỉ định rõ ràng.

class MyDenseLayer(tf.keras.layers.Layer):
  def __init__(self, num_outputs):
    super(MyDenseLayer, self).__init__()
    self.num_outputs = num_outputs

  def build(self, input_shape):
    self.kernel = self.add_weight("kernel",
                                  shape=[int(input_shape[-1]),
                                         self.num_outputs])

  def call(self, inputs):
    return tf.matmul(inputs, self.kernel)

layer = MyDenseLayer(10)
_ = layer(tf.zeros([10, 5])) # Calling the layer `.builds` it.
print([var.name for var in layer.trainable_variables])
['my_dense_layer/kernel:0']

Nhìn chung, mã dễ đọc và dễ bảo trì hơn nếu nó sử dụng các lớp tiêu chuẩn bất cứ khi nào có thể, vì những người đọc khác sẽ quen thuộc với hành vi của các lớp tiêu chuẩn. Nếu bạn muốn sử dụng một lớp không có trong tf.keras.layers , hãy cân nhắc gửi vấn đề github hoặc tốt hơn nữa là gửi cho chúng tôi một yêu cầu kéo!

Mô hình: Sáng tác các lớp

Nhiều thứ thú vị giống như lớp trong mô hình học máy được thực hiện bằng cách soạn các lớp hiện có. Ví dụ: mỗi khối còn lại trong mạng lưới lại là một thành phần của phức hợp, chuẩn hóa hàng loạt và một phím tắt. Các lớp có thể được lồng vào bên trong các lớp khác.

Thông thường, bạn kế thừa từ keras.Model khi bạn cần các phương thức mô hình như: Model.fit , Model.evaluateModel.save (xem các lớp và mô hình Keras tùy chỉnh để biết chi tiết).

Một tính năng khác được cung cấp bởi keras.Model (thay vì keras.layers.Layer ) là ngoài việc theo dõi các biến, keras.Model cũng theo dõi các lớp bên trong của nó, giúp chúng dễ dàng kiểm tra hơn.

Ví dụ ở đây là một khối ResNet:

class ResnetIdentityBlock(tf.keras.Model):
  def __init__(self, kernel_size, filters):
    super(ResnetIdentityBlock, self).__init__(name='')
    filters1, filters2, filters3 = filters

    self.conv2a = tf.keras.layers.Conv2D(filters1, (1, 1))
    self.bn2a = tf.keras.layers.BatchNormalization()

    self.conv2b = tf.keras.layers.Conv2D(filters2, kernel_size, padding='same')
    self.bn2b = tf.keras.layers.BatchNormalization()

    self.conv2c = tf.keras.layers.Conv2D(filters3, (1, 1))
    self.bn2c = tf.keras.layers.BatchNormalization()

  def call(self, input_tensor, training=False):
    x = self.conv2a(input_tensor)
    x = self.bn2a(x, training=training)
    x = tf.nn.relu(x)

    x = self.conv2b(x)
    x = self.bn2b(x, training=training)
    x = tf.nn.relu(x)

    x = self.conv2c(x)
    x = self.bn2c(x, training=training)

    x += input_tensor
    return tf.nn.relu(x)


block = ResnetIdentityBlock(1, [1, 2, 3])
_ = block(tf.zeros([1, 2, 3, 3]))
block.layers
[<keras.layers.convolutional.Conv2D at 0x7fc7e439bf90>,
 <keras.layers.normalization.batch_normalization.BatchNormalization at 0x7fc7dc1e5dd0>,
 <keras.layers.convolutional.Conv2D at 0x7fc7dc1a1cd0>,
 <keras.layers.normalization.batch_normalization.BatchNormalization at 0x7fc7dc12c490>,
 <keras.layers.convolutional.Conv2D at 0x7fc7dc12c8d0>,
 <keras.layers.normalization.batch_normalization.BatchNormalization at 0x7fc7dc12cf50>]
len(block.variables)
18
block.summary()
Model: ""
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             multiple                  4         
                                                                 
 batch_normalization (BatchN  multiple                 4         
 ormalization)                                                   
                                                                 
 conv2d_1 (Conv2D)           multiple                  4         
                                                                 
 batch_normalization_1 (Batc  multiple                 8         
 hNormalization)                                                 
                                                                 
 conv2d_2 (Conv2D)           multiple                  9         
                                                                 
 batch_normalization_2 (Batc  multiple                 12        
 hNormalization)                                                 
                                                                 
=================================================================
Total params: 41
Trainable params: 29
Non-trainable params: 12
_________________________________________________________________

Tuy nhiên, phần lớn thời gian, các mô hình tạo ra nhiều lớp chỉ đơn giản là gọi lớp này đến lớp kia. Điều này có thể được thực hiện trong rất ít mã bằng cách sử dụng tf.keras.Sequential .

my_seq = tf.keras.Sequential([tf.keras.layers.Conv2D(1, (1, 1),
                                                    input_shape=(
                                                        None, None, 3)),
                             tf.keras.layers.BatchNormalization(),
                             tf.keras.layers.Conv2D(2, 1,
                                                    padding='same'),
                             tf.keras.layers.BatchNormalization(),
                             tf.keras.layers.Conv2D(3, (1, 1)),
                             tf.keras.layers.BatchNormalization()])
my_seq(tf.zeros([1, 2, 3, 3]))
<tf.Tensor: shape=(1, 2, 3, 3), dtype=float32, numpy=
array([[[[0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.]],

        [[0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.]]]], dtype=float32)>
my_seq.summary()
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d_3 (Conv2D)           (None, None, None, 1)     4         
                                                                 
 batch_normalization_3 (Batc  (None, None, None, 1)    4         
 hNormalization)                                                 
                                                                 
 conv2d_4 (Conv2D)           (None, None, None, 2)     4         
                                                                 
 batch_normalization_4 (Batc  (None, None, None, 2)    8         
 hNormalization)                                                 
                                                                 
 conv2d_5 (Conv2D)           (None, None, None, 3)     9         
                                                                 
 batch_normalization_5 (Batc  (None, None, None, 3)    12        
 hNormalization)                                                 
                                                                 
=================================================================
Total params: 41
Trainable params: 29
Non-trainable params: 12
_________________________________________________________________

Bước tiếp theo

Bây giờ bạn có thể quay lại sổ ghi chép trước đó và điều chỉnh ví dụ hồi quy tuyến tính để sử dụng các lớp và mô hình để có cấu trúc tốt hơn.