日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

利用 TensorFlow 实现上下文的 Chat-bots

發(fā)布時間:2025/3/21 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用 TensorFlow 实现上下文的 Chat-bots 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在我們的日常聊天中,情景才是最重要的。我們將使用 TensorFlow 構(gòu)建一個聊天機(jī)器人框架,并且添加一些上下文處理機(jī)制來使得機(jī)器人更加智能。


“Whole World in your Hand”?—?Betty Newman-Maguire (http://www.bettynewmanmaguire.ie/)

你是否想過一個問題,為什么那么多的聊天機(jī)器人會缺乏會話情景功能?

鑒于上下文在所有的對話場景中的重要性,那么又該如何加入這個特性?

接下來,我們將創(chuàng)建一個聊天機(jī)器人的框架,并且以一個島嶼輕便摩托車租賃店為例子,建立一個對話模型。這個小企業(yè)的聊天機(jī)器人需要處理一些關(guān)于租賃時間,租賃選項(xiàng)等的簡單問題。我們也希望這個機(jī)器人可以處理一些上下文的信息,比如查詢同一天的租賃信息。如果可以解決這個問題,那么我們將節(jié)約很多的時間。

關(guān)于構(gòu)建聊天機(jī)器人,我們通過以下三部進(jìn)行:

  • 我們會利用 TensorFlow 來編寫對話意圖模型。
  • 接下啦,我們將構(gòu)建一個處理對話的聊天機(jī)器人框架。
  • 最后,我們將介紹如何將上下文信息合并到我們的響應(yīng)式處理器中。
  • 在模型中,我們將使用?tflearn?框架,這是一個?TensorFlow?的高層 API,并且我們將使用?IPython?作為開發(fā)工具。

    1. 我們會利用 TensorFlow 來編寫對話意圖模型。

    完整的 notebook 文檔,可以點(diǎn)擊這里。

    對于一個聊天機(jī)器人框架,我們需要定義一個會話意圖的結(jié)構(gòu)。最簡單方便的方式是使用一個 JSON 格式的文件,如下所示:


    chat-bot intents

    每個會話意圖包含:

    • 標(biāo)簽(唯一的名稱)
    • 模式(我們的神經(jīng)網(wǎng)絡(luò)文本分類器需要分類的句子)
    • 回應(yīng)(一個將被用作回應(yīng)的句子)

    稍后,我們也會添加一些基本的上下文元素。

    首先,我們來導(dǎo)入一些我們需要的包:

    # things we need for NLP import nltk from nltk.stem.lancaster import LancasterStemmer stemmer = LancasterStemmer()# things we need for Tensorflow import numpy as np import tflearn import tensorflow as tf import random

    如果你還不了解 TensorFlow,那么可以學(xué)習(xí)一下這個教程或者這個教程。

    # import our chat-bot intents file import json with open('intents.json') as json_data:intents = json.load(json_data)

    代碼中的 JSON 文件可以這里下載,接下來我們可以開始組織代碼的文件,數(shù)據(jù)和分類器。

    words = [] classes = [] documents = [] ignore_words = ['?'] # loop through each sentence in our intents patterns for intent in intents['intents']:for pattern in intent['patterns']:# tokenize each word in the sentencew = nltk.word_tokenize(pattern)# add to our words listwords.extend(w)# add to documents in our corpusdocuments.append((w, intent['tag']))# add to our classes listif intent['tag'] not in classes:classes.append(intent['tag'])# stem and lower each word and remove duplicates words = [stemmer.stem(w.lower()) for w in words if w not in ignore_words] words = sorted(list(set(words)))# remove duplicates classes = sorted(list(set(classes)))print (len(documents), "documents") print (len(classes), "classes", classes) print (len(words), "unique stemmed words", words)

    我們創(chuàng)建了一個文件列表(每個句子),每個句子都是由一些詞干組成,并且每個文檔都屬于一個特定的類別。

    27 documents 9 classes ['goodbye', 'greeting', 'hours', 'mopeds', 'opentoday', 'payments', 'rental', 'thanks', 'today'] 44 unique stemmed words ["'d", 'a', 'ar', 'bye', 'can', 'card', 'cash', 'credit', 'day', 'do', 'doe', 'good', 'goodby', 'hav', 'hello', 'help', 'hi', 'hour', 'how', 'i', 'is', 'kind', 'lat', 'lik', 'mastercard', 'mop', 'of', 'on', 'op', 'rent', 'see', 'tak', 'thank', 'that', 'ther', 'thi', 'to', 'today', 'we', 'what', 'when', 'which', 'work', 'you']

    比如,詞干?tak?將和?take,taking,takers?等匹配。在實(shí)際過程中,我們可以刪除一些無用的條目,但在這里已經(jīng)足夠了。

    不幸的是,這種數(shù)據(jù)結(jié)構(gòu)不能在 TensorFlow 中使用,我們需要進(jìn)一步將這個數(shù)據(jù)進(jìn)行轉(zhuǎn)換:從單詞轉(zhuǎn)換到數(shù)字的張量。

    # create our training data training = [] output = [] # create an empty array for our output output_empty = [0] * len(classes)# training set, bag of words for each sentence for doc in documents:# initialize our bag of wordsbag = []# list of tokenized words for the patternpattern_words = doc[0]# stem each wordpattern_words = [stemmer.stem(word.lower()) for word in pattern_words]# create our bag of words arrayfor w in words:bag.append(1) if w in pattern_words else bag.append(0)# output is a '0' for each tag and '1' for current tagoutput_row = list(output_empty)output_row[classes.index(doc[1])] = 1training.append([bag, output_row])# shuffle our features and turn into np.array random.shuffle(training) training = np.array(training)# create train and test lists train_x = list(training[:,0]) train_y = list(training[:,1])

    請注意,我們的數(shù)據(jù)順序已經(jīng)被打亂了。 TensorFlow 會選取其中的一些數(shù)據(jù)作為測試數(shù)據(jù),用來測試訓(xùn)練的模型的準(zhǔn)確度。

    如果我們觀察單個的?x?向量和?y?向量,那么這就是一個詞袋模型,一個表示需要匹配的模式,一個表示匹配的目標(biāo)。

    train_x example: [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, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1] train_y example: [0, 0, 1, 0, 0, 0, 0, 0, 0]

    接下來,我們來構(gòu)建我們的模型。

    # reset underlying graph data tf.reset_default_graph() # Build neural network net = tflearn.input_data(shape=[None, len(train_x[0])]) net = tflearn.fully_connected(net, 8) net = tflearn.fully_connected(net, 8) net = tflearn.fully_connected(net, len(train_y[0]), activation='softmax') net = tflearn.regression(net)# Define model and setup tensorboard model = tflearn.DNN(net, tensorboard_dir='tflearn_logs') # Start training (apply gradient descent algorithm) model.fit(train_x, train_y, n_epoch=1000, batch_size=8, show_metric=True) model.save('model.tflearn')

    這個模型使用的是 2 層神經(jīng)網(wǎng)絡(luò)模型,跟這篇文章中的是一樣的。


    interactive build of a model in tflearn

    我們完成了這部分的工作,現(xiàn)在需要保存我們的模型和文檔, 以便在后續(xù)的代碼中可以使用它們。

    # save all of our data structures import pickle pickle.dump( {'words':words, 'classes':classes, 'train_x':train_x, 'train_y':train_y}, open( "training_data", "wb" ) )

    構(gòu)建我們的聊天機(jī)器人框架

    這部分,完整的代碼在這里。

    我們將構(gòu)建一個簡單的狀態(tài)機(jī)來處理響應(yīng),并且使用我們的在上一部分中提到的意圖模型來作為我們的分類器。如果你想了解聊天機(jī)器人的工作原理,那么可以點(diǎn)擊這里。


    我們需要導(dǎo)入和上一部分相同的包,然后?un-pickle?我們的模型和句子,正如我們在上一部分中操作的。請記住,我們的聊天機(jī)器人框架與我們的模型是分開構(gòu)建的 —— 除非意圖模式改變了,那么我們需要重新運(yùn)行我們的模型,否則不需要重構(gòu)模型。如果擁有數(shù)百種意圖和數(shù)千種模式,模型可能需要幾分鐘的時間才能構(gòu)建完成。

    # restore all of our data structures import pickle data = pickle.load( open( "training_data", "rb" ) ) words = data['words'] classes = data['classes'] train_x = data['train_x'] train_y = data['train_y']# import our chat-bot intents file import json with open('intents.json') as json_data:intents = json.load(json_data)

    接下來,我們需要導(dǎo)入剛剛利用 TensorFlow(tflearn 框架)訓(xùn)練好的模型。請注意,你第一步還是需要去定義 TensorFlow 模型結(jié)構(gòu),正如我們在第一部分中做的那樣。

    # load our saved model model.load('./model.tflearn')

    在我們開始處理對話意圖之前,我們需要一種從用戶輸入數(shù)據(jù)生詞詞袋的方法。而這個方法,跟我們前面所使用的方法是相同的。

    def clean_up_sentence(sentence):# tokenize the patternsentence_words = nltk.word_tokenize(sentence)# stem each wordsentence_words = [stemmer.stem(word.lower()) for word in sentence_words]return sentence_words# return bag of words array: 0 or 1 for each word in the bag that exists in the sentence def bow(sentence, words, show_details=False):# tokenize the patternsentence_words = clean_up_sentence(sentence)# bag of wordsbag = [0]*len(words) for s in sentence_words:for i,w in enumerate(words):if w == s: bag[i] = 1if show_details:print ("found in bag: %s" % w)return(np.array(bag)) p = bow("is your shop open today?", words) print (p) [0 0 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 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0]

    現(xiàn)在,我們可以開始構(gòu)建我們的響應(yīng)處理器了。

    ERROR_THRESHOLD = 0.25 def classify(sentence):# generate probabilities from the modelresults = model.predict([bow(sentence, words)])[0]# filter out predictions below a thresholdresults = [[i,r] for i,r in enumerate(results) if r>ERROR_THRESHOLD]# sort by strength of probabilityresults.sort(key=lambda x: x[1], reverse=True)return_list = []for r in results:return_list.append((classes[r[0]], r[1]))# return tuple of intent and probabilityreturn return_listdef response(sentence, userID='123', show_details=False):results = classify(sentence)# if we have a classification then find the matching intent tagif results:# loop as long as there are matches to processwhile results:for i in intents['intents']:# find a tag matching the first resultif i['tag'] == results[0][0]:# a random response from the intentreturn print(random.choice(i['responses']))results.pop(0)

    傳遞給?response()?的每個句子都會被分類。我們分類器使用?model.predict()?函數(shù)來進(jìn)行類別預(yù)測,這個方法非常快。模型返回的概率值和我們定義的意圖是一直的,用來生成潛在的響應(yīng)列表。

    如果一個或多個分類結(jié)果高于閾值,那么我們會選取出一個與意圖匹配的標(biāo)簽,然后處理。我們將我們的分類列表作為一個堆棧,并從這個堆棧中尋找一個適合的匹配,直到找到一個最好的或者直到堆棧變空。

    我們來舉一個例子,模型會返回最有可能的標(biāo)簽和其概率。

    classify('is your shop open today?') [('opentoday', 0.9264171123504639)]

    請注意,“is your shop open today?” 不是這個意圖中的任何模式:“pattern : ["Are you open today?", "When do you open today?", "What are your hours today?"]”。但是,“open” 和 “today” 術(shù)語對我們的模式是非常有用的(他們在選擇意圖時,有決定性的作用)。

    我們現(xiàn)在從用戶的輸入數(shù)據(jù)中產(chǎn)生一個結(jié)果:

    response('is your shop open today?') Our hours are 9am-9pm every day

    再來一些例子:

    response('do you take cash?') We accept VISA, Mastercard and AMEXresponse('what kind of mopeds do you rent?') We rent Yamaha, Piaggio and Vespa mopedsresponse('Goodbye, see you later') Bye! Come back again soon.

    接下來讓我們結(jié)合一些基礎(chǔ)的語境來設(shè)計(jì)一個聊天機(jī)器人,比如拖車租賃聊天機(jī)器人。

    語境

    我們想處理的是一個關(guān)于租賃摩托車的問題,并詢問一些有關(guān)租金的事。對于用戶問題的理解應(yīng)該是非常容易的,語境非常清晰。如果用戶詢問 “today”,那么上下文的租賃信息就是進(jìn)入時間框架,那么最好你還能指定是哪一個自行車,這樣交流起來就不會浪費(fèi)時間。

    為了實(shí)現(xiàn)這一點(diǎn),我們需要在框架中再加入一個概念 “state” 。這需要一個數(shù)據(jù)結(jié)構(gòu)來維護(hù)這個新的概念和原來的意圖。

    因?yàn)槲覀冃枰覀兊臓顟B(tài)機(jī)是一個非常容易的維護(hù),恢復(fù)和復(fù)制等等操作,所以我們需要把數(shù)據(jù)都保存在一個諸如字典的數(shù)據(jù)結(jié)構(gòu)中,這是非常重要的。

    接下來,我們給出基本語境的回復(fù)過程:

    # create a data structure to hold user context context = {}ERROR_THRESHOLD = 0.25 def classify(sentence):# generate probabilities from the modelresults = model.predict([bow(sentence, words)])[0]# filter out predictions below a thresholdresults = [[i,r] for i,r in enumerate(results) if r>ERROR_THRESHOLD]# sort by strength of probabilityresults.sort(key=lambda x: x[1], reverse=True)return_list = []for r in results:return_list.append((classes[r[0]], r[1]))# return tuple of intent and probabilityreturn return_listdef response(sentence, userID='123', show_details=False):results = classify(sentence)# if we have a classification then find the matching intent tagif results:# loop as long as there are matches to processwhile results:for i in intents['intents']:# find a tag matching the first resultif i['tag'] == results[0][0]:# set context for this intent if necessaryif 'context_set' in i:if show_details: print ('context:', i['context_set'])context[userID] = i['context_set']# check if this intent is contextual and applies to this user's conversationif not 'context_filter' in i or \(userID in context and 'context_filter' in i and i['context_filter'] == context[userID]):if show_details: print ('tag:', i['tag'])# a random response from the intentreturn print(random.choice(i['responses']))results.pop(0)

    我們的上下文狀態(tài)是一個字典,它將包含每個用戶的狀態(tài)。我將為每個用戶使用一個唯一的標(biāo)識(例如,cell#)。這允許我們的框架和狀態(tài)機(jī)同事維護(hù)多個用戶的狀態(tài)。

    # create a data structure to hold user context context = {}

    我們在意圖處理流程中,添加了上下文信息,具體如下:

    if i['tag'] == results[0][0]:# set context for this intent if necessaryif 'context_set' in i:if show_details: print ('context:', i['context_set'])context[userID] = i['context_set']# check if this intent is contextual and applies to this user's conversationif not 'context_filter' in i or \(userID in context and 'context_filter' in i and i['context_filter'] == context[userID]):if show_details: print ('tag:', i['tag'])# a random response from the intentreturn print(random.choice(i['responses']))

    如果一個意圖想要設(shè)置上下文信息,那么我們可以這樣做:

    {“tag”: “rental”,“patterns”: [“Can we rent a moped?”, “I’d like to rent a moped”, … ],“responses”: [“Are you looking to rent today or later this week?”],“context_set”: “rentalday”}

    如果另一個意圖想要與上下文進(jìn)行關(guān)聯(lián),那么可以這樣做:

    {“tag”:today”,“patterns”: [“today”],“responses”: [“For rentals today please call 1800-MYMOPED”, …], “context_filter”: “rentalday”}

    以這種方法構(gòu)建的信息庫,如果用戶只是輸入 "today" 而沒有上下文信息,那么這個 “today” 的用戶意圖是不會被處理的。如果用戶輸入的 "today" 是對我們的一個時間回應(yīng),即觸動了意圖標(biāo)簽 "rental" ,那么這個意圖將會被處理。

    response('we want to rent a moped') Are you looking to rent today or later this week?response('today') Same-day rentals please call 1-800-MYMOPED

    我們上下文信息也改變了:

    context {'123': 'rentalday'}

    我們定義我們的 "greeting" 意圖用來清除上下文語境信息,這就像我們打招呼一樣,標(biāo)志著我們要開啟一個新的對話。我們還添加了 "show_details" 參數(shù),用來幫助我們看到程序里面的信息。

    response("Hi there!", show_details=True) context: '' tag: greeting Good to see you again

    讓我們再次嘗試輸入 "今天" 這個詞,一些有趣的事情就發(fā)生了。

    response('today') We're open every day from 9am-9pmclassify('today') [('today', 0.5322513580322266), ('opentoday', 0.2611265480518341)]

    首先,我們對沒有上下文信息的 "today" 的回應(yīng)是不同的。我們的分類產(chǎn)生了 2 個合適的意圖,但 "opentoday" 被選中了。所以這個隨機(jī)性就比較大,上下文信息很重要!

    response("thanks, your great") Happy to help!

    現(xiàn)在需要考慮的事情就是如何將對話放置到具體語境中了。

    狀態(tài)處理

    沒錯,你的機(jī)器人將會成為你的私人機(jī)器人了,不再是那么大眾化。除非你想要重建狀態(tài),重新加載你的模型和文檔 —— 每次調(diào)用你的機(jī)器人框架,你都會需要加載一個模型狀態(tài)。

    這不是那么困難,你可以在自己的進(jìn)程中運(yùn)行一個有狀態(tài)的聊天機(jī)器人框架,并使用 RPC(遠(yuǎn)程過程調(diào)用)或 RMI(遠(yuǎn)程方法調(diào)用)調(diào)用它,我推薦使用?Pyro

    用戶界面(客戶端)通常是無狀態(tài)的,例如:HTTP 或 SMS。

    你的聊天機(jī)器人客戶端將通過 Pyro 函數(shù)進(jìn)行調(diào)用,你的狀態(tài)服務(wù)將由它處理,是不是很贊。

    這里有一個手把手教你如何構(gòu)建一個 Twilio SMS 機(jī)器人客戶端的方法,這里是一個構(gòu)建 Facebook 機(jī)器人的方法。


    不要將狀態(tài)存儲在局部變量中

    所有狀態(tài)信息都必須放在諸如字典之類的數(shù)據(jù)結(jié)構(gòu)中,易于持久化,重新加載或者以原子狀態(tài)進(jìn)行復(fù)制。

    每個用戶的對話和上下文語境都會保存在用戶 ID 下面,這個ID必須是唯一的。

    我們會復(fù)制有些用戶的對話信息來進(jìn)行場景分析,如果這些信息被保存在臨時變量中,那么就非常難來處理,這是一個最大的考慮。


    所以,現(xiàn)在你已經(jīng)學(xué)會了如何去構(gòu)建一個聊天機(jī)器人框架,一個使它能記住上下文信息的機(jī)器人,已經(jīng)如何分析文本。未來的聊天機(jī)器人也都是能分析上下文語境的,這是一個大趨勢。

    我們聯(lián)想到意圖的構(gòu)建會影響上下文的對話反應(yīng),所以我們可以創(chuàng)建各種各樣的會話環(huán)境。

    快去動手試試吧!



    來源:Medium

    總結(jié)

    以上是生活随笔為你收集整理的利用 TensorFlow 实现上下文的 Chat-bots的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。