简体   繁体   中英

Subclass definitions of TensorFlow models with customizable hidden layers

I am learning about Models subclass definitions in TensorFlow

A pretty straightforward definition will be something like this

class MyNetwork1(tf.keras.Model):
    def __init__(self, num_classes = 10):
        super().__init__()
        self.num_classes = num_classes
    
        self.input_layer = tf.keras.layers.Flatten()
        self.hidden_1 = tf.keras.layers.Dense(128, activation = 'relu')
        self.hidden_2 = tf.keras.layers.Dense(64, activation = 'relu')
        self.output_layer = tf.keras.layers.Dense(self.num_classes, activation = 'softmax')
    
    def call(self, input_tensor):
        x = self.input_layer(input_tensor)
        x = self.hidden_1(x)
        x = self.hidden_2(x)
        x = self.output_layer(x)
        
        return x

After building the model,

Model1 = MyNetwork1()
Model1.build((None, 28, 28, 1))

It will look like

Model: "my_network1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
flatten (Flatten)            multiple                  0         
_________________________________________________________________
dense (Dense)                multiple                  100480    
_________________________________________________________________
dense_1 (Dense)              multiple                  8256      
_________________________________________________________________
dense_2 (Dense)              multiple                  650       
=================================================================
Total params: 109,386
Trainable params: 109,386
Non-trainable params: 0

Since this method cannot customize the number of neurons and activation type per layer I have tried to edit it a little bit.

I have tried the following definition

class MyNetwork2(tf.keras.Model):
    
    def __init__(self, num_classes = 2, hidden_dimensions = [100], 
                  hidden_activations = ['relu']):
        super().__init__()
        self.inputlayer = tf.keras.layers.Flatten()
        i = 0
        self.hidden_layers = []
        
        for d,a in zip(hidden_dimensions,hidden_activations):
            i += 1
            setattr(self, 'hidden_' + str(i) , 
                    tf.keras.layers.Dense(d, activation = a))
            self.hidden_layers.append('self.hidden_' + str(i) + '(x)')
            
        self.outputlayer = tf.keras.layers.Dense(num_classes, activation = 'softmax')
        self.num_layers = len(hidden_dimensions) + 2
        
    def call(self, inputtensor):
        
        x = self.inputlayer(inputtensor)
        
        for h in self.hidden_layers:
            # print(h)
            x = eval(h,{}, x)
            
        x = self.outputlayer(x)
        
        return x

In this code, I tried to do as same as the previous definition.

Model2 = MyNetwork2(num_classes = 10, hidden_dimensions = [128,64], 
                        hidden_activations = ['relu', 'relu'])

Model2.build((None, 28, 28, 1))

However, I faced the following error:

TypeError: Only integers, slices (`:`), ellipsis (`...`), tf.newaxis (`None`) and scalar tf.int32/tf.int64 tensors are valid indices, got 'self'

How can I fix this error to achieve my goal?

Seems like a very complicated way to do things. If you use a dictionary for a variable number of layers instead of eval, everything works fine.

class MyNetwork2(tf.keras.Model):
    def __init__(self, num_classes=2, hidden_dimensions=[100],
                 hidden_activations=['relu']):
        super(MyNetwork2, self).__init__()
        self.inputlayer = tf.keras.layers.Flatten()
        self.hidden_layers = dict()

        for i, (d, a) in enumerate(zip(hidden_dimensions, hidden_activations)):
            self.hidden_layers['hidden_'+str(i)]=tf.keras.layers.Dense(d, activation=a)

        self.outputlayer = tf.keras.layers.Dense(num_classes, activation='softmax')
        self.num_layers = len(hidden_dimensions) + 2

Running example:

import tensorflow as tf
import numpy as np


class MyNetwork2(tf.keras.Model):
    def __init__(self, num_classes=2, hidden_dimensions=[100],
                 hidden_activations=['relu']):
        super(MyNetwork2, self).__init__()
        self.inputlayer = tf.keras.layers.Flatten()
        self.hidden_layers = dict()

        for i, (d, a) in enumerate(zip(hidden_dimensions, hidden_activations)):
            self.hidden_layers['hidden_'+str(i)]=tf.keras.layers.Dense(d, activation=a)

        self.outputlayer = tf.keras.layers.Dense(num_classes, activation='softmax')
        self.num_layers = len(hidden_dimensions) + 2

    def call(self, inputtensor, training=None, **kwargs):

        x = self.inputlayer(inputtensor)
        for k, v in self.hidden_layers.items():
            x = v(x)

        x = self.outputlayer(x)

        return x

Model2 = MyNetwork2(num_classes = 10, hidden_dimensions = [128,64],
                        hidden_activations = ['relu', 'relu'])

Model2.build((None, 28, 28, 1))

Model2(np.random.uniform(0, 1, (1, 28, 28, 1)).astype(np.float32))
<tf.Tensor: shape=(1, 10), dtype=float32, numpy=
array([[0.14969216, 0.10196744, 0.0874036 , 0.08350615, 0.18459582,
        0.07227989, 0.08263624, 0.08537506, 0.10291573, 0.04962786]],
      dtype=float32)>

The hidden layers as a dictionary:

Model2.hidden_layers
{'hidden_0': <tensorflow.python.keras.layers.core.Dense at 0x1891b5c13a0>,
 'hidden_1': <tensorflow.python.keras.layers.core.Dense at 0x1891b5c1d00>}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM