TensorFlow實(shí)戰(zhàn)-TensorFlow實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)

在圖像中,我們很難根據(jù)認(rèn)為我理解提取出有效而豐富的特征。在深度學(xué)習(xí)出現(xiàn)之前,我們必須借助SIFT,HoG等算法提取有良好區(qū)分性的特征,再集合SVM等進(jìn)行圖像識(shí)別。但是SIFT算法錯(cuò)誤率常年難以突破,卷積神經(jīng)網(wǎng)絡(luò)提取的特征則可以達(dá)到更好的效果。CNN最大特點(diǎn)在于卷積的權(quán)值共享結(jié)構(gòu),可以大幅減少神經(jīng)網(wǎng)絡(luò)的參數(shù)量,防止過(guò)擬合的同時(shí)又降低了神經(jīng)網(wǎng)絡(luò)模型的復(fù)雜度。
在卷積神經(jīng)網(wǎng)絡(luò)中,第一各卷積層會(huì)直接接受圖像像素級(jí)的輸入,每一個(gè)卷積操作只處理一小塊圖像,進(jìn)行卷積變化后再傳入后面的網(wǎng)絡(luò),每一層卷積(或者說(shuō)濾波器)都可以提取數(shù)據(jù)中最有效的特征。再進(jìn)行組合抽象形成更高階的特征。
一般的卷積神經(jīng)網(wǎng)絡(luò)由多個(gè)卷積層構(gòu)成,每個(gè)卷積層通常有如下幾個(gè)操作:
(1)圖像會(huì)通過(guò)多個(gè)不同的卷積核的濾波,并加偏置(bias),提取出局部特征,每一個(gè)卷積核會(huì)映射出一個(gè)新的2D圖像;
(2)將前面卷積核的濾波輸出結(jié)果,進(jìn)行非線性的激活函數(shù)處理。目前常用ReLu,以前sigmoid最多;
(3)對(duì)激活函數(shù)的結(jié)果再進(jìn)行池化操作(即降采樣,比如將2x2的圖片降為1x1的圖片),目前一般是使用最大池化,保留最顯著特征,并提升模型的畸變?nèi)萑棠芰?br> 權(quán)限共享降低模型復(fù)雜度,減輕過(guò)擬合并且降低計(jì)算量
通過(guò)局部鏈接,可以明顯降低參數(shù)量,但是仍然偏多,但是使用卷積核可以大量降低
卷積的好處是,不管圖片尺寸如何,我們需要訓(xùn)練的權(quán)重?cái)?shù)量只跟卷積核大小,卷積核數(shù)量有關(guān),我們可以使用非常少的參數(shù)快速處理任意大小的圖片
每一層卷積層提取的特征,在后面的層中都會(huì)抽象組合成更高階的特征。而且多層抽象的卷積網(wǎng)絡(luò)表達(dá)能力更強(qiáng),效率更高,相比只使用一個(gè)隱含層提取全部高階特征,反而可以節(jié)省大量的參數(shù)
最后總結(jié)一下,卷積神經(jīng)網(wǎng)絡(luò)的要點(diǎn)就是局部連接,權(quán)值共享和池化層中的降采樣。
下面使用TensorFlow實(shí)現(xiàn)一個(gè)簡(jiǎn)單的卷積網(wǎng)絡(luò),首先載入MNIST數(shù)據(jù)集,并創(chuàng)建默認(rèn)Interactive Session:

from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
sess = tf.InteractiveSession()

tf.InteractiveSession():它能讓你在運(yùn)行圖的時(shí)候,插入一些計(jì)算圖,這些計(jì)算圖是由某些操作(operations)構(gòu)成的。這對(duì)于工作在交互式環(huán)境中的人們來(lái)說(shuō)非常便利,比如使用IPython。
tf.Session():需要在啟動(dòng)session之前構(gòu)建整個(gè)計(jì)算圖,然后啟動(dòng)該計(jì)算圖。
意思就是在我們使用tf.InteractiveSession()來(lái)構(gòu)建會(huì)話的時(shí)候,我們可以先構(gòu)建一個(gè)session然后再定義操作(operation),如果我們使用tf.Session()來(lái)構(gòu)建會(huì)話我們需要在會(huì)話構(gòu)建之前定義好全部的操作(operation)然后再構(gòu)建會(huì)話。
接下來(lái)創(chuàng)建所需要的權(quán)重和偏置。先定義好初始化函數(shù)以便重復(fù)使用。我們需要給權(quán)重制造一些隨機(jī)噪聲來(lái)打破完全對(duì)稱(chēng),比如截?cái)嗟恼龖B(tài)分布噪聲,標(biāo)準(zhǔn)差設(shè)為0.1,同時(shí)因?yàn)槲覀兪褂肦eLU,也給偏置增加一些小的正值(0.1)用來(lái)避免死亡節(jié)點(diǎn)(dead neurons):

def weight_variable(shape):
  initial = tf.truncated_normal(shape, stddev=0.1)#返回元素服從截?cái)嗾龖B(tài)分布
  return tf.Variable(initial)

def bias_variable(shape):
  initial = tf.constant(0.1, shape=shape)
  return tf.Variable(initial)

下面創(chuàng)建卷積層和池化層函數(shù)。conv2d是TensorFlow的2維卷積函數(shù),x是輸入,W是卷積參數(shù)。例如[5,5,1,32]代表5x5的卷積核尺寸,1個(gè)channel(灰色),32個(gè)卷積核,也就是這個(gè)卷積核會(huì)提取多少類(lèi)特征,strides代表步長(zhǎng),都是1代表不會(huì)遺漏地劃過(guò)每一個(gè)點(diǎn)。Padding代表邊界處理方式,SAME代表給邊界加上Padding讓卷積的輸出和輸入保持同樣的尺寸。ksze指滑動(dòng)窗口尺寸:

def conv2d(x, W):
  return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

def max_pool_2x2(x):
  return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                        strides=[1, 2, 2, 1], padding='SAME')

定義輸入placeholder,x是特征,y_是真實(shí)的label。因?yàn)榫矸e神經(jīng)網(wǎng)絡(luò)會(huì)利用空間信息,因此需要把一維輸入結(jié)果轉(zhuǎn)化為二維,即1x784到28x28。[-1,28,28,1]中,-1代表樣本數(shù)量不固定,1代表顏色通道數(shù)量。tf.reshape是變形函數(shù):

x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
x_image = tf.reshape(x, [-1,28,28,1])

接下來(lái)我們定義第一個(gè)卷積層。我們先用前面寫(xiě)好的函數(shù)進(jìn)行初始化,包括weights和bias。這里的[5,5,1,32]代表卷積核尺寸為5x5,1個(gè)顏色通道,32個(gè)不同的卷積核。然后使用conv2d函數(shù)進(jìn)行卷積操作進(jìn)行卷積操作,并加上偏置,接下來(lái)使用ReLU進(jìn)行非線性處理。最后使用最大池化函數(shù)max_pool-2x2對(duì)卷積輸出結(jié)果進(jìn)行池化操作:

W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

現(xiàn)在定義第二個(gè)卷積層,不同的是會(huì)提取64種特征:

W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

然后使用reshape函數(shù)對(duì)第二個(gè)卷積層的輸出tenso進(jìn)行變形,轉(zhuǎn)成一維向量,然后連接全連接層,隱含節(jié)點(diǎn)為1024,并使用ReLU激活函數(shù):

W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

為了減輕過(guò)擬合,下面使用一個(gè)Dropout層,訓(xùn)練時(shí),隨機(jī)丟棄一部分節(jié)點(diǎn)的數(shù)據(jù)來(lái)減輕過(guò)擬合,預(yù)測(cè)時(shí)則保留全部數(shù)據(jù)來(lái)追求最好的預(yù)測(cè)性能:

keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

最后我們將Dropout層的輸出連接一個(gè)Softmax層,得到最后的概率輸出:

W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

我們定義損失函數(shù)為cross entropy,和之前一樣,但是優(yōu)化器使用Adam,并給與一個(gè)比較小的學(xué)習(xí)速率1e-4:

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv), reduction_indices=[1]))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

再定義準(zhǔn)確率操作:

correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

下面開(kāi)始訓(xùn)練。首先依然是初始化所有參數(shù),設(shè)置訓(xùn)練時(shí)Dropout的keep_prob比率為0.5。然后使用大小為50的mini-batch,共進(jìn)行2w次訓(xùn)練迭代,參與訓(xùn)練的樣本數(shù)量總共100w。其中每100次訓(xùn)練,我們會(huì)對(duì)準(zhǔn)確率進(jìn)行評(píng)測(cè) (評(píng)測(cè)時(shí)keep_prob設(shè)為1),用以實(shí)時(shí)監(jiān)測(cè)模型的性能:

tf.global_variables_initializer().run()
for i in range(20000):
  batch = mnist.train.next_batch(50)
  if i%100 == 0:
    train_accuracy = accuracy.eval(feed_dict={
        x:batch[0], y_: batch[1], keep_prob: 1.0})
    print("step %d, training accuracy %g"%(i, train_accuracy))
  train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})

全部訓(xùn)練完后,我們?cè)跍y(cè)試集上進(jìn)行全面的測(cè)試,得到整體的分類(lèi)準(zhǔn)確率:

print("test accuracy %g"%accuracy.eval(feed_dict={
    x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

最后跑了很久。。。應(yīng)該是我超極本的原因吧

然后實(shí)現(xiàn)一個(gè)進(jìn)階的卷機(jī)網(wǎng)絡(luò)
這個(gè)卷積神經(jīng)網(wǎng)絡(luò)中,我們使用了以下技巧:
(1)對(duì)weights進(jìn)行了L2的正則化;
(2)對(duì)圖片進(jìn)行翻轉(zhuǎn)、隨機(jī)剪裁等數(shù)據(jù)增強(qiáng),制造更多的樣本;
(3)在每個(gè)卷積-最大池化層后面使用了LRN層,增強(qiáng)了模型的泛化能力
先載入常用庫(kù)和數(shù)據(jù)集的默認(rèn)路徑:

import cifar10,cifar10_input
import tensorflow as tf
import numpy as np
import time

max_steps = 3000
batch_size = 128
data_dir = '/tmp/cifar10_data/cifar-10-batches-bin'

正則化即特征的權(quán)重也會(huì)成為模型的損失函數(shù)的一部分。可以理解為,為了使用某個(gè)特征,我們需要付出loss的代價(jià),除非這個(gè)特征非常有效,否則就會(huì)被loss上的增加覆蓋效果(奧卡姆剃刀)。

def variable_with_weight_loss(shape, stddev, wl):
    var = tf.Variable(tf.truncated_normal(shape, stddev=stddev))#截?cái)嗾龖B(tài)分布
    if wl is not None:
        weight_loss = tf.multiply(tf.nn.l2_loss(var), wl, name='weight_loss')#加入l2loss,相乘
        tf.add_to_collection('losses', weight_loss)
    return var

然后解壓展開(kāi)數(shù)據(jù)集到指定位置:

cifar10.maybe_download_and_extract()

產(chǎn)生需要使用的數(shù)據(jù),包括特征及其對(duì)應(yīng)的label,返回已經(jīng)封裝好的Tensor,每次執(zhí)行都會(huì)生成一個(gè)batch_size的數(shù)量的樣本。但是對(duì)圖片進(jìn)行了增強(qiáng)(課本87頁(yè))。所以需要耗費(fèi)大量的CPU時(shí)間,因此distorted_input使用了16個(gè)獨(dú)立的線程加速任務(wù):

images_train, labels_train = cifar10_input.distorted_inputs(data_dir=data_dir,
                                                            batch_size=batch_size)

再生成測(cè)試數(shù)據(jù),不需要對(duì)圖片進(jìn)行處理,不過(guò)要剪裁圖片正中間24x24大小的區(qū)塊,并進(jìn)行數(shù)據(jù)標(biāo)準(zhǔn)化操作:

images_test, labels_test = cifar10_input.inputs(eval_data=True,
                                                data_dir=data_dir,
                                                batch_size=batch_size) 

輸入特征和label:

image_holder = tf.placeholder(tf.float32, [batch_size, 24, 24, 3])
label_holder = tf.placeholder(tf.int32, [batch_size])

下面創(chuàng)建第一個(gè)卷積層。卷積核大小5x5,顏色通道3,,6個(gè)。標(biāo)準(zhǔn)差0.05。尺寸和步長(zhǎng)不一致,增加數(shù)據(jù)的豐富性。在之后,使用tf.nn.lrn函數(shù),即LRN對(duì)結(jié)果進(jìn)行處理。LRN層模仿了生物神經(jīng)網(wǎng)絡(luò)的“側(cè)抑制”機(jī)制,對(duì)局部神經(jīng)元的活動(dòng)創(chuàng)建競(jìng)爭(zhēng)環(huán)境,使得其中響應(yīng)比較大的值變得相對(duì)更大,并抑制其他反饋較小的神經(jīng)元,增強(qiáng)了模型的泛化能力。LRN對(duì)ReLU這種沒(méi)有上限邊界的激活函數(shù)會(huì)比較有用,因?yàn)樗鼤?huì)從附件的多個(gè)卷積核的響應(yīng)(response)中挑選比較大的反饋,但不適用于Sigmoid這種有固定邊界并且能夠抑制過(guò)大值的激活函數(shù):

weight1 = variable_with_weight_loss(shape=[5, 5, 3, 64], stddev=5e-2, wl=0.0)#創(chuàng)建卷積核函數(shù)并初始化
kernel1 = tf.nn.conv2d(image_holder, weight1, [1, 1, 1, 1], padding='SAME')
bias1 = tf.Variable(tf.constant(0.0, shape=[64]))
conv1 = tf.nn.relu(tf.nn.bias_add(kernel1, bias1))#與偏置相加
pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
                       padding='SAME')
norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75)

現(xiàn)在來(lái)創(chuàng)建第二個(gè)卷積層。這里的步驟和第一步很像,區(qū)別如下:輸入通道調(diào)整為64;bias初始化為0.1,而不是0;調(diào)整最大池化層和LRN層的順序:

weight2 = variable_with_weight_loss(shape=[5, 5, 64, 64], stddev=5e-2, wl=0.0)
kernel2 = tf.nn.conv2d(norm1, weight2, [1, 1, 1, 1], padding='SAME')
bias2 = tf.Variable(tf.constant(0.1, shape=[64]))
conv2 = tf.nn.relu(tf.nn.bias_add(kernel2, bias2))
norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75)
pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
                       padding='SAME')

在兩個(gè)卷積層后,將使用一個(gè)全連接層,這里先reshape第二個(gè)卷積層的輸出結(jié)果。我們希望這個(gè)全連接層不要過(guò)擬合,所以設(shè)了非0的weight loss值0.04,讓這一層所有參數(shù)都被L2正則所約束:

reshape = tf.reshape(pool2, [batch_size, -1])
dim = reshape.get_shape()[1].value#獲取扁平化后的長(zhǎng)度
weight3 = variable_with_weight_loss(shape=[dim, 384], stddev=0.04, wl=0.004)
bias3 = tf.Variable(tf.constant(0.1, shape=[384]))
local3 = tf.nn.relu(tf.matmul(reshape, weight3) + bias3)

接下來(lái)的這個(gè)全連接層和前一層很像,只不過(guò)其隱含層節(jié)點(diǎn)數(shù)下降了一半,其他參數(shù)不變:

weight4 = variable_with_weight_loss(shape=[384, 192], stddev=0.04, wl=0.004)
bias4 = tf.Variable(tf.constant(0.1, shape=[192]))                                      
local4 = tf.nn.relu(tf.matmul(local3, weight4) + bias4)

下面是最后一層,依然先創(chuàng)建這一層的weight,其正態(tài)分布標(biāo)準(zhǔn)差是上一層隱含節(jié)點(diǎn)數(shù)的倒數(shù),并且不計(jì)入L2正則。因?yàn)閟oftmax主要是為了計(jì)算loss,因此整合到后面比較合適:

weight5 = variable_with_weight_loss(shape=[192, 10], stddev=1/192.0, wl=0.0)
bias5 = tf.Variable(tf.constant(0.0, shape=[10]))
logits = tf.add(tf.matmul(local4, weight5), bias5)

完成模型的inference部分的構(gòu)建,接下來(lái)計(jì)算CNN的loss。這里依然使用cross entropy,需要注意的是我們把softmax的計(jì)算和cross entropy的計(jì)算合在一起了。使用tf.reduce_mean對(duì)cross entropy計(jì)算均值,再使用tf.add_to_collection把cross entropy的loss添加到整體losses的collection中。最后,全部loss求和:

def loss(logits, labels):
    labels = tf.cast(labels, tf.int64)
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
        logits=logits, labels=labels, name='cross_entropy_per_example')
    cross_entropy_mean = tf.reduce_mean(cross_entropy, name='cross_entropy')
    tf.add_to_collection('losses', cross_entropy_mean)
    return tf.add_n(tf.get_collection('losses'), name='total_loss')

接著將logits節(jié)點(diǎn)和label_holder傳入loss函數(shù)獲得最終的loss:

loss = loss(logits, label_holder)

優(yōu)化器:

train_op = tf.train.AdamOptimizer(1e-3).minimize(loss) #0.72

返回分?jǐn)?shù)自高的那一類(lèi):

top_k_op = tf.nn.in_top_k(logits, label_holder, 1)

創(chuàng)建默認(rèn)session,初始化全部模型參數(shù):

sess = tf.InteractiveSession()
tf.global_variables_initializer().run()

啟動(dòng)圖片增強(qiáng)線程:

tf.train.start_queue_runners()

下面開(kāi)始訓(xùn)練過(guò)程。每隔10步計(jì)算當(dāng)前l(fā)oss、每秒能訓(xùn)練的樣本數(shù)量,以及訓(xùn)練一個(gè)batch數(shù)據(jù)所花費(fèi)的時(shí)間:

###
for step in range(max_steps):
    start_time = time.time()
    image_batch,label_batch = sess.run([images_train,labels_train])
    _, loss_value = sess.run([train_op, loss],feed_dict={image_holder: image_batch, 
                                                         label_holder:label_batch})
    duration = time.time() - start_time

    if step % 10 == 0:
        examples_per_sec = batch_size / duration
        sec_per_batch = float(duration)
    
        format_str = ('step %d, loss = %.2f (%.1f examples/sec; %.3f sec/batch)')
        print(format_str % (step, loss_value, examples_per_sec, sec_per_batch))

接下來(lái)測(cè)試數(shù)據(jù)集。使用固定的batch_size,然后一個(gè)batch一個(gè)batch地輸入測(cè)試數(shù)據(jù):

###
num_examples = 10000
import math
num_iter = int(math.ceil(num_examples / batch_size))
true_count = 0  
total_sample_count = num_iter * batch_size
step = 0
while step < num_iter:
    image_batch,label_batch = sess.run([images_test,labels_test])
    predictions = sess.run([top_k_op],feed_dict={image_holder: image_batch,
                                                 label_holder:label_batch})
    true_count += np.sum(predictions)
    step += 1

最后打印準(zhǔn)確率的評(píng)測(cè)結(jié)果計(jì)算并打印出來(lái):

precision = true_count / total_sample_count
print('precision @ 1 = %.3f' % precision)

最終結(jié)果大致73%。持續(xù)增加max_step,可以期望準(zhǔn)確率逐漸增加。如果max_steps比較大,推薦使用學(xué)習(xí)速率衰減(decay)的SGD進(jìn)行訓(xùn)練,這樣訓(xùn)練過(guò)程的準(zhǔn)確率會(huì)大致接近86%。
數(shù)據(jù)增強(qiáng)(Data Augmenation)在外面的訓(xùn)練作用很大,它可以給單幅畫(huà)增加多個(gè)副本,提高圖片的利用率,防止過(guò)擬合。
從本章的例子可以發(fā)現(xiàn),卷積層一般需要和一個(gè)池化層連接。卷積層最后幾個(gè)全連接層的作用是輸出分類(lèi)結(jié)果,前面的卷積層主要是特征提取工作,直到最后全連接層更復(fù)雜,訓(xùn)練全連接層基本是進(jìn)行一些矩陣運(yùn)算,而目前卷積層的訓(xùn)練基本依賴(lài)于cuDNN的實(shí)現(xiàn)。

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

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