slim 搭建rnn_RNN入门(三)利用LSTM生成旅游点评
介紹
前幾天,某個(gè)公眾號發(fā)文質(zhì)疑馬蜂窩網(wǎng)站,認(rèn)為它搬運(yùn)其它網(wǎng)站的旅游點(diǎn)評,對此,馬蜂窩網(wǎng)站迅速地做出了回應(yīng)。相信大多數(shù)關(guān)注時(shí)事的群眾已經(jīng)了解了整個(gè)事情的經(jīng)過,在這里,我們且不論這件事的是是非非,也不關(guān)心它是否是通過爬蟲等其他技術(shù)手段實(shí)現(xiàn)的。本文將會展示一種自動(dòng)生成旅游點(diǎn)評的技術(shù)手段。我們用到的模型為LSTM模型。
LSTM模型是深度學(xué)習(xí)中一種重要的模型,全稱為Long Short-Term Memory,中文譯為長短期記憶網(wǎng)絡(luò),是RNN家族中的重要成員,它模擬了人的大腦,具有一定的記憶功能,適合于處理和預(yù)測時(shí)間序列中間隔和延遲相對較長的重要事件,在翻譯語言、控制機(jī)器人、圖像分析、文檔摘要、語音識別圖像識別、手寫識別、控制聊天機(jī)器人、預(yù)測疾病、點(diǎn)擊率和股票、合成音樂等方面有較多應(yīng)用。
在本文中,你將會看到LSTM在自動(dòng)生成文字(在這里就是旅游點(diǎn)評)方面的應(yīng)用,如果你感到好奇的話,請繼續(xù)閱讀~
獲取數(shù)據(jù)集
第一步,就是獲取數(shù)據(jù)集,我們利用Python爬蟲來實(shí)現(xiàn)。我們需要爬取的旅游評論來自于攜程網(wǎng)站上的旅游評論,在本文中,我們以杭州西湖景點(diǎn)的旅游評論為例,頁面如下:
我們爬取這些評論中的第1至10頁,采用concurrent.futures模塊實(shí)現(xiàn)并發(fā)爬取。完整的Python代碼如下:
import requests
import pandas as pd
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
# 評論列表
comments = []
# 提取評論,傳入?yún)?shù)為網(wǎng)址url
def get_comment(url):
global comments
try:
# 發(fā)送HTTP請求
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'}
r = requests.get(url=url, headers=headers)
# 解析網(wǎng)頁,定位到評論部分
soup = BeautifulSoup(r.text, 'lxml')
main_content = soup.find_all('div', class_='comment_single')
# 提取評論
for para in main_content:
comment = para.find('span', class_='heightbox')
#print(comment.text)
comments.append(comment.text.replace('"', ''))
except Exception as err:
print(err)
def main():
# 請求網(wǎng)址
urls = ["http://you.ctrip.com/sight/hangzhou14/49894-dianping-p%d.html"%x for x in range(1,11)]
urls[0] = urls[0].replace('-p1', '')
# 利用多線程爬取景點(diǎn)評論
executor = ThreadPoolExecutor(max_workers=10) # 可以自己調(diào)整max_workers,即線程的個(gè)數(shù)
# submit()的參數(shù): 第一個(gè)為函數(shù), 之后為該函數(shù)的傳入?yún)?shù),允許有多個(gè)
future_tasks = [executor.submit(get_comment, url) for url in urls]
# 等待所有的線程完成,才進(jìn)入后續(xù)的執(zhí)行
wait(future_tasks, return_when=ALL_COMPLETED)
# 創(chuàng)建DataFrame并保存到csv文件
comments_table = pd.DataFrame({'id': range(1, len(comments)+1),
'comments': comments})
print(comments_table)
comments_table.to_csv(r"E://LSTM/hangzhou.csv", index=False)
main()
運(yùn)行完該代碼,就會得到hangzhou.csv文件,在這個(gè)文件中,我們需要把旅游評論中的文字做一些修改,比如去掉特殊字符,添加掉電,去掉換行,修改個(gè)別錯(cuò)別字等。修改完后的csv文件(部分)如下:
得到該csv文件后,我們需要將這些評論(只包含評論)轉(zhuǎn)移到txt文件,以便后續(xù)的操作,利用下面的Python
代碼即可完成:
import pandas as pd
# 讀取csv文件
df = pd.read_csv('E://LSTM/hangzhou.csv')['comments']
# 將pandas中的評論修改后,寫入txt文件
for item in df:
comments = item.replace('\n','').replace('"','') \
.replace(r' ', '').replace(r'#', '').replace(r'&','') \
.replace(r'<', '《').replace(r'>', '》') \
.replace(r'↑', '').replace(r'[', '').replace(r']', '') \
.replace(r'?', '')
with open('E://LSTM/comments.txt', 'a', encoding='utf-8') as f:
f.write(comments)
f.write('\n')
#print(comments)
txt文件部分如下:
該txt文件一共含有41412個(gè)文字。我們將會以這些評論為數(shù)據(jù)集,在此基礎(chǔ)上利用Keras建立LSTM模型,訓(xùn)練完模型后,能自動(dòng)生成其他的旅游點(diǎn)評。
LSTM模型
Keras是一個(gè)高級的神經(jīng)網(wǎng)絡(luò)API,利用它能夠輕松地搭建一些復(fù)雜的神經(jīng)網(wǎng)絡(luò)模型,是一個(gè)不錯(cuò)的深度學(xué)習(xí)框架。對于剛才得到的旅游點(diǎn)評,為了能夠生成其他的旅游點(diǎn)評(人類可讀),我們將會用到LSTM模型,之所以使用這個(gè)模型,是因?yàn)長STM具有長短時(shí)記憶功能,能夠很好地處理文本中的文字之間的聯(lián)系,而不是將文字看成是獨(dú)立的個(gè)體。
在搭建LSTM模型之前,我們需要做一些準(zhǔn)備工作。首先我們需要將每個(gè)文字對應(yīng)到一個(gè)數(shù)字,該模型的輸入特征向量為前10個(gè)文字對應(yīng)的數(shù)字組成的向量,目標(biāo)變量為該10個(gè)文字的下一個(gè)文字對應(yīng)的數(shù)字。該txt文件中一共有1949個(gè)文字(包括漢子和標(biāo)點(diǎn)符號),按照我們的處理模式,共有41402個(gè)樣本,將這些樣本傳入到LSTM模型中。我們建立的模型很簡單,先是一個(gè)LSTM層,利用含有256個(gè)LSTM結(jié)構(gòu),然后是一個(gè)Dropout層,能有效防止模型發(fā)生過擬合,最后是Softmax層,將它轉(zhuǎn)化為多分類的問題,采用交叉熵作為模型的損失函數(shù)。
訓(xùn)練模型的Python代碼如下:
# 搭建簡單的LSTM模型用于生成旅游評論
import numpy
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import LSTM
from keras.callbacks import ModelCheckpoint
from keras.utils import np_utils
# 讀取txt文件
filename = "E://LSTM/comments.txt"
with open(filename, 'r', encoding='utf-8') as f:
raw_text = f.read().lower()
# 創(chuàng)建文字和對應(yīng)數(shù)字的字典
chars = sorted(list(set(raw_text)))
#print(chars)
char_to_int = dict((c, i) for i, c in enumerate(chars))
int_to_char = dict((i, c) for i, c in enumerate(chars))
# 對加載數(shù)據(jù)做總結(jié)
n_chars = len(raw_text)
n_vocab = len(chars)
print("總的文字?jǐn)?shù): ", n_chars)
print("總的文字類別: ", n_vocab)
# 解析數(shù)據(jù)集,轉(zhuǎn)化為輸入向量和輸出向量
seq_length = 10
dataX = []
dataY = []
for i in range(0, n_chars-seq_length, 1):
seq_in = raw_text[i:i + seq_length]
seq_out = raw_text[i + seq_length]
dataX.append([char_to_int[char] for char in seq_in])
dataY.append(char_to_int[seq_out])
n_patterns = len(dataX)
print("Total Patterns: ", n_patterns)
# 將X重新轉(zhuǎn)化為[samples, time steps, features]的形狀
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))
# 正則化
X = X/n_vocab
# 對輸出變量做one-hot編碼
y = np_utils.to_categorical(dataY)
# 定義LSTM模型
model = Sequential()
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2])))
model.add(Dropout(0.2))
model.add(Dense(y.shape[1], activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
#print(model.summary())
# 定義checkpoint
filepath="E://LSTM/weights-improvement-{epoch:02d}-{loss:.4f}.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='loss', verbose=1, save_best_only=True, mode='min')
callbacks_list = [checkpoint]
# 訓(xùn)練模型,每批訓(xùn)練128個(gè)樣本,總共訓(xùn)練1000次
epochs = 1000
model.fit(X, y, epochs=epochs, batch_size=128, callbacks=callbacks_list)
首先讓我們看一下模型的結(jié)構(gòu)及參數(shù)情況, 使用代碼中的print(model.summary())即可,輸出如下:
Layer (type) Output Shape Param #
=================================================================
lstm_1 (LSTM) (None, 256) 264192
_________________________________________________________________
dropout_1 (Dropout) (None, 256) 0
_________________________________________________________________
dense_1 (Dense) (None, 1949) 500893
=================================================================
Total params: 765,085
Trainable params: 765,085
Non-trainable params: 0
_________________________________________________________________
雖然是一個(gè)很簡單的LSTM模型,但也有76萬多個(gè)參數(shù),深度學(xué)習(xí)的參數(shù)的個(gè)數(shù)可見一斑~
運(yùn)行代碼,訓(xùn)練該模型,在訓(xùn)練了漫長的4,5個(gè)小時(shí)后,在613次的時(shí)候,損失值為0.3040,我們就以這個(gè)文件作為模型訓(xùn)練的結(jié)果,而不是1000次,因?yàn)?000次太費(fèi)時(shí)了。文件如下:
請注意刪除沒用的文件,因?yàn)檫@些生成的文件都很大。
生成旅游點(diǎn)評
好不容易訓(xùn)練完模型后,下一步,我們將要利用這個(gè)模型來生成旅游點(diǎn)評。怎么樣,是不是有點(diǎn)期待?生成旅游點(diǎn)評的完整Python如下(我們以輸入的句子“杭州西湖天下聞名,西”為例,請注意,每次輸入正好10個(gè)文字,因?yàn)槟P陀?xùn)練的輸入向量為含10個(gè)元素的向量):
# 搭建簡單的LSTM模型用于生成旅游評論
import numpy
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import LSTM
from keras.callbacks import ModelCheckpoint
from keras.utils import np_utils
# 讀取txt文件
filename = "E://LSTM/comments.txt"
with open(filename, 'r', encoding='utf-8') as f:
raw_text = f.read().lower()
# 創(chuàng)建文字和對應(yīng)數(shù)字的字典
chars = sorted(list(set(raw_text)))
#print(chars)
char_to_int = dict((c, i) for i, c in enumerate(chars))
int_to_char = dict((i, c) for i, c in enumerate(chars))
# 對加載數(shù)據(jù)做總結(jié)
n_chars = len(raw_text)
n_vocab = len(chars)
print("總的文字?jǐn)?shù): ", n_chars)
print("總的文字類別: ", n_vocab)
# 解析數(shù)據(jù)集,轉(zhuǎn)化為輸入向量和輸出向量
seq_length = 10
dataX = []
dataY = []
for i in range(0, n_chars-seq_length, 1):
seq_in = raw_text[i:i + seq_length]
seq_out = raw_text[i + seq_length]
dataX.append([char_to_int[char] for char in seq_in])
dataY.append(char_to_int[seq_out])
n_patterns = len(dataX)
print("Total Patterns: ", n_patterns)
# 將X重新轉(zhuǎn)化為[samples, time steps, features]的形狀
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))
# 正則化
X = X/n_vocab
# 對輸出變量做one-hot編碼
y = np_utils.to_categorical(dataY)
# 定義LSTM模型
model = Sequential()
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2])))
model.add(Dropout(0.2))
model.add(Dense(y.shape[1], activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
# 導(dǎo)入訓(xùn)練完后的文件
filename = "E://LSTM/weights-improvement-613-0.3040.hdf5"
model.load_weights(filename)
# 示例的輸入句子
input = '杭州西湖天下聞名,西'
pattern = [char_to_int[value] for value in input]
print("輸入:")
print(''.join([int_to_char[value] for value in pattern]))
print("輸出:")
# 生成1000個(gè)文字
for i in range(1000):
x = numpy.reshape(pattern, (1, len(pattern), 1))
x = x / float(n_vocab)
prediction = model.predict(x, verbose=0)
index = numpy.argmax(prediction)
result = int_to_char[index]
print(result, end='')
seq_in = [int_to_char[value] for value in pattern]
pattern.append(index)
pattern = pattern[1:len(pattern)]
print("\n生成完畢。")
運(yùn)行該代碼,就能看到生成的文字如下:
輸入:
杭州西湖天下聞名,西
輸出:
湖一年四季特色紛呈,西湖有湖光山色交相輝應(yīng),既可看湖又可看山,西湖上的橋也是兼具南北特色,長橋不長,斷橋不斷。
西湖古跡遍布,山水秀麗,景色宜人,西湖處處有勝景。最著名的西湖十景,西湖十景”是指浙江省杭州市著名旅游景點(diǎn)西湖上的十處特色風(fēng)景,分別是蘇堤春曉、曲苑風(fēng)荷、平湖秋月、斷橋殘雪、柳浪聞鶯、花港觀魚、雷峰夕照、雙峰插云、南屏晚鐘、三潭印月等十個(gè)景點(diǎn)是杭州游覽的熱點(diǎn),不用按照目前的時(shí)髦話說什么“非看不可”、“非去不可”,但是,如果去了杭州不看這些景點(diǎn),不看這些景點(diǎn)的碑刻,就有點(diǎn)可惜了,特別是有康熙爺、乾隆爺?shù)挠H筆題詞,不去看看,多少會對老祖宗的“大不敬”。
如果天氣晴朗下午五點(diǎn)以后去西湖,如果拍視頻你就會拍到天藍(lán)藍(lán)水藍(lán)藍(lán)的西湖和夕陽西下漸黃昏的完美,西湖邊上有小凳子可以坐下來靜靜的欣賞西湖美景也可和同行的伙伴聊聊接下來的行程,目的是等待晚上更值得期待的音樂噴泉,得早早坐下來否則就看不到了,看噴泉不允許站著凳子坐滿其余人站凳子后面。
西湖游船是游西湖必不可少的。另外早晨可以早點(diǎn)去,人少,而且涼爽?;ǜ塾^魚的景色也是不錯(cuò)。雷峰塔就看你需求了,可以俯瞰整個(gè)西湖(其實(shí)去雷峰塔也是為了看西湖吧,雷峰塔本身貌似沒什么看的)吃飯的話,別在景區(qū)吃,強(qiáng)烈推薦去弄堂里。好吃又便宜。
8月份出差路過杭州,可以輕松的偷閑半天,順便預(yù)約了離西湖比較近便的酒店入住。8月底的清晨已經(jīng)有了絲絲的涼意,順著西湖邊開始溜達(dá)。早上人還是比較少,本地起來鍛煉的大爺大媽比較多,有蘸水在地上練字的,有在小公園練嗓子的,還有坐在長條凳上練二胡的。9點(diǎn)多點(diǎn),游客開始多了,各種游船排隊(duì)等候,暑假期間帶小孩匆匆而過的人也不少,基本都是到此一游,很少有仔細(xì)的欣賞和解說景點(diǎn)的出處。乘涼的地方還是不少,但是蚊子也多的嚇人。蘇堤的景色不錯(cuò),特別是兩邊的高樹遮擋了大多數(shù)的陽光,即使在這里溜達(dá)也不會覺得熱,如果時(shí)間允許的話,建議溜達(dá)過去,步行約30分鐘左右,南邊的出口還有蘇東坡博物館,比較小,免費(fèi)開放。
西湖的范圍蠻大的,從北山路(北山路上的老建筑,浙江博物館,斷橋殘雪,錦帶橋,保俶塔,樓外樓,孤山,西冷印社,平湖秋月等。)到南線景區(qū)(南山路,西湖天地,御碼頭,錢王祠,柳浪聞鶯,萬松書院,長橋,南屏晚鐘,凈慈寺,雷鋒塔太子灣等)以及三堤,外西湖,西里湖等,小南湖,小瀛洲,從白堤_蘇堤_曲院風(fēng)荷_楊公堤_鵒鴣灣_茅家埠。飛來峰景
生成完畢。
讓我們來看一下這段生成的文字,首先,這段文字的可讀性還是很高的,基本上人類能夠理解,其次,與原文相對比,這段文字并不是一味地抄襲原文,而是有選擇地將原文件中的旅游點(diǎn)評組合起來,雖然每部分的旅游點(diǎn)評與原先的相差不多,但重新組合后,是能夠生成新的旅游點(diǎn)評的,并不算真正意義上的抄襲。
用LSTM訓(xùn)練出來的模型生成的文本,是能夠作為新的旅游點(diǎn)評的,并不是完全的抄襲,但是對于未在原文中出現(xiàn)的輸入向量,可能訓(xùn)練出來的效果就不會太理想,這是需要改進(jìn)的地方。
總結(jié)
本文純屬自娛自樂,如果不當(dāng)之處,還望大家批評指正~~
當(dāng)然,對于該項(xiàng)目,還有一些值得改進(jìn)的地方,比如數(shù)據(jù)集不夠大,這個(gè)可以爬取更多的評論;數(shù)據(jù)預(yù)處理過于簡單,僅僅做了文字與向量的一一對應(yīng)以及輸入向量的正則化;模型過于簡單,讀者可以嘗試搭建多個(gè)LSTM層或其他結(jié)構(gòu);模型訓(xùn)練過于耗時(shí),可以嘗試GPU或改進(jìn)模型結(jié)構(gòu)或數(shù)據(jù)預(yù)處理方式,等等等等。希望讀者在閱讀完本文后,能對LSTM模型在文字生成方面有一定的了解,歡迎擁抱LSTM~~
參考文獻(xiàn)
Text Generation With LSTM Recurrent Neural Networks in Python with Keras: https://machinelearningmaster...
注意:本人現(xiàn)已開通微信公眾號: Python爬蟲與算法(微信號為:easy_web_scrape), 歡迎大家關(guān)注哦~~
總結(jié)
以上是生活随笔為你收集整理的slim 搭建rnn_RNN入门(三)利用LSTM生成旅游点评的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 模电学习02:晶体三极管
- 下一篇: win10自带看图工具不见,修改注册表就