不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)

學了python,又苦於沒有練手的項目?python的書都翻爛了,但是真正做起項目來,卻不知如何下手?莫慌,本文選了一個比較簡單入手,但又有點意思的項目,給未來的python大牛練練手。

簡單介紹一下,本項目在GitHub上有開源,我根據上面的源碼做了部分修改,使其看起來更簡單易懂。同時,代碼的規範更符合新手入門。好了,不多說,就讓我們開始吧。


不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)

準備工作:

編程工具IDE:pycharm

python版本: 3.6.0

首先新建一個py文件,命名為:ai_poem.py

PS: 以下七步的代碼直接複製到單個py文件裡面就可以直接運行。(七步成詩)為了讓讀者方便寫代碼,我把代碼都貼出來了,但是排版存在問題,我又把在pycharm的代碼排版給截圖出來。


第一步:導入相關的python包

<code>#encoding:utf-8


from gensim.models import Word2Vec # 詞向量
from random import choice
from os.path import exists
from warnings import filterwarnings
filterwarnings('ignore') # 不打印警告
import re/<code>

老規矩,一步一步來,先介紹每個包的作用。 gensim 包是自然語言處理的其中一個python包,簡單容易使用,是入門NLP算法必用的一個python包。如果你想往人工智能方向發展,這個包必須學會。random包

用來生成隨機數,或者從某個列表隨機抽取一個元素。os包,本項目只用到了對文件的操作功能。re包是用於正則表達式,做爬蟲的朋友經常會用到這個包來對數據進行清洗。warning包,是包含了程序運行警告的一些功能。

不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)

代碼排版

以上這些包,不是關鍵,學習的時候,如果不懂,可以先跳過。等理解、跑通整個程序流程後,可以一個一個包有針對性地去學習、去看文檔。


第二步:參數設定

<code>class CONF:
path = '古詩詞.txt' # 語料路徑
window = 16 # 滑窗大小
min_count = 60 # 過濾低頻字
size = 125 # 詞向量維度
topn = 14 # 生成詩詞的開放度
model_path = 'gushici.model' # 模型路徑/<code>

這裡是個人編程的習慣,我習慣把一些配置,例如:文件路徑、模型存放路徑、模型參數統一放在一個類中。當然,實際項目開發的時候,是用config 文本文件存放,不會直接寫在代碼裡,這裡為了演示方便,就寫在一起,也方便運行。

不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)

代碼排版


第三步:模型的初始化函數

<code>class Model:
def __init__(self, window, topn, model):
self.window = window
self.topn = topn
self.model = model # 詞向量模型
self.chr_dict = model.wv.index2word # 字典


"""模型初始化"""
@classmethod
def initialize(cls, config):
if exists(config.model_path):
# 模型讀取
model = Word2Vec.load(config.model_path)
else:
# 語料讀取
with open(config.path, encoding='utf-8') as f:
ls_of_ls_of_c = [list(line.strip()) for line in f]
# 模型訓練和保存
model = Word2Vec(sentences=ls_of_ls_of_c, size=config.size,
window=config.window, min_count=config.min_count)


model.save(config.model_path)
return cls(config.window, config.topn, model)/<code>

initialize() 函數和 __init__() 函數 是對象初始化和實例化,其中包括基本參數的賦值、模型的導入、模型的訓練、模型的保存、最後返回用戶一個對象。這裡作為一個類的基本操作,是屬於一個通用模板,在大多數項目中,都可以這麼去寫。大家可以翻看我之前寫的幾篇關於python項目,基本都是這個寫法,所以這個模板還是有必要記住的。

不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)

代碼排版

第四步: 古詩詞生成(類裡面的函數)

<code>class Model:
......
"""古詩詞生成"""
def poem_generator(self, title, form, author='佚名', type_name=''):
# list_of_tuples --> list_of_strings 並過濾標點符號
filter = lambda lst: [t[0] for t in lst if t[0] not in [',', '。']]
# 標題補全
if not title:
title += choice(self.chr_dict)
tmp_n = 0
for _ in range(4 - len(title)):

