Deploying NLP model chatbot This blog is the 2nd in the series of Demystifying RasaNLU. In we have explored the various pipeline stages that the training data goes through before getting converted into a trained ML model. Part 1 In this part, we will explore how this trained model is served via a REST API to predict the intent and entities during runtime in . Rasa Again if you are a newbie to the whole chatbot domain, here is where you start Understand what’s & why’s of chatbot Build your first chatbot with RasaNLU Part 1 — What happens when you train you chatbot? Let’s Begin part 2 Server — What does a developer see? RasaNLU uses the , a python web framework to serve predictions using the trained model via APIs. The RasaNLU framework creates the configurations for the server and starts it at twisted localhost:5000 python -m rasa_nlu.server --path projects Once the server is up and running, you can query an NLP result for a sentence using endpoint with as a query parameter. The rest of the blog will cover the transitions that the query string went through to arrive at the output. /parse q for a mexican restaurant http://localhost:5000/parse?q=looking What happens under the hood? Load the Model MetaData Create a processing pipeline Process text through the pipeline 1. Load the Model MetaData At the end of , we have discussed that the ML model gets stored in a file. Another important file that gets stored is the which is the snapshot of all the pipeline transformations and its parameters that the training samples went through. Part 1 .pkl ModelMetaData The important parameters of each pipeline component being the of the component, its and The context attributes are specific to the component. name class contextParms. The following is a snippet of a generated metadata file for component. Apart from the and the attributes include the in which model is stored, tuning parameters like which are specific to the SklearnIntentClassifer name class context classifier_file C, Kernel SkLearnIntentClassifier. {'language': 'en','pipeline': [... {'name': 'intent_classifier_sklearn','classifier_file': 'intent_classifier_sklearn.pkl','class': 'SklearnIntentClassifier','C': [1, 2, 5, 10, 20, 100],'kernels': ['linear'],'max_cross_validation_folds': 5}... 2. Creating Pipeline Components Each item in the metadata’s pipeline defines an ML component. In this step, An object is created using the metadata which is the same as the one we got as an output from the training step which is later used to reconstruct the processing pipeline. Interpreter class Interpreter:def create(model_metadata): component_builder = components.ComponentBuilder()pipeline = [] # 1. Create component builder object # 2. For each component in metadata# 2.1 Create component object# 2.2 Add component to pipeline for component\_name in model\_metadata.component\_classes: component = component\_builder.load\_component( component\_name, model\_metadata.model\_dir, model\_metadata, \*\*context) pipeline.append(component) return **Interpreter(pipeline, context, model\_metadata)** 3. Processing the Query through the pipeline In this step, The query string is fed into various pipeline components. These are the stages that our training data went through. But while serving the model insights are derived from the text using the saved model, instead of training the model will loop through the pipeline and process the message we got via the query string. Interpreter metadata = self._read_model_metadata(model_name)interpreter = Interpreter.create(metadata, component_builder)for component in interpreter.pipeline:component.process(message, **self.context) 3.1 Preprocessing The preprocessing step is similar to the one in training. This step transforms the input query string to a bunch of numbers(Vectors) which is used to perform predictions on the ML model. 3.1.1. Tokenize word In this step, we use to tokenize sentences into words. We do this because later in the pipeline we construct a dependency among the words to identify the user intent. SpacyTokenizer Input >>> 'spacy_doc' from previous step Code >>> tokens = [Token(t.text, t.idx) for t in doc] Output >>>{'tokens': [i, am, looking, for, a, mexican, restaurant]} 3.1.2. Convert words into Vectors As mentioned in part 1, An ML algorithm understands only numerical data. It is the featurizer’s job to convert tokens into word vectors. We use to achieve this. At the end of this step, we will have a list of numbers which will make sense only for ML models. Spacy’s token comes with a vector attribute which makes this conversion easy. SpacyFeaturizer Input >>> tokens Code >>> features = [token.vector for token in tokens] Output >>>'text_features': array([ 7.84102738e-01, -2.11456835e-01, 8.09298396e-01, 1.77501714e+00,... 3.1.3. Match Regular Expressions Since this particular example has no regex patterns to match, It returns an empty list. In case of a regex-based example, looks for matching regular expression from the trained samples and would return 1.0 for words that match the regex pattern. RegexFeaturizer Input >>> tokens Code >>> found = []for i, exp in enumerate(self.known_patterns):match = re.search(exp["pattern"], message.text)if <match_in_token>:found.append(1.0)else:found.append(0.0) Output >>> [] 3.2 Entity Extraction NER_CRF EntityExtractor 3.2.1. Predict Entities using The first step in entity extraction at runtime is to Create an object using the metadata. The metadata for the restaurant chatbot from RasaNLU site would look something like this. EntityExtractor >>> metadata {'BILOU_flag': True, 'features': [[...]],'max_iterations': 50, 'L1_c': 0.1, 'L2_c': 0.1, 'name': 'ner_crf', , 'class':'CRFEntityExtractor'} 'classifier_file': 'crf_model.pkl' >>> def load(metadata)ent_tagger = joblib.load(metadata[" "])return CRFEntityExtractor(meta, ent_tagger) classifier_file Creating the model object using the pickle file enables you to preserve the training information. Input >>> text_features Code >>>def extract_entity(message):text_data = self._from_text_to_crf(message)features = self._sentence_to_features(text_data)ents = self.ent_tagger.predict_marginals_single(features)return self._from_crf_to_json(message, ents) Output >>>'entities': [{'start': 20, 'end': 27, 'value': 'mexican','entity':'cuisine', 'confidence': 0.5007341271762173,'extractor': 'ner_crf'}] 3.2.2. Extract Synonyms During synonym extraction, the reads the JSON file created during the training phase and matches the entities extracted in NER phase against it. If there is a match, the entity dict gets updated. The process is repeated for all the entities captured during NER. In the end, we get an updated entity list. NERSynonymExtractor Input >>> entitiesCode >>> for entity in entities:entity_value = entity["value"]if entity_value.lower() in self.synonyms:entity["value"] = self.synonyms[entity_value.lower()] Output >>>'entities': [{'start': 20, 'end': 27, 'value': 'mexican','entity':'cuisine', 'confidence': 0.5007341271762173,'extractor': 'ner_crf'}] 3.3. Intent Classification Any ML 101 tutorial will teach you two things and The fit is where the training happens, and now we have to predict over the trained model by calling using fit predict. predict SkLearnIntentClassifier. Input >>> text_features Code >>>X = message.get("text_features").reshape(1, -1)intent_ids, probabilities = self.predict(X)intents = self.transform_labels_num2str(intent_ids) Output >>>'intent_ranking': [{'name': 'restaurant_search', 'confidence': 0.7617989648263017}, {'name': 'affirm', 'confidence': 0.13003887740062095},{'name': 'goodbye', 'confidence': 0.05772400386318094},{'name': 'greet', 'confidence': 0.050438153909896435}] Final Output The final output is your intent and entity predicted and given to you in the form of a JSON. Using this information you can perform the respective action and generate reply messages accordingly. We will digger deeper and understand the Entity Extractor. In the next part, Was this post useful to you? Hold the clap button and give a shout out to me on twitter . ❤️