【轉載】語義分割網絡DeepLab-v3的架構設計思想和TensorFlow實現

https://baijiahao.baidu.com/s?id=1595995875370065359&wfr=spider&for=pc


選自Medium

作者:Thalles Silva

機器之心編譯

參與:Nurhachu Null、劉曉坤

深度卷積神經網絡在各類計算機視覺應用中取得了顯著的成功驯耻,語義分割也不例外。這篇文章介紹了語義分割的 TensorFlow 實現种呐,并討論了一篇和通用目標的語義分割最相關的論文——DeepLab-v3。DeepLab-v3 是由谷歌開發(fā)的語義分割網絡弃甥,近日爽室,谷歌還開源了該系列的最新版本——DeepLab-v3+。

GitHub 地址:https://github.com/sthalles/deeplab_v3

語義分割

常規(guī)的圖像分類深度卷積神經網絡擁有相似的結構潘飘。這些模型以圖像作為輸入肮之,并輸出一個代表圖像類別的數值。

通常卜录,分類深度卷積神經網絡有 4 種主要運算。卷積眶明、激活函數艰毒、池化以及全連接層。傳遞一張圖片搜囱,通過一系列這些運算會輸出一個包含每個類別標簽的概率的特征向量丑瞧。請注意柑土,在這種設定下,我們是對圖片的整體進行分類绊汹。也就是說稽屏,為一張圖像分配一個標簽。

用于圖像識別的標準深度學習模型西乖。

與圖像分類不同的是狐榔,在語義分割中我們將對圖像中的每一個像素作出分類。所以获雕,對每個像素而言薄腻,模型需要將它歸類為預定義的類別之一。換言之届案,語義分割是在像素級別理解圖像庵楷。

請記住,語義分割不會區(qū)分目標實例楣颠。因此尽纽,如果我們有同一個類的兩個目標,它們最終將具有相同的類別標簽童漩。實例分割是區(qū)分同一類實例的問題蜓斧。

語義分割與實例分割的區(qū)別。(中) 雖然它們是相同的目標睁冬,但它們被分類為不同的目標(實例分割)挎春。(右) 相同的目標,相同的類別(語義分割)豆拨。

然而直奋,常規(guī)的深度卷積神經網絡 (如 AlexNet 和 VGG ) 并不適用于密集預測的任務。首先施禾,這些模型包含許多用于減小輸入特征的空間維度的層脚线。結果,這些層最終產生缺乏清晰細節(jié)的高度抽象的特征向量弥搞。第二邮绿,全連接層在計算過程中具有固定的輸入規(guī)模和松散的空間信息。

作為一個例子攀例,試想通過一系列的卷積來傳遞圖像船逮,而不是使用池化和全連接層。我們將每次卷積都設置成步長為 1粤铭,padding 為「SAME」挖胃。通過這種處理,每一次卷積都保留了輸入的空間維度。我們可以堆疊很多這種卷積酱鸭,并最終得到一個分割模型吗垮。

用于密集預測的全卷積神經網絡。請注意凹髓,不存在池化層和全連接層烁登。

這個模型可以輸出形狀為 [W,H,C] 的概率張量,其中 W 和 H 代表的是寬度和高度蔚舀,C 代表的是類別標簽的個數饵沧。在第三個維度上應用最大化函數會得到形狀為 [W,H,1] 的張量。然后蝗敢,我們計算真實圖像和我們的預測的每個像素之間的交叉熵捷泞。最終,我們對計算結果取平均值寿谴,并且使用反向傳播算法訓練網絡锁右。

然而,這個方法存在一個問題讶泰。正如前面所提到的咏瑟,使用步長為 1,padding 為「SAME」痪署,保留了輸入的維度码泞。但是,那樣做的后果就是模型會極其耗費內存狼犯,而且計算復雜度也是很大的余寥。

為了緩解這個問題,分割網絡通常會有三個主要的組成部分:卷積層悯森、降采樣層和上采樣層宋舷。

圖像語義分割模型的編碼器-解碼器結構。

在卷積神經網絡中實現降采樣的常用方式有兩個:通過改變卷積步長或者常規(guī)的池化操作瓢姻。一般而言祝蝠,降采樣的目標就是減少給定特征圖的空間維度。因此幻碱,降采樣可以讓我們在執(zhí)行更深的卷積運算時不用過多地考慮內存绎狭。然而,這樣一來在計算的時候會損失一些特征褥傍。

值得注意的是儡嘶,這個架構的第一部分看上去類似于普通的分類深度卷積神經網絡。不同的是摔桦,其中沒有設置全連接層社付。

在第一部分之后承疲,我們就得到了形狀為 [W, H, D] 的特征向量邻耕,其中 W,H,D 分別是特征張量的寬度鸥咖、高度和深度。注意兄世,這個壓縮向量的空間維度比原始輸入更加少啼辣,但是更緊致。


頂部:VGG-16 網絡的原始形式御滩。要注意的是鸥拧,堆疊的卷積層的頂部有三個全連接層。底部:VGG-16 網絡中用 1x1 的卷積代替全連接層削解。這種改變可以讓網絡輸出粗略的熱圖富弦。

此時,常規(guī)的分類深度卷積神經網絡會輸出一個包含每個類別概率的密集(非空間)向量氛驮。取而代之腕柜,我們將這個壓縮向量輸入到一系列上采樣層中。這些上采樣層的作用就是重建與輸入維度相同的輸出向量矫废。

通常盏缤,上采樣都是基于步長置換卷積(strided transpose convolution)完成的。這些函數從深而窄的層變成淺而寬的層蓖扑。這里唉铜,我們使用置換卷積將特征向量的維度增加到期望的結果。

在大多數論文中律杠,分割網絡的這兩個部分被稱作編碼器和解碼器潭流。簡而言之,第一部分將信息「編碼」為壓縮向量來代表輸入柜去。第二部分(解碼器)的作用是將這個信號重建為期望的輸出灰嫉。

有很多基于編碼器—解碼器結構的神經網絡實現。FCNs诡蜓、SegNet熬甫,以及 UNet 是最流行的幾個。

模型架構

與大多數編碼器—解碼器架構設計不同的是蔓罚,Deeplab 提供了一種與眾不同的語義分割方法椿肩。Deeplab 提出了一種用于控制信號抽取和學習多尺度語境特征的架構。

Deeplab 把在 ImagNet 上預訓練得到的 ResNet 作為它的主要特征提取網絡豺谈。但是郑象,它為多尺度的特征學習添加了一個新的殘差塊。最后一個 ResNet 塊使用了空洞卷積(atrous convolution)茬末,而不是常規(guī)的卷積厂榛。此外盖矫,這個殘差塊內的每個卷積都使用了不同的擴張率來捕捉多尺度的語境信息。

另外击奶,這個殘差塊的頂部使用了空洞空間金字塔池化 (ASPP辈双,Atrous Spatial Pyramid Pooling)。ASPP 使用了不同擴張率的卷積來對任意尺度的區(qū)域進行分類柜砾。

為了理解 Deeplab 的架構湃望,我們需要著重注意這三個部分。(i)ResNet 架構痰驱,(ii) 空洞卷積证芭,(iii) 空洞空間金字塔池化(ASPP)。接下來我們將逐一介紹這幾個部分担映。

ResNets

ResNet 是一個非常流行的深度卷積神經網絡架構废士,它贏得了 ILSVRC 2015 分類任務挑戰(zhàn)賽的冠軍。它的主要貢獻之一就是提供了簡化深度學習模型訓練的框架蝇完。

在 ResNet 的原始形式中官硝,它含有 4 個計算模塊。每個模塊包含不同數量的殘差單元四敞。這些單元以特別的形式執(zhí)行一系列的卷積運算泛源。同樣,每個模塊都夾雜了最大池化操作來減少空間維度忿危。

原始論文提出了兩種殘差單元:基線塊和瓶頸塊达箍。

基線塊包含兩個 3x3 的卷積,卷積中使用了 BN(批歸一化)和 ReLU 激活函數铺厨。

殘差模塊缎玫。左:基線塊;右:瓶頸塊解滓。

第二個是瓶頸塊赃磨,它包括三個堆疊的部分,用一系列的 1x1洼裤、3x3 和 1x1 的卷積代替了之前的設計邻辉。兩個 1x1 的卷積操作被用來減少和恢復維度。這使得中間的 3x3 的卷積可以在一個密度相對較低的特征向量上進行操作腮鞍。此外潮售,每個卷積之后苦银、每個非線性 ReLU 之前都應用了 BN。

為了有助于澄清這個問題潮酒,我們將這一組操作定義為一個輸入為 x 的函數 F——F(x)托修。

在 F(x) 中的非線性變換之后敲董,這個單元將 F(x) 的結果和原始輸入 x 相結合瓦糕。這種結合是通過對兩個函數求和得到的。原始輸入 x 和非線性函數 F(x) 合并帶來了一些優(yōu)勢蜜徽。它使得前面的層可以訪問后面層的梯度信號。換句話說票摇,跳過 F(x) 上的操作允許前面的層訪問更強的梯度信號拘鞋。這種類型的連接已經被證明有助于更深網絡的訓練。

當我們增加模型容量時兄朋,非瓶頸單元也表明有助于準確率的提高掐禁。然而怜械,瓶頸殘差單元具有一些實際優(yōu)勢颅和。首先,它們在幾乎相同數量的參數下可執(zhí)行更多的計算缕允。第二峡扩,它們與非瓶頸單元的計算復雜度相似。

在實際中障本,瓶頸單元更適合于訓練更深的模型教届,因為它們需要的訓練時間和計算資源更少。

在我們的實現中驾霜,我們將使用完全預激活殘差單元(full pre-activation Residual Unit)案训,與標準瓶頸單元的唯一區(qū)別在于 BN 和 ReLU 激活函數的放置順序。對于完全預激活粪糙,BN 和 ReLU(按此順序)出現在卷積之前强霎。

不同的 ResNet 構建模塊塊體系架構。最左邊:原始 ResNet 模塊蓉冈;最右邊:改進的完全預激活版本城舞。

正如《Identity Mappings in Deep Residual Networks》中所展示的一樣。完全預激活單元要優(yōu)于其他的變體寞酿。

注意家夺,這些設計之間的唯一區(qū)別是卷積堆棧中 BN 和 ReLU 的順序。

空洞卷積

空洞卷積(或者擴張卷積)是具有一個因子的常規(guī)卷積伐弹,這個因子使得我們能夠擴展濾波器的視野拉馋。

以 3×3 卷積濾波器為例。當擴張因子等于 1 時惨好,它的行為類似于標準卷積煌茴。但是,如果將擴張因子設置為 2昧狮,則它具有擴大卷積核的效果景馁。

理論上,它是這樣工作的:首先逗鸣,根據擴張率對卷積濾波器進行擴張合住。然后绰精,它用零填充空白空間,創(chuàng)建稀疏的類似濾波器透葛。最后笨使,使用擴張的濾波器進行常規(guī)卷積。

不同擴張率的空洞卷積

因此僚害,大小為 3x3硫椰、擴張率為 2 的卷積將使其能夠覆蓋 5x5 的區(qū)域。然而萨蚕,因為它的作用就像一個稀疏的過濾器靶草,只有原始的 3 x3 單元將執(zhí)行計算并生成結果。

以類似的方式岳遥,擴張因子為 3 的常規(guī) 3×3 的卷積能夠得到對應的 7×7 區(qū)域的信號奕翔。

這種效果允許我們控制計算特征響應的分辨率。此外浩蓉,空洞卷積在不增加參數數量或計算量的情況下增加了更大范圍的語境信息派继。

Deeplab 還表明,必須根據特征圖的大小來調整擴張率捻艳。他們研究了在小特征圖上使用大擴張率的結果驾窟。

給小特征圖設置更大的擴張率的副作用。對于 14×14 的輸入圖像认轨,使用擴張率為 15 的 3×3 卷積绅络,其結果和常規(guī)的 1×1 卷積類似。

當擴張率非常接近特征圖的尺寸時好渠,一個常規(guī)的 3×3 的空洞濾波器的效果與標準的 1×1 卷積是一樣的昨稼。

換句話說,空洞卷積的效率依賴于對擴張率的選擇拳锚。由于這一原因假栓,理解神經網絡中的輸出步長(output stride)的概念是很重要的。

輸出步長反映輸入圖像大小與輸出特征圖大小的比率霍掺,它定義了輸入向量在通過網絡時經受的信號抽象程度匾荆。

輸出步長為 16,圖像大小為 224x224x3 時杆烁,輸出特征向量比輸入圖像的維度小 16 倍牙丽,變成了 14x14。

此外兔魂,Deeplab 還討論了不同輸出步長對分割模型的影響烤芦。Deeplab 認為過強的信號抽象不利于密集預測任務∥鲂#總之构罗,具有較小輸出步長 (較弱信號抽象) 的模型傾向于輸出更精細的分割結果铜涉。然而,使用較小的輸出步長訓練模型需要更多的訓練時間遂唧。

Deeplab 還展示了兩種輸出步長(8 和 16)設置下的結果芙代。和預期的一樣,步長等于 8 能夠產生稍微好一些的結果盖彭。在這里纹烹,出于實際原因,我們選擇了 16 為輸出步長召边。

此外铺呵,由于空洞卷積塊沒有實現降采樣,所以 ASPP 也運行在相同的特征響應大小上掌实。因此陪蜻,它允許使用相對較大的擴張率從多尺度的語境中學習特征。

新型空洞殘差塊包含三個殘差單元贱鼻。三個單元都總共擁有三個 3×3 的卷積塊。在多重網格(multigrid)方法的啟發(fā)下滋将,Deeplab 為每個卷積設置了不同的擴張率邻悬。總之随闽,多重網格為三個卷積中的每個卷積定義了不同的擴張率父丰。

在實際中:

對于 block 4,當輸出步長是 16掘宪,多重網格為(1,2,4)的時候蛾扇,這三個卷積的擴張率分別是(2,4,8)。

空洞空間金字塔池化

空洞空間金字塔池化(ASPP)的思想是提供具有多尺度信息的模型魏滚。為了做到這一點镀首,ASPP 添加了一系列具有不同擴張率的空洞卷積。這些擴張率是被設計用來捕捉大范圍語境的鼠次。此外更哄,為了增加全局的語境信息,ASPP 還通過全局平均池化(GAP)結合了圖像級別的特征腥寇。

這個版本的 ASPP 包含 4 個并行的操作成翩。它們分別是一個 1×1 的卷積以及三個 3×3 的卷積(擴張率分別是(6,12,18))。正如我們前面所提及的赦役,現在麻敌,特征圖的標稱步長(nominal stride)是 16.

在原始實現的基礎上,我們使用 513 x513 的裁剪尺寸進行訓練和測試掂摔。因此术羔,使用 16 的輸出步長意味著 ASPP 接收大小為 32 x32 的特征向量职辅。

此外,為了添加更多全局語境信息聂示,ASPP 結合了圖像級別的特征域携。首先,它將 GAP 應用于從最后一個空洞塊輸出的特征上鱼喉。其次秀鞭,所得特征被輸入到具有 256 個濾波器的 1x 1 卷積中。最后扛禽,將結果進行雙線性上采樣到正確的維度大小锋边。

@slim.add_arg_scope

def atrous_spatial_pyramid_pooling(net, scope, depth=256):

"""

ASPP consists of (a) one 1×1 convolution and three 3×3 convolutions with rates = (6, 12, 18) when output stride = 16

(all with 256 filters and batch normalization), and (b) the image-level features as described in https://arxiv.org/abs/1706.05587

:param net: tensor of shape [BATCH_SIZE, WIDTH, HEIGHT, DEPTH]

:param scope: scope name of the aspp layer

:return: network layer with aspp applyed to it.

"""

with tf.variable_scope(scope):

feature_map_size = tf.shape(net)

# apply global average pooling

image_level_features = tf.reduce_mean(net, [1, 2], name='image_level_global_pool', keep_dims=True)

image_level_features = slim.conv2d(image_level_features, depth, [1, 1], scope="image_level_conv_1x1", activation_fn=None)

image_level_features = tf.image.resize_bilinear(image_level_features, (feature_map_size[1], feature_map_size[2]))

at_pool1x1 = slim.conv2d(net, depth, [1, 1], scope="conv_1x1_0", activation_fn=None)

at_pool3x3_1 = slim.conv2d(net, depth, [3, 3], scope="conv_3x3_1", rate=6, activation_fn=None)

at_pool3x3_2 = slim.conv2d(net, depth, [3, 3], scope="conv_3x3_2", rate=12, activation_fn=None)

at_pool3x3_3 = slim.conv2d(net, depth, [3, 3], scope="conv_3x3_3", rate=18, activation_fn=None)

net = tf.concat((image_level_features, at_pool1x1, at_pool3x3_1, at_pool3x3_2, at_pool3x3_3), axis=3,

name="concat")

net = slim.conv2d(net, depth, [1, 1], scope="conv_1x1_output", activation_fn=None)

return net

最后,各個分支的特征都被通過連接操作結合成一個單獨的向量编曼。然后使用另一個 1×1(采用 BN豆巨,和 256 個濾波器)的卷積對這個輸出進行卷積。

ASPP 之后掐场,我們將結果輸入到另一個 1×1 的卷積中去生成最終的分割邏輯往扔。

實現細節(jié)

這個實現用 ResNet-50 作為特征提取器,Deeplab_v3 采取了以下網絡配置:

輸出步長=16

為新的空洞殘差塊(block 4)使用固定的多重網格空洞卷積率(1,2,4)

在最后一個空洞卷積殘差塊之后使用擴張率為(6,12,18)的 ASPP熊户。

將輸出步長設置為 16 有利于可持續(xù)地快速訓練萍膛。與另一個輸出步長 8 相比,輸出步長為 16 使得空洞殘差塊處理的特征圖比步長為 8 時處理的特征圖小四倍嚷堡。

將多重網格擴張率應用于空洞殘差塊內部的 3 個卷積蝗罗。

最終,ASPP 中的三個并行的卷積得到了不同的擴張率——(6,12,18)蝌戒。

在計算交叉熵損失函數之前串塑,我們將分割邏輯調整為輸入圖像的大小。正如論文中所指出的北苟,為了保持分辨率細節(jié)桩匪,調整分割邏輯的大小比調整真實標簽的大小更好。

基于原始的訓練過程粹淋,我們使用一個 0.5 到 2 之間的隨機因子對每個圖像做了擴展吸祟。此外,我們還對縮放后的圖像做了隨機的左右翻轉桃移。

最終屋匕,我們?yōu)橛柧毢蜏y試裁剪了 513 x513 大小的圖像。

def deeplab_v3(inputs, args, is_training, reuse):

# mean subtraction normalization

inputs = inputs - [_R_MEAN, _G_MEAN, _B_MEAN]

# inputs has shape [batch, 513, 513, 3]

with slim.arg_scope(resnet_utils.resnet_arg_scope(args.l2_regularizer, is_training,

args.batch_norm_decay,

args.batch_norm_epsilon)):

resnet = getattr(resnet_v2, args.resnet_model)

_, end_points = resnet(inputs,

args.number_of_classes,

is_training=is_training,

global_pool=False,

spatial_squeeze=False,

output_stride=args.output_stride,

reuse=reuse)

with tf.variable_scope("DeepLab_v3", reuse=reuse):

# get block 4 feature outputs

net = end_points[args.resnet_model + '/block4']

net = atrous_spatial_pyramid_pooling(net, "ASPP_layer", depth=256, reuse=reuse)

net =slim.conv2d(net, args.number_of_classes, [1, 1], activation_fn=None,

normalizer_fn=None, scope='logits')

size = tf.shape(inputs)[1:3]

# resize the output logits to match the labels dimensions

# net = tf.image.resize_nearest_neighbor(net, size)

net = tf.image.resize_bilinear(net, size)

return net

為了實現殘差網絡 block4 中具有多重網格的空洞卷積借杰,我們僅僅改變了 resnet_utils.py 文件中的以下這段代碼:

...

with tf.variable_scope('unit_%d' % (i + 1), values=[net]):

# If we have reached the target output_stride, then we need to employ

# atrous convolution with stride=1 and multiply the atrous rate by the

# current unit's stride for use in subsequent layers.

if output_stride is not None and current_stride == output_stride:

# Only uses atrous convolutions with multi-graid rates in the last (block4) block

if block.scope == "block4":

net = block.unit_fn(net, rate=rate * multi_grid[i], **dict(unit, stride=1))

else:

net = block.unit_fn(net, rate=rate, **dict(unit, stride=1))

rate *= unit.get('stride', 1)

訓練

為了訓練網絡过吻,我們決定使用來自于《Semantic contours from inverse detectors》的擴增版的 Pascal VOC 數據集。

訓練數據由 8252 張圖像組成。訓練集有 5623 張纤虽,驗證集有 2299 張乳绕。為了使用原始的 VOC2012 驗證數據集來測試模型,我們從驗證集中刪去了 558 張圖像逼纸。這 558 張圖片也出現在官方的 VOC 驗證集中洋措。此外,我還添加了來自 VOC 2012 訓練集中的 330 幅圖像杰刽,它們既沒出現在 5623 張訓練集中菠发,也沒出現在 2299 張的驗證集中。最后贺嫂,8252 張圖像中的 10%(大約 825 張圖像)用來驗證滓鸠,其余的圖像留著訓練。

注意第喳,這與原始論文是不一樣的:這次實現沒有在 COCO 數據集上預訓練糜俗。此外,論文中描述到的一些訓練和評估技術也沒有用到曲饱。

結果

模型能夠在 PASCAL VOC 驗證集上得到良好的結果悠抹。

像素準確率:大約 91%

平均準確率:大約 82%

均交并比(mIoU):大約 74%

頻權交并比(FWIoU):大約 86%

以下是 PASCAL VOC 驗證集的圖像分割的結果。

結論

語義分割無疑是計算機視覺領域中最流行的領域之一渔工。Deeplab 提供了一個傳統(tǒng)編碼器-解碼器體系架構的替代方案锌钮。它提倡在多范圍的語境中使用空洞卷積學習特征。

原文鏈接:https://medium.freecodecamp.org/diving-into-deep-convolutional-semantic-segmentation-networks-and-deeplab-v3-4f094fa387df

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末引矩,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子侵浸,更是在濱河造成了極大的恐慌旺韭,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掏觉,死亡現場離奇詭異区端,居然都是意外死亡,警方通過查閱死者的電腦和手機澳腹,發(fā)現死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門织盼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人酱塔,你說我怎么就攤上這事沥邻。” “怎么了羊娃?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵唐全,是天一觀的道長。 經常有香客問我蕊玷,道長邮利,這世上最難降的妖魔是什么弥雹? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮延届,結果婚禮上剪勿,老公的妹妹穿的比我還像新娘。我一直安慰自己方庭,他們只是感情好厕吉,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著二鳄,像睡著了一般赴涵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上订讼,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天髓窜,我揣著相機與錄音,去河邊找鬼欺殿。 笑死寄纵,一個胖子當著我的面吹牛,可吹牛的內容都是我干的脖苏。 我是一名探鬼主播程拭,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼棍潘!你這毒婦竟也來了恃鞋?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤亦歉,失蹤者是張志新(化名)和其女友劉穎恤浪,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體肴楷,經...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡水由,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了赛蔫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片砂客。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖呵恢,靈堂內的尸體忽然破棺而出鞠值,到底是詐尸還是另有隱情,我是刑警寧澤瑰剃,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布齿诉,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏粤剧。R本人自食惡果不足惜歇竟,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抵恋。 院中可真熱鬧焕议,春花似錦、人聲如沸弧关。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽世囊。三九已至别瞭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間株憾,已是汗流浹背蝙寨。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嗤瞎,地道東北人墙歪。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像贝奇,于是被迫代替她去往敵國和親虹菲。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內容