Tensorflow版本yolo v3源碼閱讀筆記(2)

在上一篇中學(xué)習(xí)了yolov3中的darknet53模型发框,在這一篇中我們繼續(xù)來分析yolov3的源代碼绪抛。

需要說明的是询吴,我學(xué)習(xí)的這個yolov3的源碼出自這里malin9402

這次我們要分析的是yolov3.py的源碼谐算。下面開始吧叫确。

下面先了解一下文件開頭的一些參數(shù)

#yolov3能夠檢測到的類別的數(shù)目
NUM_CLASS       = len(utils.read_class_names(cfg.YOLO.CLASSES))
#yolov3中3個尺度的3個先驗框的大小
ANCHORS         = utils.get_anchors(cfg.YOLO.ANCHORS)
#yolov3中3個尺度的步長
STRIDES         = np.array(cfg.YOLO.STRIDES)
#IOU的閾值
IOU_LOSS_THRESH = cfg.YOLO.IOU_LOSS_THRESH



接下來看yolov3模型

def YOLOv3(input_layer):
    route_1, route_2, conv = backbone.darknet53(input_layer)

    #[bs,13,13,1024] => [bs,13,13,512]
    conv = common.convolutional(conv, (1, 1, 1024,  512))
    #[bs,13,13,512] => [bs,13,13,1024]
    conv = common.convolutional(conv, (3, 3,  512, 1024))
    #[bs,13,13,1024] => [bs,13,13,512]
    conv = common.convolutional(conv, (1, 1, 1024,  512))
    #[bs,13,13,512] => [bs,13,13,1024]
    conv = common.convolutional(conv, (3, 3,  512, 1024))
    #[bs,13,13,1024] => [bs,13,13,512]
    conv = common.convolutional(conv, (1, 1, 1024,  512))

    #[bs,13,13,512] => [bs,13,13,1024]
    conv_lobj_branch = common.convolutional(conv, (3, 3, 512, 1024))
    #[bs,13,13,1024] => [bs,13,13,255]
    conv_lbbox = common.convolutional(conv_lobj_branch, (1, 1, 1024, 3*(NUM_CLASS + 5)), activate=False, bn=False)

    #[bs,13,13,512] => [bs,13,13,256]
    conv = common.convolutional(conv, (1, 1,  512,  256))
    #[bs,13,13,256] => [bs,26,26,256]
    conv = common.upsample(conv)

    #[bs,26,26,256] + [bs,26,26,512] => [bs,26,26,768]
    conv = tf.concat([conv, route_2], axis=-1)

    #[bs,26,26,768] => [bs,26,26,256]
    conv = common.convolutional(conv, (1, 1, 768, 256))
    #[bs,26,26,256] => [bs,26,26,512]
    conv = common.convolutional(conv, (3, 3, 256, 512))
    #[bs,26,26,512] => [bs,26,26,256]
    conv = common.convolutional(conv, (1, 1, 512, 256))
    #[bs,26,26,256] => [bs,26,26,512]
    conv = common.convolutional(conv, (3, 3, 256, 512))
    #[bs,26,26,512] => [bs,26,26,256]
    conv = common.convolutional(conv, (1, 1, 512, 256))

    #[bs,26,26,256] => [bs,26,26,512]
    conv_mobj_branch = common.convolutional(conv, (3, 3, 256, 512))
    #[bs,26,26,512] => [bs,26,26,255]
    conv_mbbox = common.convolutional(conv_mobj_branch, (1, 1, 512, 3*(NUM_CLASS + 5)), activate=False, bn=False)

    #[bs,26,26,256] => [bs,26,26,128]
    conv = common.convolutional(conv, (1, 1, 256, 128))
    #[bs,26,26,128] => [bs,52,52,128]
    conv = common.upsample(conv)

    #[bs,52,52,128] + [bs,52,52,256] => [bs,52,52,384]
    conv = tf.concat([conv, route_1], axis=-1)

    #[bs,52,52,384] => [bs,52,52,128]
    conv = common.convolutional(conv, (1, 1, 384, 128))
    #[bs,52,52,128] => [bs,52,52,256]
    conv = common.convolutional(conv, (3, 3, 128, 256))
    #[bs,52,52,256] => [bs,52,52,128]
    conv = common.convolutional(conv, (1, 1, 256, 128))
    #[bs,52,52,128] => [bs,52,52,256]
    conv = common.convolutional(conv, (3, 3, 128, 256))
    #[bs,52,52,256] => [bs,52,52,128]
    conv = common.convolutional(conv, (1, 1, 256, 128))

    #[bs,52,52,128] => [bs,52,52,256]
    conv_sobj_branch = common.convolutional(conv, (3, 3, 128, 256))
    #[bs,52,52,256] => [bs,52,52,255]
    conv_sbbox = common.convolutional(conv_sobj_branch, (1, 1, 256, 3*(NUM_CLASS +5)), activate=False, bn=False)

    return [conv_sbbox, conv_mbbox, conv_lbbox]

從上面的代碼可以看到,輸入圖片首先通過darknet53模塊得到3個尺度的特征膀钠,然后通過多個卷積層對這3個尺度的特征進行操作掏湾,最終得到小尺度的特征輸出conv_sbbox,中尺度的特征輸出conv_mbbox肿嘲,大尺度的特征輸出conv_lbbox融击。

下面再詳細介紹一下這些特征圖:

1.conv_sbbox:小尺度特征圖,shape=[bs,52,52,255]雳窟,主要用來檢測圖片中的小尺寸物體尊浪。這個尺度可以這樣理解,它把圖片分成了52x52的網(wǎng)格圖片封救,每個網(wǎng)格有3個預(yù)測框拇涤,每個預(yù)測框有85(5+80)個信息,5的意思是它包含(x,y,w,h, confidence)5個基本參數(shù)誉结,80的意思是它有80個類別的檢測概率鹅士。
2. conv_mbbox::中尺度特征圖,shape=[bs,26,26,255]惩坑,主要用來檢測圖片中的中尺寸物體掉盅,它把圖片分成了26x26的網(wǎng)格圖片也拜,每個網(wǎng)格有3個預(yù)測框,每個預(yù)測框有85(5+80)個信息趾痘,理解意思與conv_sbbox相似慢哈。
3. conv_lbbox:大尺度特征圖,shape=[bs,13,13,255]永票,主要用來檢測圖片中的大尺寸物體卵贱,它把圖片分成了13x13的網(wǎng)格圖片,每個網(wǎng)格有3個預(yù)測框侣集,每個預(yù)測框有85(5+80)個信息艰赞,理解意思與conv_sbbox相似。
下面重點關(guān)注一下(x,y,w,h, confidence)5個基本參數(shù):
  1. x: 預(yù)測框的中心橫坐標的偏移量肚吏。
  2. y: 預(yù)測框的中心縱坐標的偏移量方妖。
  3. w: 預(yù)測框的寬度的偏移量。
  4. h: 預(yù)測框的高度的偏移量罚攀。
  5. confidence: 預(yù)測框中檢測到物體的概率党觅。


了解了yolov3的輸出后,接著來看decode方法斋泄,它的主要功能是把yolov3的輸出解碼出來杯瞻,方便后續(xù)計算損失值。

在看代碼之前炫掐,我們先了解一下decode方法的計算流程:

  1. 假設(shè)輸入的形狀為[4,52,52,255]魁莉,這里的4是指每次訓(xùn)練4張圖片,52是指特征圖的高寬大小募胃,可以理解為特征圖把原始圖片劃分成了52x52的格子旗唁,每個格子中255個通道。
    2.將這個輸入的形狀改變?yōu)閇4,52,52,3,85]痹束,3是指每個格子有3個預(yù)測框检疫,85是指每個預(yù)測框有4個位置信息(2個中心位置的偏移量+2個高寬的偏移量+1個置信度+80個類別的概率)
    3.將2個中心位置的偏移量,2個高寬的偏移量祷嘶,1個置信度屎媳,80個類別的概率都提取出來。
  2. 計算每個預(yù)測框的絕對坐標和高寬论巍。
  3. 計算預(yù)測框的置信值和分類值烛谊。
我們看一下先驗框和預(yù)測框的示意圖。
先驗框和預(yù)測框示意圖
  • bh 和 bw 分別表示預(yù)測框的高寬
  • bx 和 by 分別表示預(yù)測框中心位置的橫坐標和縱坐標嘉汰。
  • ph 和 pw 分別表示先驗框的高寬
  • cx 和 cy 分別表示預(yù)測框左上角的坐標
  • th 和 tw 分別表示預(yù)測框高寬的偏移量
  • tx 和 ty 分別表示預(yù)測框中心位置距離左上角位置的偏移量

