使用ONNX部署深度學(xué)習(xí)和傳統(tǒng)機(jī)器學(xué)習(xí)模型

目錄

ONNX簡(jiǎn)介

開放神經(jīng)網(wǎng)絡(luò)交換ONNX(Open Neural Network Exchange)是一套表示深度神經(jīng)網(wǎng)絡(luò)模型的開放格式窒悔,由微軟和Facebook于2017推出胳施,然后迅速得到了各大廠商和框架的支持刀崖。通過短短幾年的發(fā)展或舞,已經(jīng)成為表示深度學(xué)習(xí)模型的實(shí)際標(biāo)準(zhǔn),并且通過ONNX-ML仔引,可以支持傳統(tǒng)非神經(jīng)網(wǎng)絡(luò)機(jī)器學(xué)習(xí)模型芝薇,大有一統(tǒng)整個(gè)AI模型交換標(biāo)準(zhǔn)。

ONNX定義了一組與環(huán)境和平臺(tái)無關(guān)的標(biāo)準(zhǔn)格式嫌佑,為AI模型的互操作性提供了基礎(chǔ),使AI模型可以在不同框架和環(huán)境下交互使用侨歉。硬件和軟件廠商可以基于ONNX標(biāo)準(zhǔn)優(yōu)化模型性能屋摇,讓所有兼容ONNX標(biāo)準(zhǔn)的框架受益。目前幽邓,ONNX主要關(guān)注在模型預(yù)測(cè)方面(inferring)炮温,使用不同框架訓(xùn)練的模型,轉(zhuǎn)化為ONNX格式后牵舵,可以很容易的部署在兼容ONNX的運(yùn)行環(huán)境中柒啤。

ONNX標(biāo)準(zhǔn)介紹

ONNX規(guī)范由以下幾個(gè)部分組成:

  • 一個(gè)可擴(kuò)展的計(jì)算圖模型:定義了通用的計(jì)算圖中間表示法(Intermediate Representation)。
  • 內(nèi)置操作符集:ai.onnxai.onnx.ml畸颅,ai.onnx是默認(rèn)的操作符集担巩,主要針對(duì)神經(jīng)網(wǎng)絡(luò)模型,ai.onnx.ml主要適用于傳統(tǒng)非神經(jīng)網(wǎng)絡(luò)機(jī)器學(xué)習(xí)模型没炒。
  • 標(biāo)準(zhǔn)數(shù)據(jù)類型涛癌。包括張量(tensors)、序列(sequences)和映射(maps)。

目前拳话,ONNX規(guī)范有兩個(gè)官方變體先匪,主要區(qū)別在與支持的類型和默認(rèn)的操作符集。ONNX神經(jīng)網(wǎng)絡(luò)變體只使用張量作為輸入和輸出弃衍;而作為支持傳統(tǒng)機(jī)器學(xué)習(xí)模型的ONNX-ML呀非,還可以識(shí)別序列和映射,ONNX-ML為支持非神經(jīng)網(wǎng)絡(luò)算法擴(kuò)展了ONNX操作符集镜盯。

ONNX使用protobuf序列化AI模型姜钳,頂層是一個(gè)模型(Model)結(jié)構(gòu),主要由關(guān)聯(lián)的元數(shù)據(jù)和一個(gè)圖(Graph)組成形耗;圖由元數(shù)據(jù)、模型參數(shù)辙浑、輸入輸出激涤、和計(jì)算節(jié)點(diǎn)(Node)序列組成,這些節(jié)點(diǎn)構(gòu)成了一個(gè)計(jì)算無環(huán)圖判呕,每一個(gè)計(jì)算節(jié)點(diǎn)代表了一次操作符的調(diào)用倦踢,主要由節(jié)點(diǎn)名稱、操作符侠草、輸入列表辱挥、輸出列表和屬性列表組成,屬性列表主要記錄了一些運(yùn)行時(shí)常量边涕,比如模型訓(xùn)練時(shí)生成的系數(shù)值晤碘。

為了更直觀的了解ONNX格式內(nèi)容,下面功蜓,我們訓(xùn)練一個(gè)簡(jiǎn)單的LogisticRegression模型园爷,然后導(dǎo)出ONNX。仍然使用常用的分類數(shù)據(jù)集iris

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y)

clr = LogisticRegression()
clr.fit(X_train, y_train)

使用skl2onnx把Scikit-learn模型序列化為ONNX格式:

from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType

initial_type = [('float_input', FloatTensorType([1, 4]))]
onx = convert_sklearn(clr, initial_types=initial_type)
with open("logreg_iris.onnx", "wb") as f:
    f.write(onx.SerializeToString())

使用ONNX Python API查看和驗(yàn)證模型:

import onnx

model = onnx.load('logreg_iris.onnx')
print(model)

輸出模型信息如下:

ir_version: 5
producer_name: "skl2onnx"
producer_version: "1.5.1"
domain: "ai.onnx"
model_version: 0
doc_string: ""
graph {
  node {
    input: "float_input"
    output: "label"
    output: "probability_tensor"
    name: "LinearClassifier"
    op_type: "LinearClassifier"
    attribute {
      name: "classlabels_ints"
      ints: 0
      ints: 1
      ints: 2
      type: INTS
    }
    attribute {
      name: "coefficients"
      floats: 0.375753253698349
      floats: 1.3907358646392822
      floats: -2.127762794494629
      floats: -0.9207873344421387
      floats: 0.47902926802635193
      floats: -1.5524250268936157
      floats: 0.46959221363067627
      floats: -1.2708674669265747
      floats: -1.5656673908233643
      floats: -1.256540060043335
      floats: 2.18996000289917
      floats: 2.2694246768951416
      type: FLOATS
    }
    attribute {
      name: "intercepts"
      floats: 0.24828049540519714
      floats: 0.8415762782096863
      floats: -1.0461325645446777
      type: FLOATS
    }
    attribute {
      name: "multi_class"
      i: 1
      type: INT
    }
    attribute {
      name: "post_transform"
      s: "LOGISTIC"
      type: STRING
    }
    domain: "ai.onnx.ml"
  }
  node {
    input: "probability_tensor"
    output: "probabilities"
    name: "Normalizer"
    op_type: "Normalizer"
    attribute {
      name: "norm"
      s: "L1"
      type: STRING
    }
    domain: "ai.onnx.ml"
  }
  node {
    input: "label"
    output: "output_label"
    name: "Cast"
    op_type: "Cast"
    attribute {
      name: "to"
      i: 7
      type: INT
    }
    domain: ""
  }
  node {
    input: "probabilities"
    output: "output_probability"
    name: "ZipMap"
    op_type: "ZipMap"
    attribute {
      name: "classlabels_int64s"
      ints: 0
      ints: 1
      ints: 2
      type: INTS
    }
    domain: "ai.onnx.ml"
  }
  name: "deedadd605a34d41ac95746c4feeec1f"
  input {
    name: "float_input"
    type {
      tensor_type {
        elem_type: 1
        shape {
          dim {
            dim_value: 1
          }
          dim {
            dim_value: 4
          }
        }
      }
    }
  }
  output {
    name: "output_label"
    type {
      tensor_type {
        elem_type: 7
        shape {
          dim {
            dim_value: 1
          }
        }
      }
    }
  }
  output {
    name: "output_probability"
    type {
      sequence_type {
        elem_type {
          map_type {
            key_type: 7
            value_type {
              tensor_type {
                elem_type: 1
              }
            }
          }
        }
      }
    }
  }
}
opset_import {
  domain: ""
  version: 9
}
opset_import {
  domain: "ai.onnx.ml"
  version: 1
}

我們可以看到頂層字段記錄了一些模型的元數(shù)據(jù)信息式撼,代表的含義都比較直觀童社,字段詳細(xì)解釋可以參考文檔 Open Neural Network Exchange - ONNXopset_import記錄了該模型引入的操作符集著隆∪怕ィ空的domain操作符集表示引入ONNX默認(rèn)的操作符集ai.onnxai.onnx.ml代表支持傳統(tǒng)非神經(jīng)網(wǎng)絡(luò)模型操作符集美浦,比如以上模型中的LinearClassifier弦赖、NormalizerZipMap。圖(graph)中定義了以下元素:

  • 四個(gè)計(jì)算節(jié)點(diǎn)(node)抵代。
  • 一個(gè)輸入變量float_input腾节,類型為1*4的張量,elem_type是一個(gè)DataType枚舉型變量,1代表FLOAT案腺。
  • 兩個(gè)輸出變量output_labeloutput_probability庆冕,output_label類型為維數(shù)為1的INT64(elem_type: 7)張量,代表預(yù)測(cè)目標(biāo)分類劈榨; output_probability類型是映射的序列访递,映射的鍵是INT64(key_type: 7),值為維數(shù)為1的FLOAT同辣,代表每一個(gè)目標(biāo)分類的概率拷姿。

可以使用Netron,圖像化顯示ONNX模型的計(jì)算拓?fù)鋱D旱函,以上模型如下圖:

ONNX-graph

下面我們使用ONNX Runtime Python API預(yù)測(cè)該ONNX模型响巢,當(dāng)前僅使用了測(cè)試數(shù)據(jù)集中的第一條數(shù)據(jù):

import onnxruntime as rt
import numpy
sess = rt.InferenceSession("logreg_iris.onnx")
input_name = sess.get_inputs()[0].name
label_name = sess.get_outputs()[0].name
probability_name = sess.get_outputs()[1].name
pred_onx = sess.run([label_name, probability_name], {input_name: X_test[0].astype(numpy.float32)})

# print info
print('input_name: ' + input_name)
print('label_name: ' + label_name)
print('probability_name: ' + probability_name)
print(X_test[0])
print(pred_onx)

打印的模型信息和預(yù)測(cè)值如下:

input_name: float_input
label_name: output_label
probability_name: output_probability
[5.5 2.6 4.4 1.2]
[array([1], dtype=int64), [{0: 0.012208569794893265, 1: 0.5704444646835327, 2: 0.4173469841480255}]]

完整的程序,可以參考以下notebook:onnx.ipynb

ONNX與PMML

ONNX和PMML都是與平臺(tái)和環(huán)境無關(guān)的模型表示標(biāo)準(zhǔn)棒妨,可以讓模型部署脫離模型訓(xùn)練環(huán)境踪古,簡(jiǎn)化了部署流程,加速模型快速上線到生產(chǎn)環(huán)境中券腔。這兩個(gè)標(biāo)準(zhǔn)都得到了各大廠商和框架的支持伏穆,具有廣泛的應(yīng)用。

  • PMML是一個(gè)比較成熟的標(biāo)準(zhǔn)纷纫,在ONNX誕生之前枕扫,可以說是模型表示的實(shí)際標(biāo)準(zhǔn),對(duì)傳統(tǒng)數(shù)據(jù)挖掘模型有豐富的支持辱魁,最新 PMML4.4 可以支持多達(dá)19種模型類型烟瞧。但是,目前PMML缺乏對(duì)深度學(xué)習(xí)模型的支持商叹,下一版本5.0有可能會(huì)添加對(duì)深度神經(jīng)網(wǎng)絡(luò)的支持燕刻,但是因?yàn)镻MML是基于老式的XML格式,使用文本格式來存儲(chǔ)深度神經(jīng)網(wǎng)絡(luò)模型結(jié)構(gòu)和參數(shù)會(huì)帶來模型大小和性能的問題剖笙,目前該問題還沒有一個(gè)完美的解決方案卵洗。關(guān)于PMML的詳細(xì)介紹,可以參考文章《使用PMML部署機(jī)器學(xué)習(xí)模型》弥咪。

  • ONNX作為一個(gè)新的標(biāo)準(zhǔn)过蹂,剛開始主要提供對(duì)深度神經(jīng)網(wǎng)絡(luò)模型的支持,解決模型在不同框架下互操作和交換的問題聚至。目前通過ONNX-ML酷勺,ONNX已經(jīng)可以支持傳統(tǒng)非神經(jīng)網(wǎng)絡(luò)機(jī)器學(xué)習(xí)模型,但是目前模型類型還不夠豐富扳躬。ONNX使用protobuf二進(jìn)制格式來序列化模型脆诉,可以提供更好的傳輸性能甚亭。

ONNX和PMML這兩種格式都有成熟的開源類庫(kù)和框架支持,PMML有JPMML击胜,PMML4S亏狰,PyPMML等。ONNX有微軟的ONNX runtime偶摔,NVIDIA TensorRT等暇唾。用戶可以根據(jù)自己的實(shí)際情況選擇合適的跨平臺(tái)格式來部署AI模型。

DaaS簡(jiǎn)介

DaaS(Deployment-as-a-Service)是AutoDeployAI公司推出的AI模型自動(dòng)部署系統(tǒng)辰斋,支持多種模型類型的上線部署策州,以下我們介紹如何在DaaS中使用ONNX格式來部署傳統(tǒng)機(jī)器學(xué)習(xí)模型和深度神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)模型,DaaS使用ONNX Runtime作為ONNX模型的執(zhí)行引擎宫仗,ONNX Runtime是微軟開源的ONNX預(yù)測(cè)類庫(kù)够挂,提供高性能預(yù)測(cè)服務(wù)功能。首先藕夫,登陸DaaS系統(tǒng)后下硕,創(chuàng)建一個(gè)新的工程ONNX,下面的操作都在該工程下進(jìn)行汁胆。關(guān)于DaaS的詳細(xì)信息,可以參考文章《自動(dòng)部署PMML模型生成REST API》霜幼。

使用ONNX部署傳統(tǒng)機(jī)器學(xué)習(xí)模型

  1. 導(dǎo)入模型嫩码。選擇上面訓(xùn)練的Logistic Regression模型logreg_iris.onnx

    daas-import-model-logreg

    導(dǎo)入成功后,頁(yè)面轉(zhuǎn)到模型主頁(yè)面罪既≈猓可以看到模型有一個(gè)輸入字段float_input,類型是tensor(float)琢感,維數(shù)(1,4)丢间。兩個(gè)輸出字段:output_labeloutput_probability

    daas-model-overview-logreg
  2. 測(cè)試模型驹针。點(diǎn)擊標(biāo)簽頁(yè)測(cè)試烘挫,輸入預(yù)測(cè)數(shù)據(jù)[[5.5, 2.6, 4.4, 1.2]],然后點(diǎn)擊提交命令柬甥,輸出頁(yè)面顯示預(yù)測(cè)測(cè)試結(jié)果:

    daas-model-test-logreg
  3. 創(chuàng)建默認(rèn)實(shí)時(shí)預(yù)測(cè)Web服務(wù)饮六。點(diǎn)擊標(biāo)簽頁(yè)部署,然后點(diǎn)擊添加服務(wù)命令苛蒲,輸入服務(wù)名稱卤橄,其他使用默認(rèn)值:

    daas-create-web-service-logreg
  4. 測(cè)試Web服務(wù)。服務(wù)創(chuàng)建成功后臂外,頁(yè)面轉(zhuǎn)到服務(wù)部署主頁(yè)窟扑,當(dāng)服務(wù)副本狀態(tài)為運(yùn)行中時(shí)喇颁,代表Web服務(wù)已經(jīng)成功上線,可以接受外部請(qǐng)求嚎货。有兩種方式測(cè)試該服務(wù):

    • 在DaaS系統(tǒng)中通過測(cè)試頁(yè)面橘霎。點(diǎn)擊標(biāo)簽頁(yè)測(cè)試,輸入JSON格式的請(qǐng)求正文厂抖,點(diǎn)擊提交命令:

      daas-test-web-service-logreg
    • 通過任意的RSET客戶端茎毁,使用標(biāo)準(zhǔn)的REST API來測(cè)試。這里我們使用curl命令行程序來調(diào)用Web服務(wù)忱辅,點(diǎn)擊生成代碼命令七蜘,彈出顯示使用curl命令調(diào)用REST API的對(duì)話框:

      daas-curl-logreg

      復(fù)制該curl命令,打開shell頁(yè)面墙懂,執(zhí)行命令:

      daas-run-curl-logreg

使用ONNX部署深度神經(jīng)網(wǎng)絡(luò)模型

我們嘗試部署ONNX Model Zoo中已經(jīng)訓(xùn)練好的模型橡卤,這里我們選擇MNIST-手寫數(shù)字識(shí)別CNN模型,下載基于ONNX1.3的模型最新版本:mnist.tar.gz损搬。

  1. 導(dǎo)入模型碧库。選擇已下載模型mnist.tar.gz

    daas-import-model-mnist

    導(dǎo)入成功后,頁(yè)面轉(zhuǎn)到模型主頁(yè)面巧勤∏痘遥可以看到模型有一個(gè)輸入字段Input3,類型是tensor(float)颅悉,維數(shù)(1,1,28,28)沽瞭。一個(gè)輸出字段:Plus214_Output_0,類型同樣是tensor(float)剩瓶,維數(shù)(1,10)驹溃。

    daas-model-overview-mnist
  2. 測(cè)試模型。點(diǎn)擊標(biāo)簽頁(yè)測(cè)試延曙,然后點(diǎn)擊JSON命令豌鹤,DaaS系統(tǒng)會(huì)自動(dòng)創(chuàng)建符合輸入數(shù)據(jù)格式的隨機(jī)數(shù)據(jù),以方便測(cè)試枝缔。點(diǎn)擊提交命令布疙,輸出頁(yè)面顯示預(yù)測(cè)測(cè)試結(jié)果:

    daas-model-test-mnist
  3. 創(chuàng)建自定義實(shí)施預(yù)測(cè)腳本。為了能支持輸入圖像愿卸,并且直接輸出預(yù)測(cè)值拐辽,我們需要?jiǎng)?chuàng)建自定義預(yù)測(cè)腳本。點(diǎn)擊標(biāo)簽頁(yè)實(shí)時(shí)預(yù)測(cè)擦酌,然后點(diǎn)擊生成自定義實(shí)時(shí)預(yù)測(cè)腳本命令俱诸,

    daas-generate-custom-scoring-mnist

    腳本生成后,點(diǎn)擊命令作為API測(cè)試赊舶,進(jìn)入腳本測(cè)試頁(yè)面睁搭,我們可以自由添加自定義預(yù)處理和后處理功能赶诊。添加以下函數(shù)預(yù)處理圖像:

    def rgb2gray(rgb):
        """Convert the input image into grayscale"""
        import numpy as np
        return np.dot(rgb[...,:3], [0.299, 0.587, 0.114])
    
    
    def resize_img(img_to_resize):
        """Resize image to MNIST model input dimensions"""
        import cv2
        r_img = cv2.resize(img_to_resize, dsize=(28, 28), interpolation=cv2.INTER_AREA)
        r_img.resize((1, 1, 28, 28))
        return r_img
    
    
    def preprocess_image(img_to_preprocess):
        """Resize input images and convert them to grayscale."""
        if img_to_preprocess.shape == (28, 28):
            img_to_preprocess.resize((1, 1, 28, 28))
            return img_to_preprocess
    
        grayscale = rgb2gray(img_to_preprocess)
        processed_img = resize_img(grayscale)
        return processed_img
    

    在已有preprocess_files函數(shù)中調(diào)用preprocess_image,代碼如下:

    import matplotlib.image as mpimg
    for key, file in files.items():
        img = mpimg.imread(file)
        record[key] = preprocess_image(img)
    

    在已有postprocess函數(shù)中添加如下代碼后處理預(yù)測(cè)結(jié)果以獲取最終的預(yù)測(cè)值:

    def postprocess(result):
        """postprocess the predicted results"""
        import numpy as np
        return [int(np.argmax(np.array(result).squeeze(), axis=0))]
    

    點(diǎn)擊命令保存园骆,然后在請(qǐng)求頁(yè)面中輸入函數(shù)名為predict舔痪,選擇請(qǐng)求正文基于表單,輸入表單名稱為模型唯一的輸入字段名Input3锌唾,類型選擇文件锄码,點(diǎn)擊上傳,選擇測(cè)試圖像2.png晌涕,最后點(diǎn)擊提交命令滋捶,測(cè)試該腳本是否按照我們的期望工作:

    daas-test-custom-scoring-mnist
  4. 創(chuàng)建正式部署Web服務(wù)。當(dāng)腳本測(cè)試成功后余黎,點(diǎn)擊部署標(biāo)簽頁(yè)重窟,然后點(diǎn)擊添加網(wǎng)絡(luò)服務(wù)命令,輸入服務(wù)名稱惧财,其他使用默認(rèn)值:

    daas-create-web-service-mnist
  5. 測(cè)試Web服務(wù)巡扇。服務(wù)創(chuàng)建成功后,頁(yè)面轉(zhuǎn)到服務(wù)部署主頁(yè)垮衷,當(dāng)服務(wù)副本狀態(tài)為運(yùn)行中時(shí)厅翔,代表Web服務(wù)已經(jīng)成功上線,可以接受外部請(qǐng)求搀突。有兩種方式測(cè)試該服務(wù):

    • 在DaaS系統(tǒng)中通過測(cè)試頁(yè)面知给。點(diǎn)擊標(biāo)簽頁(yè)測(cè)試,選擇請(qǐng)求正文基于表單描姚,選擇輸入測(cè)試圖像5.jpg,點(diǎn)擊提交命令:

      daas-test-web-service-mnist.png
    • 通過任意的RSET客戶端戈次,使用標(biāo)準(zhǔn)的REST API來測(cè)試轩勘。這里我們使用curl命令行程序來調(diào)用Web服務(wù),點(diǎn)擊生成代碼命令怯邪,彈出顯示使用curl命令調(diào)用REST API的對(duì)話框:

      daas-curl-mnist

      復(fù)制該curl命令绊寻,打開shell頁(yè)面,切換到圖像目錄下悬秉,執(zhí)行命令:

      daas-run-curl-mnist

總結(jié)

本文中我們介紹了ONNX這種跨平臺(tái)AI模型表示標(biāo)準(zhǔn)澄步,以及與PMML的區(qū)別,最后演示了如何在DaaS系統(tǒng)中通過ONNX部署傳統(tǒng)機(jī)器學(xué)習(xí)模型和深度神經(jīng)網(wǎng)絡(luò)模型和泌,可以看到ONNX讓模型部署脫離了模型訓(xùn)練環(huán)境村缸,極大簡(jiǎn)化了整個(gè)部署流程。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末武氓,一起剝皮案震驚了整個(gè)濱河市梯皿,隨后出現(xiàn)的幾起案子仇箱,更是在濱河造成了極大的恐慌,老刑警劉巖东羹,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剂桥,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡属提,警方通過查閱死者的電腦和手機(jī)权逗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冤议,“玉大人斟薇,你說我怎么就攤上這事∏罄啵” “怎么了奔垦?”我有些...
    開封第一講書人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)尸疆。 經(jīng)常有香客問我椿猎,道長(zhǎng),這世上最難降的妖魔是什么寿弱? 我笑而不...
    開封第一講書人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任犯眠,我火速辦了婚禮,結(jié)果婚禮上症革,老公的妹妹穿的比我還像新娘筐咧。我一直安慰自己,他們只是感情好噪矛,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開白布量蕊。 她就那樣靜靜地躺著,像睡著了一般艇挨。 火紅的嫁衣襯著肌膚如雪残炮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,785評(píng)論 1 314
  • 那天缩滨,我揣著相機(jī)與錄音势就,去河邊找鬼。 笑死脉漏,一個(gè)胖子當(dāng)著我的面吹牛苞冯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播侧巨,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼舅锄,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了司忱?” 一聲冷哼從身側(cè)響起巧娱,我...
    開封第一講書人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤碉怔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后禁添,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撮胧,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年老翘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了芹啥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铺峭,死狀恐怖墓怀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卫键,我是刑警寧澤傀履,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站莉炉,受9級(jí)特大地震影響钓账,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜絮宁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一梆暮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绍昂,春花似錦啦粹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至忍饰,卻和暖如春贪嫂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喘批。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铣揉,地道東北人饶深。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像逛拱,于是被迫代替她去往敵國(guó)和親敌厘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361