detr容器部署和訓練VOC數(shù)據(jù)集

獲取源碼

開源地址 git clone https://github.com/facebookresearch/detr.git

訓練環(huán)境部署

這里使用的資源是在內(nèi)網(wǎng)服務器上棠耕,首先當然要預裝好可以掛載gpu的docker炊林,Nvidia的顯卡等相關驅(qū)動,輸入nvidia-smi 可以看到GPU就可以了破衔。
然后打包可以運行detr的容器鏡像:編輯Dockerfile文件

FROM pytorch/pytorch:1.5-cuda10.1-cudnn7-runtime

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update -qq && \
    apt-get install -y git vim libgtk2.0-dev && \
    rm -rf /var/cache/apk/*

RUN pip --no-cache-dir install Cython

RUN git clone https://github.com/philferriere/cocoapi.git

RUN cd cocoapi && cd PythonAPI \
    make

RUN pip --no-cache-dir install pycocotools

RUN cd .. && git clone https://gitee.com/qiaodl/panopticapi.git && \
    cd panopticapi && \
    python setup.py install


# 強烈建議修改
COPY requirements.txt /workspace

RUN pip install  --no-cache-dir -r  /workspace/requirements.txt

修改python依賴包, cat requirements.txt

submitit
torch>=1.5.0
torchvision
scipy
onnx
onnxruntime

構(gòu)建鏡像 docker build -t yihui8776/detr:v0.1 .
鏡像可以從docker hub上pull
docker pull yihui8776/detr:v0.1

數(shù)據(jù)準備

voc和coco數(shù)據(jù)集

我們可能更多人知道著名的ImageNet辉懒,ImageNet是斯坦福大學李飛飛教授主持設立的關于計算機視覺的數(shù)據(jù)庫阳惹,有上千萬圖片,數(shù)萬個分類眶俩,其實就是模擬人的認知系統(tǒng)設立的視覺項目莹汤,也是深度學習領域一個非常火熱的競賽颠印。

同時視覺領域還有很多比較實用的數(shù)據(jù)集纲岭,相對來說我們平時可以更容易使用和訓練
,如VOC的數(shù)據(jù)集 线罕,有20分類止潮,Coco數(shù)據(jù)集有91分類。

VOC 數(shù)據(jù)集是最為常用的數(shù)據(jù)集钞楼,而且VOC的數(shù)據(jù)格式也是比較直觀通用喇闸,我們?nèi)绻柧氉约旱臄?shù)據(jù)也是要先使用標注軟件 類似labelImg,進行打標生成圖片相應的xml文件,也就是VOC主要保存格式燃乍。

數(shù)據(jù)集網(wǎng)頁
voc全名是# The PASCAL Visual Object Classes 唆樊,主要是2005到2012年舉辦的著名圖像識別類的比賽,主要包括圖像分類橘沥,目標檢測窗轩,圖像分割(專業(yè)人士可以略過)

但是到了2012年項目主要無償貢獻者Mark Everingham 去世了,后面就沒有維護座咆,現(xiàn)在可以在 :https://pjreddie.com/projects/pascal-voc-dataset-mirror/ 下載數(shù)據(jù)集

image.png

最新的數(shù)據(jù)2012痢艺,是包括了2007和2012的所有數(shù)據(jù)。共17125張圖片介陶。

數(shù)據(jù)集結(jié)構(gòu)
下載voc數(shù)據(jù)集后查看文件夾結(jié)構(gòu):

image.png

├── Annotations # 里面存放 .xml 文件堤舒,圖片的標簽,比如坐標位置信息等哺呜。
├── ImageSets # 這個目錄下有三個文件夾舌缤,文件夾存放的都是 .txt 文件,類別標簽某残,
│ ├── Layout
│ ├── Main # Main 目錄主要是分train/val 的txt文件国撵,如train.txt就是所有訓練集的圖片名組成,也含有各個類的訓練集txt玻墅,包括正負樣本介牙,方便各類選擇訓練,也便于抽樣澳厢, 這里主要任務是目標檢測环础,所以只要使用這個文件夾。
│ └── Segmentation
├── JPEGImages # 圖像文件 .jpg 格式
├── labels
├── SegmentationClass # 存放的是圖片文件剩拢,分割后的圖片
└── SegmentationObject # 存放的是圖片文件线得,分割后的圖片

可以從Main中知道有哪些類


[圖片上傳中...(image.png-1cd64-1626770867618-0)]

可以知道每張圖都是有多個類的多個樣本,里面有 xx_train.txt, xx_test.txt , xx_trainval.txt, xx_val.txt 文件徐伐,xx表示分類贯钩,總共20類
人:人

動物:鳥、貓办素、牛魏保、狗、馬摸屠、羊

車輛:飛機、自行車粱哼、船季二、巴士、汽車、摩托車胯舷、火車

室內(nèi):瓶刻蚯、椅子、餐桌桑嘶、盆栽植物炊汹、沙發(fā)、電視/監(jiān)視器

所以這里做目標檢測主要保留這些文件夾
├── Annotations
├── ImageSets
├── ├── Main
├── JPEGImages

Annotation

Annotations文件夾中存放的是xml格式的標簽文件逃顶,每一個xml文件都對應于JPEGImages文件夾中的一張圖片讨便。


image.png
03414743cfc5605888c3ccdec7f095c9_SouthEast.png

JPEGImages文件夾中包含了PASCAL VOC所提供的所有的圖片,包含訓練圖片和測試圖片以政,共有17125張霸褒。圖片均以“年份_編號.jpg”格式命名。圖片的尺寸大小不一盈蛮,所以在后面訓練的時候需要對圖片進行resize操作废菱。

圖片的像素尺寸大小不一,但是橫向圖的尺寸大約在500 * 375左右抖誉,縱向圖的尺寸大約在375 * 500左右殊轴,基本不會偏差超過100。(在之后的訓練中袒炉,第一步就是將這些圖片都resize到300*300或是500 * 500旁理,所有原始圖片不能離這個標準過遠)

更多查看 https://blog.csdn.net/xingwei_09/article/details/79142558
https://pjreddie.com/media/files/VOC2012_doc.pdf

coco數(shù)據(jù)集
coco數(shù)據(jù)集叫Microsoft COCO(Common Objects in Context)
類別更多有91個,圖片超過300000個梳杏,而且每張圖片的類別也更多韧拒,難度更大

1、2014年數(shù)據(jù)集的下載
http://msvocds.blob.core.windows.net/coco2014/train2014.zip

2十性、2017的數(shù)據(jù)集的下載
http://images.cocodataset.org/zips/train2017.zip
http://images.cocodataset.org/annotations/annotations_trainval2017.zip

http://images.cocodataset.org/zips/val2017.zip
http://images.cocodataset.org/annotations/stuff_annotations_trainval2017.zip

http://images.cocodataset.org/zips/test2017.zip
http://images.cocodataset.org/annotations/image_info_test2017.zip

coco api
coco數(shù)據(jù)集可以直接使用api進行操作叛溢,方便調(diào)用,如sklearn的dataset一樣劲适,同時coco API也有python matlab lua等不同版本楷掉,在部署階段我們也看到下載,detr的代碼也是直接調(diào)用coco API的

coco數(shù)據(jù)集下載解壓后霞势,文件夾主要就是標注文件 annotation和圖片集烹植,一般分為train和val兩個文件夾保存;
path/to/coco/
├── annotations/ # 標注json文件
├── train2017/ # 訓練集圖片
├── val2017/ # 驗證集圖片

COCO數(shù)據(jù)集現(xiàn)在有3種標注類型:object instances(目標實例), object keypoints(目標上的關鍵點), 和image captions(看圖說話)愕贡,使用JSON文件存儲草雕。比如 2017的如下


image.png

詳細信息

image.png

參考
https://blog.csdn.net/wc781708249/article/details/79603522
https://blog.csdn.net/bestrivern/article/details/88846977

voc格式轉(zhuǎn)coco格式

和detr一樣,detr 家族的項目很多是針對coco數(shù)據(jù)集的固以,所以我們自己要轉(zhuǎn)換為coco格式墩虹。
這個很多案例和開源嘱巾,這里只是做個記錄和整合,用已有的輪子改

先將數(shù)據(jù)集劃分诫钓,可以直接用voc 的main的txt 旬昭,生成,也可以對圖片數(shù)據(jù)直接打亂抽樣菌湃,做自己的訓練和驗證集合问拘。

直接對圖片進行抽取,按比例復制到各文件夾

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 將一個文件夾下圖片按比例分在三個文件夾下
import os
import random
import shutil
from shutil import copy2

datadir_normal = "./VOCdevkit/VOC2019/JPEGImages/"

all_data = os.listdir(datadir_normal)  # (圖片文件夾)
num_all_data = len(all_data)
print("num_all_data: " + str(num_all_data))
index_list = list(range(num_all_data))
# print(index_list)
random.shuffle(index_list)
num = 0

trainDir = "./cocodata/train/"  # (將訓練集放在這個文件夾下)
if not os.path.exists(trainDir):
    os.mkdir(trainDir)

validDir = './cocodata/val/'  # (將驗證集放在這個文件夾下)
if not os.path.exists(validDir):
    os.mkdir(validDir)

testDir = './cocodata/test/'  # (將測試集放在這個文件夾下)
if not os.path.exists(testDir):
    os.mkdir(testDir)

for i in index_list:
    fileName = os.path.join(datadir_normal, all_data[i])
    if num < num_all_data * 0.6:
        # print(str(fileName))
        copy2(fileName, trainDir)
    elif num > num_all_data * 0.6 and num < num_all_data * 0.8:
        # print(str(fileName))
        copy2(fileName, validDir)
    else:
        copy2(fileName, testDir)
    num += 1

當然最好的是直接先將 train和val的圖片id 保存為txt格式文件,就如Main目錄下的惧所,然后在進行圖片和標注文件的復制轉(zhuǎn)移骤坐。最后將xml轉(zhuǎn)為json格式

import os
import random

trainval_percent = 0.9
train_percent = 0.8
xmlfilepath = 'Annotations'
txtsavepath = 'ImageSets\Main'
total_xml = os.listdir(xmlfilepath)

num=len(total_xml)
list=range(num)
tv=int(num*trainval_percent)
tr=int(tv*train_percent)
trainval= random.sample(list,tv)
train=random.sample(trainval,tr)

ftrainval = open('ImageSets/Main/trainval1.txt', 'w')
ftest = open('ImageSets/Main/test1.txt', 'w')
ftrain = open('ImageSets/Main/train1.txt', 'w')
fval = open('ImageSets/Main/val1.txt', 'w')

for i  in list:
    name=total_xml[i][:-4]+'\n'
    if i in trainval:
        ftrainval.write(name)
        if i in train:
            ftrain.write(name)
        else:
            fval.write(name)
    else:
        ftest.write(name)

ftrainval.close()
ftrain.close()
fval.close()
ftest .close()

根據(jù)txt文件生成相應圖片文件夾


import os, random, shutil
from shutil import copy2
   
if __name__ == '__main__':
    fileDir = "E:/yolo3/VOCdevkit/VOC2012/JPEGImages/"    #源圖片文件夾路徑
    trainDir = 'E:/yolo3/VOCdevkit/VOC2012/train2017/'    #移動到新的文件夾路徑
    valDir = 'E:/yolo3/VOCdevkit/VOC2012/val2017/'
    testDir = 'E:/yolo3/VOCdevkit/VOC2012/test2017/'


    train = []
    with open('E:/yolo3/VOCdevkit/VOC2012/ImageSets/Main/train1.txt', 'r') as f:
        for line in f:
            train.append(line.strip('\n'))
    #print(train)
    for  name in train:
        shutil.copy2(fileDir + name+'.jpg', trainDir + name+'.jpg')

    val = []
    with open('E:/yolo3/VOCdevkit/VOC2012/ImageSets/Main/val1.txt', 'r') as f:
        for line in f:
            val.append(line.strip('\n'))
        # print(train)
    for name in val:
        shutil.copy2(fileDir + name + '.jpg', valDir + name + '.jpg')

    test = []
    with open('E:/yolo3/VOCdevkit/VOC2012/ImageSets/Main/test1.txt', 'r') as f:
        for line in f:
            test.append(line.strip('\n'))
            # print(train)
    for name in test:
        shutil.copy2(fileDir + name + '.jpg', testDir + name + '.jpg')

同樣可以移動xml 標注文件

import os, random, shutil
 
if __name__ == '__main__':
    fileDir = "E:/yolo3/VOCdevkit/VOC2012/Annotations/"    #源圖片文件夾路徑
    trainDir = 'E:/yolo3/VOCdevkit/VOC2012/xml/xml_train/'    #移動到新的文件夾路徑
    valDir = 'E:/yolo3/VOCdevkit/VOC2012/xml/xml_val/'
    testDir = 'E:/yolo3/VOCdevkit/VOC2012/xml/xml_test/'


    train = []
    with open('E:/yolo3/VOCdevkit/VOC2012/ImageSets/Main/train1.txt', 'r') as f:
        for line in f:
            train.append(line.strip('\n'))
    #print(train)
    for  name in train:
        shutil.copy2(fileDir + name+'.xml', trainDir + name+'.xml')

    val = []
    with open('E:/yolo3/VOCdevkit/VOC2012/ImageSets/Main/val1.txt', 'r') as f:
        for line in f:
            val.append(line.strip('\n'))
        # print(train)
    for name in val:
        shutil.copy2(fileDir + name + '.xml', valDir + name + '.xml')

    test = []
    with open('E:/yolo3/VOCdevkit/VOC2012/ImageSets/Main/test1.txt', 'r') as f:
        for line in f:
            test.append(line.strip('\n'))
            # print(train)

    for name in test:
        shutil.copy2(fileDir + name + '.xml', testDir + name + '.xml')

轉(zhuǎn)換xml 為json, voc2coco.py

#!/usr/bin/python

# pip install lxml

import sys
import os
import json
import xml.etree.ElementTree as ET
import glob

START_BOUNDING_BOX_ID = 1
PRE_DEFINE_CATEGORIES = None
# If necessary, pre-define category and its id
#  PRE_DEFINE_CATEGORIES = {"aeroplane": 1, "bicycle": 2, "bird": 3, "boat": 4,
#  "bottle":5, "bus": 6, "car": 7, "cat": 8, "chair": 9,
#  "cow": 10, "diningtable": 11, "dog": 12, "horse": 13,
#  "motorbike": 14, "person": 15, "pottedplant": 16,
#  "sheep": 17, "sofa": 18, "train": 19, "tvmonitor": 20}


def get(root, name):
    vars = root.findall(name)
    return vars


def get_and_check(root, name, length):
    vars = root.findall(name)
    if len(vars) == 0:
        raise ValueError("Can not find %s in %s." % (name, root.tag))
    if length > 0 and len(vars) != length:
        raise ValueError(
            "The size of %s is supposed to be %d, but is %d."
            % (name, length, len(vars))
        )
    if length == 1:
        vars = vars[0]
    return vars

#
# def get_filename_as_int(filename):
#     try:
#         filename = filename.replace("\\", "/")
#         filename = os.path.splitext(os.path.basename(filename))[0]
#         return int(filename)
#     except:
#         raise ValueError("Filename %s is supposed to be an integer." % (filename))



def get_filename_as_integer(filename):
    filename = filename.replace("\\", "/")
    filename = os.path.splitext(os.path.basename(filename))[0]
    filename1 =filename.split('_')
    filename2 = ''
    for i in range(len(filename1)):
        filename2 += filename1[i]
    return int(filename2)



def get_categories(xml_files):
    """Generate category name to id mapping from a list of xml files.
    
    Arguments:
        xml_files {list} -- A list of xml file paths.
    
    Returns:
        dict -- category name to id mapping.
    """
    classes_names = []
    for xml_file in xml_files:
        tree = ET.parse(xml_file)
        root = tree.getroot()
        for member in root.findall("object"):
            classes_names.append(member[0].text)
    classes_names = list(set(classes_names))
    classes_names.sort()
    return {name: i for i, name in enumerate(classes_names)}


def convert(xml_files, json_file):
    json_dict = {"images": [], "type": "instances", "annotations": [], "categories": []}
    if PRE_DEFINE_CATEGORIES is not None:
        categories = PRE_DEFINE_CATEGORIES
    else:
        categories = get_categories(xml_files)
    bnd_id = START_BOUNDING_BOX_ID
    for xml_file in xml_files:
        tree = ET.parse(xml_file)
        root = tree.getroot()
        path = get(root, "path")
        if len(path) == 1:
            filename = os.path.basename(path[0].text)
        elif len(path) == 0:
            filename = get_and_check(root, "filename", 1).text
        else:
            raise ValueError("%d paths found in %s" % (len(path), xml_file))
        ## The filename must be a number
        #image_id = get_filename_as_int(filename)
        image_id = get_filename_as_integer(filename)
        size = get_and_check(root, "size", 1)
        width = int(get_and_check(size, "width", 1).text)
        height = int(get_and_check(size, "height", 1).text)
        image = {
            "file_name": filename,
            "height": height,
            "width": width,
            "id": image_id,
        }
        json_dict["images"].append(image)
        ## Currently we do not support segmentation.
        #  segmented = get_and_check(root, 'segmented', 1).text
        #  assert segmented == '0'
        for obj in get(root, "object"):
            category = get_and_check(obj, "name", 1).text
            if category not in categories:
                new_id = len(categories)
                categories[category] = new_id
            category_id = categories[category]
            bndbox = get_and_check(obj, "bndbox", 1)
            xmin = int(get_and_check(bndbox, "xmin", 1).text) - 1
            ymin = int(float((get_and_check(bndbox, "ymin", 1).text)))- 1
            xmax = int(get_and_check(bndbox, "xmax", 1).text)
            ymax = int(get_and_check(bndbox, "ymax", 1).text)
            assert xmax > xmin
            assert ymax > ymin
            o_width = abs(xmax - xmin)
            o_height = abs(ymax - ymin)
            ann = {
                "area": o_width * o_height,
                "iscrowd": 0,
                "image_id": image_id,
                "bbox": [xmin, ymin, o_width, o_height],
                "category_id": category_id,
                "id": bnd_id,
                "ignore": 0,
                "segmentation": [],
            }
            json_dict["annotations"].append(ann)
            bnd_id = bnd_id + 1

    for cate, cid in categories.items():
        cat = {"supercategory": "none", "id": cid, "name": cate}
        json_dict["categories"].append(cat)

    os.makedirs(os.path.dirname(json_file), exist_ok=True)
    json_fp = open(json_file, "w")
    json_str = json.dumps(json_dict)
    json_fp.write(json_str)
    json_fp.close()


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(
        description="Convert Pascal VOC annotation to COCO format."
    )
    parser.add_argument("xml_dir", help="Directory path to xml files.", type=str)
    parser.add_argument("json_file", help="Output COCO format json file.", type=str)
    args = parser.parse_args()
    xml_files = glob.glob(os.path.join(args.xml_dir, "*.xml"))

    # If you want to do train/test split, you can pass a subset of xml files to convert function.
    print("Number of xml files: {}".format(len(xml_files)))
    convert(xml_files, args.json_file)
    print("Success: {}".format(args.json_file))

運行只要執(zhí)行 python voc2coco sourcedir targetdir 如
python voc2coco.py ../xml/xml_train ./data/coco/instance_train2017.json

當然這些步驟可以集成到一個文件一鍵操作。
參考: https://github.com/Tony607/voc2coco

目前VOC比較常用的是2007和2012數(shù)據(jù)集纯路,但是2012沒有test或油,所以多使用這兩個組合, 可以使用 VOC2007 和 VOC2012 的 train+val(16551) 上訓練驰唬,然后使用 VOC2007 的 test(4952) 測試顶岸。
當然還要別的組合 可以參考:
https://blog.csdn.net/mzpmzk/article/details/88065416

配置更改

數(shù)據(jù)準備好了岔乔,接下來就要根據(jù)自己的數(shù)據(jù)進行代碼的修改
我們當然可以從頭訓練自己的深度學習模型席赂,但是比較難的,而且需要很多資源谴咸,所以一般使用預訓練模型搓逾,也就是已經(jīng)在別的數(shù)據(jù)集上訓練過的模型拿來再進行訓練卷谈。
如圖像的通常指的是在Imagenet上訓練的CNN

這里我們可以直接下載 detr 訓練coco數(shù)據(jù)集的模型,也就是91類的模型架構(gòu)霞篡,
下載模型 :
wget https://dl.fbaipublicfiles.com/detr/detr-r50-e632da11.pth
這是detr 訓練的 resnet50 經(jīng)典的cnn結(jié)構(gòu)
這些模型也可通過torch hub找到世蔗,以用預訓練的權重加載DETR R50,只需執(zhí)行以下操作:
model = torch.hub.load('facebookresearch/detr', 'detr_resnet50', pretrained=True)

PyTorch Hub是一個簡易API和工作流程朗兵,為復現(xiàn)研究提供了基本構(gòu)建模塊污淋,包含預訓練模型庫。并且余掖,PyTorch Hub還支持Colab寸爆,能與論文代碼結(jié)合網(wǎng)站Papers With Code集成,用于更廣泛的研究盐欺。torch hub使得我們可以更好地推廣和獲取各種訓練模型赁豆,相當于模型管理的倉庫和API∪呙溃可以集成到python代碼里魔种。
如查詢可用模型:

torch.hub.list('pytorch/vision')

['alexnet',
'deeplabv3_resnet101',
'densenet121',
...
'vgg16',
'vgg16_bn',
'vgg19',
 'vgg19_bn']

detr相關的hub配置全放在 hubconf.py文件里。


image.png

更改模型結(jié)構(gòu) 粉洼,適應自己的類別個數(shù): change.py

pretrained_weights = torch.load("./detr-r50-e632da11.pth")
 
num_class = 20 + 1 # 類別+1
pretrained_weights["model"]["class_embed.weight"].resize_(num_class+1,256)
pretrained_weights["model"]["class_embed.bias"].resize_(num_class+1)
torch.save(pretrained_weights,'detr_r50_%d.pth'%num_class)

這樣生成新的預訓練模型

修改模型代碼部分 models/detr.py


image.png

這里也說明到务嫡,要將參數(shù)設為類別+1甲抖,一個是背景類

所有準備工作基本都好了,可以開始煉丹了

這里使用的是docker 心铃,要注意因為內(nèi)存使用的比較大,而docker 有限制共享內(nèi)存 默認是64M 挫剑,所有運行docker 時候要加上參數(shù) --shm-size

將數(shù)據(jù)集掛載到代碼目錄的data下去扣,

docker run --gpus all -itd --shm-size 8G -v /media/nizhengqi/7a646073-10bf-41e4-93b5-4b89df793ff8/wyh/data:/workspace/data -v /media/nizhengqi/7a646073-10bf-41e4-93b5-4b89df793ff8/wyh/detr:/workspace --name detr1 yihui8776/detr:v0.1

進入docker 容器
docker exec -it detr1 /bin/bash
開始訓練
python main.py --coco_path "data" --epoch 1000 --batch_size=2 --num_workers=4 --output_dir="outputs_1" --resume="detr_r50_21.pth"

image.png

第一階段完成,接下來就是fine-tune了樊破。

測評
這里就訓練 了62 個epochs
選用這時的checkpoint進行評價愉棱,還是用trainval數(shù)據(jù)集,當然最好用沒用過的測試集
python main.py --batch_size 1 --no_aux_loss --eval --resume ./outputs_1/checkpoint.pth --coco_path data


image.png

python main.py --batch_size 2 --no_aux_loss --eval --resume ./outputs_1/checkpoint.pth --coco_path data


image.png
image.png

參考:
http://www.reibang.com/p/d7a06a720a2b

https://github.com/DataXujing/detr_transformer
https://www.bilibili.com/video/BV1GC4y1h77h

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哲戚,一起剝皮案震驚了整個濱河市奔滑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌顺少,老刑警劉巖朋其,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異脆炎,居然都是意外死亡梅猿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門秒裕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來袱蚓,“玉大人,你說我怎么就攤上這事几蜻±耍” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵梭稚,是天一觀的道長颖低。 經(jīng)常有香客問我,道長哨毁,這世上最難降的妖魔是什么枫甲? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮扼褪,結(jié)果婚禮上想幻,老公的妹妹穿的比我還像新娘。我一直安慰自己话浇,他們只是感情好脏毯,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著幔崖,像睡著了一般食店。 火紅的嫁衣襯著肌膚如雪渣淤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天吉嫩,我揣著相機與錄音价认,去河邊找鬼。 笑死自娩,一個胖子當著我的面吹牛用踩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忙迁,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼脐彩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了姊扔?” 一聲冷哼從身側(cè)響起惠奸,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恰梢,沒想到半個月后佛南,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡删豺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年共虑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呀页。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡妈拌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蓬蝶,到底是詐尸還是另有隱情尘分,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布丸氛,位于F島的核電站培愁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏缓窜。R本人自食惡果不足惜定续,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望禾锤。 院中可真熱鬧私股,春花似錦、人聲如沸恩掷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽黄娘。三九已至峭状,卻和暖如春克滴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背优床。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工劝赔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胆敞。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓望忆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親竿秆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

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