下面我們在代碼中看具體實現(xiàn)流程丹禀。

def decode(conv_output, i=0):
    """
    return tensor of shape [batch_size, output_size, output_size, anchor_per_scale, 5 + num_classes]
            contains (x, y, w, h, score, probability)
    """

    conv_shape       = tf.shape(conv_output)
    batch_size       = conv_shape[0]#樣本數(shù)
    output_size      = conv_shape[1]#輸出特征圖的高寬

    conv_output = tf.reshape(conv_output, (batch_size, output_size, output_size, 3, 5 + NUM_CLASS))

    conv_raw_dxdy = conv_output[:, :, :, :, 0:2]#預(yù)測框中心位置的偏移量
    conv_raw_dwdh = conv_output[:, :, :, :, 2:4]#預(yù)測框高寬的偏移量
    conv_raw_conf = conv_output[:, :, :, :, 4:5]#預(yù)測框檢測到物體的置信度
    conv_raw_prob = conv_output[:, :, :, :, 5: ]#預(yù)測框的類別的概率

    # 1.對每個先驗框生成在特征圖上的相對坐標,以左上角為基準,其坐標單位為格子湃崩,即數(shù)值表示是第幾個格子
    y = tf.tile(tf.range(output_size, dtype=tf.int32)[:, tf.newaxis], [1, output_size]) # shape = [52,52]
    x = tf.tile(tf.range(output_size, dtype=tf.int32)[tf.newaxis, :], [output_size, 1]) # shape = [52,52]

    xy_grid = tf.concat([x[:, :, tf.newaxis], y[:, :, tf.newaxis]], axis=-1) # shape = [52,52,2]
    xy_grid = tf.tile(xy_grid[tf.newaxis, :, :, tf.newaxis, :], [batch_size, 1, 1, 3, 1]) # shape = [batch_size, 52,52,3,2]
    xy_grid = tf.cast(xy_grid, tf.float32)


     # 2.計算預(yù)測框的絕對坐標和高寬度
     # 根據(jù)上圖公式計算預(yù)測框的中心位置
    pred_xy = (tf.sigmoid(conv_raw_dxdy) + xy_grid) * STRIDES[i] # xy_grid表示特征圖上左上角的位置,即是第幾行第幾列格子接箫,STRIDES表示格子的長度攒读,即特征圖上的一個格子在原圖上的長度
     # 根據(jù)上圖公式計算預(yù)測框的高寬
    pred_wh = (tf.exp(conv_raw_dwdh) * ANCHORS[i]) * STRIDES[i] # ANCHORS[i]) * STRIDES[i] 表示先驗框在原圖上的大小
    pred_xywh = tf.concat([pred_xy, pred_wh], axis=-1)

    # 3. 計算預(yù)測框的置信度和分類值
    pred_conf = tf.sigmoid(conv_raw_conf)
    pred_prob = tf.sigmoid(conv_raw_prob)

    return tf.concat([pred_xywh, pred_conf, pred_prob], axis=-1)


bbox_iou

bbox_iou 函數(shù)用來計算兩個預(yù)測框之間的距離,在utils.py文件中有bboxes_iou方法也實現(xiàn)了類似的功能辛友,它們之間的區(qū)別是輸入的預(yù)測框的參數(shù)不同薄扁。

bbox_iou:參數(shù)是預(yù)測框的中心坐標+預(yù)測框的高寬
bboxes_iou:參數(shù)是預(yù)測框的左上角坐標+預(yù)測框的右下角坐標

iou值實際上就是兩個框的交集面積除以并集面積,這個值越大废累,兩個框的距離就越近邓梅。如下圖所示:


兩個預(yù)測框的交集面積和并集面積

下面我們具體看一下代碼是如何實現(xiàn)的。

def bbox_iou(boxes1, boxes2):

    boxes1_area = boxes1[..., 2] * boxes1[..., 3]#第一個框的面積
    boxes2_area = boxes2[..., 2] * boxes2[..., 3]#第二個框的面積

    boxes1 = tf.concat([boxes1[..., :2] - boxes1[..., 2:] * 0.5,
                        boxes1[..., :2] + boxes1[..., 2:] * 0.5], axis=-1)#將第一個框由中心坐標+高寬的形式轉(zhuǎn)換為左上角坐標+右下角坐標的形式
    boxes2 = tf.concat([boxes2[..., :2] - boxes2[..., 2:] * 0.5,
                        boxes2[..., :2] + boxes2[..., 2:] * 0.5], axis=-1)#將第二個框由中心坐標+高寬的形式轉(zhuǎn)換為左上角坐標+右下角坐標的形式

    left_up = tf.maximum(boxes1[..., :2], boxes2[..., :2])#計算兩個框的交集的左上角坐標邑滨,上圖中是(xmin2,ymin2)
    right_down = tf.minimum(boxes1[..., 2:], boxes2[..., 2:])#計算兩個框的交集的右下角坐標日缨,上圖中是(xmax1,ymax1)

    inter_section = tf.maximum(right_down - left_up, 0.0)
    inter_area = inter_section[..., 0] * inter_section[..., 1]#計算兩個框的交集面積
    union_area = boxes1_area + boxes2_area - inter_area#計算兩個框的并集面積

    return 1.0 * inter_area / union_area#最后交集面積/并集面積


bbox_giou

bbox_giou的功能也是用來計算兩個預(yù)測框之間的距離,按理說掖看,上面的bbox_iou已經(jīng)可以計算兩個框的面積了匣距,為啥還要重要再弄一個方法呢,
這是因為使用bbox_iou來度量預(yù)測框的距離時存在兩個嚴重的問題:
1:如果兩個預(yù)測框之間沒有重合哎壳,那么iou的值就為0毅待,這樣就會導(dǎo)致計算損失函數(shù)時梯度為0,無法進行優(yōu)化归榕。
2:因為iou的計算方法是交集面積除以并集面積尸红,這樣就會導(dǎo)致同一個iou值會有多種不同的形態(tài),如下圖所示:


相同的iou值對應(yīng)不同的形態(tài)

上面三幅圖中的iou = 0.33刹泄,但是giou值分別是0.33,0.24,-0.1外里,這表明如果兩個框重疊和對齊得越好,那么giou值就會越高特石。

因此级乐,基于iou存在的問題,yolov3使用了giou作為預(yù)測框的損失函數(shù)县匠,其計算方式為:


giou計算方法

其中C代表A和B的最小外接矩形的面積风科,通過這種度量方式,兩個預(yù)測框之間沒有相交時乞旦,也能計算距離贼穆。

下面看具體代碼實現(xiàn)。同樣用下圖舉例兰粉。


giou計算示意圖.jpg
def bbox_giou(boxes1, boxes2):

    boxes1 = tf.concat([boxes1[..., :2] - boxes1[..., 2:] * 0.5,
                        boxes1[..., :2] + boxes1[..., 2:] * 0.5], axis=-1)#把第一個預(yù)測框從中心坐標+高寬的形式轉(zhuǎn)換為左上角坐標+右下角坐標的形式
    boxes2 = tf.concat([boxes2[..., :2] - boxes2[..., 2:] * 0.5,
                        boxes2[..., :2] + boxes2[..., 2:] * 0.5], axis=-1)#把第二個預(yù)測框從中心坐標+高寬的形式轉(zhuǎn)換為左上角坐標+右下角坐標的形式

    boxes1 = tf.concat([tf.minimum(boxes1[..., :2], boxes1[..., 2:]),
                        tf.maximum(boxes1[..., :2], boxes1[..., 2:])], axis=-1)#重新整理一下預(yù)測框的坐標
    boxes2 = tf.concat([tf.minimum(boxes2[..., :2], boxes2[..., 2:]),
                        tf.maximum(boxes2[..., :2], boxes2[..., 2:])], axis=-1)

    boxes1_area = (boxes1[..., 2] - boxes1[..., 0]) * (boxes1[..., 3] - boxes1[..., 1])#計算第一個預(yù)測框的面積
    boxes2_area = (boxes2[..., 2] - boxes2[..., 0]) * (boxes2[..., 3] - boxes2[..., 1])#計算第二個預(yù)測框的面積

    left_up = tf.maximum(boxes1[..., :2], boxes2[..., :2])#計算兩個框的交集的左上角坐標故痊,在上圖中是(xmin2,ymin2)
    right_down = tf.minimum(boxes1[..., 2:], boxes2[..., 2:])#計算兩個框的交集的右下角坐標玖姑,在上圖中是(xmax1,ymax1)

    inter_section = tf.maximum(right_down - left_up, 0.0)
    inter_area = inter_section[..., 0] * inter_section[..., 1]#計算交集的面積
    union_area = boxes1_area + boxes2_area - inter_area#計算并集的面積
    iou = inter_area / union_area#計算iou值

    enclose_left_up = tf.minimum(boxes1[..., :2], boxes2[..., :2])#計算最小外接矩形的左上角坐標愕秫,在上圖中是(xmin1,ymin1)
    enclose_right_down = tf.maximum(boxes1[..., 2:], boxes2[..., 2:])#計算最小外接矩形的右下角坐標慨菱,在上圖中是(xmax2,ymax2)
    enclose = tf.maximum(enclose_right_down - enclose_left_up, 0.0)
    enclose_area = enclose[..., 0] * enclose[..., 1]#計算最小外接矩形的面積
    giou = iou - 1.0 * (enclose_area - union_area) / enclose_area#根據(jù)上面的公式計算giou值

    return giou


compute_loss

compute_loss 函數(shù)被用來計算損失。
損失分為3類:框回歸損失戴甩,置信度損失和分類損失符喝。

框回歸損失

計算過程:

  • 獲得置信度respond_bbox。
  • 計算bbox_loss_scale = 2.0 - (真實框的面積)/(輸入原圖的面積)
  • 損失 giou_loss = respond_bbox * bbox_loss_scale * (1-giou)
置信度損失

計算過程:

  • 對所有預(yù)測框求出它和所有真實框的iou值甜孤。
  • 然后找出每個預(yù)測框的iou值中的最大的一個值协饲。
  • 如果每個預(yù)測框找出的這個最大iou值小于指定的閾值,那么認為這個預(yù)測框不包含物體缴川,為背景框(負樣本)茉稠,否則這個框是前景框(正樣本)。還有一種是這個iou值大于指定的閾值把夸,但是這個預(yù)測框沒有包含物體的情況而线。這種情況不需要參與損失函數(shù)的計算,在代碼中被巧妙的處理掉了恋日。
  • 計算正樣本誤差和負樣本誤差吞获,最后相加。
分類損失

對于分類損失谚鄙,同樣只考慮正樣本誤差各拷,使用交叉熵損失函數(shù)計算誤差。

輸入:
pred: 經(jīng)過decode解碼后的檢測框闷营,即原圖上的檢測框烤黍。
conv: 沒有經(jīng)過解碼的檢測框,即特征圖上的檢測框傻盟。
label: 標簽的格式為 [batch_size, output_size, output_size, anchor_per_scale, 85=(2個中心坐標xy+2個形狀wh+1個置信值+80個類別)]速蕊;
bboxes: 每個尺度的真實框集合,里面存放的是真實框的4個參數(shù)(2個中心點坐標+2個高寬長度)
i: 表示第幾個尺度上的特征圖(總共有3個尺度)娘赴。

搞清楚了損失函數(shù)的計算流程和參數(shù)后规哲,我們看看代碼是如何實現(xiàn)的。

def compute_loss(pred, conv, label, bboxes, i=0):

    conv_shape  = tf.shape(conv)#特征圖形狀
    batch_size  = conv_shape[0]#處理的圖片數(shù)量
    output_size = conv_shape[1]#特征圖的大小
    input_size  = STRIDES[i] * output_size#原圖的大小
    conv = tf.reshape(conv, (batch_size, output_size, output_size, 3, 5 + NUM_CLASS))#將特征圖轉(zhuǎn)換形式

    conv_raw_conf = conv[:, :, :, :, 4:5]#特征圖的置信度
    conv_raw_prob = conv[:, :, :, :, 5:]#特征圖中類別的概率

    pred_xywh     = pred[:, :, :, :, 0:4]#預(yù)測框在原圖上的坐標和高寬
    pred_conf     = pred[:, :, :, :, 4:5]#預(yù)測框處理后的置信度

    label_xywh    = label[:, :, :, :, 0:4]#真實框的坐標和高寬
    respond_bbox  = label[:, :, :, :, 4:5]#真實框的置信度诽表,有目標的為1唉锌,沒目標的為0
    label_prob    = label[:, :, :, :, 5:]#真實框的類別概率

# 1.框回歸損失
    # 計算預(yù)測框和真實框的giou值
    giou = tf.expand_dims(bbox_giou(pred_xywh, label_xywh), axis=-1)
    input_size = tf.cast(input_size, tf.float32)
    # bbox_loss_scale 制衡誤差 
    bbox_loss_scale = 2.0 - 1.0 * label_xywh[:, :, :, :, 2:3] * label_xywh[:, :, :, :, 3:4] / (input_size ** 2)
    # 計算giou_loss
    giou_loss = respond_bbox * bbox_loss_scale * (1- giou)

# 2.置信度損失
    # 計算所有預(yù)測框和真實框的iou值
    iou = bbox_iou(pred_xywh[:, :, :, :, np.newaxis, :], bboxes[:, np.newaxis, np.newaxis, np.newaxis, :, :])
    # 找出每個預(yù)測框的最大iou值
    max_iou = tf.expand_dims(tf.reduce_max(iou, axis=-1), axis=-1)
    
    # respond_bgd 形狀為 [batch_size, output_size, output_size, anchor_per_scale, x],當無目標且小于閾值時x為1竿奏,否則為0
    respond_bgd = (1.0 - respond_bbox) * tf.cast( max_iou < IOU_LOSS_THRESH, tf.float32 )

    conf_focal = tf.pow(respond_bbox - pred_conf, 2)

    conf_loss = conf_focal * (
      # 正樣本誤差
            respond_bbox * tf.nn.sigmoid_cross_entropy_with_logits(labels=respond_bbox, logits=conv_raw_conf)
            +
      # 負樣本誤差
            respond_bgd * tf.nn.sigmoid_cross_entropy_with_logits(labels=respond_bbox, logits=conv_raw_conf)
    )

# 3.分類損失
    使用交叉熵損失計算損失值
    prob_loss = respond_bbox * tf.nn.sigmoid_cross_entropy_with_logits(labels=label_prob, logits=conv_raw_prob)

    # 誤差平均
    giou_loss = tf.reduce_mean(tf.reduce_sum(giou_loss, axis=[1,2,3,4]))
    conf_loss = tf.reduce_mean(tf.reduce_sum(conf_loss, axis=[1,2,3,4]))
    prob_loss = tf.reduce_mean(tf.reduce_sum(prob_loss, axis=[1,2,3,4]))

    return giou_loss, conf_loss, prob_loss

yolov3的損失函數(shù)看起來比較明白易懂袄简,但這可能是經(jīng)過原作者多次試驗后得出來的最優(yōu)解,我雖然看懂了代碼泛啸,但是對于代碼中損失函數(shù)為什么要這樣計算還不是很懂绿语,看來還需要更加深入的學(xué)習(xí)。

這次yolov3模型以及損失函數(shù)的計算分享就結(jié)束了,下篇文章我們進行數(shù)據(jù)集制作代碼的分析吕粹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末种柑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子匹耕,更是在濱河造成了極大的恐慌聚请,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泌神,死亡現(xiàn)場離奇詭異良漱,居然都是意外死亡舞虱,警方通過查閱死者的電腦和手機欢际,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矾兜,“玉大人损趋,你說我怎么就攤上這事∫嗡拢” “怎么了浑槽?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長返帕。 經(jīng)常有香客問我桐玻,道長,這世上最難降的妖魔是什么荆萤? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任镊靴,我火速辦了婚禮,結(jié)果婚禮上链韭,老公的妹妹穿的比我還像新娘偏竟。我一直安慰自己,他們只是感情好敞峭,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布踊谋。 她就那樣靜靜地躺著,像睡著了一般旋讹。 火紅的嫁衣襯著肌膚如雪殖蚕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天沉迹,我揣著相機與錄音嫌褪,去河邊找鬼。 笑死胚股,一個胖子當著我的面吹牛笼痛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼缨伊,長吁一口氣:“原來是場噩夢啊……” “哼摘刑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起刻坊,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤枷恕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谭胚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徐块,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年灾而,在試婚紗的時候發(fā)現(xiàn)自己被綠了胡控。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡旁趟,死狀恐怖昼激,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锡搜,我是刑警寧澤橙困,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站耕餐,受9級特大地震影響凡傅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肠缔,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一夏跷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧桩砰,春花似錦拓春、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至煮纵,卻和暖如春懂鸵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背行疏。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工匆光, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人酿联。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓终息,卻偏偏與公主長得像夺巩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子周崭,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

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