PaddlePaddle學習之數(shù)字識別

正文之前

本文純粹是為了記筆記而生,同時也算是對官方文檔的代碼的驗證,如果有朋友遇到問題可以來找我討論。內(nèi)容是官方文檔的精簡版。另外,還有一個大佬寫的關(guān)于paddle的教程:
《PaddlePaddle從入門到煉丹》十一——自定義圖像數(shù)據(jù)集識別

正文

當我們學習編程的時候,編寫的第一個程序一般是實現(xiàn)打印"Hello World"。而機器學習(或深度學習)的入門教程,一般都是 MNIST 數(shù)據(jù)庫上的手寫識別問題。原因是手寫識別屬于典型的圖像分類問題,比較簡單,同時MNIST數(shù)據(jù)集也很完備。MNIST數(shù)據(jù)集作為一個簡單的計算機視覺數(shù)據(jù)集,包含一系列如圖1所示的手寫數(shù)字圖片和對應(yīng)的標簽。圖片是28x28的像素矩陣,標簽則對應(yīng)著0~9的10個數(shù)字。每張圖片都經(jīng)過了大小歸一化和居中處理。

本教程中,我們從簡單的Softmax回歸模型開始,帶大家了解手寫字符識別,并向大家介紹如何改進模型,利用多層感知機(MLP)和卷積神經(jīng)網(wǎng)絡(luò)(CNN)優(yōu)化識別效果。

數(shù)據(jù)定義:

  • X是輸入:MNIST圖片是28×28 的二維圖像,為了進行計算,我們將其轉(zhuǎn)化為784維向量,即X=(x0,x1,…,x783)。

  • Y是輸出:分類器的輸出是10類數(shù)字(0-9),即Y=(y0,y1,…,y9),每一維yi代表圖片分類為第ii類數(shù)字的概率。

  • Label 是圖片的真實標簽:Label=(l0,l1,…,l9)也是10維,但只有一維為1,其他都為0。例如某張圖片上的數(shù)字為2,則它的標簽為(0,0,1,0,…,0)

一、最簡單的Softmax回歸模型是先將輸入層經(jīng)過一個全連接層得到特征,然后直接通過 softmax 函數(shù)計算多個類別的概率并輸出[9]。

圖為softmax回歸的網(wǎng)絡(luò)圖,圖中權(quán)重用藍線表示、偏置用紅線表示、+1代表偏置參數(shù)的系數(shù)為1。

image.png

在分類問題中,我們一般采用交叉熵代價損失函數(shù)(cross entropy loss),公式如下:

image.gif

二、多層感知機(Multilayer Perceptron, MLP)?

Softmax回歸模型采用了最簡單的兩層神經(jīng)網(wǎng)絡(luò),即只有輸入層和輸出層,因此其擬合能力有限。為了達到更好的識別效果,我們考慮在輸入層和輸出層中間加上若干個隱藏層[10]。

  1. 經(jīng)過第一個隱藏層,可以得到 H1=?(W1X+b1),其中??代表激活函數(shù),常見的有sigmoid、tanh或ReLU等函數(shù)。

  2. 經(jīng)過第二個隱藏層,可以得到 H2=?(W2H1+b2)。

  3. 最后,再經(jīng)過輸出層,得到的Y=softmax(W3H2+b3),即為最后的分類結(jié)果向量。

圖3為多層感知器的網(wǎng)絡(luò)結(jié)構(gòu)圖,圖中權(quán)重用藍線表示、偏置用紅線表示、+1代表偏置參數(shù)的系數(shù)為1。

image.png

圖3. 多層感知器網(wǎng)絡(luò)結(jié)構(gòu)圖

三、卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Network, CNN)?

在多層感知器模型中,將圖像展開成一維向量輸入到網(wǎng)絡(luò)中,忽略了圖像的位置和結(jié)構(gòu)信息,而卷積神經(jīng)網(wǎng)絡(luò)能夠更好的利用圖像的結(jié)構(gòu)信息。LeNet-5是一個較簡單的卷積神經(jīng)網(wǎng)絡(luò)。圖4顯示了其結(jié)構(gòu):輸入的二維圖像,先經(jīng)過兩次卷積層到池化層,再經(jīng)過全連接層,最后使用softmax分類作為輸出層。下面我們主要介紹卷積層和池化層。

image.png

圖4. LeNet-5卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)

卷積層?

卷積層是卷積神經(jīng)網(wǎng)絡(luò)的核心基石。在圖像識別里我們提到的卷積是二維卷積,即離散二維濾波器(也稱作卷積核)與二維圖像做卷積操作,簡單的講是二維濾波器滑動到二維圖像上所有位置,并在每個位置上與該像素點及其領(lǐng)域像素點做內(nèi)積。卷積操作被廣泛應(yīng)用與圖像處理領(lǐng)域,不同卷積核可以提取不同的特征,例如邊沿、線性、角等特征。在深層卷積神經(jīng)網(wǎng)絡(luò)中,通過卷積操作可以提取出圖像低級到復雜的特征。

image.png

圖5. 卷積層圖片

圖5給出一個卷積計算過程的示例圖,輸入圖像大小為H=5,W=5,D=3,即5×5大小的3通道(RGB,也稱作深度)彩色圖像。

這個示例圖中包含兩(用KK表示)組卷積核,即圖中FilterW0 和 FilterW1。在卷積計算中,通常對不同的輸入通道采用不同的卷積核,如圖示例中每組卷積核包含(D=3))個3×3(用F×F表示)大小的卷積核。另外,這個示例中卷積核在圖像的水平方向(WW方向)和垂直方向(H方向)的滑動步長為2(用S表示);對輸入圖像周圍各填充1(用P表示)個0,即圖中輸入層原始數(shù)據(jù)為藍色部分,灰色部分是進行了大小為1的擴展,用0來進行擴展。經(jīng)過卷積操作得到輸出為3×3×2(用Ho×Wo×K表示)大小的特征圖,即3×3大小的2通道特征圖,其中Ho計算公式為:Ho=(H?F+2×P)/S+1,Wo同理。 而輸出特征圖中的每個像素,是每組濾波器與輸入圖像每個特征圖的內(nèi)積再求和,再加上偏置bo,偏置通常對于每個輸出特征圖是共享的。輸出特征圖o[:,:,0]中的最后一個?2計算如圖5右下角公式所示。

  • 局部連接:每個神經(jīng)元僅與輸入神經(jīng)元的一塊區(qū)域連接,這塊局部區(qū)域稱作感受野(receptive field)。在圖像卷積操作中,即神經(jīng)元在空間維度(spatial dimension,即上圖示例H和W所在的平面)是局部連接,但在深度上是全部連接。對于二維圖像本身而言,也是局部像素關(guān)聯(lián)較強。這種局部連接保證了學習后的過濾器能夠?qū)τ诰植康妮斎胩卣饔凶顝姷捻憫?yīng)。局部連接的思想,也是受啟發(fā)于生物學里面的視覺系統(tǒng)結(jié)構(gòu),視覺皮層的神經(jīng)元就是局部接受信息的。

  • 權(quán)重共享:計算同一個深度切片的神經(jīng)元時采用的濾波器是共享的。例如圖5中計算o[:,:,0]o[:,:,0]的每個每個神經(jīng)元的濾波器均相同,都為W0W0,這樣可以很大程度上減少參數(shù)。共享權(quán)重在一定程度上講是有意義的,例如圖片的底層邊緣特征與特征在圖中的具體位置無關(guān)。但是在一些場景中是無意的,比如輸入的圖片是人臉,眼睛和頭發(fā)位于不同的位置,希望在不同的位置學到不同的特征 (參考斯坦福大學公開課)。請注意權(quán)重只是對于同一深度切片的神經(jīng)元是共享的,在卷積層,通常采用多組卷積核提取不同特征,即對應(yīng)不同深度切片的特征,不同深度切片的神經(jīng)元權(quán)重是不共享。另外,偏重對同一深度切片的所有神經(jīng)元都是共享的。

池化層?

image.png

圖6. 池化層圖片

池化是非線性下采樣的一種形式,主要作用是通過減少網(wǎng)絡(luò)的參數(shù)來減小計算量,并且能夠在一定程度上控制過擬合。通常在卷積層的后面會加上一個池化層。池化包括最大池化、平均池化等。其中最大池化是用不重疊的矩形框?qū)⑤斎雽臃殖刹煌膮^(qū)域,對于每個矩形框的數(shù)取最大值作為輸出層,如圖6所示。

常見激活函數(shù)介紹?

  • sigmoid激活函數(shù):
image.gif
  • tanh激活函數(shù):
image.gif

實際上,tanh函數(shù)只是規(guī)模變化的sigmoid函數(shù),將sigmoid函數(shù)值放大2倍之后再向下平移1個單位:tanh(x) = 2sigmoid(2x) - 1 。

  • ReLU激活函數(shù): f(x)=max(0,x)

激活函數(shù)是用來加入非線性因素的,因為線性模型的表達能力不夠。

在下面的代碼示例中,我們將深入了解上述內(nèi)容:

加載 PaddlePaddle 的 Fluid API 包。

from __future__ import print_function # 將python3中的print特性導入當前版本
import os
from PIL import Image # 導入圖像處理模塊
import matplotlib.pyplot as plt
import numpy
import paddle # 導入paddle模塊
import paddle.fluid as fluid
    

Program Functions 配置

def softmax_regression():
    """
    定義softmax分類器:
        一個以softmax為激活函數(shù)的全連接層
    Return:
        predict_image -- 分類的結(jié)果
    """
    
    # 輸入的原始數(shù)據(jù),28 * 28 * 1
    img = fluid.layers.data(name='img', shape=[1,28,28], dtype='float32')
    
    # 以softmax為激活函數(shù)的全連接層,輸出層的大小必須為數(shù)字的個數(shù)10
    predict = fluid.layers.fc(
        input='img', size=10, act='softmax'
    )
    return predict
    
    
def multilayer_perceptron():
    """
    定義多層感知機分類器:
        含有兩個隱藏層(全連接層)的多層感知器
        其中前兩個隱藏層的激活函數(shù)采用 ReLU,輸出層的激活函數(shù)用 Softmax

    Return:
        predict_image -- 分類的結(jié)果
    """
    # 輸入的原始圖像數(shù)據(jù),大小為28*28*1
    img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32')
    # 第一個全連接層,激活函數(shù)為ReLU
    hidden = fluid.layers.fc(input=img, size=200, act='relu')
    # 第二個全連接層,激活函數(shù)為ReLU
    hidden = fluid.layers.fc(input=hidden, size=200, act='relu')
    # 以softmax為激活函數(shù)的全連接輸出層,輸出層的大小必須為數(shù)字的個數(shù)10
    prediction = fluid.layers.fc(input=hidden, size=10, act='softmax')
    return prediction
    

def convolutional_neural_network():
    """
    定義卷積神經(jīng)網(wǎng)絡(luò)分類器:
        輸入的二維圖像,經(jīng)過兩個卷積-池化層,使用以softmax為激活函數(shù)的全連接層作為輸出層

    Return:
        predict -- 分類的結(jié)果
    """
    # 輸入的原始圖像數(shù)據(jù),大小為28*28*1
    img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32')
    # 第一個卷積-池化層
    # 使用20個5*5的濾波器,池化大小為2,池化步長為2,激活函數(shù)為Relu
    conv_pool_1 = fluid.nets.simple_img_conv_pool(
        input=img,
        filter_size=5,
        num_filters=20,
        pool_size=2,
        pool_stride=2,
        act="relu")
    conv_pool_1 = fluid.layers.batch_norm(conv_pool_1)
    # 第二個卷積-池化層
    # 使用50個5*5的濾波器,池化大小為2,池化步長為2,激活函數(shù)為Relu
    conv_pool_2 = fluid.nets.simple_img_conv_pool(
        input=conv_pool_1,
        filter_size=5,
        num_filters=50,
        pool_size=2,
        pool_stride=2,
        act="relu")
    # 以softmax為激活函數(shù)的全連接輸出層,輸出層的大小必須為數(shù)字的個數(shù)10
    prediction = fluid.layers.fc(input=conv_pool_2, size=10, act='softmax')
    return prediction

Train Program 配置

然后我們需要設(shè)置訓練程序 train_program。它首先從分類器中進行預測。 在訓練期間,它將從預測中計算 avg_cost。

注意: 訓練程序應(yīng)該返回一個數(shù)組,第一個返回參數(shù)必須是 avg_cost。訓練器使用它來計算梯度。


def train_program():
    """
    配置train_program
    
    :return: 
        predict -- 分類結(jié)果
        avg-cost -- 平均損失
        acc -- 分類的準確率
    """
    
    # 標簽層 label,對應(yīng)輸入圖片的類別
    label = fluid.layers.data(name='label', shape=[1], dtype='int64')
    
    # predict = softmax_regression() # 取消注釋將使用 Softmax回歸
#     Best pass is 4, testing Avgcost is 0.0630938182697093
#     The classification accuracy is 97.91%
    
    # predict = multilayer_perceptron() # 取消注釋將使用 多層感知器
#     Best pass is 4, testing Avgcost is 0.0609021570576521
#     The classification accuracy is 97.99%
    
    predict = convolutional_neural_network() # 取消注釋將使用 LeNet5卷積神經(jīng)網(wǎng)絡(luò)
#     Best pass is 4, testing Avgcost is 0.018020916773774882
#     The classification accuracy is 99.31%
    # 使用交叉熵函數(shù)計算predict和label之間的損失函數(shù)
    
    cost = fluid.layers.cross_entropy(input = predict, label = label)
    
    # 計算平均損失
    avg_cost = fluid.layers.mean(cost)
    
    acc = fluid.layers.accuracy(input=predict, label=label)
    return predict, [ avg_cost, acc]

Optimizer Function 配置

在下面的 Adam optimizer,learning_rate 是學習率,它的大小與網(wǎng)絡(luò)的訓練收斂速度有關(guān)系。


def optimizer_program():
    return fluid.optimizer.Adam(learning_rate=0.001)

數(shù)據(jù)集 Feeders 配置

下一步,我們開始訓練過程。paddle.dataset.mnist.train()和paddle.dataset.mnist.test()分別做訓練和測試數(shù)據(jù)集。這兩個函數(shù)各自返回一個reader——PaddlePaddle中的reader是一個Python函數(shù),每次調(diào)用的時候返回一個Python yield generator。

下面shuffle是一個reader decorator,它接受一個reader A,返回另一個reader B。reader B 每次讀入buffer_size條訓練數(shù)據(jù)到一個buffer里,然后隨機打亂其順序,并且逐條輸出。

batch是一個特殊的decorator,它的輸入是一個reader,輸出是一個batched reader。在PaddlePaddle里,一個reader每次yield一條訓練數(shù)據(jù),而一個batched reader每次yield一個minibatch。

# 一個minibatch中有64個數(shù)據(jù)
BATCH_SIZE = 64

# 每次讀取訓練集中的500個數(shù)據(jù)并隨機打亂,傳入batched reader中,batched reader 每次 yield 64個數(shù)據(jù)
train_reader = paddle.batch(
    paddle.reader.shuffle(
        paddle.dataset.mnist.train(), buf_size=500
    ),
    batch_size=BATCH_SIZE
)

# 讀取測試集的數(shù)據(jù),每次 yield 64個數(shù)據(jù)
test_reader = paddle.batch(
    paddle.reader.shuffle(
        paddle.dataset.mnist.test(), buf_size=500
    ),
    batch_size=BATCH_SIZE
)

Event Handler 配置

我們可以在訓練期間通過調(diào)用一個handler函數(shù)來監(jiān)控訓練進度。 我們將在這里演示兩個 event_handler 程序。請隨意修改 Jupyter Notebook ,看看有什么不同。

event_handler 用來在訓練過程中輸出訓練結(jié)果

def event_handler(pass_id, batch_id, cost):
    # 打印訓練的中間結(jié)果,訓練輪次,batch數(shù),損失函數(shù)
    print("Pass %d, Batch %d, Cost %f" % (pass_id,batch_id, cost))
    
from paddle.utils.plot import Ploter

train_prompt = "Train cost"
test_prompt = "Test cost"
cost_ploter = Ploter(train_prompt, test_prompt)


# 將訓練過程繪圖表示
def event_handler_plot(ploter_title, step, cost):
    cost_ploter.append(ploter_title, step, cost)
    cost_ploter.plot()
    

開始訓練

  • 可以加入我們設(shè)置的 event_handler 和 data reader,然后就可以開始訓練模型了。
  • 設(shè)置一些運行需要的參數(shù),配置數(shù)據(jù)描述 feed_order 用于將數(shù)據(jù)目錄映射到 train_program
  • 創(chuàng)建一個反饋訓練過程中誤差的train_test
# 該模型運行在單個CPU上
use_cuda = False
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()

# 調(diào)用train_program 獲取預測值和損失值
prediction, [avg_loss, acc] = train_program()

# 輸入的原始圖像名稱,img 28*28*1
# 標簽層,名稱為label,對應(yīng)輸入圖片的類別標簽
# 告知網(wǎng)絡(luò)傳入的數(shù)據(jù)分為兩部分,第一部分是img值,第二部分是label值

feeder = fluid.DataFeeder(feed_list=['img', 'label'], place = place)

# 選擇Adam優(yōu)化器
optimizer = optimizer_program()
optimizer.minimize(avg_loss)


# 訓練五輪
EPOCH_NUM = 5
epochs = [epoch_id for epoch_id in range(EPOCH_NUM)]

# 將模型參數(shù)保存在save_dirname中
save_dirname = "recognize_digits.inference.model"

exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
main_program = fluid.default_main_program()
test_program = main_program.clone(for_test=True)


def tarin_test(train_test_program,
               train_test_feed, train_test_reader):
    # 將分類準確率存儲在acc_set中
    acc_set = []
    # 將平均損失存儲在avg_loss_set中
    avg_loss_set = []
    # 將測試 reader yield 出的每一個數(shù)據(jù)傳入網(wǎng)絡(luò)中進行訓練
    for test_data in train_test_reader():
        acc_np, avg_loss_np = exe.run(
            program = train_test_program,
            feed = train_test_feed.feed(test_data),
            fetch_list=[acc, avg_loss]
        )
        acc_set.append(float(acc_np))
        avg_loss_set.append(float(float(avg_loss_np)))
    # 獲得測試數(shù)據(jù)上的準確率和損失值
    acc_val_mean = numpy.array(acc_set).mean()
    avg_loss_val_mean = numpy.array(avg_loss_set).mean()

    # 返回平均損失值,平均準確率
    return avg_loss_val_mean, acc_val_mean

開始訓練

lists = []
step = 0

for epoch_id in epochs:
    metric = 0
    for step_id, data in enumerate(train_reader()):
        metrics = exe.run(
            program = main_program, 
            feed = feeder.feed(data),
            fetch_list = [avg_loss, acc]
        )
        if step % 100 == 0: #每訓練100次 打印一次log
            event_handler_plot(train_prompt, step, metrics[0])
            print("Pass %d, Batch %d, Cost %f" % (step, epoch_id, metrics[0]))
        step += 1
        metric = metrics[0]
    
    # 測試每個epoch分類的效果
    avg_loss_val, acc_val = tarin_test(train_test_program=test_program,
                                       train_test_reader=test_reader,
                                       train_test_feed=feeder)
    print("Test with Epoch %d, avg_cost: %s, acc: %s" %(epoch_id, avg_loss_val, acc_val))
    event_handler_plot(test_prompt, step, metric)
    
    lists.append((epoch_id, avg_loss_val, acc_val))
    
    # 保存訓練好的模型參數(shù)用于后續(xù)的預測
    if save_dirname is not None:
        fluid.io.save_inference_model(save_dirname,
                                      ["img"], [prediction], exe,
                                      model_filename = None, 
                                      params_filename=None)
best = sorted(lists, key=lambda list: float(list[1]))[0]
print('Best pass is %s, testing Avgcost is %s' % (best[0], best[1]))
print('The classification accuracy is %.2f%%' % (float(best[2]) * 100))
Best pass is 3, testing Avgcost is 0.0381211013488268
The classification accuracy is 98.76%



<Figure size 432x288 with 0 Axes>

應(yīng)用模型

可以使用訓練好的模型對手寫體數(shù)字圖片進行分類,下面程序展示了如何使用訓練好的模型進行推斷。

生成預測輸入數(shù)據(jù)

infer_5.jpeg 是數(shù)字 3 的一個示例圖像。把它變成一個 numpy 數(shù)組以匹配數(shù)據(jù)feed格式。

def load_image(file):
    # 讀取圖片文件,轉(zhuǎn)化為灰度圖
    im = Image.open(file).convert('L')
    # 將輸入圖片調(diào)整為28*28的高質(zhì)量圖
    im = im.resize((28,28), Image.ANTIALIAS)
    # 將圖片轉(zhuǎn)化為我numpy的數(shù)組
    im = numpy.array(im).reshape(1,1,28,28).astype(numpy.float32)
    #對數(shù)據(jù)做歸一化處理
    im = im / 255.0 * 2.0 -1
    return im

cur_dir = os.getcwd()
tensor_img = load_image(cur_dir + '/image/infer_5.jpeg')
tensor_img = load_image(cur_dir + '/image/infer_5.jpeg')

Inference 創(chuàng)建及預測

通過load_inference_model來設(shè)置網(wǎng)絡(luò)和經(jīng)過訓練的參數(shù)。我們可以簡單地插入在此之前定義的分類器。

inference_scope = fluid.core.Scope()
with fluid.scope_guard(inference_scope):
    # 使用 fluid.io.load_inference_model 獲取 inference program desc,
    # feed_target_names 用于指定需要傳入網(wǎng)絡(luò)的變量名
    # fetch_targets 指定希望從網(wǎng)絡(luò)中fetch出的變量名
    [inference_program, feed_target_names,
     fetch_targets] = fluid.io.load_inference_model(
        save_dirname, exe, None, None
     )
    # 將feed構(gòu)建成字典 { feed_target_names: feed_target_data}
    # 結(jié)果將包含一個與fetch——targets對應(yīng)的數(shù)據(jù)列表
    
    results = exe.run(inference_program,
                      feed = {feed_target_names[0] : tensor_img},
                      fetch_list=fetch_targets)
    lab = numpy.argsort(results)
    
    # 打印infer_圖片的預測結(jié)果
    img = Image.open('image/infer_5.jpeg')
    plt.show(img)
    print("Inference result of image/infer_5.jpeg is: %d" % lab[0][0][-1])
Inference result of image/infer_5.jpeg is: 5

正文之后

附贈我用于測試的圖片,講道理,準確度感人。。。

infer_5.jpeg
infer_9.jpeg
infer_1.png
infer_3.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

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