Open In App

Intent Recognition using TensorFlow

Last Updated : 31 Jul, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Intent recognition is a method of natural language processing, which deals with determining intent of a given sentence, or in simple terms “what the sentence means”. It is commonly used in chatbots, virtual assistants, and other conversational AI systems to understand user requests and provide appropriate responses.

In this article, We will show a basic of how Intent Recognition can be made using TensorFlow

TensorFlow : TensorFlow is an open-source library for machine learning developed by Google. It provides various tools and functions to build and train neural networks efficiently, and a neural network is a computational model inspired by the functioning of the human brain, composed of interconnected artificial neurons that can learn and make predictions from input data.

To perform Intent Recognition using TensorFlow, we typically follow these steps:

Import Libraries:

We start by importing all necessary modules.

Python3




import tensorflow as tf
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
import numpy as np
import random
import json
 
import warnings
warnings.filterwarnings('ignore')


We import ‘tensorflow' to access the core TensorFlow functionality, ‘Tokenizer' to preprocess text data by tokenizing it into sequences, and ‘pad_sequences' to pad the sequences to a fixed length.

Data Collection:

Then, we need a dataset consisting of labeled examples where each example contains a text input and its corresponding intent label. For example, we consider a dataset from kaggle, to view: Chatbots: Intent Recognition Dataset, it is in JSON format and perfect for intent recognition model.

Python3




with open('Intent Recognition/Intent.json', 'r') as f:
    data = json.load(f)
 
print(data.keys())
print(type(data['intents']))
print(len(data['intents']))
print(data['intents'][0].keys())
data['intents'][-1]


Output:

dict_keys(['intents'])
<class 'list'>
22
dict_keys(['intent', 'text', 'responses', 'extension', 'context', 'entityType', 'entities'])
{'intent': 'SelfAware',
 'text': ['Can you prove you are self-aware',
  'Can you prove you are self aware',
  'Can you prove you have a conscious',
  'Can you prove you are self-aware please',
  'Can you prove you are self aware please',
  'Can you prove you have a conscious please',
  'prove you have a conscious'],
 'responses': ['That is an interesting question, can you prove that you are?',
  'That is an difficult question, can you prove that you are?',
  'That depends, can you prove that you are?'],
 'extension': {'function': '', 'entities': False, 'responses': []},
 'context': {'in': '', 'out': '', 'clear': False},
 'entityType': 'NA',
 'entities': []}

We load data from JSON file like shown above.

Data Cleaning:

We can’t directly process this data. First, we have to clean it, this usually includes, removing punctuation marks or anything which might produce unwanted results. This is also done to reduce number of tokens, as we don’t want to tokenize everything.

Python3




def clean(line):
    cleaned_line = ''
    for char in line:
        if char.isalpha():
            cleaned_line += char
        else:
            cleaned_line += ' '
    cleaned_line = ' '.join(cleaned_line.split())
    return cleaned_line


We define a function to clean sentence provided to it, by removing punctuations. This can also be done by using Regular Expression module in python.

Data Preprocessing:

The next step is to preprocess the data to make it suitable for training a neural network. This usually involves tokenization, which means breaking down each input sentence into individual words or sub-words.

But before we do that, we need to prepare data in a format {intent : text data}

Python3




#list of intents
intents = []                                           
unique_intents = []
#all text data to create a corpus
text_input= []   
#dictionary mapping intent with appropriate response
response_for_intent = {}                               
for intent in data['intents']:
    #list of unique intents
    if intent['intent'] not in unique_intents:           
        unique_intents.append(intent['intent']) 
    for text in intent['text']:
        #cleaning is done before adding text to corpus
        text_input.append(clean(text))                   
        intents.append(intent['intent'])
    if intent['intent'] not in response_for_intent:
        response_for_intent[intent['intent']] = []
    for response in intent['responses']:
        response_for_intent[intent['intent']].append(response)


We have created a dataset which is ready to be preprocessed, we can see sample data below:

Python3




print("Intent :",intents[0])
print("Number of Intent:",len(intents))
print("Sample Input:", text_input[0])
print('Length of text_input:',len(text_input))
print("Sample Response: ", response_for_intent[intents[0]])


Output:

Intent : Greeting
Number of Intent: 143
Sample Input: Hi
Length of text_input: 143
Sample Response:  ['Hi human, please tell me your GeniSys user',
'Hello human, please tell me your GeniSys user',
 'Hola human, please tell me your GeniSys user']

Tokenization and Embedding

Now, our data is ready to be tokenized, with the help of inbuilt TensorFlow tokenizer, We can make both tokenization and embedding.

