เลเยอร์ที่กำหนดเอง

ดูบน TensorFlow.org ทำงานใน Google Colab ดูแหล่งที่มาบน GitHub ดาวน์โหลดโน๊ตบุ๊ค

เราขอแนะนำให้ใช้ tf.keras เป็น API ระดับสูงสำหรับการสร้างเครือข่ายประสาทเทียม ที่กล่าวว่า TensorFlow API ส่วนใหญ่ใช้งานได้พร้อมการดำเนินการที่กระตือรือร้น

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

เลเยอร์: ชุดปฏิบัติการที่มีประโยชน์ทั่วไป

เวลาส่วนใหญ่ในการเขียนโค้ดสำหรับโมเดลการเรียนรู้ของเครื่อง คุณต้องการดำเนินการในระดับนามธรรมที่สูงกว่าการดำเนินการแต่ละรายการและการจัดการตัวแปรแต่ละตัว

โมเดลแมชชีนเลิร์นนิงจำนวนมากสามารถแสดงออกได้ในฐานะองค์ประกอบและการซ้อนเลเยอร์ที่ค่อนข้างง่าย และ TensorFlow มีทั้งชุดของเลเยอร์ทั่วไปจำนวนมาก ตลอดจนวิธีง่ายๆ ในการเขียนเลเยอร์เฉพาะแอปพลิเคชันของคุณเองตั้งแต่เริ่มต้นหรือเป็นองค์ประกอบของ ชั้นที่มีอยู่

TensorFlow มี Keras API แบบเต็มในแพ็คเกจ tf.keras และเลเยอร์ Keras นั้นมีประโยชน์มากเมื่อสร้างแบบจำลองของคุณเอง

# 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))

รายการทั้งหมดของเลเยอร์ที่มีอยู่ก่อนสามารถดูได้ใน เอกสารประกอบ ประกอบด้วย Dense (เลเยอร์ที่เชื่อมต่ออย่างสมบูรณ์), Conv2D, LSTM, BatchNormalization, Dropout และอื่นๆ อีกมากมาย

# 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)>)

การใช้เลเยอร์ที่กำหนดเอง

วิธีที่ดีที่สุดในการใช้เลเยอร์ของคุณเองคือการขยายคลาส tf.keras.Layer และนำไปใช้:

  1. __init__ ซึ่งคุณสามารถเริ่มต้นการป้อนข้อมูลอิสระทั้งหมดได้
  2. build โดยที่คุณทราบรูปร่างของเทนเซอร์อินพุตและสามารถทำการเริ่มต้นที่เหลือได้
  3. call ที่คุณทำการคำนวณไปข้างหน้า

โปรดทราบว่าคุณไม่จำเป็นต้องรอจนกว่าจะมีการเรียก build เพื่อสร้างตัวแปรของคุณ คุณยังสามารถสร้างพวกมันใน __init__ ได้ อย่างไรก็ตาม ข้อดีของการสร้างพวกมันใน build ด์คือช่วยให้สามารถสร้างตัวแปรช่วงปลายตามรูปร่างของอินพุตที่เลเยอร์จะทำงาน ในอีกทางหนึ่ง การสร้างตัวแปรใน __init__ จะทำให้ต้องระบุรูปร่างที่จำเป็นในการสร้างตัวแปรอย่างชัดเจน

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']

โค้ดโดยรวมจะอ่านและบำรุงรักษาได้ง่ายขึ้นหากใช้เลเยอร์มาตรฐานทุกครั้งที่ทำได้ เนื่องจากผู้อ่านคนอื่นๆ จะคุ้นเคยกับการทำงานของเลเยอร์มาตรฐาน หากคุณต้องการใช้เลเยอร์ที่ไม่มีอยู่ใน tf.keras.layers ให้พิจารณายื่นเรื่อง github หรือส่งคำขอดึงให้เรา!

รุ่น: การเขียนเลเยอร์

สิ่งต่าง ๆ ที่คล้ายกับเลเยอร์ที่น่าสนใจในโมเดลการเรียนรู้ของเครื่องนั้นถูกนำไปใช้โดยการเขียนเลเยอร์ที่มีอยู่ ตัวอย่างเช่น แต่ละบล็อกที่เหลือใน resnet เป็นองค์ประกอบของการบิดเบี้ยว การปรับให้เป็นมาตรฐานแบบกลุ่ม และทางลัด เลเยอร์สามารถซ้อนกันภายในเลเยอร์อื่นได้

โดยทั่วไปแล้ว คุณจะสืบทอดจาก keras.Model เมื่อคุณต้องการเมธอด model เช่น Model.fit , Model.evaluate และ Model.save (ดูรายละเอียดใน เลเยอร์และโมเดล Keras ที่กำหนดเอง )

ฟีเจอร์อื่นๆ ที่จัดทำโดย keras.Model (แทนที่จะเป็น keras.layers.Layer ) คือนอกเหนือจากการติดตามตัวแปรแล้ว keras.Model ยังติดตามเลเยอร์ภายในด้วย ทำให้ตรวจสอบได้ง่ายขึ้น

ตัวอย่างเช่นนี่คือบล็อก 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
_________________________________________________________________

อย่างไรก็ตาม ส่วนใหญ่แล้ว โมเดลที่ประกอบด้วยหลายเลเยอร์มักจะเรียกชั้นหนึ่งต่อจากอีกชั้นหนึ่ง ซึ่งสามารถทำได้ในโค้ดเพียงเล็กน้อยโดยใช้ 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
_________________________________________________________________

ขั้นตอนถัดไป

ตอนนี้คุณสามารถกลับไปที่สมุดบันทึกก่อนหน้าและปรับตัวอย่างการถดถอยเชิงเส้นเพื่อใช้เลเยอร์และแบบจำลองเพื่อให้มีโครงสร้างที่ดีขึ้น