Faster-RCNN的原理及演變

由于在2017年第一次接觸到faster-rcnn模型到在已經(jīng)有2年多時間风瘦,準備今天稍微回憶總結(jié)下垄分。首先分別介紹一下faster-rcnn演變歷史以及其具體原理。其運行速度為GPU上的幀率為5fps皆愉。

Faster-RCNN演變歷史


我們按照RCNN -> Fast RCNN -> SPP net -> Faster RCNN流程來回顧和總結(jié)其演變歷史

1. RCNN(Region-CNN)

RCNN.png
1.1 步驟

這里進行訓(xùn)練方式分成以下3個步驟:

|
步驟1

步驟2

步驟3

步驟4

步驟5
步驟 示例
一概作、 訓(xùn)練(或者下載)一個分類模型(比如AlexNet) 步驟1
二腋妙、對該模型做fine-tuning: 1. 將分類數(shù)從1000改為20  2. 去掉最后一個全連接層 步驟2
三、特征提取 1. 提取圖像的所有候選框(選擇性搜索) 利用選擇性搜索(利用圖像中的紋理仆嗦、邊緣辉阶、顏色等信息)或者EdgeBoxes在輸入圖像中選取ROI(regions of Interest)即候選框,這些框之間是可以互相重疊互相包含的瘩扼,比如選取2000個候選框,避免暴力枚舉所有框垃僚。 2. 對于每一個區(qū)域:修正區(qū)域大小(因為取出的區(qū)域大小各自不同集绰,所以需要將每個Region Proposal縮放(warp)成統(tǒng)一的大小)以適合CNN的輸入,做一次前向運算谆棺,將第五個池化層的輸出(就是對候選框提取到的特征)存到硬盤 步驟3
四栽燕、訓(xùn)練一個SVM分類器(二分類)來判斷這個候選框里物體的類別每個類別對應(yīng)一個SVM,判斷是不是屬于這個類別改淑,是就是positive碍岔,反之nagative 比如右圖,就是狗分類的SVM 步驟4
五朵夏、使用回歸器精細修正候選框位置:對于每一個類蔼啦,訓(xùn)練一個線性回歸模型去判定這個框是否框得完美。 步驟5
1.2 缺點:
  1. 利用selective search 提取候選框都是在CPU上進行仰猖,速度是比較慢捏肢。并且得到2000左右的候選框在進行CNN+SVM分類計算量大速度慢,一張圖達到47秒饥侵。

  2. 卷積核沒有共享鸵赫。即在每個框之間很難通過權(quán)重信息共享。所以計算量依然很大躏升,其中有不少其實是重復(fù)計算

  3. 通過warped對選取出來的圖像統(tǒng)一大小對信息也是一種失真辩棒。

  4. 訓(xùn)練耗時,占用磁盤空間大:卷積出來的特征數(shù)據(jù)還需要單獨保存

2. SPP Net(Spatial Pyramid Pooling空間金字塔池化)

SPP Net其實就是在RCNN中CNN網(wǎng)絡(luò)的卷積層和全連接層之間加上了ROI池化操作。
因為我們知道卷積層不需要固定固定輸入一睁,而全連接是需要固定輸入藕赞。這就要求對輸入數(shù)據(jù)crop或warp等操作使網(wǎng)絡(luò)輸入大小固定,RCNN利用這些操作在進行圖片分類卖局。

那我們ROI pooling是如何操作的呢斧蜕?我們可以通過如下圖來理解。
ROI polling
2.1 SPP 網(wǎng)絡(luò)特點
  1. 從中可以看出無論卷積層輸出大小是多少砚偶,SPP layer中每一個pooling的filter 會更具輸入調(diào)整大小批销。所以SPP的輸出始終是固定大小的。
  2. 在卷積層和全連接層之間加入了SPP layer染坯。此時網(wǎng)絡(luò)的輸入可以是任意尺度的均芽,在SPP layer中每一個pooling的filter會根據(jù)輸入調(diào)整大小,而SPP的輸出尺度始終是固定的单鹿。如上圖掀宋,SPP使用空間金字塔采樣(spatial pyramid pooling)將每個window劃分為4*4, 2*2, 1*1的塊,然后每個塊使用max-pooling下采樣仲锄,這樣對于每個window經(jīng)過SPP層之后都得到了一個長度為(4*4+2*2+1)*256維度的特征向量劲妙,將這個作為全連接層的輸入進行后續(xù)操作。SPP針對同一個輸入使用了多個不同尺寸的池化操作儒喊,把不同尺度的結(jié)果拼接作為輸出镣奋;而ROI Pooling可看作單尺度的SPP,對于一個輸入只進行一次池化操作怀愧。(具體理解可以結(jié)合這篇文章一文讀懂Faster RCNN文字描述的很清楚)
    image.png
  3. 我們知道RCNN中顯示對每一個候選框resize統(tǒng)一大小再進行CNN得到統(tǒng)一大小的feature map侨颈。這種效率很低。所以SPP net就是將原圖進行卷積操作得到feature map, 之后找到候選框在feature map映射的patch(可以形象理解為不同候選框在feature map上的表達芯义,這里可以理解為通過特征圖上的感受野找到原始圖像對應(yīng)的特征框)哈垢,之后將詞patch作為每個候選框的特征輸入到SPP layter之后的層。節(jié)省時間扛拨,比RCNN快100倍左右耘分。我們可以通過下面的圖看出SPPnet的改進思路。


    SPP net

2.2 SPP網(wǎng)絡(luò)的優(yōu)缺點

優(yōu)點 缺點
實現(xiàn)CNN多尺度輸入鬼癣, 使使用了selective search等預(yù)處理步驟來提取潛在的bounding box作為輸入陶贼,但是RCNN仍會有嚴重的速度瓶頸
只對原圖提取一次卷積特征,提升速度(共享卷積),

3. Fast RCNN

Fast RCNN

說到Fast RCNN 其實就是在SPP Net基礎(chǔ)上稍微有兩點進行了修改待秃。

  • 用softmax替代SVM分類
  • 同時利用Multi-task Loss(多任務(wù)損失函數(shù))將邊框回歸和分類一起進行如下圖所示拜秧。


3.1 步驟
Fast-RCNN流程圖

好了我們總結(jié)下Fast RCNN的步驟吧

Fast RCNN 步驟
1. 特征提取:以整張圖片為輸入利用CNN得到圖片的特征層章郁;
2. region proposal:通過Selective Search等方法從原始圖片提取區(qū)域候選框枉氮,并把這些候選框一一投影到最后的特征層志衍;
3.區(qū)域歸一化:針對特征層上的每個區(qū)域候選框進行RoI Pooling操作,得到固定大小的特征表示聊替; ROI pooling可以 speed up both train and test time
4. 分類與回歸:然后再通過兩個全連接層楼肪,分別用softmax做多目標分類,用回歸模型進行邊框位置與大小微調(diào)惹悄。
3.2 優(yōu)缺點
缺點 使使用了selective search等預(yù)處理步驟來提取潛在的bounding box作為輸入春叫,但是RCNN仍會有嚴重的速度瓶頸
優(yōu)點 我們使用 ROI 池化將特征圖塊轉(zhuǎn)換為固定的大小,并饋送到全連接層進行分類和定位泣港。因為 Fast-RCNN 不會重復(fù)提取特征暂殖,因此它能顯著地減少處理時間。

4. Faster RCNN

說到這里我強烈推薦這篇文章一文讀懂Faster RCNN)当纱,第一次學(xué)習(xí)這個模型我通過這篇文章很輕松的了解里面的原理及內(nèi)容呛每。當(dāng)然肯定少不了閱讀原論文Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks。在這里我也推薦關(guān)于Faster RCNN的github代碼坡氯,同時也推薦一篇博客專門對重要代碼進行了詳解晨横。

Faster RCNN

其實Faster RCNN就是在Fast RCNN基礎(chǔ)上添加了RPN網(wǎng)絡(luò)。一下給一個詳細的流程圖我們可以根據(jù)這個流程圖詳細介紹一下Faster RCNN.

4.1 步驟
Faster RCNN流程圖

在這里我們可以將其分成4個部分:

步驟 內(nèi)容 圖示
1.Feature Extraction 卷積層(conv layers)箫柳,用于提取圖片的特征手形,輸入為整張圖片, 輸出為提取出的特征稱為feature maps
2. Region Proposal Network RPN網(wǎng)絡(luò)(Region Proposal Network)滞时,用于推薦候選區(qū)域叁幢,這個網(wǎng)絡(luò)是用來代替之前的search selective的。輸入為圖片(因為這里RPN網(wǎng)絡(luò)和Fast R-CNN共用同一個CNN坪稽,所以這里輸入也可以認為是featrue maps),輸出為多個候選區(qū)域鳞骤,這里的細節(jié)會在后面詳細介紹
3. ROI Polling RoI pooling窒百,和Fast R-CNN一樣,將不同大小的輸入轉(zhuǎn)換為固定長度的輸出豫尽,輸入輸出和Faste R-CNN中RoI pooling一樣
4.Classification and Regression 分類和回歸篙梢,這一層的輸出是最終目的,輸出候選區(qū)域所屬的類美旧,和候選區(qū)域在圖像中的精確位置渤滞。
4.2 步驟詳解
  1. Conv Layer
    Faster RCNN首先是支持輸入任意大小的圖片的,比如上圖中輸入的PQ榴嗅,進入網(wǎng)絡(luò)之前對圖片進行了規(guī)整化尺度的設(shè)定妄呕,如可設(shè)定圖像短邊不超過600,圖像長邊不超過1000嗽测,我們可以假定MN=1000600(如果圖片少于該尺寸绪励,可以邊緣補0肿孵,即圖像會有黑色邊緣)
    ① 13個conv層:kernel_size=3,pad=1,stride=1;
    卷積公式:


    所以,conv層不會改變圖片大惺栉骸(即:輸入的圖片大小=輸出的圖片大型W觥)
    ② 13個relu層:激活函數(shù),不改變圖片大小
    ③ 4個pooling層:kernel_size=2,stride=2;pooling層會讓輸出圖片是輸入圖片的1/2
    經(jīng)過Conv layers大莫,圖片大小變成(M/16)
    (N/16)蛉腌,即:6040(1000/16≈60,600/16≈40);則只厘,F(xiàn)eature Map就是6040512-d(注:VGG16是512-d,ZF是256-d)烙丛,表示特征圖的大小為6040,數(shù)量為512

  2. RPN (Region Proposal Network)
    這里與Fast RCNN區(qū)別在于通過RPN網(wǎng)絡(luò)來替代原來的Selective Search選取候選框懈凹。


    RPN
  • Anchor
    說到這里之前我們先介紹下PRN網(wǎng)絡(luò)是用什么方法選取候選框的呢蜀变?其實才用了anchor的機制。下面在介紹RPN網(wǎng)絡(luò)之前讓我們先了解下anchor介评。
    其實anchor就是我們在feature map上預(yù)先生成的候選框库北。讓我們看一下anchor究竟長什么樣子。
[[ -84.  -40.   99.   55.]
 [-176.  -88.  191.  103.]
 [-360. -184.  375.  199.]
 [ -56.  -56.   71.   71.]
 [-120. -120.  135.  135.]
 [-248. -248.  263.  263.]
 [ -36.  -80.   51.   95.]
 [ -80. -168.   95.  183.]
 [-168. -344.  183.  359.]]

anchor

generate anchor

這個矩陣即是我們的anchor表示们陆。從橫向來看對于每一行總共有4個值分別表示()表示候選框左上和右下角的坐標寒瓦。但是為什么大小都是這么大呢?這是因為輸入的如下我們都會統(tǒng)一將其reshape成為800x600, anchors中長寬1:2中最大為352x704坪仇,長寬2:1中最大736x384杂腰,基本是cover了800x600的各個尺度和形狀。從縱向來看總共有9個anchor椅文,為什么是9個anchor喂很。這是因為在feature map上每一個像素點會生成大小不同的的3個框選擇(, 以及),而每一個大小不同的候選框又會有3個不同寬高比例(1:1,1:2,2:1)的候選框皆刺。因此我們會生成9個不同大小的anchor∩倮保現(xiàn)在我們來看看一個feature map 我們能產(chǎn)生多少個anchors呢?原圖800x600羡蛾,VGG下采樣16倍漓帅,feature map每個點設(shè)置9個Anchor,所以:ceil(800/16)x ceil(600/16)x9 = 50 x 38 x 9 = 17100(其中ceil()表示向上取整痴怨,是因為VGG輸出的feature map size= 5038)忙干。一般會產(chǎn)生17100個anchor,這么多anchor我們?nèi)慷祭蒙蠁崂嗽澹科鋵嵅蝗晃覀儠M行篩選捐迫,我們后面將會介紹到。每一個anchor在feature map上映射到原圖其實就是一個候選框珠移,可以理解為這就是一個個感受野弓乙。源碼中末融,通過width:(0~60)16,height(0~40)*16建立shift偏移量數(shù)組,再和base_ancho基準坐標數(shù)組累加暇韧,得到特征圖上所有像素對應(yīng)的Anchors的坐標值勾习,是一個[216000,4]的數(shù)組.

2.1 RPN 網(wǎng)絡(luò)流程


3*3 conv
  • 我們看出來生成出來的feature map上有許許多多的anchors, 我們篩選出來的anchor 需要先進行33卷積,這里33卷積這里應(yīng)該是增加感受野的范圍懈玻。順便插一句現(xiàn)在為什么很多卷積喜歡用多個3*3卷積核替換大卷積核呢巧婶?有兩點原因:1.網(wǎng)絡(luò)層數(shù)增加了,這增加了網(wǎng)絡(luò)的非線性表達能力涂乌。2.參數(shù)減少艺栈。
1*1 conv
  • 這里用1*1卷積分別走了兩個分支上面分支生成了,上面這一條分支生成18個通道,而下一條分支生成了36個分支湾盒。這是因為對于上面一條路徑來說是用來做前景分類湿右, 下面一條路徑是用來做前景回歸前景bounding box。對于feature map每一個像素點有9個anchor罚勾,在分類中有2個分類(前景/背景)毅人,對于回歸有4個坐標點(x,y,w,h)所以上面一條有2x9個通道數(shù),而下面一條有4x9個通道數(shù)尖殃。
reshape
  • 對于這里進行兩次的reshape具體原因這就要從caffe的實現(xiàn)形式說起了丈莺。在caffe基本數(shù)據(jù)結(jié)構(gòu)blob中以如下形式保存數(shù)據(jù):blob=[batch_size, channel,height送丰,width]對應(yīng)至上面的保存positive/negative anchors的矩陣缔俄,其在caffe blob中的存儲形式為[1, 2x9, H, W]。而在softmax分類時需要進行positive/negative二分類器躏,所以reshape layer會將其變?yōu)閇1, 2, 9xH, W]大小俐载,即單獨“騰空”出來一個維度以便softmax分類,之后再reshape回復(fù)原狀登失。
  1. Proposal Layer.
  • anchors 定義正負樣本準則:
準則
1. 對每個標定的ground truth瞎疼,與其重疊比例IoU最大的anchor記為正樣本,這樣可以保證每個ground truth至少對應(yīng)一個正樣本anchor
2. 對每個anchors壁畸,如果其與某個ground truth的重疊比例IoU大于0.7,則記為正樣本(目標)茅茂;如果小于0.3捏萍,則記為負樣本(背景)
3. 剩下的既不是正樣本也不是負樣本,不用于最終訓(xùn)練.
  • 保留anchor原則:
順序 操作 anchors 大致數(shù)量
1. 生成anchors, 利用[d_x(A), d_y(A), d_w(A),d_h(A)]對所有的anchors做bounding box regression回歸空闲,這里的anchors生成和訓(xùn)練完全一致 600*800*9
2. 按照輸入的foreground softmax score由大到小排序anchors,提取前TopN(6000)個令杈,即提取修正位置后的foreground anchors 6000
3. 只保留圖像內(nèi)部的anchors ≈5000
4. 剔除非常小的foreground anchor
5. NMS(按照softmax score進行從大到小排序,提取前2000個預(yù)proposal碴倾,對這個2000個進行NMS(非極大值抑制)) ≈2000
6. 隨機選取正負樣本個128個(也可以選擇正負樣本1:4選榷贺) 256
  • 非極大抑制(NMS)


    NMS
  • \star\star\starProposal Loss
    論文中proposal loss 表示為

    Loss 表示

    上述公式i表示anchor index, p_i表示positive softmax probability, p_i^*代表對應(yīng)的GT predict概率(即當(dāng)?shù)趇個anchor與GT間IoU>0.7掉丽,認為是該anchor是positive,p_i^*=1;反之IoU<0.3時异雁,認為是該anchor是negative捶障,p_i^*=0;至于那些0.3<IoU<0.7的anchor則不參與訓(xùn)練);t代表predict bounding box, t^*代表對應(yīng)positive anchor對應(yīng)的GT box纲刀。可以看到,整個Loss分為2部分:

  1. cls loss救崔,即rpn_cls_loss層計算的softmax loss囤耳,用于分類anchors為positive與negative的網(wǎng)絡(luò)訓(xùn)練
  2. reg loss,即rpn_loss_bbox層計算的soomth L1 loss面褐,用于bounding box regression網(wǎng)絡(luò)訓(xùn)練拌禾。注意在該loss中乘了p_i^*,相當(dāng)于只關(guān)心positive anchors的回歸(其實在回歸中也完全沒必要去關(guān)心negative)展哭。

為什么Faster-rcnn中使用Smooth L1 Loss 而不用Smooth L2 Loss湃窍。 smooth L1損失函數(shù)曲線如下圖9所示,作者這樣設(shè)置的目的是想讓loss對于離群點更加魯棒摄杂,相比于L2損失函數(shù)坝咐,其對離群點、異常值(outlier)不敏感析恢,可控制梯度的量級使訓(xùn)練時不容易跑飛墨坚。


Smooth L1 Loss
  • RPN bounding box regression

提取的過程也是個訓(xùn)練的過程,前面的RPN classification給所有的anchor打上label后映挂,我們需用一個表達式來建立anchor與ground truth的關(guān)系泽篮,假設(shè)anchor中心位置坐標是[A_x, A_y],長高為Aw和Ah柑船,對應(yīng)ground truth的4個值為[Gx,Gy,Gw,Gh]帽撑,他們間的關(guān)系可以用公式1來表示。[d_x(A), d_y(A), d_w(A),d_h(A)]就是anchor與ground truth之間的偏移量鞍时,由公式1可以推導(dǎo)出公式2亏拉,這里用對數(shù)來表示長寬的差別,是為了在差別大時能快速收斂逆巍,差別小時能較慢收斂來保證精度

公式1

公式2

有了這4個偏移量及塘,你就可以拿他們?nèi)ビ?xùn)練圖2 RPN中下面一個分支的輸出。完成訓(xùn)練后RPN就具備識別每一個anchor到與之對應(yīng)的最優(yōu)proposal偏移量的能力([, ,, ])锐极,換個角度看就是得到了所有proposal的位置和尺寸笙僚。要注意的是如果一個feature map中有多個ground truth,每個anchor只會選擇和它重疊度最高的ground truth來計算偏移量灵再。
image.png

  1. Classification and Regression
    在前面RPN網(wǎng)絡(luò)相當(dāng)于得到前/背景的分類肋层,以及前景大致的回歸框亿笤。在Classification and Regression 上面會對前景框進行進一步分類以及回歸,我們能得知前景究竟屬于哪一類栋猖,以及對應(yīng)的精準回歸框净薛。

有關(guān)于faster-RCNN方面的改進在日后會繼續(xù)更新,敬請期待掂铐。罕拂。。全陨。

參考:

  1. RCNN,fast RCNN,faster RCNN區(qū)別
  2. 一文讀懂Faster RCNN
  3. 目標檢測學(xué)習(xí)總結(jié)之RCNN爆班、SPP-net、Fast RCNN辱姨、Faster RCNN柿菩、YOLO、SSD的區(qū)別
  4. Faster R-CNN文章詳細解讀
  5. Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks雨涛。
  6. Faster R-CNN 源碼解析(Tensorflow版)
  7. Faster RCNN學(xué)習(xí)筆記
  8. 非極大抑制
  9. 為什么Faster-rcnn枢舶、SSD中使用Smooth L1 Loss 而不用Smooth L2 Loss
  10. 從結(jié)構(gòu)、原理到實現(xiàn)替久,F(xiàn)aster R-CNN全解析(原創(chuàng))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凉泄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蚯根,更是在濱河造成了極大的恐慌后众,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颅拦,死亡現(xiàn)場離奇詭異蒂誉,居然都是意外死亡,警方通過查閱死者的電腦和手機距帅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門右锨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碌秸,你說我怎么就攤上這事绍移。” “怎么了讥电?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵登夫,是天一觀的道長。 經(jīng)常有香客問我允趟,道長,這世上最難降的妖魔是什么鸦致? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任潮剪,我火速辦了婚禮涣楷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抗碰。我一直安慰自己狮斗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布弧蝇。 她就那樣靜靜地躺著碳褒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪看疗。 梳的紋絲不亂的頭發(fā)上沙峻,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音两芳,去河邊找鬼摔寨。 笑死,一個胖子當(dāng)著我的面吹牛怖辆,可吹牛的內(nèi)容都是我干的是复。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼竖螃,長吁一口氣:“原來是場噩夢啊……” “哼淑廊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起特咆,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤季惩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后坚弱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜀备,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年荒叶,在試婚紗的時候發(fā)現(xiàn)自己被綠了碾阁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡些楣,死狀恐怖脂凶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情愁茁,我是刑警寧澤蚕钦,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站鹅很,受9級特大地震影響嘶居,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一邮屁、第九天 我趴在偏房一處隱蔽的房頂上張望整袁。 院中可真熱鬧,春花似錦佑吝、人聲如沸坐昙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炸客。三九已至,卻和暖如春戈钢,著一層夾襖步出監(jiān)牢的瞬間痹仙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工逆趣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蝶溶,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓宣渗,卻偏偏與公主長得像抖所,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子痕囱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359

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