Python3




tokenizer = Tokenizer(filters='',oov_token='<unk>')
tokenizer.fit_on_texts(text_input)
sequences = tokenizer.texts_to_sequences(text_input)
padded_sequences = pad_sequences(sequences, padding='pre')
print('Shape of Input Sequence:',padded_sequences.shape)
padded_sequences[:5]


Output:

Shape of Input Sequence: (143, 9)
array([[ 0,  0,  0,  0,  0,  0,  0,  0, 52],
       [ 0,  0,  0,  0,  0,  0,  0, 52, 53],
       [ 0,  0,  0,  0,  0,  0,  0,  0, 68],
       [ 0,  0,  0,  0,  0,  0,  0,  0, 39],
       [ 0,  0,  0,  0,  0,  0,  0, 39, 53]], dtype=int32)

Feature Extraction:

Neural network cannot process sentences, so numerical representation of sentences have to be provided to it, this is done by doing Feature Extraction, for that we map all words with their indexes and create a matrix mapping it to its category (intent).

Python3




intent_to_index = {}
categorical_target = []
index = 0
 
for intent in intents:
    if intent not in intent_to_index:
        intent_to_index[intent] = index
        index += 1
    categorical_target.append(intent_to_index[intent])
 
num_classes = len(intent_to_index)
print('Number of Intents :',num_classes)
 
# Convert intent_to_index to index_to_intent
index_to_intent = {index: intent for intent, index in intent_to_index.items()}
index_to_intent


Output:

Number of Intents : 22
{0: 'Greeting',
 1: 'GreetingResponse',
 2: 'CourtesyGreeting',
 3: 'CourtesyGreetingResponse',
 4: 'CurrentHumanQuery',
 5: 'NameQuery',
 6: 'RealNameQuery',
 7: 'TimeQuery',
 8: 'Thanks',
 9: 'NotTalking2U',
 10: 'UnderstandQuery',
 11: 'Shutup',
 12: 'Swearing',
 13: 'GoodBye',
 14: 'CourtesyGoodBye',
 15: 'WhoAmI',
 16: 'Clever',
 17: 'Gossip',
 18: 'Jokes',
 19: 'PodBayDoor',
 20: 'PodBayDoorResponse',
 21: 'SelfAware'}

One-Hot Encoding

Apply One-Hot Encoding for categorical_target

Python3




categorical_vec = tf.keras.utils.to_categorical(categorical_target,
                                                num_classes=num_classes, dtype='int32')
 
print('Shape of Ca',categorical_vec.shape)
categorical_vec[:5]


Output:

Shape of Ca (143, 22)
array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
      dtype=int32)

Model Building:

First step of building a model is defining hyperparameters, in simple words they are settings which we predefine before training our model. They include parameters like no. of epochs, embedding dimensions, size of vocabulary, and target length. They can be adjusted accordingly, to increase performance of model.

Python3




epochs=100
embed_dim=300
lstm_num=50
output_dim=categorical_vec.shape[1]
input_dim=len(unique_intents)
print("Input Dimension :{},\nOutput Dimension :{}".format(input_dim,output_dim))


Output:

Input Dimension :22,
Output Dimension :22

As both input dimension and output dimension are same, we can proceed with building our model.

Now, we can define the architecture of our neural network using TensorFlow. A common model for intent recognition is the recurrent neural network (RNN) or its variant, the long short-term memory (LSTM) network. These networks can handle sequential data, such as sentences, effectively. We can also use pre-trained models like BERT or GPT to achieve better performance.

Here we are using a RNN, by using ‘Sequential’ model from TensorFlow’s Keras API. It consists of an embedding layer, an LSTM layer for sequence processing, and two dense layers for classification. You can see model summary below.

Python3




model = tf.keras.models.Sequential([
    tf.keras.layers.Embedding(len(tokenizer.word_index) + 1, embed_dim),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(lstm_num, dropout=0.1)), 
    tf.keras.layers.Dense(lstm_num, activation='relu'),
    tf.keras.layers.Dropout(0.4),
    tf.keras.layers.Dense(output_dim, activation='softmax')
])
 
optimizer = tf.keras.optimizers.Adam(lr=0.001
model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()


Output:

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 embedding (Embedding)       (None, None, 300)         35700     
                                                                 
 bidirectional (Bidirectiona  (None, 100)              140400    
 l)                                                              
                                                                 
 dense (Dense)               (None, 50)                5050      
                                                                 
 dropout (Dropout)           (None, 50)                0         
                                                                 
 dense_1 (Dense)             (None, 22)                1122      
                                                                 
=================================================================
Total params: 182,272
Trainable params: 182,272
Non-trainable params: 0
_________________________________________________________________

Training:

With the model architecture defined, we can start training the network using our labeled dataset. During training, the model adjusts its internal parameters to minimize the difference between its predicted intents and the true intents in the training data. This process involves forward propagation, where the model makes predictions, and backward propagation, where the model’s parameters are updated based on the prediction errors.

Python3




model.fit(padded_sequences, categorical_vec, epochs=epochs, verbose=0)


Output:

<keras.callbacks.History at 0x7f75fff7df10>

Here we train the model by fitting it to the padded sequences and its respective categorical sequence. The model adjusts its internal parameters to minimize the difference between its predicted intents and the true intents in the training data. The training is performed for a specified number of epochs, and might stop early if there is no improvement in it’s loss after 4 consecutive epochs.

Evaluate:

To check if our model works correctly, we give it unseen data along with labels and check if it works correctly or not. Thus, we give text inputs along with it’s intent and we test our model, this is known as evaluation of model. It is important step which helps predict accuracy of model, or if it is overfit or underfit.

Python3




test_text_inputs = ["Hello",
                    "my name is adam",
                    "how are you?",
                    "can you guess my name?",
                    "Do you get me","Adios"]
 
test_intents = ["Greeting",
                "GreetingResponse",
                "CourtesyGreeting",
                "CurrentHumanQuery",
                "UnderstandQuery",
                "GoodBye"]
 
test_sequences = tokenizer.texts_to_sequences(test_text_inputs)
test_padded_sequences = pad_sequences(test_sequences,  padding='pre')
test_labels = np.array([unique_intents.index(intent) for intent in test_intents])
test_labels = tf.keras.utils.to_categorical(test_labels, num_classes=num_classes)
loss, accuracy = model.evaluate(test_padded_sequences, test_labels)


Output:

1/1 [==============================] - 1s 572ms/step - loss: 0.4058 - accuracy: 1.0000

Predict:

We have finished training our model and can now use it to make predictions on new, unseen sentences. Given an input sentence, the model processes it using the learned parameters and produces a probability distribution over the possible intents. The intent with the highest probability is considered the predicted intent.

Python3




def response(sentence):
    sent_tokens = []
    # Split the input sentence into words
    words = sentence.split()
    # Convert words to their corresponding word indices
    for word in words:                                          
        if word in tokenizer.word_index:
            sent_tokens.append(tokenizer.word_index[word])
        else:
            # Handle unknown words
            sent_tokens.append(tokenizer.word_index['<unk>'])
    sent_tokens = tf.expand_dims(sent_tokens, 0)
    #predict numerical category
    pred = model(sent_tokens)   
    #category to intent
    pred_class = np.argmax(pred.numpy(), axis=1)               
    # random response to that intent
    return random.choice(
        response_for_intent[index_to_intent[pred_class[0]]]), index_to_intent[pred_class[0]]


Chatbots: Intent Recognition

We have defined a function response to predict intent and give appropriate response. This is a loop to take input from user recognize intent and give appropriate response.

Python3




print("Note: Enter 'quit' to break the loop.")  
while True:                                               
    query = input('You: ')
    if query.lower() == 'quit':
        break
    bot_response, typ = response(query)
    print('Geek: {} -- TYPE: {}'.format(bot_response, typ))
    print()


Output:

Note: Enter 'quit' to break the loop.
You:  Hi, Who are you?
Geek: Hello, how are you? I am great thanks! Please tell me your GeniSys user -- TYPE: CourtesyGreeting

You:  Can you prove you have a conscious?
Geek: That is an difficult question, can you prove that you are? -- TYPE: SelfAware

You:  Can you prove you are self-aware?
Geek: They call you <HUMAN>, what can I do for you? -- TYPE: CurrentHumanQuery

You:  My name is Pawan Gunjan.
Geek: <HUMAN>, what can I do for you? -- TYPE: CurrentHumanQuery

You:  Tell me a Jokes
Geek: A woman goes into a US sporting goods store to buy a rifle. 'It's for my husband', she tells the clerk. 'Did he tell you what gauge to get?' asks the clerk. Are you kidding?' she says. 'He doesn't even know that I'm going to shoot him!' -- TYPE: Jokes

You:  Tell me aJokes
Geek: Let me see -- TYPE: WhoAmI

You:  Tell me a Jokes
Geek: A team of scientists were nominated for the Nobel Prize. They had used dental equipment to discover and measure the smallest particles yet known to man. They became known as 'The Graders of the Flossed Quark...' -- TYPE: Jokes

You:  quit


Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads