Classify Texts with TensorFlow and Twilio to Answer Loves Me, Loves Me Not

栏目: IT技术 · 发布时间: 4年前

内容简介:Make a Python file calledThis next function will read the training data, remove punctuation, handle contractions, and extract words in each sentence, appending them to a word list.

Classify Texts with TensorFlow and Twilio to Answer Loves Me, Loves Me Not

Valentine's Day is coming up and both love and machine learning are in the air. Some would use flower petals to determine if someone loves them or not, but developers might use a tool like TensorFlow. This post will go over how to perform binary text classification with neural networks using Twilio and TensorFlow in Python.

Classify Texts with TensorFlow and Twilio to Answer Loves Me, Loves Me Not

Prerequisites

Setup

Classify Texts with TensorFlow and Twilio to Answer Loves Me, Loves Me Not

Activate a virtual environment in Python 3 and download this requirements.txt file . Be sure to use Python 3.6.x for TensorFlow. On the command line run pip3 install -r requirements.txt to import all the necessary libraries and then to import nltk , make a new directory with mkdir nltk_data , cd into it and then run python3 -m nltk.downloader . You should see a window like this, select all packages as shown in the screenshot below:

Classify Texts with TensorFlow and Twilio to Answer Loves Me, Loves Me Not

Your Flask app will need to be visible from the web so Twilio can send requests to it. Ngrok simplifies this. With Ngrok installed, run ngrok http 5000 in the directory your code is in.

You should see the screen above. Grab that ngrok URL to configure your Twilio number:

Classify Texts with TensorFlow and Twilio to Answer Loves Me, Loves Me Not

Prepare Training Data

Make a new file called data.json to contain two arrays of phrases corresponding to labels: either "loves me" or "loves me not". Feel free to modify phrases to the arrays or add your own (the more training data, the better--this is not close to being enough but it's a fun start.)

{
    "loves me": [
        "do you want some food",
        "you're so nice",
        "i got you some food",
        "I like your hair",
        "You looked nice today",
        "Let's dance",
        "I spent time on this for you",
        "i got this for you",
        "heyyyyyyy",
        "i got you pizza"
    ],
    "loves me not": [
        "I didn't have the time",
        "Can you get your own food",
        "You'll have to get your own food",
        "Do it yourself",
        "i can't",
        "next time",
        "i'm sorry",
        "you up",
        "hey",
        "wyd",
        "k", 
        "idk man",
        "cool"
    ]
}

Make a Python file called main.py . At the top import the required libraries, then make a function open_file to save the data from data.json as a variable data .

import re
from nltk.tokenize import word_tokenize
from nltk.stem import WordNetLemmatizer
import numpy as np
import tflearn
import tensorflow as tf
import random
import json
from twilio.twiml.messaging_response import MessagingResponse
from flask import Flask, request

def open_file(file):
    with open(file, 'r') as f:
        data = json.load(f)
        return data
data = open_file('data.json')
print(data)

Read Training Data

This post will use a lemmatizer to get to the base of a word, ie. turning "going" into "go". A stemmer, which also reduces words to their word stem, could be used for this task but would be unable to identify that "good" is the lemma of "better." Though lemmas take more time to use, they tend to be more efficient. You can experiment with both stemmers and lemmatizers when working with natural language processing (NLP).

Right underneath the data variable declaration, initialize the lemmatizer and make this function to stem each word:

lemma = WordNetLemmatizer()
def tokenize_and_stem_text(text):
    return [lemma.lemmatize(word.lower()) for word in text] 
binary_categories = list(data.keys())
training_words = []
json_data = []

This next function will read the training data, remove punctuation, handle contractions, and extract words in each sentence, appending them to a word list.

Next, get the possible labels ("loves me" and "loves me not") that the model will train for and initialize an empty list json_data to hold tuples of words from the sentence and also the label name. The training_words list will contain all the unique stemmed words from the training data JSON and binary_categories contains the possible categories they could classify as.

def read_training_data(data):
    for label in data.keys(): 
        for text in data[label]:
            for word in text.split():
                if word.lower() in contractions:
                    text = text.replace(word, contractions[word.lower()])
            text = re.sub("[^a-zA-Z' ]+", ' ', text)
            training_words.extend(word_tokenize(text))
            json_data.append((word_tokenize(text), label))
    return json_data

The json_data returned is a list of words from each sentence and either loves_me or loves_me_not ; for example, one element of that list is  ([“do”, “you”, “want”, "some", "food], “loves_me”) . This list does not cover every possible contraction but you get the idea:

contractions = {
    "aren't": "are not",
    "can't": "cannot",
    "could've": "could have",
    "couldn't": "could not",
    "didn't": "did not",
    "don't": "do not",
    "hadn't": "had not",
    "hasn't": "has not",
    "haven't": "have not",
    "how'd": "how did",
    "how's": "how is",
    "i'd": "I had",
    "i'll": "I will",
    "i'm": "I am",
    "i've": "I have",
    "isn't": "is not",
    "let's": "let us",
    "should've": "should have",
    "shouldn't": "should not",
    "that'd": "that had",
    "that's": "that is",
    "there's": "there is",
    "wasn't": "was not",
    "we'd": "we would",
    "we'll": "we will",
    "we're": "we are",
    "we've": "we have",
    "what'll": "what  will",
    "what's": "what is",
    "when's": "when is",
    "where'd": "where did",
    "where's": "where is",
    "won't": "will not",
    "would've": "would have",
    "wouldn't": "would not",
    "you'd": "you had",
    "you'll": "you will",
    "you're": "you are",
}

Then stem each word to remove duplicates and call the read_training_data function.

training_words = tokenize_and_stem_text(training_words)
print(read_training_data(data))
read_training_data(data)

For TensorFlow to understand this data the strings must be converted into numbers. This can be done with the  bag-of-words NLP model , which keeps a count of the total number of occurrences of the most commonly-used words. For example, the sentence "Never gonna give you up never gonna let you down" could be represented as:

Classify Texts with TensorFlow and Twilio to Answer Loves Me, Loves Me Not

For the loves_me and loves_me_not labels a bag-of-words is initiated as a list of tokenized words, called vector here. We loop through the words in the phrase, stemming them and comparing with each word in the vocabulary. If the sentence has a word in our training data or vocabulary, 1 is appended to the vector, signaling which label the word belongs to. If not, a 0 is appended.

At the end our training set has a bag of words model and the output row corresponding to the label the bag belongs to.

training = []
for item in json_data:
    bag_vector = []
    token_words = item[0]
    token_words = [lemma.lemmatize(word.lower()) for word in token_words]
    for word in training_words:
        if word in token_words:
            bag_vector.append(1) 
        else:
            bag_vector.append(0)
    output_row = list([0] * len(binary_categories)) 
    output_row[binary_categories.index(item[1])] = 1
    training.append([bag_vector, output_row])

Convert training to a numpy array so TensorFlow can process it as well, and split it into two variables: data has the bag of words and labels has the label.

training = np.array(training)
data = list(training[:, 0])
labels = list(training[:, 1])

Now reset the underlying graph data, and clear defined variables and operations from the previous cell each time the model is run. Next build a neural network with three layers:

  1. The input_data input layer is for inputting or feeding data to a network, and the input to the network has size  len(data[0]) for the length of our encoded bag of words and labels.
  2. Then make two fully-connected intermediate layers with 32 hidden units or neurons. While some functions need more than one layer to run, more than three layers probably won't make a difference, so two layers is enough and shouldn't be too computationally-expensive. We use the softmax activation function in this case because the labels are exclusive.
  3. Lastly, we make the final net from the estimator layer , like regression. At a high level, regression (linear or logistic) helps predict the outcome of an event based on the data. Neural networks have multiple layers to better learn more complicated abstractions relationships from the input.
tf.reset_default_graph()
net = tflearn.input_data(shape=[None, len(data[0])]) 
net = tflearn.fully_connected(net, 32)
net = tflearn.fully_connected(net, len(labels[0]), activation='softmax') 
net = tflearn.regression(net)

A deep neural network (DNN) automatically performs neural network classifier tasks like training the model and prediction based on input. Calling the fit method begins training and applies the gradient descent algorithm, a common first-order optimization deep learning algorithm. n_epoch is the number of times the network will see all the data and batch_size is the size data is sliced in to for the model to train on.

model = tflearn.DNN(net)
model.fit(data, labels, n_epoch=100, batch_size=16, show_metric=True)

Similar to how the data for the bag-of-words model was processed, this data needs to be converted to a numerical form that can be passed to TensorFlow.

def clean_for_tf(text):
    input_words = tokenize_and_stem_text(word_tokenize(text))
    vector = [0]*len(training_words)
    for input_word in input_words:
        for ind, word in enumerate(training_words):
            if word == input_word:
                vector[ind] = 1
    return(np.array(vector))

To test this without text messages you could add

tensor = model.predict([clean_for_tf(INSERT-TEXT-HERE)])
print(binary_categories[np.argmax(tensor)])

This calls the predict method on the model, getting the position of the largest value which represents the prediction.

We will test this with text messages by building a Flask application.

Create a Flask App

Add the following code to make a Flask app, get the inbound text message, create a tensor, and call the model.

app = Flask(__name__)
@app.route("/sms", methods=['POST'])
def sms():
    resp = MessagingResponse()
    inbMsg = request.values.get('Body').lower().strip()
    tensor = model.predict([clean_for_tf(inbMsg)])
    resp.message(
        f'The message {inbMsg!r} corresponds to {binary_categories[np.argmax(tensor)]!r}.')
    return str(resp)

Open a new terminal tab separate from the one running ngrok. In the folder housing your code run

export FLASK_APP=main

export FLASK_ENV=development

flask run  --without-threads

and text your Twilio number a phrase like "get someone else to do it" and you should see something like this:

Classify Texts with TensorFlow and Twilio to Answer Loves Me, Loves Me Not

The complete code and requirements.txt can be found on GitHub here .

What's Next

Classify Texts with TensorFlow and Twilio to Answer Loves Me, Loves Me Not

What will you classify next? You could use TensorFlow's Universal Sentence Encoder to perform similar text classification in JavaScript, classify phone calls or emails, use a different activation function like sigmoid if you have categories that are mutually exclusive, and more. Let me know what you're building online or in the comments.  

Authors


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

PHP高级编程

PHP高级编程

Jesus Castagnetto / 机械工业出版社 / 2001-3 / 78.00元

本书介绍PHP的基本知识与高级特一起来看看 《PHP高级编程》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试