API Fungsional Keras di TensorFlow



Keras memiliki dua API untuk dengan cepat membangun arsitektur jaringan saraf Sekuensial dan Fungsional. Jika yang pertama memungkinkan Anda untuk membangun hanya arsitektur berurutan dari jaringan saraf, maka dengan menggunakan API Fungsional Anda dapat menentukan jaringan saraf dalam bentuk grafik asiklik yang diarahkan secara sewenang-wenang, yang memberikan lebih banyak peluang untuk membangun model yang kompleks. Artikel ini adalah terjemahan dari Panduan Fitur API Fungsional dari situs web TensorFlow.

Pendahuluan


API Fungsional memungkinkan Anda membuat model lebih fleksibel daripada Sequential API, ia dapat memproses model dengan topologi non-linear, model dengan lapisan umum, dan model dengan beberapa input atau output.

Hal ini didasarkan pada fakta bahwa model pembelajaran dalam biasanya merupakan grafik asiklik terarah (DAG) dari lapisan

API Fungsional adalah seperangkat alat untuk merencanakan lapisan .

Pertimbangkan model berikut:

(input: vektor 784 dimensi)

[Lapisan padat (64 elemen, aktivasi relu)]

[Lapisan padat (64 elemen, aktivasi relu)]

[Lapisan padat (10 elemen, aktivasi softmax)]

(output: distribusi probabilitas lebih dari 10 kelas)
Ini adalah grafik sederhana 3 lapisan.

Untuk membangun model ini menggunakan API Fungsional, Anda harus mulai dengan membuat simpul input:

from tensorflow import keras inputs = keras.Input(shape=(784,)) 

Di sini kami hanya menunjukkan dimensi data kami: vektor 784 dimensi. Harap perhatikan bahwa jumlah data selalu dihilangkan, kami hanya menunjukkan dimensi dari setiap elemen. Untuk memasukkan ukuran yang dimaksudkan untuk gambar `(32, 32, 3)`, kita akan menggunakan:

 img_inputs = keras.Input(shape=(32, 32, 3)) 

inputs apa yang dikembalikan berisi informasi tentang ukuran dan jenis data yang Anda rencanakan untuk ditransfer ke model Anda:

 inputs.shape 

 TensorShape([None, 784]) 

 inputs.dtype 

 tf.float32 

Anda membuat simpul baru dalam grafik layer dengan memanggil layer pada objek inputs ini:

 from tensorflow.keras import layers dense = layers.Dense(64, activation='relu') x = dense(inputs) 

"Memanggil layer" mirip dengan menggambar panah dari "input" ke dalam layer yang kita buat. Kami “meneruskan” input ke lapisan dense , dan kami mendapatkan x .

Mari kita tambahkan beberapa layer lagi ke grafik layer kita:

 x = layers.Dense(64, activation='relu')(x) outputs = layers.Dense(10, activation='softmax')(x) 

Sekarang kita dapat membuat Model menentukan input dan outputnya dalam grafik layer:

 model = keras.Model(inputs=inputs, outputs=outputs) 

Mari kita lihat lagi proses definisi model lengkap:

 inputs = keras.Input(shape=(784,), name='img') x = layers.Dense(64, activation='relu')(inputs) x = layers.Dense(64, activation='relu')(x) outputs = layers.Dense(10, activation='softmax')(x) model = keras.Model(inputs=inputs, outputs=outputs, name='mnist_model') 

Mari kita lihat seperti apa ringkasan model:

 model.summary() 

 Model: "mnist_model" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= img (InputLayer) [(None, 784)] 0 _________________________________________________________________ dense_3 (Dense) (None, 64) 50240 _________________________________________________________________ dense_4 (Dense) (None, 64) 4160 _________________________________________________________________ dense_5 (Dense) (None, 10) 650 ================================================================= Total params: 55,050 Trainable params: 55,050 Non-trainable params: 0 _________________________________________________________________ 

Kami juga dapat menggambar model sebagai grafik:

 keras.utils.plot_model(model, 'my_first_model.png') 

gambar

Dan secara opsional menurunkan dimensi input dan output dari setiap lapisan pada grafik yang dibangun:

 keras.utils.plot_model(model, 'my_first_model_with_shape_info.png', show_shapes=True) 

gambar

Gambar ini dan kode yang kami tulis identik. Dalam versi kode, panah yang mengikat hanya diganti dengan operasi panggilan.

"Lapisan grafik" adalah gambar mental yang sangat intuitif untuk model pembelajaran yang mendalam, dan API Fungsional adalah cara untuk membuat model yang mencerminkan citra mental ini secara dekat.

Pelatihan, penilaian dan kesimpulan


Mempelajari, mengevaluasi, dan menurunkan pekerjaan untuk model yang dibuat menggunakan API Fungsional seperti pada model Sequential.

Pertimbangkan demo cepat.

Di sini kita memuat dataset gambar MNIST, mengubahnya menjadi vektor, melatih model pada data (sambil memantau kualitas pekerjaan pada sampel uji), dan akhirnya kami mengevaluasi model kami pada data uji:

 (x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data() x_train = x_train.reshape(60000, 784).astype('float32') / 255 x_test = x_test.reshape(10000, 784).astype('float32') / 255 model.compile(loss='sparse_categorical_crossentropy', optimizer=keras.optimizers.RMSprop(), metrics=['accuracy']) history = model.fit(x_train, y_train, batch_size=64, epochs=5, validation_split=0.2) test_scores = model.evaluate(x_test, y_test, verbose=2) print('Test loss:', test_scores[0]) print('Test accuracy:', test_scores[1]) 

Menyimpan dan Serializing


Menyimpan dan membuat serial untuk model yang dibangun menggunakan Fungsional API bekerja persis sama dengan untuk model Sequential.

Cara standar untuk menyimpan model Fungsional adalah memanggil model.save( ), yang memungkinkan Anda menyimpan seluruh model dalam satu file.

Anda nanti dapat mengembalikan model yang sama dari file ini, bahkan jika Anda tidak lagi memiliki akses ke kode yang membuat model.

File ini termasuk:

  • Arsitektur model
  • Bobot model (yang diperoleh selama pelatihan)
  • Konfigurasi pelatihan model (apa yang Anda lewati dalam compile )
  • Pengoptimal dan kondisinya, jika itu (ini memungkinkan Anda untuk melanjutkan pelatihan dari tempat Anda tinggalkan)

 model.save('path_to_my_model.h5') del model # Recreate the exact same model purely from the file: model = keras.models.load_model('path_to_my_model.h5') 

Menggunakan grafik lapisan yang sama untuk mendefinisikan beberapa model


Dalam Fungsional API, model dibuat dengan menentukan input dan output data dalam grafik layer. Ini berarti bahwa grafik lapisan tunggal dapat digunakan untuk menghasilkan beberapa model.

Dalam contoh di bawah ini, kami menggunakan tumpukan lapisan yang sama untuk membuat dua model:
model (encoder) yang mengubah gambar input menjadi vektor 16 dimensi, dan model (autoencoder) ujung ke ujung untuk pelatihan.

 encoder_input = keras.Input(shape=(28, 28, 1), name='img') x = layers.Conv2D(16, 3, activation='relu')(encoder_input) x = layers.Conv2D(32, 3, activation='relu')(x) x = layers.MaxPooling2D(3)(x) x = layers.Conv2D(32, 3, activation='relu')(x) x = layers.Conv2D(16, 3, activation='relu')(x) encoder_output = layers.GlobalMaxPooling2D()(x) encoder = keras.Model(encoder_input, encoder_output, name='encoder') encoder.summary() x = layers.Reshape((4, 4, 1))(encoder_output) x = layers.Conv2DTranspose(16, 3, activation='relu')(x) x = layers.Conv2DTranspose(32, 3, activation='relu')(x) x = layers.UpSampling2D(3)(x) x = layers.Conv2DTranspose(16, 3, activation='relu')(x) decoder_output = layers.Conv2DTranspose(1, 3, activation='relu')(x) autoencoder = keras.Model(encoder_input, decoder_output, name='autoencoder') autoencoder.summary() 

Harap dicatat bahwa kami membuat arsitektur penguraian secara simetris dengan arsitektur pengodean, sehingga kami mendapatkan dimensi data output sama dengan data input (28, 28, 1) . Lapisan Conv2D ke lapisan Conv2D , dan lapisan MaxPooling2D akan menjadi kembali ke lapisan MaxPooling2D .

Model dapat disebut sebagai lapisan


Anda dapat menggunakan model apa saja seolah-olah itu adalah lapisan, memanggilnya pada Input atau pada output dari lapisan lain.

Perhatikan bahwa dengan menggunakan model, Anda tidak hanya menggunakan kembali arsitekturnya, Anda juga menggunakan kembali bobotnya. Mari kita lihat dalam aksi. Berikut ini contoh lain dari auto-encoder, ketika model encoder, model decoder dibuat, dan mereka terhubung dalam dua panggilan untuk mendapatkan model auto-encoder:

 encoder_input = keras.Input(shape=(28, 28, 1), name='original_img') x = layers.Conv2D(16, 3, activation='relu')(encoder_input) x = layers.Conv2D(32, 3, activation='relu')(x) x = layers.MaxPooling2D(3)(x) x = layers.Conv2D(32, 3, activation='relu')(x) x = layers.Conv2D(16, 3, activation='relu')(x) encoder_output = layers.GlobalMaxPooling2D()(x) encoder = keras.Model(encoder_input, encoder_output, name='encoder') encoder.summary() decoder_input = keras.Input(shape=(16,), name='encoded_img') x = layers.Reshape((4, 4, 1))(decoder_input) x = layers.Conv2DTranspose(16, 3, activation='relu')(x) x = layers.Conv2DTranspose(32, 3, activation='relu')(x) x = layers.UpSampling2D(3)(x) x = layers.Conv2DTranspose(16, 3, activation='relu')(x) decoder_output = layers.Conv2DTranspose(1, 3, activation='relu')(x) decoder = keras.Model(decoder_input, decoder_output, name='decoder') decoder.summary() autoencoder_input = keras.Input(shape=(28, 28, 1), name='img') encoded_img = encoder(autoencoder_input) decoded_img = decoder(encoded_img) autoencoder = keras.Model(autoencoder_input, decoded_img, name='autoencoder') autoencoder.summary() 

Seperti yang Anda lihat, sebuah model dapat disarangkan: sebuah model dapat berisi submodel (karena model dapat dianggap sebagai layer).

Kasus penggunaan umum untuk model bersarang adalah ansambel .

Sebagai contoh, inilah cara menggabungkan satu set model menjadi satu model yang rata-rata perkiraannya:

 def get_model(): inputs = keras.Input(shape=(128,)) outputs = layers.Dense(1, activation='sigmoid')(inputs) return keras.Model(inputs, outputs) model1 = get_model() model2 = get_model() model3 = get_model() inputs = keras.Input(shape=(128,)) y1 = model1(inputs) y2 = model2(inputs) y3 = model3(inputs) outputs = layers.average([y1, y2, y3]) ensemble_model = keras.Model(inputs=inputs, outputs=outputs) 


Memanipulasi topologi grafik yang kompleks


Model dengan banyak input dan output


API Fungsional menyederhanakan manipulasi beberapa input dan output. Ini tidak dapat dilakukan dengan Sequential API.

Ini adalah contoh sederhana.

Misalkan Anda membuat sistem untuk menentukan peringkat aplikasi pelanggan berdasarkan prioritas dan mengirimkannya ke departemen yang tepat.

Model Anda akan memiliki 3 input:

  • Header Aplikasi (input teks)
  • Konten teks dari aplikasi (input teks)
  • Tag apa pun yang ditambahkan oleh pengguna (input kategorikal)

Model akan memiliki 2 output:

  • Skor prioritas antara 0 dan 1 (skalar sigmoid output)
  • Departemen yang harus memproses aplikasi (output softmax mengenai banyak departemen)

Mari kita membangun model dalam beberapa baris menggunakan API Fungsional.

 num_tags = 12 #     num_words = 10000 #         num_departments = 4 #     title_input = keras.Input(shape=(None,), name='title') #      body_input = keras.Input(shape=(None,), name='body') #      tags_input = keras.Input(shape=(num_tags,), name='tags') #    `num_tags` #      64-  title_features = layers.Embedding(num_words, 64)(title_input) #      64-  body_features = layers.Embedding(num_words, 64)(body_input) #        128-  title_features = layers.LSTM(128)(title_features) #        32-  body_features = layers.LSTM(32)(body_features) #          x = layers.concatenate([title_features, body_features, tags_input]) #         priority_pred = layers.Dense(1, activation='sigmoid', name='priority')(x) #       department_pred = layers.Dense(num_departments, activation='softmax', name='department')(x) #   ,     model = keras.Model(inputs=[title_input, body_input, tags_input], outputs=[priority_pred, department_pred]) 

Mari kita menggambar grafik model:

 keras.utils.plot_model(model, 'multi_input_and_output_model.png', show_shapes=True) 



Saat mengkompilasi model ini, kami dapat menetapkan fungsi kerugian yang berbeda untuk setiap output.

Anda bahkan dapat menetapkan bobot yang berbeda untuk setiap fungsi kerugian untuk memvariasikan kontribusinya terhadap keseluruhan fungsi hilangnya pembelajaran.

 model.compile(optimizer=keras.optimizers.RMSprop(1e-3), loss=['binary_crossentropy', 'categorical_crossentropy'], loss_weights=[1., 0.2]) 

Karena kami memberi nama ke lapisan output kami, kami juga dapat menentukan fungsi kerugian:

 model.compile(optimizer=keras.optimizers.RMSprop(1e-3), loss={'priority': 'binary_crossentropy', 'department': 'categorical_crossentropy'}, loss_weights=[1., 0.2]) 

Kita dapat melatih model dengan melewati daftar array input dan label Numpy:

 import numpy as np # Dummy input data title_data = np.random.randint(num_words, size=(1280, 10)) body_data = np.random.randint(num_words, size=(1280, 100)) tags_data = np.random.randint(2, size=(1280, num_tags)).astype('float32') # Dummy target data priority_targets = np.random.random(size=(1280, 1)) dept_targets = np.random.randint(2, size=(1280, num_departments)) model.fit({'title': title_data, 'body': body_data, 'tags': tags_data}, {'priority': priority_targets, 'department': dept_targets}, epochs=2, batch_size=32) 

Ketika memanggil cocok dengan objek Dataset , salah satu tupel daftar seperti ([title_data, body_data, tags_data], [priority_targets, dept_targets]) , atau tupel kamus ({'title': title_data, 'body': body_data, 'tags': tags_data}, {'priority': priority_targets, 'department': dept_targets}) harus dikembalikan ({'title': title_data, 'body': body_data, 'tags': tags_data}, {'priority': priority_targets, 'department': dept_targets}) .

Pelatihan model resnet


Selain model dengan banyak input dan output, API Fungsional menyederhanakan manipulasi topologi dengan konektivitas non-linear, yaitu model di mana lapisan yang tidak terhubung secara seri. Model semacam itu juga tidak dapat diimplementasikan menggunakan Sequential API (sesuai namanya).

Kasus penggunaan umum untuk ini adalah koneksi residual.

Mari kita membangun model pelatihan ResNet untuk CIFAR10 untuk mendemonstrasikan ini.

 inputs = keras.Input(shape=(32, 32, 3), name='img') x = layers.Conv2D(32, 3, activation='relu')(inputs) x = layers.Conv2D(64, 3, activation='relu')(x) block_1_output = layers.MaxPooling2D(3)(x) x = layers.Conv2D(64, 3, activation='relu', padding='same')(block_1_output) x = layers.Conv2D(64, 3, activation='relu', padding='same')(x) block_2_output = layers.add([x, block_1_output]) x = layers.Conv2D(64, 3, activation='relu', padding='same')(block_2_output) x = layers.Conv2D(64, 3, activation='relu', padding='same')(x) block_3_output = layers.add([x, block_2_output]) x = layers.Conv2D(64, 3, activation='relu')(block_3_output) x = layers.GlobalAveragePooling2D()(x) x = layers.Dense(256, activation='relu')(x) x = layers.Dropout(0.5)(x) outputs = layers.Dense(10, activation='softmax')(x) model = keras.Model(inputs, outputs, name='toy_resnet') model.summary() 

Mari kita menggambar grafik model:

 keras.utils.plot_model(model, 'mini_resnet.png', show_shapes=True) 



Dan ajari dia:

 (x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data() x_train = x_train.astype('float32') / 255. x_test = x_test.astype('float32') / 255. y_train = keras.utils.to_categorical(y_train, 10) y_test = keras.utils.to_categorical(y_test, 10) model.compile(optimizer=keras.optimizers.RMSprop(1e-3), loss='categorical_crossentropy', metrics=['acc']) model.fit(x_train, y_train, batch_size=64, epochs=1, validation_split=0.2) 

Berbagi lapisan


Penggunaan lain yang baik dari Functional API adalah model yang menggunakan lapisan umum. Lapisan umum adalah contoh lapisan yang digunakan kembali dalam model yang sama: mereka mempelajari fitur yang berhubungan dengan beberapa jalur dalam grafik lapisan.

Lapisan umum sering digunakan untuk menyandikan data input yang berasal dari ruang yang sama (misalnya, dari dua bagian teks yang memiliki kamus yang sama), karena mereka memberikan pertukaran informasi antara data yang berbeda ini, yang memungkinkan model semacam itu untuk dilatih dengan data yang lebih sedikit. Jika kata tertentu muncul di salah satu input, ini akan memudahkan pemrosesan pada semua input yang melewati level umum.

Untuk berbagi lapisan dalam Fungsional API, panggil instance dari lapisan yang sama beberapa kali. Sebagai contoh, di sini layer Embedding dibagi pada dua input teks:

 #   1000    128-  shared_embedding = layers.Embedding(1000, 128) #     text_input_a = keras.Input(shape=(None,), dtype='int32') #     text_input_b = keras.Input(shape=(None,), dtype='int32') #           encoded_input_a = shared_embedding(text_input_a) encoded_input_b = shared_embedding(text_input_b) 

Mengambil dan menggunakan kembali node dalam grafik layer


Karena grafik lapisan yang Anda manipulasi dalam Fungsional API adalah struktur data statis, Anda dapat mengaksesnya dan memeriksanya. Inilah cara kami membangun model Fungsional, misalnya, dalam bentuk gambar.

Ini juga berarti bahwa kita dapat mengakses aktivasi lapisan menengah ("node" dalam grafik) dan menggunakannya di tempat lain. Ini sangat berguna untuk mengekstraksi sifat, misalnya!

Mari kita lihat sebuah contoh. Ini adalah model VGG19 dengan timbangan yang telah dilatih sebelumnya di ImageNet:

 from tensorflow.keras.applications import VGG19 vgg19 = VGG19() 

Dan ini adalah aktivasi model menengah yang diperoleh dengan menanyakan struktur data grafik:

 features_list = [layer.output for layer in vgg19.layers] 

Kita dapat menggunakan fitur ini untuk membuat model ekstraksi fitur baru yang mengembalikan nilai aktivasi tingkat menengah - dan kita bisa melakukan semuanya dalam 3 baris

 feat_extraction_model = keras.Model(inputs=vgg19.input, outputs=features_list) img = np.random.random((1, 224, 224, 3)).astype('float32') extracted_features = feat_extraction_model(img) 

Ini nyaman saat menerapkan transfer gaya saraf, seperti dalam kasus lain.

Memperluas API dengan menulis lapisan khusus


tf.keras memiliki berbagai lapisan tf.keras . Berikut ini beberapa contohnya:

Lapisan konvolusional: Conv1D , Conv2D , Conv3D , Conv2DTranspose , dll.
Lapisan MaxPooling1D : MaxPooling1D , MaxPooling2D , MaxPooling3D , MaxPooling3D , dll.
Lapisan RNN: GRU , LSTM , ConvLSTM2D , dll.
BatchNormalization , Dropout , Embedding , dll.

Jika Anda belum menemukan yang Anda butuhkan, mudah untuk memperpanjang API dengan membuat layer Anda sendiri.

Semua lapisan subkelas kelas Layer dan mengimplementasikan:

Metode call yang mendefinisikan perhitungan yang dilakukan oleh layer.
Metode build yang menciptakan bobot layer (perhatikan bahwa ini hanya konvensi gaya; Anda juga bisa membuat bobot dalam __init__ ).

Berikut ini adalah implementasi sederhana dari layer Dense :

 class CustomDense(layers.Layer): def __init__(self, units=32): super(CustomDense, self).__init__() self.units = units def build(self, input_shape): self.w = self.add_weight(shape=(input_shape[-1], self.units), initializer='random_normal', trainable=True) self.b = self.add_weight(shape=(self.units,), initializer='random_normal', trainable=True) def call(self, inputs): return tf.matmul(inputs, self.w) + self.b inputs = keras.Input((4,)) outputs = CustomDense(10)(inputs) model = keras.Model(inputs, outputs) 

Jika Anda ingin layer kustom Anda mendukung serialisasi, Anda juga harus mendefinisikan metode get_config yang mengembalikan argumen konstruktor dari instance layer:

 class CustomDense(layers.Layer): def __init__(self, units=32): super(CustomDense, self).__init__() self.units = units def build(self, input_shape): self.w = self.add_weight(shape=(input_shape[-1], self.units), initializer='random_normal', trainable=True) self.b = self.add_weight(shape=(self.units,), initializer='random_normal', trainable=True) def call(self, inputs): return tf.matmul(inputs, self.w) + self.b def get_config(self): return {'units': self.units} inputs = keras.Input((4,)) outputs = CustomDense(10)(inputs) model = keras.Model(inputs, outputs) config = model.get_config() new_model = keras.Model.from_config( config, custom_objects={'CustomDense': CustomDense}) 

Secara opsional, Anda juga dapat mengimplementasikan metode kelas from_config (cls, config) , yang bertanggung jawab untuk membuat kembali instance layer, mengingat kamus konfigurasinya. from_config default from_config terlihat seperti ini:

 def from_config(cls, config): return cls(**config) 

Kapan menggunakan API Fungsional


Bagaimana menentukan kapan lebih baik menggunakan Fungsional API untuk membuat model baru, atau cukup dengan subkelas Model secara langsung?

Secara umum, Functional API lebih tingkat tinggi dan mudah digunakan, ia memiliki sejumlah fungsi yang tidak didukung oleh model subclass.

Namun, subkelas Model memberi Anda fleksibilitas besar saat membuat model yang tidak mudah digambarkan sebagai grafik lapisan asiklik yang diarahkan (misalnya, Anda tidak dapat mengimplementasikan Tree-RNN dengan API Fungsional, Anda perlu subklas Model secara langsung).

Kekuatan API Fungsional:


Properti yang tercantum di bawah ini semuanya benar untuk model Sequential (yang juga merupakan struktur data), tetapi mereka berlaku untuk model subkelas (yang merupakan kode Python, bukan struktur data).

API Fungsional menghasilkan kode yang lebih pendek.


Tidak ada super(MyClass, self).__init__(...) , tidak ada def call(self, ...): dll.

Bandingkan:

 inputs = keras.Input(shape=(32,)) x = layers.Dense(64, activation='relu')(inputs) outputs = layers.Dense(10)(x) mlp = keras.Model(inputs, outputs) 

Dengan versi subklas:

 class MLP(keras.Model): def __init__(self, **kwargs): super(MLP, self).__init__(**kwargs) self.dense_1 = layers.Dense(64, activation='relu') self.dense_2 = layers.Dense(10) def call(self, inputs): x = self.dense_1(inputs) return self.dense_2(x) #   . mlp = MLP() #    . #            . _ = mlp(tf.zeros((1, 32))) 

Model Anda divalidasi saat ditulis.


Dalam Fungsional API, spesifikasi input (bentuk dan tipe) dibuat terlebih dahulu (melalui `Input`), dan setiap kali Anda memanggil layer, layer memeriksa bahwa spesifikasi yang diteruskan sesuai dengan asumsi, jika tidak, Anda akan menerima pesan kesalahan yang berguna .

Ini memastikan bahwa model apa pun yang Anda bangun dengan API Fungsional dimulai. Semua debugging (tidak terkait dengan debugging konvergensi) akan terjadi secara statis selama konstruksi model, dan tidak pada saat dijalankan. Ini mirip dengan mengetikkan pengecekan di kompiler.

Model Fungsional Anda dapat direpresentasikan secara grafis, dan juga dapat diuji.


Anda dapat menggambar model dalam bentuk grafik, dan Anda dapat dengan mudah mengakses node perantara dari grafik, misalnya, untuk mengekstrak dan menggunakan kembali aktivasi lapisan menengah, seperti yang kita lihat dalam contoh sebelumnya:

 features_list = [layer.output for layer in vgg19.layers] feat_extraction_model = keras.Model(inputs=vgg19.input, outputs=features_list) 

Karena model Fungsional lebih merupakan struktur data daripada sepotong kode, maka dapat diserialisasi dengan aman dan dapat disimpan sebagai file tunggal yang memungkinkan Anda membuat ulang model yang persis sama tanpa akses ke kode sumber.

Kelemahan API Fungsional


Itu tidak mendukung arsitektur dinamis.


API Fungsional memproses model sebagai lapisan DAG. Ini berlaku untuk arsitektur pembelajaran yang paling mendalam, tetapi tidak untuk semua orang: misalnya, jaringan rekursif atau RNN Pohon tidak memenuhi asumsi ini dan tidak dapat diimplementasikan dalam API Fungsional.

Terkadang Anda hanya perlu menulis semuanya dari awal.


Saat menulis arsitektur canggih, Anda mungkin ingin melakukan sesuatu yang melampaui "mendefinisikan lapisan DAG": misalnya, Anda dapat menggunakan beberapa pelatihan khusus dan metode output pada contoh model Anda. Ini membutuhkan subklasifikasi.

Menggabungkan dan menggabungkan berbagai gaya API


Penting untuk dicatat bahwa memilih antara Fungsional API atau subkelas Model bukanlah solusi biner yang membatasi Anda untuk satu kategori model.Semua model dalam API tf.keras dapat berinteraksi satu sama lain, baik itu model Sequential, model Fungsional, atau Model / Layers subkelas yang ditulis dari awal.

Anda selalu dapat menggunakan model Fungsional atau model Sequential sebagai bagian dari Model / Lapisan subclass:

 units = 32 timesteps = 10 input_dim = 5 # Define a Functional model inputs = keras.Input((None, units)) x = layers.GlobalAveragePooling1D()(inputs) outputs = layers.Dense(1, activation='sigmoid')(x) model = keras.Model(inputs, outputs) class CustomRNN(layers.Layer): def __init__(self): super(CustomRNN, self).__init__() self.units = units self.projection_1 = layers.Dense(units=units, activation='tanh') self.projection_2 = layers.Dense(units=units, activation='tanh') # Our previously-defined Functional model self.classifier = model def call(self, inputs): outputs = [] state = tf.zeros(shape=(inputs.shape[0], self.units)) for t in range(inputs.shape[1]): x = inputs[:, t, :] h = self.projection_1(x) y = h + self.projection_2(state) state = y outputs.append(y) features = tf.stack(outputs, axis=1) print(features.shape) return self.classifier(features) rnn_model = CustomRNN() _ = rnn_model(tf.zeros((1, timesteps, input_dim))) 

Sebaliknya, Anda dapat menggunakan Lapisan atau Model subkelas apa pun di API Fungsional jika Anda menerapkan metode callyang cocok dengan salah satu pola berikut: di

call(self, inputs, **kwargs)mana inputsstruktur tensor atau bersarang tensor (mis. Daftar tensor), dan di mana **kwargsargumen non-tensor (bukan input) .
call(self, inputs, training=None, **kwargs)di mana trainingnilai Boolean menunjukkan dalam mode apa layer, pembelajaran atau output harus berperilaku.
call(self, inputs, mask=None, **kwargs)di mana masktensor topeng boolean (berguna untuk RNN, misalnya).
call(self, inputs, training=None, mask=None, **kwargs)- tentu saja Anda dapat memiliki kedua parameter yang mendefinisikan perilaku layer pada saat yang sama.

Selain itu, jika Anda menerapkan metode `get_config` pada Layer atau Model kustom Anda, model Fungsional yang Anda buat dengannya akan serializable dan dikloning.

Di bawah ini adalah contoh kecil di mana kami menggunakan RNN khusus yang ditulis dari awal Model fungsional:

 units = 32 timesteps = 10 input_dim = 5 batch_size = 16 class CustomRNN(layers.Layer): def __init__(self): super(CustomRNN, self).__init__() self.units = units self.projection_1 = layers.Dense(units=units, activation='tanh') self.projection_2 = layers.Dense(units=units, activation='tanh') self.classifier = layers.Dense(1, activation='sigmoid') def call(self, inputs): outputs = [] state = tf.zeros(shape=(inputs.shape[0], self.units)) for t in range(inputs.shape[1]): x = inputs[:, t, :] h = self.projection_1(x) y = h + self.projection_2(state) state = y outputs.append(y) features = tf.stack(outputs, axis=1) return self.classifier(features) #           #  `batch_shape`,     `CustomRNN`  #    (     `state`). inputs = keras.Input(batch_shape=(batch_size, timesteps, input_dim)) x = layers.Conv1D(32, 3)(inputs) outputs = CustomRNN()(x) model = keras.Model(inputs, outputs) rnn_model = CustomRNN() _ = rnn_model(tf.zeros((1, 10, 5))) 

Ini menyimpulkan Panduan API Fungsional kami!

Sekarang Anda memiliki satu set alat yang kuat untuk membangun model pembelajaran yang mendalam.

Setelah verifikasi, terjemahan juga akan muncul di Tensorflow.org. Jika Anda ingin berpartisipasi dalam terjemahan dokumentasi situs web Tensorflow.org ke dalam bahasa Rusia, silakan hubungi secara pribadi atau komentar. Setiap koreksi atau komentar sangat dihargai. Sebagai ilustrasi, kami menggunakan gambar model GoogLeNet, yang juga merupakan grafik asiklik terarah.

Source: https://habr.com/ru/post/id483664/


All Articles