addons icon indicating copy to clipboard operation
addons copied to clipboard

[CRF] Get the decoded_sequence from the output list of CRF layer

Open xuxingya opened this issue 5 years ago • 5 comments

In layers/crf CRF Layer, the output is [decoded_sequence, potentials, sequence_length, self.chain_kernel], however, when I want to get the first element of the output like the code below :

from tensorflow.keras.layers import Input, Embedding, Bidirectional, GRU, Dense
from tensorflow.keras.models import Model
import tensorflow as tf
from tensorflow_addons.layers.crf import CRF
from tensorflow_addons.text.crf import crf_log_likelihood

def unpack_data(data):
    if len(data) == 2:
        return data[0], data[1], None
    elif len(data) == 3:
        return data
    else:
        raise TypeError("Expected data to be a tuple of size 2 or 3.")


class ModelWithCRFLoss(tf.keras.Model):
    """Wrapper around the base model for custom training logic."""

    def __init__(self, base_model):
        super().__init__()
        self.base_model = base_model

    def call(self, inputs):
        return self.base_model(inputs)

    def compute_loss(self, x, y, sample_weight, training=False):
        y_pred = self(x, training=training)
        _, potentials, sequence_length, chain_kernel = y_pred

        # we now add the CRF loss:
        crf_loss = -crf_log_likelihood(potentials, y, sequence_length, chain_kernel)[0]

        if sample_weight is not None:
            crf_loss = crf_loss * sample_weight

        return tf.reduce_mean(crf_loss), sum(self.losses)

    def train_step(self, data):
        x, y, sample_weight = unpack_data(data)

        with tf.GradientTape() as tape:
            crf_loss, internal_losses = self.compute_loss(
                x, y, sample_weight, training=True
            )
            total_loss = crf_loss + internal_losses

        gradients = tape.gradient(total_loss, self.trainable_variables)
        self.optimizer.apply_gradients(zip(gradients, self.trainable_variables))

        return {"crf_loss": crf_loss, "internal_losses": internal_losses}

    def test_step(self, data):
        x, y, sample_weight = unpack_data(data)
        crf_loss, internal_losses = self.compute_loss(x, y, sample_weight)
        return {"crf_loss_val": crf_loss, "internal_losses_val": internal_losses}


def test():
    inputs = Input(shape=(None,), dtype='int32')
    output = Embedding(100, 40, trainable=True, mask_zero=True)(inputs)
    output = Bidirectional(GRU(64, return_sequences=True))(output)
    # output = Dense(9, activation=None)(output)
    crf = CRF(9)
    output = crf(output)[0]
    base_model = Model(inputs, output)
    model = ModelWithCRFLoss(base_model)
    model.build(input_shape=(None, None))
    model.compile('adam')

    x = [[5, 2, 3] * 3] * 10
    y = [[1, 2, 3] * 3] * 10

    model.fit(x=x, y=y, epochs=2, batch_size=2)
    model.save('model')


if __name__ == '__main__':
    test()

The error raised: OperatorNotAllowedInGraphError: iterating over tf.Tensor is not allowed: AutoGraph did not convert this function. Try decorating it directly with @tf.function.

Because I want to use the model on tf-serving, it asked the output to has the same batch dim with the input. So I want to get only the first dimension of the output of the CRF Layer. Is these any way to do it?

xuxingya avatar Aug 25 '20 09:08 xuxingya

The root cause is that autograph doesn't yet support list comprehension. You can use tf.map_fn for the comprehension: return tf.map_fn(lambda i: i ** 2 if i > 0 else i, x)

chazuttu avatar Jan 04 '21 05:01 chazuttu

You can also just do : index = 0 for image in inputs: .... My code ... index += 1

chazuttu avatar Jan 04 '21 05:01 chazuttu

Hi @xuxingya , your model building is incorrect. replace output = crf(output)[0] with output = crf(output) will fix your problem. You can check double it at https://colab.research.google.com/drive/1T5VMO3Q2GCN27tqRpSkrO1a8-SyhBnmG?usp=sharing.

howl-anderson avatar Aug 28 '21 09:08 howl-anderson

@bhack This issue is CRF related, so please label it with crf.

howl-anderson avatar Aug 28 '21 09:08 howl-anderson

@xuxingya Also, you may find this PR #2552 helps. It uses Custom Training Loop programming style instead of Custom Training Step. Both methods can work.

howl-anderson avatar Aug 28 '21 09:08 howl-anderson

TensorFlow Addons is transitioning to a minimal maintenance and release mode. New features will not be added to this repository. For more information, please see our public messaging on this decision: TensorFlow Addons Wind Down

Please consider sending feature requests / contributions to other repositories in the TF community with a similar charters to TFA: Keras Keras-CV Keras-NLP

seanpmorgan avatar Mar 01 '23 05:03 seanpmorgan