Contents

Keras Ticket Classification

Uma das coisas incríveis sobre trabalhar com engenharia de software é o maior número de APIs de código aberto disponíveis na web para utilização. Qualquer um pode utilizar alguma ferramenta complexa que abstraia qualquer complexidade, sem um conhecimento profundo na área, e então a partir desta primeira utilização, adquirir algum conhecimento sobre esse complexo processo. Essa foi minha intenção quando passei um fim de semana explorando Keras. Keras é uma API Tensorflow de alto nível, já que não sou um cientista de dados Keras é uma ferramenta de iniciação perfeita para entender como AI / PNL, Redes Neurais e CNNs funcionam na prática.

O código completo pode ser encontrado no seguinte github repo: TicketActivityClassifier.

Esse é outro modelo de classificação de texto, usando uma classificação de rede neural fazendo coisas básicas de aprendizado de máquina como no fluxo de trabalho abaixo.

NAME

Keras Ticket Classification Model

O objetivo deste projeto é criar um modelo que seja capaz de indicar o que é a Classificação do Ingresso com base na Descrição Curta e na Categoria do Ingresso.

Obter / preparar conjunto de dados -> Word vectors e embedding layers -> Criação de modelo -> Avaliação e persistência de modelo -> Previsão do conjunto de dados

Get/Prepare dataset

Primeiro, usando Pandas lemos o arquivo de entrada CSV e o convertemos em um DataFrame Pandas .Também usando o Pandas, removemos os valores nulos que são entradas obrigatórias para o treinamento do modelo usando o método ‘dropna’.

 99
100
101
102
103
104
105
    def load_prepare_dataset(self, dataset, *args, **kwargs):
        """
        loading dataset from csv and removal of null keys which are mandatory for training:
            TicketShortDesc and Activity
        """
        logging.info("Preparing to read csv dataset: " + str(dataset))
        data = pd.read_csv(os.path.join(myapp_config.DATASETS_PATH, dataset), dtype=str)

Also using Pandas we remove null values which are mandatory inputs for model training using ‘dropna’ method.

106
107
108
109
110
111
        drop_if_na = ["ShortDescription", "Activity"]
        for i in range(0, len(drop_if_na)):
            logging.info("Removing nulls from column " + str(drop_if_na[i]))
            data.dropna(subset=[drop_if_na[i]], inplace=True)

        return data

Word vectors and embedding layers

Precisamos representar o texto com valores numéricos porque é o que o formato de que input esperado pelos modelos de Machine Learning. Keras Tokenizer é usado para converter texto em valores inteiros. O tokenizer atribuirá um número inteiro às 10.000 (input_words) palavras usadas com mais frequência.

 99
100
101
102
103
104
105
106
107
       X_train, X_test, Y_train, Y_test, Z_train, Z_test = train_test_split(
            data["ShortDescription"], data["Category"], data["Activity"], test_size=0.15        )
        # define Tokenizer with Vocab Sizes
        vocab_size = 10000
        tokenizer = Tokenizer(num_words=vocab_size)
        tokenizer2 = Tokenizer(num_words=vocab_size)

        tokenizer.fit_on_texts(X_train)
        tokenizer2.fit_on_texts(Y_train)

116
117
118
119
120
        x_train = tokenizer.texts_to_matrix(X_train, mode="tfidf")
        x_test = tokenizer.texts_to_matrix(X_test, mode="tfidf")

        y_train = tokenizer2.texts_to_matrix(Y_train, mode="tfidf")
        y_test = tokenizer2.texts_to_matrix(Y_test, mode="tfidf")

I use Keras Tokenizer to convert text into integer values. Tokenizer will assign a integer to the 10000 (input_words) most frequently used words.

116
117
118
119
120
121
122
        # Create classes file
        encoder = LabelBinarizer()
        encoder.fit(Z_train)
        text_labels = encoder.classes_
        with open(os.path.join(myapp_config.OUTPUT_PATH, "classes.txt"), "w") as f:
            for item in text_labels:
                f.write("%s\n" % item)
116
117
118
119
        z_train = encoder.transform(Z_train)
        z_test = encoder.transform(Z_test)
        num_classes = len(text_labels)
        logging.info("Numbers of classes found: " + str(num_classes))

Model creation

O modelo está usando ReLU como função de ativação no Input Layer do modelo, no Output Layer a função softmax é usada como função de ativação, Softmax estende os recursos de regressão logística para problemas de multiclasses, atribuindo probabilidades decimais para cada categoria.

O modelo tem duas entradas: Descrição e Categoria. Categorial crossentropy é a função de Loss usada para nosso problema de classificação multiclasse, que mede o desempenho do modelo de classificação. A otimização Adam é usada como Otimizador.

 99
100
101
102
103
        # Model creation and summarization
        batch_size = 100
        input1 = Input(shape=(vocab_size1,), name="main_input")
        x1 = Dense(512, activation="relu")(input1)
        x1 = Dropout(0.5)(x1)
 99
100
101
102
103
104
105
        input2 = Input(shape=(vocab_size2,), name="cat_input")
        main_output = Dense(num_classes, activation="softmax", name="main_output")(x1)
        model = Model(inputs=[input1, input2], outputs=[main_output])
        model.compile(
            loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"]
        )
        model.summary()

Model evaluation and persistence

177
178
179
180
181
182
183
184
185
       # Model Evaluation
        history = model.fit(
            [x_train, y_train],
            z_train,
            batch_size=batch_size,
            epochs=10,
            verbose=1,
            validation_split=0.10,
        )

177
178
179
180
181
182
        score = model.evaluate(
            [x_test, y_test], z_test, batch_size=batch_size, verbose=1
        )

        logging.info("Test accuracy:", str(score[1]))
        self.accuracy = score[1]

177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
        # serialize model to JSON
        model_json = model.to_json()
        with open(
            os.path.join(
                myapp_config.OUTPUT_PATH, "model_" + myapp_config.MODEL_NAME + ".json"
            ),
            "w",
        ) as json_file:
            json_file.write(model_json)
        # creates a HDF5 file 'my_model.h5'
        model.save(
            os.path.join(
                myapp_config.OUTPUT_PATH, "model_" + myapp_config.MODEL_NAME + ".h5"
            )
        )

177
178
179
180
181
182
183
184
185
        # Save Tokenizer i.e. Vocabulary
        with open(
            os.path.join(
                myapp_config.OUTPUT_PATH,
                "tokenizer" + myapp_config.MODEL_NAME + ".pickle",
            ),
            "wb",
        ) as handle:
            pickle.dump(tokenizer, handle, protocol=pickle.HIGHEST_PROTOCOL)

Dataset Prediction

200
201
202
203
204
205
206
207
        # ShortDescriptions
        x_pred = self._tokenizer.texts_to_matrix(short_description, mode="tfidf")
        # Categorias
        y_pred = self._tokenizer.texts_to_matrix(category, mode="tfidf")

        model_predictions = self._model.predict(
            {"main_input": x_pred, "cat_input": y_pred}
        )
200
201
202
        logging.info("Running Individual Ticket Prediction")
        sorting = (-model_predictions).argsort()
        sorted_ = sorting[0][:5]

200
201
202
203
204
205
206
207
208
209
210
        for value in sorted_:
            predicted_label = self.labels[value]
            # just some rounding steps
            prob = (model_predictions[0][value]) * 100
            prob = "%.2f" % round(prob, 2)
            top5_pred_probs.append([prob, predicted_label])
        output = {
            "short_description": short_description[0],
            "category": category[0],
            "top5_pred_probs": top5_pred_probs,
        }

200
201
202
        with open(
            os.path.join(myapp_config.OUTPUT_PATH, "activity_predict_output.json"), "w"
        ) as fp:

SYNOPSIS

Creating the Model

1
2
3
4
5
6
from TicketClassifierModel import TicketClassifierModel

ticket_model = TicketClassifierModel(training_dataset='TicketTrainingData.csv',
                                    testing_dataset='TicketTestingData.csv',
                                    recreate_model=True)
ticket_model.evaluate_model(testing_dataset=testing_dataset)

Making Predictions

1
2
3
4
5
6
7
from ActivityClassify import TicketActivityPredict
classifier = TicketActivityPredict()
# Return top 5 prediction scores 
prediction = classifier.predict_text(ShortDescription='Unlock of an Active Directory Admin or Server Account account or account',
                        Category='Account Update Account Administration')
print(prediction)
#{'short_description': 'Unlock of an Active Directory Admin or Server Account account or account', 'category': 'Account Update Account Administration', 'top5_pred_probs': [['87.09', 'AD User Isse'], ['12.90', 'Password reset'], ['0.00', 'Application Access'], ['0.00', 'Script Execution'], ['0.00', 'DB Connection']]})

For more information about Keras Text classification I recommend the following links.

  • https://realpython.com/python-keras-text-classification/
  • https://keras.io/examples/structured_data/structured_data_classification_from_scratch/
  • Feature 1 image source: https://semiengineering.com/deep-learning-spreads/