Created
February 7, 2021 13:04
-
-
Save bumie-e/7d8530f2b7d2acc1f7f93083b57d8d79 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import random | |
import json | |
import torch | |
import torch.nn as nn | |
from torch.utils.data import Dataset, DataLoader | |
from nltk_utils import bag_of_words, tokenize, stem | |
from model import NeuralNet | |
with open('intents.json', 'r') as f: | |
intents = json.load(f) | |
all_words = [] | |
tags = [] | |
doc = [] | |
# loop through each sentence in our intents patterns | |
for intent in intents['intents']: | |
tag = intent['tag'] | |
# add to tag list | |
tags.append(tag) | |
for pattern in intent['patterns']: | |
# tokenize each word in the sentence | |
w = tokenize(pattern) | |
# add to our words list | |
all_words.extend(w) | |
# add to xy pair | |
doc.append((w, tag)) | |
# stem and lower each word | |
ignore_words = ['?', '.', '!'] | |
all_words = [stem(w) for w in all_words if w not in ignore_words] | |
# remove duplicates and sort | |
all_words = sorted(set(all_words)) | |
tags = sorted(set(tags)) | |
print(len(doc), "patterns") | |
print(len(tags), "tags:", tags) | |
print(len(all_words), "unique stemmed words:", all_words) | |
# create training data | |
X_train = [] | |
y_train = [] | |
for (pattern_sentence, tag) in xy: | |
# X: bag of words for each pattern_sentence | |
bag = bag_of_words(pattern_sentence, all_words) | |
X_train.append(bag) | |
# y: PyTorch CrossEntropyLoss needs only class labels, not one-hot | |
label = tags.index(tag) | |
y_train.append(label) | |
X_train = np.array(X_train) | |
y_train = np.array(y_train) | |
# Hyper-parameters | |
num_epochs = 1000 | |
batch_size = 8 | |
learning_rate = 0.001 | |
input_size = len(X_train[0]) | |
hidden_size = 8 | |
output_size = len(tags) | |
print(input_size, output_size) | |
class ChatDataset(Dataset): | |
def __init__(self): | |
self.n_samples = len(X_train) | |
self.x_data = X_train | |
self.y_data = y_train | |
# support indexing such that dataset[i] can be used to get i-th sample | |
def __getitem__(self, index): | |
return self.x_data[index], self.y_data[index] | |
# we can call len(dataset) to return the size | |
def __len__(self): | |
return self.n_samples | |
dataset = ChatDataset() | |
train_loader = DataLoader(dataset=dataset, | |
batch_size=batch_size, | |
shuffle=True, | |
num_workers=0) | |
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') | |
model = NeuralNet(input_size, hidden_size, output_size).to(device) | |
# Loss and optimizer | |
criterion = nn.CrossEntropyLoss() | |
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) | |
# Train the model | |
for epoch in range(num_epochs): | |
for (words, labels) in train_loader: | |
words = words.to(device) | |
labels = labels.to(dtype=torch.long).to(device) | |
# Forward pass | |
outputs = model(words) | |
# if y would be one-hot, we must apply | |
# labels = torch.max(labels, 1)[1] | |
loss = criterion(outputs, labels) | |
# Backward and optimize | |
optimizer.zero_grad() | |
loss.backward() | |
optimizer.step() | |
if (epoch+1) % 100 == 0: | |
print (f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}') | |
print(f'final loss: {loss.item():.4f}') | |
data = { | |
"model_state": model.state_dict(), | |
"input_size": input_size, | |
"hidden_size": hidden_size, | |
"output_size": output_size, | |
"all_words": all_words, | |
"tags": tags | |
} | |
FILE = "data.pth" | |
torch.save(data, FILE) | |
print(f'training complete. file saved to {FILE}') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment