Getting results from custom component

I have been trying to integrate ULMfit as an intent classifier for RASA NLU. I have managed to train it via the train nlu command when importing the component for parsing messages I can’t seem to get response.

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from rasa_nlu.components import Component
import ulmfit

class ULMfit_Classifier(Component):
    """A new component"""

    # Name of the component to be used when integrating it in a
    # pipeline. E.g. ``[ComponentA, ComponentB]``
    # will be a proper pipeline definition where ``ComponentA``
    # is the name of the first component of the pipeline.
    name = "ULMfit"

    # Defines what attributes the pipeline component will
    # provide when called. The listed attributes
    # should be set by the component on the message object
    # during test and train, e.g.
    # ```message.set("entities", [...])```
    provides = ['intent']

    # Which attributes on a message are required by this
    # component. e.g. if requires contains "tokens", than a
    # previous component in the pipeline needs to have "tokens"
    # within the above described `provides` property.
    requires = []

    # Defines the default configuration parameters of a component
    # these values can be overwritten in the pipeline configuration
    # of the model. The component should choose sensible defaults
    # and should be able to create reasonable results with the defaults.
    defaults = {}

    # Defines what language(s) this component can handle.
    # This attribute is designed for instance method: `can_handle_language`.
    # Default value is None which means it can handle all languages.
    # This is an important feature for backwards compatibility of components.
    language_list = None

    def __init__(self, component_config=None):
        super(ULMfit_Classifier, self).__init__(component_config)

    def train(self, training_data, cfg, **kwargs):
        """Train this component.

        This is the components chance to train itself provided
        with the training data. The component can rely on
        any context attribute to be present, that gets created
        by a call to :meth:`components.Component.pipeline_init`
        of ANY component and
        on any context attributes created by a call to
        :meth:`components.Component.train`
        of components previous to this one."""

        learn = ulmfit.ULMfit.TrainLanguageModel(1, 'data_nlu/train_nlu_data.json', epochs = 1, learning_rate = 1e-2, drop_mult=0.3)

        learn = ulmfit.ULMfit.TrainTextClassifier(1, 'data_nlu/train_nlu_data.json', Train=True,  epochs = 25, learning_rate = 1e-2, drop_mult=0.1)

        ulmfit.ULMfit.Save_Model(1, learn,'ep_25_lr_1e-2_drpt_5_dt_20')
    def process(self, message, **kwargs):
        """Process an incoming message.

        This is the components chance to process an incoming
        message. The component can rely on
        any context attribute to be present, that gets created
        by a call to :meth:`components.Component.pipeline_init`
        of ANY component and
        on any context attributes created by a call to
        :meth:`components.Component.process`
        of components previous to this one."""
        learn = ulmfit.ULMfit.TrainTextClassifier(1, 'data_nlu/train_nlu_data.json', Train=False,  epochs = 10, learning_rate = 1e-2, drop_mult=0.3)

        learn = ulmfit.ULMfit.Load_Model(1, 'ep_25_lr_1e-2_drpt_5_dt_20', learn)
        m = message.text
        print(type(m))
        pred = learn.predict(str(m))
        
        return {'name': str(pred[0]), 'confidence': round(float(max(pred[2])), 2)}
    def persist(self, model_dir):
        """Persist this component to disk for future loading."""

        pass

    @classmethod
    def load(cls, model_dir=None, model_metadata=None, cached_component=None,
             **kwargs):
        """Load this component from file."""

        if cached_component:
            return cached_component
        else:
            component_config = model_metadata.for_component(cls.name)
            return cls(component_config)

I get the following output for the parse command.

{'intent': {'name': None, 'confidence': 0.0}, 'entities': [], 'text': 'hi'}

I’m not sure about this, but looking at the embedding intent classifier code (rasa_nlu/embedding_intent_classifier.py at master · RasaHQ/rasa_nlu · GitHub), your process method should return something like this :

message.set("intent", intent, add_to_output=True)
message.set("intent_ranking", intent_ranking, add_to_output=True)
2 Likes

Thanks that works out :grin: