System_Dialogowy_Janet/DL_Chatbot_ver_1_0.ipynb

21 KiB
Raw Blame History

0. Instalacja i importowanie modułów

0.1. Ogólne
!pip install tflearn
!pip install tensorflow
import numpy as np
import tflearn
import tensorflow
import random
import json
import nltk
nltk.download('punkt')
from nltk.stem.lancaster import LancasterStemmer
stemmer_en = LancasterStemmer()
0.3. Polski Stemmer (Docelowy): https://pypi.org/project/pystempel/
!pip install pystempel
from stempel import StempelStemmer

stemmer_pl = StempelStemmer.default() #może wersja ".polimorf()" jest lepsza?

1. Załadowanie plików .json z bazą słów

1.1. Docelowa baza słów polskich do nauki modelu (10 rodzajów odp - PL)
with open("intents_pl.json") as file:
  data_pl = json.load(file)

print(data_pl)
{'intents': [{'tag': 'greeting', 'patterns': ['Cześć', 'Elo', 'Jesteś?', 'Hej', 'Dzień dobry', 'Sup'], 'responses': ['Cześć!', 'Dobrze Cię widzieć!', 'Hej, w czym mogę pomóc?'], 'context_set': ''}, {'tag': 'goodbye', 'patterns': ['narazie', 'Do zobaczenia', 'Dowidzenia', 'Dobranoc', 'Miłego dnia'], 'responses': ['Do zobaczenia później', 'Mam nadzieję, że później pogadamy', 'Narazie!'], 'context_set': ''}, {'tag': 'age', 'patterns': ['Ile masz lat', 'Ile lat ma Janet', 'Wiek', 'Jak stara jesteś', 'urodziny'], 'responses': ['Mam kilka dni', 'Urodziłam się 17.03.2021'], 'context_set': ''}, {'tag': 'name', 'patterns': ['Jak masz na imię', 'Jak Cię zwą?', 'twoje imie?', 'Imie', 'Jak cię nazywać', 'Kim jesteś'], 'responses': ['Możesz mnie nazywać Janet!', 'Jestem Janet', 'Jestem Janet, twój ulubiony chatbot'], 'context_set': ''}, {'tag': 'goout', 'patterns': ['Czy chcesz gdzieś wyjść?', 'zrobimy coś razem?', 'pójdziemy gdzieś razem?'], 'responses': ['Może kiedy indziej', 'Odezwę się latem'], 'context_set': ''}, {'tag': 'doing', 'patterns': ['Co robisz teraz?', 'co słychać', 'jakie masz plany?', 'jak się masz?'], 'responses': ['Gram w grę', 'Słucham muzyki', 'nie twój interes', 'nie mam czasu odpowiadać', ''], 'context_set': ''}, {'tag': 'game', 'patterns': ['a w co grasz?', 'a w co?', 'grasz?'], 'responses': ['nie interesuj się', 'a co cię to obchodzi', '...', 'w coś', 'W OSRS'], 'context_set': ''}, {'tag': 'music', 'patterns': ['czego?', 'czego słuchasz?', 'jakiej muzyki?'], 'responses': ['Starego vinyla z 1995 roku', 'mojego ulubionego setu rejwowego', 'czegoś tam...'], 'context_set': ''}, {'tag': 'angry', 'patterns': ['bo co?', 'dlaczego?', 'jak to?'], 'responses': ['Czas zakończyć rozmowę', 'nie mam na to siły i czasu', 'zostaw mnie w spokoju'], 'context_set': ''}, {'tag': 'why', 'patterns': ['o co chodzi?', 'czemu jesteś zła', 'poczekaj'], 'responses': ['...', 'Nie pisz do mnie więcej', 'Odezwę się latem'], 'context_set': ''}]}
1.2. Skrócona baza słów (4 rodzaje odp - PL)
with open("intents_pl_short.json") as file:
  data_pl_short = json.load(file)

print(data_pl_short)
{'intents': [{'tag': 'greeting', 'patterns': ['Cześć', 'Elo', 'Jesteś?', 'Hej', 'Dzień dobry', 'Sup'], 'responses': ['Cześć!', 'Dobrze Cię widzieć!', 'Hej, w czym mogę pomóc?'], 'context_set': ''}, {'tag': 'goodbye', 'patterns': ['narazie', 'Do zobaczenia', 'Dowidzenia', 'Dobranoc', 'Miłego dnia'], 'responses': ['Do zobaczenia później', 'Mam nadzieję, że później pogadamy', 'Narazie!'], 'context_set': ''}, {'tag': 'age', 'patterns': ['Ile masz lat', 'Ile lat ma Janet', 'Wiek', 'Jak stara jesteś', 'urodziny'], 'responses': ['Mam kilka dni', 'Urodziłam się 17.03.2021'], 'context_set': ''}, {'tag': 'name', 'patterns': ['Jak masz na imię', 'Jak Cię zwą?', 'twoje imie?', 'Imie', 'Jak cię nazywać', 'Kim jesteś'], 'responses': ['Możesz mnie nazywać Janet!', 'Jestem Janet', 'Jestem Janet, twój ulubiony chatbot'], 'context_set': ''}]}
1.3. Testowa baza słów angielskich (6 rodzajów odp - EN)
with open("intents_en.json") as file:
  data_en = json.load(file)

print(data_en)
{'intents': [{'tag': 'greeting', 'patterns': ['Hi', 'How are you', 'Is anyone there?', 'Hello', 'Good day', 'Whats up'], 'responses': ['Hello!', 'Good to see you again!', 'Hi there, how can I help?'], 'context_set': ''}, {'tag': 'goodbye', 'patterns': ['cya', 'See you later', 'Goodbye', 'I am Leaving', 'Have a Good day'], 'responses': ['Sad to see you go :(', 'Talk to you later', 'Goodbye!'], 'context_set': ''}, {'tag': 'age', 'patterns': ['how old', 'how old is tim', 'what is your age', 'how old are you', 'age?'], 'responses': ['I am 18 years old!', '18 years young!'], 'context_set': ''}, {'tag': 'name', 'patterns': ['what is your name', 'what should I call you', 'whats your name?'], 'responses': ['You can call me Tim.', "I'm Tim!", "I'm Tim aka Tech With Tim."], 'context_set': ''}, {'tag': 'shop', 'patterns': ['Id like to buy something', 'whats on the menu', 'what do you reccommend?', 'could i get something to eat'], 'responses': ['We sell chocolate chip cookies for $2!', 'Cookies are on the menu!'], 'context_set': ''}, {'tag': 'hours', 'patterns': ['when are you guys open', 'what are your hours', 'hours of operation'], 'responses': ['We are open 7am-4pm Monday-Friday!'], 'context_set': ''}]}

2. Przygotowanie danych do nauki modelu

words = []
labels = []
docs_x = []
docs_y = []
2.1 Stworzenie tablicy ze wszystkimi możliwymi inputami użytkownika (+ labele)
for intent in data_pl_short["intents"]: #Loop przez cały json
  for pattern in intent["patterns"]: #loop przez wszystkie możliwe rodzaje przykładowego inputu użytkownika
    wrds = nltk.word_tokenize(pattern) #Tokenizing every word
    words.extend(wrds) #Add every single tokenized word
    docs_x.append(wrds) #Add the whole tokenized sentence
    docs_y.append(intent["tag"]) #Pattern x coresponds to the tag y. Potrzebne do ustalenia relacji słowa z odpowiedzią

  if intent["tag"] not in labels:
    labels.append(intent["tag"]) #Add the tag
words = [stemmer_pl.stem(w.lower()) for w in words if w not in "?"] #stemming -> take each word and bring it to the "root" form. Only the stemmed version of the word is important to us
words = sorted(list(set(words))) #Sorting

labels = sorted(labels) #sorting

training = []
output = []

out_empty = [0 for _ in range(len(labels))]
3.2. Przypisywanie słów do danej kategorii (ie. "Cześć" do Greetings)

W przypadku data_pl_short są tylko 4 rodzaje odpowiedzi. "Cześć" które zostane przypisane do labela "greeting" będzie miało formę końcowego outputu "1000" jeżeli label "greetings" jest pierwszy do wyboru.

Warto też dodać, że sieć neuronowa nie przyjmuje teksu. To jest główny powód czemu przypisujemy słowa do kategorii

for x, doc in enumerate(docs_x): #Przejście przez wszystkie słowa
  bag =[]

  wrds = [stemmer_pl.stem(w) for w in doc] #podział wszystkich słów w danym zdaniu

  for w in words:
    if w in wrds:
      bag.append(1) #this word exist
    else:
      bag.append(0) #do not exist
    
  output_row = out_empty[:] #kopia
  output_row[labels.index(docs_y[x])] = 1

  training.append(bag) #dodajemy nowe wyrażenie zamienione na ciąg binarny
  output.append(output_row)

training = np.array(training) #Zbiór treningowy
output = np.array(output) #Zbiór outputów
len(training) #dla pl_short mamy 44 słowa
44
len(output[0]) #Które można przypisać do 4 kategorii
4

3. Model i jego ćwiczenie

training = np.array(training) #zamiana typu dla sieci neuronowej
output = np.array(output) #zamiana typu dla sieci neuronowej
3.1. Stworzenie DLN i inicjacja modelu
tensorflow.compat.v1.reset_default_graph() #Reset na wszelki wypadek (w sumie nie wiem czy to jakaś super ważna linijka kodu)

net = tflearn.input_data(shape=[None, len(training[0])]) #Input layer
net = tflearn.fully_connected(net, 8) #8 neurons for hidden layer
net = tflearn.fully_connected(net, 8) #8 neurons for hidden layer
#net = tflearn.fully_connected(net, 8) #8 neurons for hidden layer
net = tflearn.fully_connected(net, len(output[0]), activation="softmax") #len(output) neurons for output layer + Softmax jako najlepsze wyjście dla tego typu danych
net = tflearn.regression(net)

model = tflearn.DNN(net)

WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tflearn/initializations.py:165: calling TruncatedNormal.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
3.2. Trening Modelu
model.fit(training, output, n_epoch=1000, batch_size=8, show_metric=True)

#Zapis Modelu
#model.save("model.tflearn")
Training Step: 5999  | total loss: 0.46985 | time: 0.036s
| Adam | epoch: 1000 | loss: 0.46985 - acc: 0.7877 -- iter: 40/44
Training Step: 6000  | total loss: 0.47602 | time: 0.046s
| Adam | epoch: 1000 | loss: 0.47602 - acc: 0.7839 -- iter: 44/44
--

4. Input Użytkownika

4.1 Funkcja "bag_of_words(s, words)" do stemmowania twojego zdania, i przypisania mu formy binarnej
def bag_of_words(s, words):
  bag = [0 for _ in range(len(words))]

  s_words = nltk.word_tokenize(s)
  s_words = [stemmer_pl.stem(word.lower()) for word in s_words]

  for se in s_words:
    for i, w in enumerate(words):
      if w == se:
        bag[i] = 1
  return np.array(bag)
4.2 Funkcja "chat()" do rozmowy z botem
def chat():
  print("Możesz rozpocząć rozmowę z Botem! (type quit to stop)")
  while True: #Ciągła rozmowa
    inp = input("Ty: ")
    if inp.lower() == "quit": #Quit by wyjść z loopa
      break

    result = model.predict([bag_of_words(inp,words)]) #Predictowanie przy pomocy wyćwiczonego modelu
    result_index = np.argmax(result)
    tag = labels[result_index]
    
    for tg in data_pl_short["intents"]: #znalezienie poprawnego tagu do zdania
      if tg['tag'] == tag:
        responses = tg['responses']
      
    print(random.choice(responses)) #Wyprintuj losową odpowiedz z danego zbioru odpowiedzi

5. Rozmowa z botem!

chat()
Możesz rozpocząć rozmowę z Botem! (type quit to stop)
Ty: hej
Dobrze Cię widzieć!
Ty: ile masz lat?
Mam kilka dni
Ty: Kim jesteś?
Dobrze Cię widzieć!
Ty: Jak masz na imię?
Jestem Janet, twój ulubiony chatbot
Ty: Miłego Dnia
Do zobaczenia później
Ty: quit