try:
chrs = self.model.similar_by_word(title[-1], self.topn // 2)
chrs = filter(chrs)
char = choice([c for c in chrs if c not in title])
except:
char = title[tmp_n]
tmp_n += 1
title += char
# 文本生成
seq = list(title)
for i in range(form[0]): # 多少行
for _ in range(form[1]): # 每行字數
chrs = self.model.predict_output_word(seq[-self.window:], max(self.topn, len(seq) + 1))
chrs = filter(chrs)
char = choice([c for c in chrs if c not in seq[len(title):]])
seq.append(char)
seq.append(',' if i % 2 == 0 else '。')
# 返回標題+主體
length = form[0] * (form[1] + 1)
title = '《%s》' % ''.join(seq[:-length])
poem = ''.join(seq[-length:])
if author != 'undefined':
return title + '\\n'+ "詩人:" + author + '\\n\\n' + poem
else:
return title + '\\n'+"--"+ type_name + '\\n\\n' + poem/<code>

作詩模型的最核心的算法,通過NLP算法對標題進行補全,對詩的內容進行預測。這裡的預測指的是根據用戶輸入的內容,找出古詩中相關性比較強的語料,再按照古詩詞的排版順序,依次預測每句詩的每個字。這是從五萬多首古詩裡面,程序自主學習得到的模型。

不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)

代碼排版

第五步:藏頭詩生成規則(類裡面的函數)

<code>class Model:
......
"""古詩詞生成 -- 藏頭詩"""
def poem_generator_hide_head(self, title, form, author='佚名', type_name=''):
# list_of_tuples --> list_of_strings 並過濾標點符號
filter = lambda lst: [t[0] for t in lst if t[0] not in [',', '。']]
# 標題補全
if len(title) < 4:
if not title:
title += choice(self.chr_dict)
tmp_n = 0
for _ in range(4 - len(title)):
try:
chrs = self.model.similar_by_word(title[-1], self.topn // 2)
chrs = filter(chrs)
char = choice([c for c in chrs if c not in title])
except:
char = title[tmp_n]
tmp_n+=1
title += char
# 文本生成
seq = list(title)
for i in range(form[0]): # 多少行
for _ in range(form[1]): # 每行字數
if _ == 0:
char = seq[i]
else:
chrs = self.model.predict_output_word(seq[-self.window:], max(self.topn, len(seq) + 1))
chrs = filter(chrs)
char = choice([c for c in chrs if c not in seq[len(title):]])
seq.append(char)
seq.append(',' if i % 2 == 0 else '。')
# 返回標題+主體
length = form[0] * (form[1] + 1)
title = '《%s》' % ''.join(seq[:-length])
poem = ''.join(seq[-length:])
if author != 'undefined':
return title + '\\n' + "詩人:" + author + '\\n\\n' + poem

else:
return title + '\\n' + "--" + type_name + '\\n\\n' + poem/<code>

藏頭詩,顧名思義就是把用戶輸入的內容,作為每句詩第一個字。源碼裡沒有這個模塊,這裡是我自己添加的,因為在這個項目發佈後,有不少網友要求能生成藏頭詩,所以我就做了這個功能。

不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)

代碼排版

第六步:一些細節上的處理

<code>def filter_char(word):
""" 過濾掉非中文字符 """
sub_str = re.sub(u"([^\\\\u4e00-\\\\u9fa5])", "", word)
return sub_str/<code>

在項目開發的時候,經常要考慮一些特殊的情況,例如用戶不按常理出牌,給你輸入一堆字母或標點符號之類的怎麼辦?我這裡寫了一個正則表達式,可以過濾掉所有的非中文字符。感興趣的朋友可以去了解一下正則表達式,挺有趣的。

不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)

代碼排版

第七步: 主流程

<code>def main(config=CONF):
form = {'五言絕句': (4, 5), '七言絕句': (4, 7)}
m = Model.initialize(config)
while True:
title = input('輸入標題:').strip()
try:
# 普通詩句
poem = m.poem_generator(title, form['五言絕句'])
print('\\033[031m%s\\033[0m' % poem) # red
poem = m.poem_generator(title, form['七言絕句'])
print('\\033[033m%s\\033[0m' % poem) # yellow

# 藏頭詩
poem = m.poem_generator_hide_head(title, form['五言絕句'])
print('\\033[031m%s\\033[0m' % poem) # red
poem = m.poem_generator_hide_head(title, form['七言絕句'])
print('\\033[033m%s\\033[0m' % poem) # yellow
except:
pass


if __name__ == '__main__':
main()
/<code>

至此,加上一個main函數去調用,所有程序的入口。我們終於完成了。

不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)

代碼排版

好了,讓我們把代碼跑起來。輸入一個主題:“清明節”,不到一秒就生成一首詩。

不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)




不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)


程序後臺結果顯示:

不會唐詩三百首,但是我會讓電腦自己寫詩(內附完整python源碼)



如果有疑問想獲取源碼(其實代碼都在上面),可以

後臺私信我,回覆:python寫詩。 我把源碼發你。最後,感謝大家的閱讀,祝大家工作生活愉快!


分享到:


相關文章: