1. 達觀動態

    達觀愿與業內同行分享 助力各企業在大數據浪潮來臨之際一起破浪前行

    文本挖掘實操 | 用文本挖掘剖析54萬首詩歌,發現了這些

    楔子

    許多年之后,面對書桌上的兩句殘詞,貶居黃州的東坡居士將會回想起,他在故鄉眉山見到朱姓老尼的那個遙遠的下午。彼時的東坡還不是東坡,還只是一個七歲孩童。有一天,他在家附近偶遇一位年約九十的朱姓老尼。老尼看到蘇軾天資聰穎,就跟他聊起自己年輕時的經歷,曾跟隨師父進入后蜀主孟昶的宮中。一日,天酷熱,孟昶和他的妃子花蕊夫人深夜納涼于摩訶池上。面對此情此景,蜀主即興賦詞一首…老尼將她印象中僅存的打頭兩句告訴了蘇軾。

    四十年后,蘇軾貶居于黃州,想起這段往事,遺憾于孟昶的詞只余兩句,突發奇想要將這兩句詞續寫完整。他先猜測出這首詞的詞牌名—“洞仙歌令”,但要還原整首詞作,必須深刻結合寫詞人當時之心情以及伴隨而來的意境。蘇軾因而循著僅存的兩句詞,根據老尼給他的描述,竭力在腦海中還原蜀主當時的創作場景和心境,最終將詞續完,成就名作《洞仙歌》:

    冰肌玉骨,自清涼無汗。水殿風來暗香滿。繡簾開,一點明月窺人,人未寢,倚枕釵橫鬢亂。起來攜素手,庭戶無聲,時見疏星渡河漢。試問夜如何,夜已三更,金波淡,玉繩低轉。但屈指西風幾時來,又不道流年暗中偷換。

    以上就是文學史上有名的“東坡續詞”,雖說是文學史上的一段佳話,但筆者從中隱約看到了數理思維的影子:

    詩詞的創作過程有如在求解一個“最優化問題”:

    在一定的約束條件下,如詩詞要遵守的平仄、押韻、對仗/對偶、五七變式、詞譜、情境等,詩詞創作者用文字將自己內心的真實感動用語言文字表達出來,在“戴著鐐銬在跳舞”的情況下,竭力達到音韻美、精煉美、言辭美、朦朧美、情感美、繪畫美和形式美的至臻境界…

    此時,詩詞之精美和數理之嚴密是可以完美結合的。

    既然詩歌的創作是有規律的,那么,通過一定的數據挖掘手段,我們能夠從中發現一些insight。在本文中,筆者循著這個思路,將運用若干文本挖掘方法對手頭的詩歌語料庫(該詩歌原始語料庫地址為https://github.com/Werneror/Poetry)進行深入挖掘和分析,該詩歌語料庫的基本統計數據如下:

    pic_001

     

    從上表可以看到,該詩歌語料庫中共計近85萬余首詩歌,詩歌作者數量達29377位之多;其中,字段包括“題目”、“朝代”、“作者”和“內容(詩歌)”。為了方便后續的分析,筆者僅取其中的律詩和絕句,且僅取其中的五言和七言,排律(如《春江花月夜》、《長恨歌》等)、雜言(如李白的將進酒)等就不在本文的分析范圍之內。

    經過數據清洗后,最終得詩504443,占到原數據庫的59.1%。以下分別是清洗后的詩歌數據統計結果和部分樣例:

    pic_002

    pic_003

     

     

    針對上述數據,筆者在本文中主要有兩個大目標:

    • 構建一個包含熱門題材標簽的詩歌語料庫,用于后續的詩歌題材分類和詩歌生成任務;
    • 基于上述詩歌語料庫的各類文本挖掘和語義分析,以期得到有趣味的發現。

    針對上述目標,本文的實現路線圖,同時也是本文的行文脈絡,如下所示(點擊圖片可放大查看):

    pic_004

    值得注意的是,上述實現路徑中,涉及到自然語言處理的兩大組成部分,即自然語言理解(分詞、語義建模、語義相似度、聚類和分類等)和自然語言生成(詩歌生成和詩歌翻譯),?看完也會對自然語言處理有一定的了解。信息量大,請耐心享用~

    詩歌分詞和熱詞發現

    給定一首詩歌文本,在其中隨機取一個片段,如何判斷這個片段是否是一個有意義的詞匯呢?

    如果這個片段左右的搭配變化較多、很豐富,同時片段內部的成分搭配很固定,那么,我們可以認為這個片段是一個詞匯,比如下圖中所示的“摩詰”就是符合這個定義,那么它就是一個詞匯。

    pic_005

    在具體實施的算法中,衡量片段外部左右搭配的豐富程度的指標叫“自由度”,可以用(左右)信息熵來度量;而片段內部搭配的固定程度叫“凝固度”,可以用子序列的互信息來度量。

    在這里,筆者利用Jiayan(甲言)對這54余萬首詩歌進行自動分詞,在結果中按照詞匯出現頻率從高到低進行排序,最終從語料庫中抽取若干有意義的高頻詞。其中,詞匯的長度從1到4。

    抽取結果如下(點擊圖片可放大查看):

    pic_006

    筆者觀察其中部分結果,發現一字詞、二字詞才能算得上一般意義上的詞匯,如“不”、“爍”、“歲寒”、“留滯”等 ;三字詞和四字詞一般是多類詞性詞匯的組合,嚴格上講,應該算作短語或者固定表達,如“隨流水”、”云深處”、“人間萬事”、“江湖萬里”等。但本文為了表述方便,筆者將它們統一稱之為詞。

    下面,筆者分別展示詞長從1到4的TOP100的高頻詞詞云(點擊圖片可放大查看)。

    pic_007

    一字高頻詞中,除去“不”、“無”、“有”這類“虛詞”,單看“人山風日天云春花年月水”這11個高頻字,暗合了中國天人合一哲學傳統,作詩如作畫,作詩者是把人放到自然環境、天地歲月這個時空大畫卷中,七情六欲、天人感應,詩情畫意就由感而生,詩意盎然了!

    詩畫本一律”,古人誠不我欺!

    pic_008

    二字高頻詞中,較為顯眼的是“萬里”、“千里”,它們描繪出巨大的空間感,在詩歌中經常跟“宏景”“貶謫”、“思鄉”、“閨怨”等主題捆綁在一起。

    此外,“明月”、“故人”、“白云”、“功名”、“人間”、“平生”和“相逢”等詞匯也是橫亙古今的熱門用語。

    pic_009

    三字高頻詞中,數字的使用很是常見,如“二三子”、“二十四”、“一樽酒”、“二千石”等。其中,最值得一提的是詩人們用數詞對時空的描繪:表達時間跨度的,如“二十年”、“四十年”、“五百年”、“十年前”、“千載后”等;表達空間距離的,如“千里外”、“三百里”、“百尺樓”…古人總是喜歡把自己置身于浩瀚渺茫的時空之中,去思考自己匆匆的人生。正如東坡在《赤壁賦》的感慨:“寄蜉蝣于天地,渺滄海之一粟。哀吾生之須臾,羨長江之無窮!

    pic_010

    在四字高頻詞中,空間方位的詞匯較多,如“南北東西”、“江南江北”、“東西南北”等詞。因四字詞詞長較長,像“人間萬事”、“千巖萬壑”、“明月清風”、“白云深處”、“相逢一笑”等詞就擁有較高的信息量,能夠還原大部分的詩歌意境了。

     

    訓練含納詩歌詞匯語義關聯性的詞嵌入模型

    詞嵌入模型可以從海量的詩歌文本中自動學習到字詞之間的關聯關系,據此可實現字詞關聯度分析、字詞相似度分析、聚類分析等任務。然而,計算機程序不能直接處理字符串形式的文本數據,所以筆者首當其沖的一個步驟就是將詩歌文本數據分詞,之后再“翻譯”為計算機可以處理的數據形式,這由一個名為“文本向量化”的操作來實現。

    先談分詞,它跟前面的高頻詞挖掘有聯系,是后續所有分析任務的起始點。結合前面積累的詞庫,再基于有向無環詞圖、句子最大概率路徑和動態規劃算法對這54萬首詩歌進行分詞操作?,F試舉一例:

    分詞前:

    “萬物生蕓蕓,與我本同氣。氤氳隨所感,形體偶然異。丘岳孰為高,塵粒孰為細。忘物亦忘我,優游何所覬?!?/p>

    分詞后:

    [‘萬物’, ‘生’, ‘蕓蕓’, ‘,’, ‘與’, ‘我’, ‘本’, ‘同’, ‘氣’, ‘。’,’氤氳’, ‘隨’, ‘所’, ‘感’, ‘,’,

    ‘形體’, ‘偶然’, ‘異’, ‘。’, ‘丘岳’, ‘孰’, ‘為’, ‘高’, ‘,’, ‘塵’, ‘粒’, ‘孰’, ‘為’, ‘細’, ‘。’,

    ‘忘’, ‘物’, ‘亦’, ‘忘我’, ‘,’, ‘優游’, ‘何’, ‘所’, ‘覬’, ‘。’]

     

    分詞之后再做適當處理就可以“喂給”詞嵌入模型(這里是Word2vec)進行訓練了。

    基于Word2vec詞嵌入模型能從大量未標注的文本數據中“學習”到字/詞向量,而且這些字/詞向量包含了字詞之間的語義關聯關系(可以是語義相關或句法相關),正如現實世界中的“物以類聚,類以群分”一樣,字詞可以由它們身邊的字(上下文語境)來定義,而Word2vec詞嵌入模型恰恰能學習到這種詞匯和語境之間的關聯性。

    其基本原理如下圖所示(點擊圖片可放大查看):

    pic_011

     

     

    訓練完該模型后,將其訓練結果投射到三維空間,則是如下景象(點擊圖片可放大查看):

    pic_012

    在訓練Word2vec的過程中,模型會從大量的詩歌文本數據中學習到詞匯之間的2類關聯關系,即聚合關系組合關系。

    • 聚合關系:如果詞匯A和詞匯B可以互相替換,則它們具有聚合關系。換言之,如果詞匯A和詞匯B含有聚合關系,在相同的語義或者句法類別中可以利用其中一個來替換另一個,但不影響對整個句子的理解。例如,“蕭蕭”、“瀟瀟”都是象聲詞,多用于描述雨聲,具有聚合關系,那么“山下蘭芽短浸溪,松間沙路凈無泥,蕭蕭暮雨子規啼”中的“蕭蕭”可以換做“瀟瀟”。
    • 組合關系:如果詞匯A和詞匯B可以在句法關系上相互結合,那么它們具有組合關系。例如,“雨打梨花深閉門,忘了青春,誤了青春。賞心樂事共誰論?”中的“忘了”和“誤了”都和“青春”存在組合關系,都是“動詞+名詞”的動賓結構。

    現在來尋找與“兵燓”存在語義關聯性的若干詞匯:

    pic_013

    結果大都是跟“戰爭”&“創傷”相關的詞匯,語義關聯關系捕獲能力較強,后續的熱門詩歌體裁挖掘任務也會用到詞嵌入模型的這個特性。

     

    度量詩歌詞匯之間的語義關聯關系

    利用余弦相似性度量詩歌詞匯關聯度

    度量詞匯之間的相似度或者關聯度,我們一般會使用兩個詞匯的詞向量之間的余弦值,詞向量之間的夾角越小,則余弦值越大,越接近1,則語義相關度越高;反之,相關度越低。如下圖所示,展示了“甲兵”、“兵戈”和“烽火”之間的余弦相似度的可視化示意圖(點擊圖片可放大查看):

     

    pic_014

    通過上述詞嵌入模型,similarity(“甲兵”,“兵戈”) = 0.75,similarity(“甲兵”,“烽火”) = 0.37,similarity(“兵戈”,“烽火”) = 0.48。則在這三個詞匯中,“甲兵”和“兵戈”之間的語義相關度最高,其次是“兵戈”和“烽火”,最次的“甲兵”和“烽火”。

    這種給一個數值來識別詞匯相關不相關的方法優點在于表達簡潔、計算高效,比如接下來將要進行的熱門詩歌題材發現/聚類。但是,這種詞匯相關度的計算沒有把詞匯之間的相關度的“因果路徑”直觀的反映出來。那么,有沒有一種直觀的方法來展示詞匯之間的語義相關性,并且能看到為什么它們是存在這樣的關聯關系(也就是找到詞匯關聯路徑或者語義演變路徑)?

    答案是—當然有。我們需要把這個找尋詞匯語義演變路徑的任務轉換成一個TSP問題(旅行商問題)。

     

    利用A*算法找尋詞匯之間的語義演變路徑

    TSP問題(Traveling Salesman Problem)又譯為旅行推銷員問題,是數學領域中著名問題之一。假設有一個旅行商人要拜訪n個城市,他必須選擇所要走的路徑,路徑的限制是每個城市只能拜訪一次,而且最后要回到原來出發的城市。路徑的選擇目標是要求得的路徑路程為所有路徑之中的最小值。

    回到詞匯相關度度量的問題上來,如果我們能在上述訓練得到的詞嵌入空間中找到兩個詞匯之間的最短“語義演變”線路,我們就能直觀的呈現出這2個詞匯之間產生語義關聯的“前因后果”。要實現這個目的,有一個很棒的算法可以實現 — A*算法(A* search algorithm)。

    A*算法,也叫A*(A-Star)算法,是一種靜態路網中求解最短路徑最有效的直接搜索方法,也是解決許多搜索問題的有效算法。算法中的距離估算值與實際值越接近,最終搜索速度越快。下圖中(點擊圖片可放大查看),網狀結果即是之前構建的word2vec詞嵌入空間,節點是其中分布的詞匯,邊由字詞之間的余弦相關度構成。

    pic_015

    筆者基于上面的詞嵌入模型,結合A*算法來計算兩個詞匯之間的最短語義路徑,部分結果如下所示(點擊圖片可放大查看):

    pic_016

    在上圖的5個詞匯對中,“漁樵”和“躬耕”之間的語義距離最短,也就是語義相關度最高,它們之間的語義演變路徑也就越短,中間只隔了2個詞匯;“燕市”和“寶婺”的語義距離最大,語義相關度最小,二者的語義演變路徑隔了12個詞匯。

    可以看到,語義關聯性越弱(distance值越大)的兩個詞匯之間的最短語義演變路徑就越長,反之越短,所以語義距離與語義演變路徑長度呈正相關關系,語義關聯度與語義演變路徑呈負相關關系。有了前面的詞嵌入模型和語義相關度做“鋪墊”,后續的熱門詩歌題材發現就水到渠成了~

     

    用文本聚類進行熱門詩歌題材發現

    先開宗明義,在本文中,關于“詩歌題材”中的“題材”二字的定義,筆者認為是:作為詩歌創作材料的社會生活的某些方面,亦特指詩人用以表現作品主題思想的素材,通常是指那些經過集中、取舍、提煉而進入作品的生活事件或生活現象。一言以蔽之,寫景、摹物、抒情、記事、明理皆是“題材”。

    因為事先不知道這54萬余首詩歌中到底會存在多少個題材,所以筆者選取的聚類算法沒有預設聚類數這個參數,且兼顧運行效率和節省計算資源,能利用前面訓練好的word2vec詞嵌入模型和語義關聯度計算。

    此時,有個很好的選擇 — 社區發現算法中的Infomap。

     

    基于社區發現的熱門詩歌題材發現

    字詞是承載詩歌題材的最小語義單元,如“五云山上五云飛,遠接群峰近拂堤。若問杭州何處好,此中聽得野鶯啼”,看到其中的“五云山”和“群峰”,則可以給該詩打上一個“山川巍峨”的題材標簽。由此,筆者接下來會基于社區發現算法,結合“詞匯簇群—>詞匯簇群語義特征—>題材標簽”的思路來發現熱門詩歌題材。

    先說說基于社區發現的大致原理。

    我們知道,在社交網絡中,每個用戶相當于每一個點,用戶之間通過互相的關注關系構成了整個線上人際網絡。在這樣的網絡中,有的用戶之間的連接較為緊密,有的用戶之間的連接關系較為稀疏。其中連接較為緊密的部分可以被看成一個社區,其內部的節點之間有較為緊密的連接,而在兩個社區間則相對連接較為稀疏。

    如何去劃分上述的社區便稱為社區發現的問題。基于社區發現算法的話題聚類/發現,在于挖掘詞匯語義網絡中居于頭部的大型“圈子”。將詞匯擬人化,詞匯之間存在的相似度/關聯度可以視為詞匯之間的親密程度,那么,詩歌題材發現任務可以看做是找到不同成員組成的“圈子”,圈子的特性可以根據其中的成員特征來確定,換言之,題材的名稱可以根據其中聚合的詞匯的內涵來擬定,比如某個詞匯簇群中包含“衛霍”、“甲兵”、“征戰”等詞匯,那么這個題材可以命名為“戰爭”。示意圖如下所示(點擊圖片可放大查看):

    pic_017

    運行社區發現算法后,居于頭部的熱門題材詞匯簇群的可視化呈現如下(點擊圖片可放大查看):

    pic_018

    其中,不同顏色表征不同的題材,字體大小代表其出現頻次,詞匯之間的距離遠近表征其相關程度大小。

    經聚類得到634個題材,根據熱度(題材下轄詞匯數量)的降序排列呈現最終結果,如下所示(點擊圖片可放大查看):

    pic_019

     

    甄別熱門詩歌題材

    在這一環節中,筆者的在于根據一些詩歌領域知識,找到上述運行結果中熱門題材及其下轄的題材專屬性詞匯。其中,“題材專屬性詞匯”的內涵主要有以下兩點:

    1. 詞匯不能再做進一步切割,否則詞義會發生變化,比如,“丈夫”在古漢語中的意義是“男子漢”,在一個獨立的詞匯,若將其切割為“丈”和 “夫”,則原意喪失殆盡;
    2. 詞匯僅在一個題材中出現,具有排他性,如“杖藜”只出現在“云游四方”這個題材中,不會出現在“金戈鐵馬”、“對酒當歌”、“悼亡故人”等其他詩歌題材中。

    根據筆者在前文中的定義,寫景、摹物、抒情、記事、明理皆是“題材”,這里的熱門題材甄別采取“抓大放小”的原則。

    此外,雖然聚類出的結果較為理想,但還是存在些許噪音,比如,出現少許跟題材相關性不強的詞匯、題材區分度較低的詞匯、詞匯簇群中的詞匯過少(如低于10個)等,這些都是需要被刨除掉的情況。

    經過筆者的仔細甄別,共甄別出23個熱門詩歌題材,分別是山川巍峨、田園躬耕、羈旅思鄉、金戈鐵馬、詠史懷古、詠物抒懷、贈友送別、愛情閨怨、悼亡故人、樓船畫舫、花開荼蘼、對酒當歌、騏驥駿馬、得道修仙、世事變遷、靜悟禪機、壯懷激烈、云游四方、黯然神傷、星宿璀璨、報效君恩、嚶嚶鳥語、蓑笠綸竿等,當然這些并不是全部的題材,限于筆者學識,仍然有大量題材沒有發掘出來。枚舉部分結果如下(點擊圖片可放大查看):

    pic_020

    在這一環節,筆者根據對詩歌背景知識的了解,篩選出部分熱門詩歌題材,并形成題材對應的關鍵詞規則體系,后續可用于對這54萬余首詩歌進行基于關鍵詞的詩歌題材分類。

    值得注意的是,由于這一環節挑選關鍵詞過于苛刻,導致數量較少,規則體系不甚健全。所以,在對詩歌語料庫進行正式的詩歌題材分類前,筆者需要使用一些“小手段”,對上述熱門題材的關鍵詞規則進行擴充。

     

    根據線性分類器特征延伸關鍵詞

    在這里,筆者先利用已得到的熱門題材分類體系及其關鍵詞規則給這54萬余首詩歌打上題材標簽,允許出現同一首詩歌命中多個標簽的情形。除去其中未命中題材標簽的數據,共計443,589行,其中多數詩歌打上了2個及以上的題材標簽。

    部分結果如下所示(點擊圖片可放大查看):

    pic_021

    有了帶標簽的數據以后,筆者將多標簽問題轉換為單標簽問題,再將上述詩歌文本及其對應的標簽“喂進”線性分類器,根據線性分類器的權重來找到每個類別下最具代表性的詞匯,也就是題材專有性詞匯。這里選擇線性分類器而不是時下流行的深度學習分類器的原因就在于它的可解釋性,能讓我們清楚的知道是哪些顯著的特征(此處是詞匯)讓詩歌分到這個題材類別下的。其大致原理如下圖所示(點擊圖片可放大查看):

    pic_022

    在筆者測試的眾多線性分類器中,即RandomForestClassifier、Perceptron、PassiveAggressiveClassifier、MultinomialNB、RidgeClassifier、SGDClassifier,RidgeClassifier的區分效果最好,其F1_score為0.519,鑒于是詞袋模型,語義表示較為簡單,且原本是多標簽分類任務,這個結果尚可接受?;赗idgeClassifier的特征詞匯權重的降序排列結果,可得到上述23個熱門詩歌題材分類中的若干題材專有性詞匯,部分結果展示如下(點擊圖片可放大查看):

    pic_023

    這樣,各個類別各取TOP500詞匯,經過筆者的甄別和梳理后,各個題材關鍵詞規則得到了不同程度的擴充,使得該分類標簽體系可以較好的輔助完成詩歌題材多標簽分類任務,且后續可以結合分類結果做不斷的擴充?;谶@個更加完善的詩歌題材分類體系,筆者運行完之后得到58W+行數據,在之前的基礎上增加了14W+行數據,數據規模提升明顯!

    至此,筆者第一個目標,即熱門詩歌題材標簽語料庫構建完畢,后續的文本挖掘任務可以在此基礎上進行。

    由分類標簽及其分類模型反向推導其中最具代表性的特征詞匯,這是一個“數據—>規律”的歸納過程,很好的體現了數據驅動思維;而模型將學習歸納得到的“經驗”推廣到新樣本的標簽預測任務中,則體現了“規則—>數據”的演繹過程。

    pic_024

     

    基于分類標簽的各類統計分析

    針對上述58W+行數據構成的詩歌題材語料庫,將其中的題材分類標簽和各類meta data(如風格、朝代、作者等)做交叉分析,得到很多有意思的分析結果。

     

    詩歌題材&風格分析

    將詩歌數據集的風格標簽和題材標簽進行交叉列表的成分占比分析,得到的結果如下(點擊圖片可放大查看):

    pic_025

     

    其中,可以發現一些明顯的統計描述性特征:

    • “贈友送別”和“嚶嚶鳥語”這兩個題材在所有詩歌風格中的占比都較高,是兩個較為“熱門”的題材;
    • “悼亡故人”和“壯懷激烈”這兩個題材在所有詩歌風格中的占比都較低,是兩個較為“冷門”的題材。

     

    題材標簽共現分析

    前面的詩歌題材分類是多標簽分類,也就是可能會出現同一首詩歌對應多個題材標簽的情況。在這種情況下,我們可以進行題材標簽的共現分析,也就是多次同時出現的題材標簽,它們之間會存在一定的關聯性。

    現對標簽共現的情況進行建模,得到的結果可視化呈現如下所示(點擊圖片可放大查看):

    pic_026

    上圖中,線條的粗細表示共現的頻次多寡,越粗表示共現頻次越高,反之越低。其中,有幾對標簽對的共現頻率較高:

    世事變遷 – 黯然神傷

    羈旅思鄉 – 世事變遷

    詠史懷古 – 蓑笠綸竿

    世事變遷 – 金戈鐵馬

    對酒當歌 – 世事變遷

    悼亡故人 – 世事變遷

     

    其中,“黯然神傷”和“世事變遷”的相關性最高,這個很好理解,畢竟“物是人事事休,欲語淚先流”,類似因感嘆逝事而傷感的詩句還有“人世幾回傷往事,山形依舊枕寒流”、“一生事業總成空,半世功名在夢中”;“羈旅思鄉”和“世事變遷”之間的相關性第二高,此類的詩句有“少小離家老大回,鄉音無改鬢毛衰”、“去日兒童皆長大,昔年親友半凋零”等。此外,我們也可以發現,在出現2個及兩個以上題材標簽的詩歌中,“世事變遷”和其他題材同時出現的概率很大:世事變遷可能導致詩人黯然神傷;也可能是戰爭導致兵連禍結,產生出“興,百姓苦,亡,百姓苦”的感慨;抑或是“桃李春風一杯酒,江湖夜雨十年燈”的對酒當歌。

     

    詩歌題材趨勢分析

    筆者將詩歌數據集中的朝代按照時間順序由遠及近進行排列,并合并其中年代接近的朝代,將其與23個熱門詩歌題材做(占比)交叉分析,得到下圖(點擊圖片可放大查看):

    pic_027

    在上圖中,可以分別從橫向維度(朝代)和縱向(詩歌題材)維度來看。

    1. 從橫向維度上看,有兩個題材經久不衰,即“贈友送別”和“嚶嚶鳥語”。

    古時候由于交通不便,通信極不發達,親人朋友之間往往一別數載難以相見,所以古人特別看重離別。離別之際,人們往往設酒餞別,折柳相送,有時還要吟詩話別,因此“贈友送別”就成為古代文人吟詠的一個永恒的題材。在這濃濃的感傷之外,往往還有其他寄寓:或用以激勵勸勉,如“莫愁前路無知己,天下誰人不識君”;或用以抒發友情,如“桃花潭水深千尺,不及汪倫送我情”;或用于寄托詩人自己的理想抱負,如“洛陽親友如相問,一片冰心在玉壺”;甚至洋溢著積極向上的青春氣息,充滿希望和夢想,如“海內存知己,天涯若比鄰”。

    “嚶嚶鳥語”題材的詩歌一般用“比興”的手法來寄寓自己的情感,筆者所了解的有兩類:一是通過寫鳥語描摹詩人淡薄、回歸山野自然的平靜心境,這方面的詩王摩詰寫的最多,如“月出驚山鳥,時鳴春澗中”、“漠漠水田飛白鷺,陰陰夏木囀黃鸝”、“雉雊麥苗秀,蠶眠桑葉稀”等;二是通過子規(杜鵑)、鴻雁等意象來表達詩人淡淡的憂傷,如“楊花落盡子規啼,聞道龍標過五溪”的依依惜別之情、“兩邊山木合,終日子規啼”的思鄉歸家之情、“雁盡書難寄,愁多夢不成”的思君心切…

    2. 從縱向維度上看,隋末唐初時期除了上述提及的兩大熱門題材外,關于“報效君恩”題材的詩歌占比較高。彼時適逢華夏第三次大一統,“貞觀之治”、“開元之治”這兩大盛世榮耀大唐在“朕即國家”的時代,廣大熱血青年渴望馳騁疆場,建功立業,報效國家。

     

    此外,筆者也注意到,從金代到到當代,“花開荼蘼”、“羈旅思鄉”、“金戈鐵馬”和“靜悟禪機”等題材就一直葆有較高的熱度,結合前面提及的2大經久不衰的詩歌題材,這表明這段時期的詩歌創作方向具有一定的延續性。

    從上表中,我們能有一些發現,但如果想更獲取一些更深層次、潛藏在表層數據中的信息,我們還需要用高階的數據挖掘方法將其轉換一下。在這里,筆者使用多元對應分析的方法將其高維表示(也就是上面的21*23維的圖表)映射為二維表示(分解為2個二維矩陣,題材為23*2,朝代為21*2),從而更直觀的揭示出詩歌題材之間、詩歌題材與朝代之間的關聯關系,如下圖所示(點擊圖片可放大查看):

    pic_028

    在上圖中,有兩類坐標—外圍有半徑圓圈的紅色點是朝代的,“x”的詩歌題材的坐標。漢代的坐標“孤懸海外”是因為數據量過小,統計特征不甚明顯,故筆者在這里不做分析。

    在圖的左上角,魏晉、南北朝、隋末唐初、隋這幾個朝代的圓圈重合度較高,說明它們的詩歌題材數量分布較為相似,聯想到這幾個朝代前后相繼,這又一次體現了詩歌創作具有時代延續性的特征。同樣,唐代及其以后的圓圈呈“扎堆狀”,標明它們的詩歌寫作題材的數量分布較為相似,反映出唐以降的朝代在詩歌創作題材方面的差異度較小,題材創作方向的創新性不高。究其原因,在于詩歌在唐代已經進化到“究極狀態”:

    唐詩的題材和意境也幾乎無所不包,修辭手段的運用已達到爐火純青的程度。它不僅繼承了漢魏民歌、樂府傳統,并且大大發展了歌行體的樣式;不僅繼承了前代的五、七言古詩,并且發展為敘事言情的長篇巨制;不僅擴展了五言、七言形式的運用,還創造了風格特別優美整齊的近體詩。近體詩是當時的新體詩,它的創造和成熟,是唐代詩歌發展史上的一件大事。它把我國古曲詩歌的音節和諧、文字精煉的藝術特色,推到前所未有的高度,為古代抒情詩找到一個最典型的形式,至今還特別為人民所喜聞樂見。

    唐詩代表了中華詩歌的最高成就,無疑是中華以及世界文壇上濃墨重彩的筆觸!這對于想要另辟新境的宋代詩人來說無疑是巨大的壓力。正如王安石和魯迅所言:

    “世間好語言,已被老杜道盡;世間俗語言,已被樂天道盡”,

    “我以為一切好詩,到唐朝已被做完,此后倘非翻出如來掌心之‘齊天大圣’,大可不必再動手了”。

     

    通過GPT-2生成表達流暢的詩歌

    從某種程度上講,詩歌生成是從另一維度對詩歌進行深度分析。

    生成什么詩歌,跟詩歌生成模型“吃下去”什么是息息相關的。詩歌生成模型的“生成”不是“無源之水”、“無本之木”,它是在充分學習和吸收前人的若干詩作后,習得了一定的“創作手法”,因而能生成效果尚可的詩歌。

    同時,我們也能從生成的結果中發現詩歌創作的一些規律,做一些深入探究。

     

    詩歌生成示例分析

    在這一部分,筆者用于訓練詩歌生成模型的語料庫是基于熱門題材標簽體系得到的帶有題材標簽(目前是23個)的律詩(七言和五言)和絕句(七言和五言),它們都滿足詩歌的結構性、音調性和語義性的要求。

    這里筆者采用的是GPT2(Generative Pre-Training 2nd),它是一個無監督語言模型,能夠生成具有連貫性的文本段落,在許多語言建模任務基準中取得了領先級表現(數據量級和參數量級擺在那里,當然跟它的后浪GPT3不能比…)。而且該模型在沒有任務特定訓練的情況下,能夠做到初步的閱讀理解、機器翻譯、問答和自動摘要。其核心思想可以總結為“給定越多參數以及越多樣、越大量的文本,無監督訓練一個語言模型或許就可讓該模型具備更強的自然語言理解能力,并在沒有任何監督的情況下開始學會解決不同類型的 NLP 任務”。

    在文本的詩歌生成任務中,筆者從零到一訓練一個詩歌生成的GPT2模型,力求讓該模型學習到詩歌數據集中的各類顯性特征(題材與詩歌的關系、詩歌與風格的關系、藏頭字和詩歌的關系等)和隱性特征(主要是詩歌的韻律),其大致原理如下圖所示:

    pic_029

    相比3年前筆者寫《用文本挖掘剖析近5萬首<全唐詩>》時用的LSTM詩歌生成模型,GPT2模型進步巨大:

    • 生成的詩歌更加通順,每一聯的出句和入句的銜接也顯得更為自然
    • 能成全局(即整首詩)著眼,記憶能力好,考慮上下文語境,前后生成的詩句緊密關聯,不會出現“跳題材”的情況
    • 能學習到詩歌數據中較為隱性的特征,如押韻、平仄、對仗、疑問語氣等
    • 因擁有上述3個優勢,生成的詩歌“廢品率”大大降低

     

    下面,筆者將“花式”呈現GPT2的詩歌生成能力:

    1)生成的詩歌可能會和前人寫的詩句有一定的相關性,但是GPT2模型可以進行“魔改”,很難看出直接的“抄襲對象”,例如以下由GPT2模型生成的七言律詩,每一聯都能在語料庫中找到語義最為接近的一句:

    戰鼙傳響徹神州,萬里中原一白頭。
    兵后英雄誰不死,眼前豪杰已無憂。
    乾坤納納歸天地,歲月悠悠老斗牛。
    安得扁舟成獨往,五湖煙浪是東流。

    pic_030

     

    2)很多生成的詩歌能較好的學習到韻律,比如符合《平水韻》的用韻規則——上一個示例就是《平水韻》中七律平起(首句入韻)的一個樣例:

    平平仄仄仄平平(韻)

    仄仄平平仄仄平(韻)

    仄仄平平平仄仄

    平平仄仄仄平平(韻)

    平平仄仄平平仄

    仄仄平平仄仄平(韻)

    仄仄平平平仄仄

    平平仄仄仄平平(韻)

    戰鼙傳響徹神州【州:十一尤】 押韻

    萬里中原一白頭【頭:十一尤】 押韻

    兵后英雄誰不死

    眼前豪杰已無憂【憂:十一尤】 押韻

    乾坤納納歸天地

    歲月悠悠老斗?!九#菏挥取?押韻

    安得扁舟成獨往

    五湖煙浪是東流【流:十一尤】 押韻

     

    另外再看兩個case:

    pic_031

    即使一些詩歌不是嚴格的用韻(即一首詩只能押一個韻),也會自動采用鄰韻的方式來緩解韻律失和的問題。

     

    3)對人張若虛的樂府舊題《春江花月夜》(因為是樂府詩,字數較多,未參與詩歌生成模型的訓練)中的若干詩句,采用對對子的方法生成下聯,毫無違和感:

    【上聯】春江潮水連海平,海上明月共潮生 【下聯】古塔風云繞山青,峰頂彩霞共靄暉

    【上聯】滟滟隨波千萬里,何處春江無月明 【下聯】幽幽如幻五十年,此間塵世有風流

    【上聯】江流宛轉繞芳甸,月照花林皆似霰 【下聯】山勢氤氳浮翠靄,風梳楊柳欲飛煙

    【上聯】斜月沉沉藏海霧,碣石瀟湘無限路 【下聯】春江漫卷漾煙雨,長河日夜有緣人

    【上聯】不知江月待何人,但見長江送流水 【下聯】只向漁家尋舊跡,試問何處答耕桑

    【上聯】白云一片去悠悠,青楓浦上不勝愁 【下聯】碧水千層橫漠漠,赤雁南來正飛歌

    【上聯】鴻雁長飛光不度,魚龍潛躍水成文 【下聯】漁家小住月相隨,鷗鷺往來船載歌

    【上聯】此時相望不相聞,愿逐月華流照君 【下聯】何處覓人猶有約?欲邀仙子去還家

    【上聯】江畔何人初見月?江月何年初照人 【下聯】天下有地可藏龍,海風哪處可觀心

    【上聯】江天一色無纖塵,皎皎空中孤月輪 【下聯】楊柳千絲猶有夢,蒙蒙江上滿船燈

     

    4)嵌入筆者所在的公司名稱—“達觀數據”作為藏頭字,分別以“山川巍峨”、“得道修仙”、“田園躬耕”為題材,生成三首七言律詩:

    《其一》

    摩七十二峰高,天下英雄氣郁陶。

    海三山云縹緲,登樓千仞勢岧峣。

    莖白發身長健,百尺丹梯路不遙。

    險未能窮勝覽,憑欄徙倚思飄飖。

    《其二》

    者由來本自然,人間何處不神仙。

    空已悟三千界,閱世方知二十年。

    點青山隨杖屨,一行白鳥下云煙。

    鞍更欲凌風去,回首孤城落照邊。

    《其三》

    摩萬象付評量,造化從來自一方。

    物有時開口笑,看人無處著心忙。

    間茅屋臨流水,幾個漁舟傍夕陽。

    得此中真面目,乾坤何地不滄桑。

    5)在訓練和生成式引入更多的詩歌標簽信息,如風格、題材和藏頭字,引導GPT2朝期望的方向的生成詩歌。訓練好模型后,筆者輸入詩歌風格(七言絕句、七言律詩)、藏頭字(滄海月明)和題材(金戈忒嗎、世事變遷、靜悟禪機等),生成如下詩歌:

    七言絕句<sep>戢戈為武<sep>金戈鐵馬<sep>兵十萬羽林郎,壁縱橫百戰場。報將軍能破敵,功原是好封疆。

    七言律詩<sep>滄海月明<sep>金戈鐵馬<sep>海干戈一戰場,西風吹淚灑衣裳。門萬里烽煙息,天地千秋雨露涼。下樓船喧鼓角,夜深笳鼓動旌旗。年此夕登臨處,獨倚闌干對夕陽。

    七言律詩<sep>滄海月明<sep>金戈鐵馬<sep>波渺渺接長河,極目蒼茫感慨多。上樓船三百里,云間樓閣五千過。明古渡漁歌起,秋入荒城鼓角和。日相逢又相別,不堪回首淚滂沱。

    七言律詩<sep>滄海月明<sep>金戈鐵馬<sep>波渺渺白鷗群,極目蒼茫萬里云。上樓船三萬里,天邊烽火一孤墳。明古渡漁歌起,霜落空山雁影分。日相逢又相別,故鄉回首淚紛紛。

    七言律詩<sep>滄海月明<sep>世事變遷<sep>桑劫火幾興亡,回首滄桑感慨傷。上樓臺空劫火,人間禾黍自悲涼。明古渡漁歌起,風靜寒潮雁影長。日相逢又相別,故鄉回首一凄涼。

    七言律詩<sep>滄海月明<sep>靜悟禪機<sep>浪萬頃白鷗群,此地曾經此地分。上樓臺今夜月,山中樓閣幾秋云。明古寺僧初定,潮落空江雁正聞。日相逢又相別,不知何處是離群。

    上述生成結果,平仄符合,押韻亦可,詩意也不錯。不敢說很完美,但至少很多人寫不出如此觀感的詩歌。上述按題材生成的結果,筆者進行了大量的題材詩歌生成測試,結果表明詩歌題材和生成詩歌之間的關聯性較高,這也從側面驗證了筆者上述構建的詩歌題材語料庫具有一定的合理性。

    此外,筆者還通過生成的詩句發現了古今詩歌表達方面的一些差異,例如,筆者以“金戈鐵馬”作為生成題材,分別用毛主席人民解放軍占領南京》和陳老總的《梅嶺三章》中的首聯打頭,各生成9首詩歌,結果如下(點擊可查看大圖):

    pic_032 pic_033

     

    上面兩張圖中占據中間C位的是原詩歌,其余的詩歌由毛主席和陳老總詩歌的首聯“引導”而成,基本含有“金戈鐵馬”相關的意象,題材貼合度較高,大都跟征戰、戌邊、殺敵保國有關,比如:

    聞道漢家多戰伐,將軍今日重南邦。

    旌旗影動三軍肅,刁斗聲傳五夜長。

    中原戰血三千里,南國英魂一斷腸。

    西風鼓角寒吹雁,南國旌旗夜渡河。

    然而,可能跟學習了大量封建時代的詩歌有關,這些生成的詩歌到末尾大都是一個悲情的基調,略顯消極,如以下幾句:

    從此邊城多戰伐,不須笳鼓更悲涼。

    一路寒聲送歸雁,秋深不見客愁窗。

    我欲從君尋舊隱,扁舟重訪草堂堂。

    獨有英靈知此意,不堪回首淚沾裳。

    回首故園歸未得,西風蕭瑟動悲歌。

    回首不堪惆悵事,夕陽芳草滿汀波。

    上述生成的詩句缺乏革命主義的樂觀豪情,這是封建時代的詩歌不具備的特質,但這恰好毛主席和陳老總這兩首詩歌的與眾不同之處。且看這兩句:

    天若有情天亦老,人間正道是滄桑。

    投身革命即為家,血雨腥風應有涯。

     

    文章合為時而著,歌詩合為事而作”,上述的結果也恰恰從側面體現了詩歌創作具有時代感和現實感,盡管是寫同一題材,但由于詩人的人生軌跡和面臨的時代背景不一樣,胸中所內含的氣象也大不相同。

    上述由GPT2生成的詩歌看起來都還不錯,很多到了以假亂真的地步,這種情況下,我們該如何甄別出其中哪些是人寫的,哪些是機器寫的?

    機器寫作詩歌歸根到底還是一個統計學問題,“解鈴還須系鈴人”,甄別“真偽”的事情還得統計學來解決。

     

    人機詩歌創作的差異比較

    詩歌生成建模大致的原理是:通過大量詩歌語料,詩歌生成模型能學習到任一詩句中相鄰的字詞之間的依賴關系,比如出現一個“漠”,GPT2按照學習到的經驗,會猜測接下來會出現哪個字,這些字都會以概率的形式“存放”在GPT2模型的“記憶”之中,如:

    “漠”:0.1205,

    “北”:0.0914

    “然”:0.0121,

    “視”:0.00124,

    一般情況下,機器“作詩”時會選擇過往出現幾率最高的字,以此類推,直到碰到“終止符”才結束,逐漸生成整首詩歌。

    pic_034

    這是最簡單的情形,生成的效果也就非常一般,很多時候是文理不通。

    為了保證生成效果,一般會(同時)用到一些復雜的生成策略,如Beam Search、Top-k sampling、Top-p sampling(NUCLEUS SAMPLING,核采樣)、Repetition_penalty(對重復性進行懲罰)、Length_penalty(對生成過長的詩句進行懲罰)等,這樣會兼顧詩歌生成的一些其他因素,如流暢度、豐富度、一致性等,詩歌生成的效果也能得到較大的提升。

    筆者基于哈佛大學的GLTR( Statistical Detection and Visualization of Generated Text)來探究下機器和人作詩時的一些差異,該工具輸入的是詩歌,輸出的是機器和人作的詩歌的字出現概率分布統計,我們從中可以發現詩歌“煉字”的一些奧秘。筆者試舉一例:

    pic_035 pic_036

     

    在上圖中,色塊的顏色代表的是字所在的概率區間,紅色代表出現概率TOP10的字,黃色的是TOP100,綠色的是TOP1000,紫色的是TOP10000。

    從結果中,我們可以看到機器作詩時,紅色和黃色的字概率分布區間占比較大,逐字生成時一般是從頭部的字概率分布中來取,從而導致會詩句生成較為常見的表達;人創作詩歌時,各顏色代表的字概率分布區間占比較為接近,至少是差異不大,最終導致詩歌的表達千變萬化,不落俗套。

    古時詩人作詩,重在“煉字”。煉字,指錘煉詞語,指詩人經過反復琢磨,從詞匯寶庫中挑選出最貼切、最精確、最形象生動的詞語來描摹事物或表情達意。從這個角度來看,具有統計學意義的“選字”策略基本不可取 — 不是詞不達意就是容易落“俗套”。

    比如,陶淵明的那句“采菊東籬下,悠然見南山”中“見”換成“望”就不好。雖然按從詩歌數據集學到的概率來講,“望”在過往出現的概率遠大于“見”,但“見”通“”現,有“無意中看見”的含義,標明作者是不經意間抬起頭來看見南山,表達了整個詩句中那種悠然自得的感觸,好像在不經意間看到了山中美景,符合“山氣日夕佳,飛鳥相與還”這種非常自然的、非常率真的意境,而“望”則顯得有些生硬。

     

    將詩歌翻譯成通俗易懂的白話文

    詩歌翻譯,也就是將文言文色彩濃重、一般人不易看懂的詩歌翻譯成現代人容易理解的白話文。

    筆者此處用到的模型是兩個BERT構成的Encoder-Decoder,目標是輸入一句或者一首詩歌,生成相應的白話文翻譯。考慮到古現代漢語存在大量詞匯方面的語義延續性,不像中英互譯這樣,源語句和目標語句之間的語義和語法結構差異極大,它們會有很多共享詞匯,所以訓練的語料數量可以適當少些。詩歌翻譯模型會從大量的翻譯語句對中學習到它們之間的語義對應關系,而且是以較為流暢(較理想的情況下)的形式進行輸出。

    以下是簡要原理圖:

    pic_037

    筆者編寫爬蟲采集了某詩歌分享網站上的若干詩歌及其翻譯數據,經清洗后,得到3萬條訓練語句。部分訓練數據如下表所示:

    pic_038

    訓練模型后,筆者選取部分未出現在訓練集中的語句作為文本翻譯的示例,部分示例如下:

    pic_039

    【詞】問君何事輕離別,一年能幾團圓月。楊柳乍如絲,故園春盡時。(菩薩蠻·問君何事輕離別,清,納蘭性德)

    【翻譯1】你在什么時候才能夠回家?只有那美麗的桃花已經過去了。

    【翻譯2】請你問我為什么這樣的輕易消失呢?一年里正是三次月下的清明之夜。楊柳剛像絲絲般柔軟,就好似在家鄉春天已經快要過去了。

     

    【詞】山抹微云,天粘衰草,畫角聲斷譙門。水流明月,風送殘花,詩心韻動江樓。(《滿庭芳·山抹微云》,前一句作者是宋,秦觀,后一句作者是GPT2)

    【翻譯】遠處的山峰上是一片輕薄的薄云,在天空中飄散著;烏鴉點綴在枯草叢里,號角聲響徹四周。明月照耀下清輝的銀河映射向西邊,傳來陣陣寒梅花的音樂,這時節讓人肝腸寸斷。

     

    【對聯】帝道真如,如今都成過去事。民心所向,自古都是往來人。(楊度自挽聯,上聯作者是民國,楊度,下一聯作者是GPT2)

    【翻譯】京城大道實在了解我的知識,就像當年地方一樣經歷過了。百姓心里依舊保護著百姓生活世界,自古以來都是從前人們來往的人間吧!

     

    【詩句】萬戶千門入建章,金繩界路柳絲黃。和風偏度樂聲細,晴日自隨宮泉長。(《宮詞·萬戶千門入建章》,宋,王仲修)

    【翻譯】皇上的宅院已經關閉了建立功名利祿,皇家大道路兩旁的楊柳依舊是那樣的嫩芽。春天來到這里,宮殿高聳入云霄,宮殿中傳出一陣清脆婉轉的流水。

     

    【詩句】沅湘兩水清且淺,林花夾岸灘聲激。洞庭浩渺通長江,春來水漲連天碧。(《少年湖南歌》,民國,楊度)

    【翻譯1】沅江兩岸的流淌在這里是多么高遠呢?樹叢生的野草和小洲環繞著江面,河畔的波濤好像是那樣寬闊無際;春天來了時節,水面上漲起伏著一片青色。
    【翻譯2】沅江兩岸的流淌著一片清澈的江水清澈,茂密的樹林環繞在河岸上。洞庭湖廣闊無際,春水滔滔不斷地流向遠方。
    【翻譯3】瀟湘兩岸的流淌著一片清澈的水,樹林間的花瓣隨風飄蕩。洞庭湖廣闊無際,波濤洶涌,波光粼粼,好像是天空相接。
    【翻譯4】沅水湘江清澈見底,水波蕩漾,岸邊樹木繁茂如淺的流動。洞庭湖浩淼遠望去,水天相接處連成一片。

     

    從結果上來看,3萬來句的效果還馬馬虎虎,很多翻譯不是直譯過來的,更傾向于“意譯”,機器翻譯的時候會“腦補”一些場景,如對“山抹微云,…,詩心韻動江樓”的翻譯,機器能夠“揣摩”出“這時節讓人肝腸寸斷”,開始“有內味”了。

    如果采用一些手段擴充下語料,如將整首詩歌和對應翻譯逐句拆分、對白話文部分進行文本增強(同義詞替換、隨機插入、隨機交換等)和將意譯改為直譯等,訓練處的模型可能會更強大些,翻譯效果能提升不少。

     

    結語

    通過上述詩歌語料庫分析流程,筆者想說一下對于(文本)數據挖掘的一些看法:

    所謂挖掘,通常帶有“發現、尋找、歸納、提煉”等內涵,既然需要去發現和提煉,那么,所要找尋的內容往往都不是顯而易見的,而是“隱蔽”和“藏匿”于文本之中,或者是人無法直接在大范圍內發現和歸納出來的。如果要抽絲剝繭,需要結合領域知識(如文中的詩歌常識),運用多種分析手段(如文中的各類NLU和NLG方法),有時甚至需要逆向思維(如文中的詩歌生成),且各類分析最好是一個前后相繼、互為補充有機整體,這樣才能以最高的效率來完成文本數據的探索任務。

     

    參考資料:

    • 《數學與文學的共鳴》,丘成桐
    • 《迦陵說詩.嘉瑩說詩講稿》, 葉嘉瑩
    • 《文本數據管理與分析》,翟成祥
    • 《文本數據挖掘》,宗成慶
    • 《古代漢語基礎》,吳鴻清
    • 《詩詞格律》,王力
    • 《語言的科學》,諾姆.喬姆斯基
    • 《現代漢語詞匯學教程》,周薦
    • 《語言的認知研究和計算分析》,袁疏林
    • 《自然語言處理的認知方法》,Bernadette Sharp
    • 《自然語言處理入門》,何晗
    • https://github.com/Werneror/Poetry
    • https://github.com/kpu/kenlm
    • https://github.com/jiaeyan/Jiayan
    • 《Catching a Unicorn with GLTR: A tool to detect automatically generated text》,http://gltr.io
    • 《Better Language Models and Their Implications》,https://openai.com/blog/better-language-models/
    • 《自由度+凝固度+統計的新詞發現》,https://blog.csdn.net/qq_39006282/article/details/91357603