Transformer各層網(wǎng)絡(luò)結(jié)構(gòu)詳解黄痪!面試必備!(附代碼實(shí)現(xiàn))

1. 什么是Transformer

《Attention Is All You Need》是一篇Google提出的將Attention思想發(fā)揮到極致的論文盔然。這篇論文中提出一個(gè)全新的模型桅打,叫 Transformer,拋棄了以往深度學(xué)習(xí)任務(wù)里面使用到的 CNN 和 RNN愈案。目前大熱的Bert就是基于Transformer構(gòu)建的挺尾,這個(gè)模型廣泛應(yīng)用于NLP領(lǐng)域,例如機(jī)器翻譯站绪,問(wèn)答系統(tǒng)潦嘶,文本摘要和語(yǔ)音識(shí)別等等方向。

2. Transformer結(jié)構(gòu)

2.1 總體結(jié)構(gòu)

Transformer的結(jié)構(gòu)和Attention模型一樣崇众,Transformer模型中也采用了 encoer-decoder 架構(gòu)掂僵。但其結(jié)構(gòu)相比于Attention更加復(fù)雜,論文中encoder層由6個(gè)encoder堆疊在一起顷歌,decoder層也一樣锰蓬。

不了解Attention模型的,可以回顧之前的文章:Attention

image

每一個(gè)encoder和decoder的內(nèi)部結(jié)構(gòu)如下圖:

image
  • encoder眯漩,包含兩層芹扭,一個(gè)self-attention層和一個(gè)前饋神經(jīng)網(wǎng)絡(luò),self-attention能幫助當(dāng)前節(jié)點(diǎn)不僅僅只關(guān)注當(dāng)前的詞赦抖,從而能獲取到上下文的語(yǔ)義舱卡。
  • decoder也包含encoder提到的兩層網(wǎng)絡(luò),但是在這兩層中間還有一層attention層队萤,幫助當(dāng)前節(jié)點(diǎn)獲取到當(dāng)前需要關(guān)注的重點(diǎn)內(nèi)容轮锥。

2.2 Encoder層結(jié)構(gòu)

首先,模型需要對(duì)輸入的數(shù)據(jù)進(jìn)行一個(gè)embedding操作要尔,也可以理解為類似w2c的操作舍杜,enmbedding結(jié)束之后,輸入到encoder層赵辕,self-attention處理完數(shù)據(jù)后把數(shù)據(jù)送給前饋神經(jīng)網(wǎng)絡(luò)既绩,前饋神經(jīng)網(wǎng)絡(luò)的計(jì)算可以并行,得到的輸出會(huì)輸入到下一個(gè)encoder还惠。

image

2.2.1 Positional Encoding

transformer模型中缺少一種解釋輸入序列中單詞順序的方法饲握,它跟序列模型還不不一樣。為了處理這個(gè)問(wèn)題,transformer給encoder層和decoder層的輸入添加了一個(gè)額外的向量Positional Encoding救欧,維度和embedding的維度一樣歪今,這個(gè)向量采用了一種很獨(dú)特的方法來(lái)讓模型學(xué)習(xí)到這個(gè)值,這個(gè)向量能決定當(dāng)前詞的位置颜矿,或者說(shuō)在一個(gè)句子中不同的詞之間的距離寄猩。這個(gè)位置向量的具體計(jì)算方法有很多種,論文中的計(jì)算方法如下:

PE(pos,2i)=sin(\frac{pos}{10000^{\frac{2i}{d_{model}}}})

PE(pos,2i+1)=cos(\frac{pos}{10000^{\frac{2i}{d_{model}}}})

其中pos是指當(dāng)前詞在句子中的位置骑疆,i是指向量中每個(gè)值的index田篇,可以看出,在偶數(shù)位置箍铭,使用正弦編碼剖毯,在奇數(shù)位置曙旭,使用余弦編碼

最后把這個(gè)Positional Encoding與embedding的值相加,作為輸入送到下一層苛谷。

image

2.2.2 Self-Attention

接下來(lái)我們?cè)敿?xì)看一下self-attention色解,其思想和attention類似然评,但是self-attention是Transformer用來(lái)將其他相關(guān)單詞的“理解”轉(zhuǎn)換成我們正在處理的單詞的一種思路颖榜,我們看個(gè)例子:

The animal didn't cross the street because it was too tired

這里的 it 到底代表的是 animal 還是 street 呢,對(duì)于我們來(lái)說(shuō)能很簡(jiǎn)單的判斷出來(lái)拍摇,但是對(duì)于機(jī)器來(lái)說(shuō)亮钦,是很難判斷的,self-attention就能夠讓機(jī)器把 it 和 animal 聯(lián)系起來(lái)充活,接下來(lái)我們看下詳細(xì)的處理過(guò)程蜂莉。

  1. 首先,self-attention會(huì)計(jì)算出三個(gè)新的向量混卵,在論文中映穗,向量的維度是512維,我們把這三個(gè)向量分別稱為Query幕随、Key蚁滋、Value,這三個(gè)向量是用embedding向量與一個(gè)矩陣相乘得到的結(jié)果合陵,這個(gè)矩陣是隨機(jī)初始化的枢赔,維度為(64,512)注意第二個(gè)維度需要和embedding的維度一樣拥知,其值在BP的過(guò)程中會(huì)一直進(jìn)行更新,得到的這三個(gè)向量的維度是64碎赢。

    image
  2. 計(jì)算self-attention的分?jǐn)?shù)值低剔,該分?jǐn)?shù)值決定了當(dāng)我們?cè)谀硞€(gè)位置encode一個(gè)詞時(shí),對(duì)輸入句子的其他部分的關(guān)注程度。這個(gè)分?jǐn)?shù)值的計(jì)算方法是Query與Key做點(diǎn)成襟齿,以下圖為例姻锁,首先我們需要針對(duì)Thinking這個(gè)詞,計(jì)算出其他詞對(duì)于該詞的一個(gè)分?jǐn)?shù)值猜欺,首先是針對(duì)于自己本身即q1·k1位隶,然后是針對(duì)于第二個(gè)詞即q1·k2。

    image
  3. 接下來(lái)开皿,把點(diǎn)成的結(jié)果除以一個(gè)常數(shù)涧黄,這里我們除以8,這個(gè)值一般是采用上文提到的矩陣的第一個(gè)維度的開(kāi)方即64的開(kāi)方8赋荆,當(dāng)然也可以選擇其他的值笋妥,然后把得到的結(jié)果做一個(gè)softmax的計(jì)算。得到的結(jié)果即是每個(gè)詞對(duì)于當(dāng)前位置的詞的相關(guān)性大小窄潭,當(dāng)然春宣,當(dāng)前位置的詞相關(guān)性肯定會(huì)會(huì)很大。

    image
  4. 下一步就是把Value和softmax得到的值進(jìn)行相乘嫉你,并相加月帝,得到的結(jié)果即是self-attetion在當(dāng)前節(jié)點(diǎn)的值。

    image

在實(shí)際的應(yīng)用場(chǎng)景幽污,為了提高計(jì)算速度嫁赏,我們采用的是矩陣的方式,直接計(jì)算出Query, Key, Value的矩陣油挥,然后把embedding的值與三個(gè)矩陣直接相乘潦蝇,把得到的新矩陣 Q 與 K 相乘,乘以一個(gè)常數(shù)深寥,做softmax操作攘乒,最后乘上 V 矩陣。

這種通過(guò) query 和 key 的相似性程度來(lái)確定 value 的權(quán)重分布的方法被稱為scaled dot-product attention惋鹅。

image
image

2.2.3 Multi-Headed Attention

這篇論文更牛逼的地方是給self-attention加入了另外一個(gè)機(jī)制则酝,被稱為“multi-headed” attention,該機(jī)制理解起來(lái)很簡(jiǎn)單闰集,就是說(shuō)不僅僅只初始化一組Q沽讹、K、V的矩陣武鲁,而是初始化多組爽雄,tranformer是使用了8組,所以最后得到的結(jié)果是8個(gè)矩陣沐鼠。

image
image

2.2.4 Layer normalization

在transformer中挚瘟,每一個(gè)子層(self-attetion叹谁,F(xiàn)eed Forward Neural Network)之后都會(huì)接一個(gè)殘缺模塊,并且有一個(gè)Layer normalization乘盖。

image

Normalization有很多種焰檩,但是它們都有一個(gè)共同的目的,那就是把輸入轉(zhuǎn)化成均值為0方差為1的數(shù)據(jù)订框。我們?cè)诎褦?shù)據(jù)送入激活函數(shù)之前進(jìn)行normalization(歸一化)析苫,因?yàn)槲覀儾幌M斎霐?shù)據(jù)落在激活函數(shù)的飽和區(qū)。

Batch Normalization

BN的主要思想就是:在每一層的每一批數(shù)據(jù)上進(jìn)行歸一化穿扳。我們可能會(huì)對(duì)輸入數(shù)據(jù)進(jìn)行歸一化衩侥,但是經(jīng)過(guò)該網(wǎng)絡(luò)層的作用后,我們的數(shù)據(jù)已經(jīng)不再是歸一化的了纵揍。隨著這種情況的發(fā)展顿乒,數(shù)據(jù)的偏差越來(lái)越大,我的反向傳播需要考慮到這些大的偏差泽谨,這就迫使我們只能使用較小的學(xué)習(xí)率來(lái)防止梯度消失或者梯度爆炸璧榄。BN的具體做法就是對(duì)每一小批數(shù)據(jù),在批這個(gè)方向上做歸一化吧雹。

Layer normalization

它也是歸一化數(shù)據(jù)的一種方式骨杂,不過(guò)LN 是在每一個(gè)樣本上計(jì)算均值和方差,而不是BN那種在批方向計(jì)算均值和方差雄卷!公式如下:

LN(x_i)=\alpha*\frac{x_i-\mu_L}{\sqrt{\sigma_L^2+\varepsilon}}+\beta

image

2.2.5 Feed Forward Neural Network

這給我們留下了一個(gè)小的挑戰(zhàn)搓蚪,前饋神經(jīng)網(wǎng)絡(luò)沒(méi)法輸入 8 個(gè)矩陣呀,這該怎么辦呢丁鹉?所以我們需要一種方式妒潭,把 8 個(gè)矩陣降為 1 個(gè),首先揣钦,我們把 8 個(gè)矩陣連在一起雳灾,這樣會(huì)得到一個(gè)大的矩陣,再隨機(jī)初始化一個(gè)矩陣和這個(gè)組合好的矩陣相乘冯凹,最后得到一個(gè)最終的矩陣谎亩。

image

2.3 Decoder層結(jié)構(gòu)

根據(jù)上面的總體結(jié)構(gòu)圖可以看出,decoder部分其實(shí)和encoder部分大同小異宇姚,剛開(kāi)始也是先添加一個(gè)位置向量Positional Encoding匈庭,方法和 2.2.1 節(jié)一樣,接下來(lái)接的是masked mutil-head attetion浑劳,這里的mask也是transformer一個(gè)很關(guān)鍵的技術(shù)阱持,下面我們會(huì)進(jìn)行一一介紹。

其余的層結(jié)構(gòu)與Encoder一樣呀洲,請(qǐng)參考Encoder層結(jié)構(gòu)紊选。

2.3.1 masked mutil-head attetion

mask 表示掩碼啼止,它對(duì)某些值進(jìn)行掩蓋道逗,使其在參數(shù)更新時(shí)不產(chǎn)生效果兵罢。Transformer 模型里面涉及兩種 mask,分別是 padding mask 和 sequence mask滓窍。其中卖词,padding mask 在所有的 scaled dot-product attention 里面都需要用到,而 sequence mask 只有在 decoder 的 self-attention 里面用到吏夯。

  1. padding mask

    什么是 padding mask 呢此蜈?因?yàn)槊總€(gè)批次輸入序列長(zhǎng)度是不一樣的也就是說(shuō),我們要對(duì)輸入序列進(jìn)行對(duì)齊噪生。具體來(lái)說(shuō)裆赵,就是給在較短的序列后面填充 0。但是如果輸入的序列太長(zhǎng)跺嗽,則是截取左邊的內(nèi)容战授,把多余的直接舍棄。因?yàn)檫@些填充的位置桨嫁,其實(shí)是沒(méi)什么意義的植兰,所以我們的attention機(jī)制不應(yīng)該把注意力放在這些位置上,所以我們需要進(jìn)行一些處理璃吧。

    具體的做法是楣导,把這些位置的值加上一個(gè)非常大的負(fù)數(shù)(負(fù)無(wú)窮),這樣的話畜挨,經(jīng)過(guò) softmax筒繁,這些位置的概率就會(huì)接近0!

    而我們的 padding mask 實(shí)際上是一個(gè)張量巴元,每個(gè)值都是一個(gè)Boolean毡咏,值為 false 的地方就是我們要進(jìn)行處理的地方。

  2. Sequence mask

    文章前面也提到务冕,sequence mask 是為了使得 decoder 不能看見(jiàn)未來(lái)的信息血当。也就是對(duì)于一個(gè)序列,在 time_step 為 t 的時(shí)刻禀忆,我們的解碼輸出應(yīng)該只能依賴于 t 時(shí)刻之前的輸出臊旭,而不能依賴 t 之后的輸出。因此我們需要想一個(gè)辦法箩退,把 t 之后的信息給隱藏起來(lái)离熏。

    那么具體怎么做呢?也很簡(jiǎn)單:產(chǎn)生一個(gè)上三角矩陣戴涝,上三角的值全為0滋戳。把這個(gè)矩陣作用在每一個(gè)序列上钻蔑,就可以達(dá)到我們的目的

  • 對(duì)于 decoder 的 self-attention奸鸯,里面使用到的 scaled dot-product attention咪笑,同時(shí)需要padding mask 和 sequence mask 作為 attn_mask,具體實(shí)現(xiàn)就是兩個(gè)mask相加作為attn_mask娄涩。
  • 其他情況窗怒,attn_mask 一律等于 padding mask。

2.3.2 Output層

當(dāng)decoder層全部執(zhí)行完畢后蓄拣,怎么把得到的向量映射為我們需要的詞呢扬虚,很簡(jiǎn)單,只需要在結(jié)尾再添加一個(gè)全連接層和softmax層球恤,假如我們的詞典是1w個(gè)詞辜昵,那最終softmax會(huì)輸入1w個(gè)詞的概率,概率值最大的對(duì)應(yīng)的詞就是我們最終的結(jié)果咽斧。

2.4 動(dòng)態(tài)流程圖

編碼器通過(guò)處理輸入序列開(kāi)啟工作堪置。頂端編碼器的輸出之后會(huì)變轉(zhuǎn)化為一個(gè)包含向量K(鍵向量)和V(值向量)的注意力向量集 ,這是并行化操作收厨。這些向量將被每個(gè)解碼器用于自身的“編碼-解碼注意力層”晋柱,而這些層可以幫助解碼器關(guān)注輸入序列哪些位置合適:

image

在完成編碼階段后,則開(kāi)始解碼階段诵叁。解碼階段的每個(gè)步驟都會(huì)輸出一個(gè)輸出序列(在這個(gè)例子里雁竞,是英語(yǔ)翻譯的句子)的元素。

接下來(lái)的步驟重復(fù)了這個(gè)過(guò)程拧额,直到到達(dá)一個(gè)特殊的終止符號(hào)碑诉,它表示transformer的解碼器已經(jīng)完成了它的輸出。每個(gè)步驟的輸出在下一個(gè)時(shí)間步被提供給底端解碼器侥锦,并且就像編碼器之前做的那樣进栽,這些解碼器會(huì)輸出它們的解碼結(jié)果 。

image

3. Transformer為什么需要進(jìn)行Multi-head Attention

原論文中說(shuō)到進(jìn)行Multi-head Attention的原因是將模型分為多個(gè)頭恭垦,形成多個(gè)子空間快毛,可以讓模型去關(guān)注不同方面的信息,最后再將各個(gè)方面的信息綜合起來(lái)番挺。其實(shí)直觀上也可以想到唠帝,如果自己設(shè)計(jì)這樣的一個(gè)模型,必然也不會(huì)只做一次attention玄柏,多次attention綜合的結(jié)果至少能夠起到增強(qiáng)模型的作用襟衰,也可以類比CNN中同時(shí)使用多個(gè)卷積核的作用,直觀上講粪摘,多頭的注意力有助于網(wǎng)絡(luò)捕捉到更豐富的特征/信息瀑晒。

4. Transformer相比于RNN/LSTM绍坝,有什么優(yōu)勢(shì)?為什么苔悦?

  1. RNN系列的模型轩褐,并行計(jì)算能力很差。RNN并行計(jì)算的問(wèn)題就出在這里间坐,因?yàn)?T 時(shí)刻的計(jì)算依賴 T-1 時(shí)刻的隱層計(jì)算結(jié)果灾挨,而 T-1 時(shí)刻的計(jì)算依賴 T-2 時(shí)刻的隱層計(jì)算結(jié)果邑退,如此下去就形成了所謂的序列依賴關(guān)系竹宋。

  2. Transformer的特征抽取能力比RNN系列的模型要好。

    具體實(shí)驗(yàn)對(duì)比可以參考:放棄幻想地技,全面擁抱Transformer:自然語(yǔ)言處理三大特征抽取器(CNN/RNN/TF)比較

    但是值得注意的是蜈七,并不是說(shuō)Transformer就能夠完全替代RNN系列的模型了,任何模型都有其適用范圍莫矗,同樣的飒硅,RNN系列模型在很多任務(wù)上還是首選,熟悉各種模型的內(nèi)部原理作谚,知其然且知其所以然三娩,才能遇到新任務(wù)時(shí),快速分析這時(shí)候該用什么樣的模型妹懒,該怎么做好雀监。

5. 為什么說(shuō)Transformer可以代替seq2seq?

seq2seq缺點(diǎn):這里用代替這個(gè)詞略顯不妥當(dāng)眨唬,seq2seq雖已老会前,但始終還是有其用武之地,seq2seq最大的問(wèn)題在于將Encoder端的所有信息壓縮到一個(gè)固定長(zhǎng)度的向量中匾竿,并將其作為Decoder端首個(gè)隱藏狀態(tài)的輸入瓦宜,來(lái)預(yù)測(cè)Decoder端第一個(gè)單詞(token)的隱藏狀態(tài)。在輸入序列比較長(zhǎng)的時(shí)候岭妖,這樣做顯然會(huì)損失Encoder端的很多信息,而且這樣一股腦的把該固定向量送入Decoder端昵慌,Decoder端不能夠關(guān)注到其想要關(guān)注的信息假夺。

Transformer優(yōu)點(diǎn):transformer不但對(duì)seq2seq模型這兩點(diǎn)缺點(diǎn)有了實(shí)質(zhì)性的改進(jìn)(多頭交互式attention模塊),而且還引入了self-attention模塊废离,讓源序列和目標(biāo)序列首先“自關(guān)聯(lián)”起來(lái)侄泽,這樣的話,源序列和目標(biāo)序列自身的embedding表示所蘊(yùn)含的信息更加豐富蜻韭,而且后續(xù)的FFN層也增強(qiáng)了模型的表達(dá)能力悼尾,并且Transformer并行計(jì)算的能力是遠(yuǎn)遠(yuǎn)超過(guò)seq2seq系列的模型柿扣,因此我認(rèn)為這是transformer優(yōu)于seq2seq模型的地方。

6. 代碼實(shí)現(xiàn)

地址:https://github.com/Kyubyong/transformer

代碼解讀:Transformer解析與tensorflow代碼解讀

機(jī)器學(xué)習(xí)通俗易懂系列文章

image

7. 參考文獻(xiàn)


作者:@mantchs

GitHub:https://github.com/NLP-LOVE/ML-NLP

歡迎大家加入討論闺魏!共同完善此項(xiàng)目未状!群號(hào):【541954936】點(diǎn)擊加入

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市析桥,隨后出現(xiàn)的幾起案子司草,更是在濱河造成了極大的恐慌,老刑警劉巖泡仗,帶你破解...
    沈念sama閱讀 212,080評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件埋虹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡娩怎,警方通過(guò)查閱死者的電腦和手機(jī)搔课,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)截亦,“玉大人爬泥,你說(shuō)我怎么就攤上這事”廊浚” “怎么了袍啡?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,630評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)却桶。 經(jīng)常有香客問(wèn)我境输,道長(zhǎng),這世上最難降的妖魔是什么肾扰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,554評(píng)論 1 284
  • 正文 為了忘掉前任畴嘶,我火速辦了婚禮,結(jié)果婚禮上集晚,老公的妹妹穿的比我還像新娘窗悯。我一直安慰自己,他們只是感情好偷拔,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布蒋院。 她就那樣靜靜地躺著,像睡著了一般莲绰。 火紅的嫁衣襯著肌膚如雪欺旧。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,856評(píng)論 1 290
  • 那天蛤签,我揣著相機(jī)與錄音辞友,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛称龙,可吹牛的內(nèi)容都是我干的留拾。 我是一名探鬼主播,決...
    沈念sama閱讀 39,014評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鲫尊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼痴柔!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起疫向,我...
    開(kāi)封第一講書(shū)人閱讀 37,752評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤咳蔚,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后搔驼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谈火,經(jīng)...
    沈念sama閱讀 44,212評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評(píng)論 2 327
  • 正文 我和宋清朗相戀三年匙奴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了堆巧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,687評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡泼菌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出啦租,到底是詐尸還是另有隱情哗伯,我是刑警寧澤,帶...
    沈念sama閱讀 34,347評(píng)論 4 331
  • 正文 年R本政府宣布篷角,位于F島的核電站焊刹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏恳蹲。R本人自食惡果不足惜虐块,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嘉蕾。 院中可真熱鬧贺奠,春花似錦、人聲如沸错忱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,777評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)以清。三九已至儿普,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掷倔,已是汗流浹背眉孩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,006評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人浪汪。 一個(gè)月前我還...
    沈念sama閱讀 46,406評(píng)論 2 360
  • 正文 我出身青樓障贸,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親吟宦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子篮洁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容