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

本章將介紹AlexNet另玖,VGGNet饼灿,Google Inception Net其掂,和ResNet
AlexNet
其主要使用到的新技術(shù):
(1)成功使用ReLU作為CNN的激活函數(shù)缤底,解決了Sigmoid在網(wǎng)絡(luò)較深時的梯度彌散問題;
(2)訓練使用Dropout隨機忽略一部分神經(jīng)元自娩,以避免過擬合用踩;
(3)在CNN中使用重疊的最大池化,避免平均池化的模糊化效果忙迁。并且提出讓步長比池化核的尺寸小脐彩,這樣池化層的輸出之間會有重疊和覆蓋,提升了特征的豐富性姊扔;
(4)提出了LRN層惠奸,對局部神經(jīng)元的活動創(chuàng)建競爭機制,使得其中響應(yīng)比較大的值變得相對更大恰梢,并抑制其他反饋較小的神經(jīng)元佛南,增加了模型泛化能力;
(5)使用CUDA加速深度卷積網(wǎng)絡(luò)的訓練嵌言,同時AlexNet的設(shè)計讓GPU之間的通信只在網(wǎng)絡(luò)某些曾進行嗅回,控制通信的性能損耗;
(6)數(shù)據(jù)增強摧茴,大大減輕過擬合绵载,提升泛化能力;
由于訓練時間過長,本章將不設(shè)計實際數(shù)據(jù)的訓練娃豹,只對它每個batch的前饋計算(forward)和反饋計算(backward)的速度進行測試焚虱。這里使用隨機圖片來計算。
首先載入幾個庫懂版,然后定義主要參數(shù):

from datetime import datetime
import math
import time
import tensorflow as tf
batch_size=32
num_batches=100

顯示網(wǎng)絡(luò)每一層結(jié)構(gòu)鹃栽,展示其姓名和尺寸:

def print_activations(t):
    print(t.op.name, ' ', t.get_shape().as_list())

接下來設(shè)計AlexNet的網(wǎng)絡(luò)結(jié)構(gòu)。先定義inference定续,接受images作為輸入谍咆,返回最后一層pool5(第五個池化層)及parameters(需要訓練的參數(shù))禾锤。首先是第一個卷積層conv1私股。tf.name_scope()可以將scope內(nèi)生成的Variable自動命名為conv1/xxx。然后定義第一個卷積層恩掷,先初始化卷積核參數(shù)kernel倡鲸。然后進行卷積操作,每隔4x4取樣一次黄娘,卷積核大小11x11峭状。將卷積層的biases全部初始化為0,再加起來得到bias逼争,并使用激活函數(shù)進行非線性處理优床,最后打印conv1,并且添加kernel和biases到parameters:

def inference(images):
    parameters = []
    # conv1
    with tf.name_scope('conv1') as scope:
        kernel = tf.Variable(tf.truncated_normal([11, 11, 3, 64], dtype=tf.float32,
                                                 stddev=1e-1), name='weights')
        conv = tf.nn.conv2d(images, kernel, [1, 4, 4, 1], padding='SAME')
        biases = tf.Variable(tf.constant(0.0, shape=[64], dtype=tf.float32),
                             trainable=True, name='biases')
        bias = tf.nn.bias_add(conv, biases)
        conv1 = tf.nn.relu(bias, name=scope)
        print_activations(conv1)
        parameters += [kernel, biases]

添加LRN層和最大池化層誓焦。參數(shù)基本是AlexNet論文中的推薦值胆敞。然后進行最大池化處理。VALID意思為取樣不能超過邊框杂伟,不像pool那樣填充邊界外的點:

  # pool1
    lrn1 = tf.nn.lrn(conv1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='lrn1')
    pool1 = tf.nn.max_pool(lrn1,
                           ksize=[1, 3, 3, 1],
                           strides=[1, 2, 2, 1],
                           padding='VALID',
                           name='pool1')
    print_activations(pool1)

接下來設(shè)計第二個卷積層移层,只有幾個參數(shù)不同:

  # conv2
    with tf.name_scope('conv2') as scope:
        kernel = tf.Variable(tf.truncated_normal([5, 5, 64, 192], dtype=tf.float32,
                                                 stddev=1e-1), name='weights')
        conv = tf.nn.conv2d(pool1, kernel, [1, 1, 1, 1], padding='SAME')
        biases = tf.Variable(tf.constant(0.0, shape=[192], dtype=tf.float32),
                             trainable=True, name='biases')
        bias = tf.nn.bias_add(conv, biases)
        conv2 = tf.nn.relu(bias, name=scope)
        parameters += [kernel, biases]
    print_activations(conv2)

接下來同樣先LRN處理,再進行最大池化處理赫粥,參數(shù)和之前完全一樣:

  # pool2
    lrn2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='lrn2')
    pool2 = tf.nn.max_pool(lrn2,
                           ksize=[1, 3, 3, 1],
                           strides=[1, 2, 2, 1],
                           padding='VALID',
                           name='pool2')
    print_activations(pool2)

第三個卷積層观话,同樣是參數(shù)不同:

  # conv3
    with tf.name_scope('conv3') as scope:
        kernel = tf.Variable(tf.truncated_normal([3, 3, 192, 384],
                                                 dtype=tf.float32,
                                                 stddev=1e-1), name='weights')
        conv = tf.nn.conv2d(pool2, kernel, [1, 1, 1, 1], padding='SAME')
        biases = tf.Variable(tf.constant(0.0, shape=[384], dtype=tf.float32),
                             trainable=True, name='biases')
        bias = tf.nn.bias_add(conv, biases)
        conv3 = tf.nn.relu(bias, name=scope)
        parameters += [kernel, biases]
        print_activations(conv3)

第四層和第五層也是修改參數(shù):

  # conv4
    with tf.name_scope('conv4') as scope:
        kernel = tf.Variable(tf.truncated_normal([3, 3, 384, 256],
                                                 dtype=tf.float32,
                                                 stddev=1e-1), name='weights')
        conv = tf.nn.conv2d(conv3, kernel, [1, 1, 1, 1], padding='SAME')
        biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),
                             trainable=True, name='biases')
        bias = tf.nn.bias_add(conv, biases)
        conv4 = tf.nn.relu(bias, name=scope)
        parameters += [kernel, biases]
        print_activations(conv4)

  # conv5
    with tf.name_scope('conv5') as scope:
        kernel = tf.Variable(tf.truncated_normal([3, 3, 256, 256],
                                                 dtype=tf.float32,
                                                 stddev=1e-1), name='weights')
        conv = tf.nn.conv2d(conv4, kernel, [1, 1, 1, 1], padding='SAME')
        biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),
                             trainable=True, name='biases')
        bias = tf.nn.bias_add(conv, biases)
        conv5 = tf.nn.relu(bias, name=scope)
        parameters += [kernel, biases]
        print_activations(conv5)

下面是一個最大池化層:

  # pool5
    pool5 = tf.nn.max_pool(conv5,
                           ksize=[1, 3, 3, 1],
                           strides=[1, 2, 2, 1],
                           padding='VALID',
                           name='pool5')
    print_activations(pool5)

    return pool5, parameters

至此函數(shù)就完成了,它可以創(chuàng)建AlexNet的卷積部分越平。還需要添加3個全連接層频蛔,隱含層節(jié)點數(shù)分別為4096,4096,1000。
接下來實現(xiàn)一個評估AlexNet每輪計算時間的函數(shù)time_tensorflow_run秦叛。第二個變量是評測的運算算子晦溪,第三個變量是測試的名稱:

def time_tensorflow_run(session, target, info_string):
#  """Run the computation to obtain the target tensor and print timing stats.
#
#  Args:
#    session: the TensorFlow session to run the computation under.
#    target: the target Tensor that is passed to the session's run() function.
#    info_string: a string summarizing this run, to be printed with the stats.
#
#  Returns:
#    None
#  """
    num_steps_burn_in = 10
    total_duration = 0.0
    total_duration_squared = 0.0

我們進行num_batches+num_step_burn_in次迭代計算,使用time.time()計算時間书闸,每次迭代通過session.run(target)執(zhí)行尼变。每10輪迭代顯示當前迭代所需要的時間。同時每輪將total_duration和total_duration_squared累加,以便后面計算每輪耗時的均值和標準差:

    for i in range(num_batches + num_steps_burn_in):
        start_time = time.time()
        _ = session.run(target)
        duration = time.time() - start_time
        if i >= num_steps_burn_in:
            if not i % 10:
                print ('%s: step %d, duration = %.3f' %
                       (datetime.now(), i - num_steps_burn_in, duration))
            total_duration += duration
            total_duration_squared += duration * duration

循環(huán)結(jié)束后計算平均耗時mn和標準差sd:

    mn = total_duration / num_batches
    vr = total_duration_squared / num_batches - mn * mn
    sd = math.sqrt(vr)
    print ('%s: %s across %d steps, %.3f +/- %.3f sec / batch' %
           (datetime.now(), info_string, num_batches, mn, sd))

接下來是主函數(shù)嫌术。首先使用with tf.Graph().as_default()定義默認的Graph方便后面使用哀澈。然后使用預(yù)先定義的inference函數(shù)構(gòu)建整個AlexNet網(wǎng)絡(luò),得到最后一個池化層的輸出pool5和網(wǎng)絡(luò)中需要訓練的參數(shù)集合parameters度气。然后初始化所有參數(shù):

def run_benchmark():
#  """Run the benchmark on AlexNet."""
    with tf.Graph().as_default():
    # Generate some dummy images.
        image_size = 224
    # Note that our padding definition is slightly different the cuda-convnet.
    # In order to force the model to start with the same activations sizes,
    # we add 3 to the image_size and employ VALID padding above.
        images = tf.Variable(tf.random_normal([batch_size,
                                           image_size,
                                           image_size, 3],
                                          dtype=tf.float32,
                                          stddev=1e-1))

    # Build a Graph that computes the logits predictions from the
    # inference model.
        pool5, parameters = inference(images)

    # Build an initialization operation.
        init = tf.global_variables_initializer()

    # Start running operations on the Graph.
        config = tf.ConfigProto()
        config.gpu_options.allocator_type = 'BFC'
        sess = tf.Session(config=config)
        sess.run(init)

下面進行forward評測割按,這里直接使用time_tensorflow_run統(tǒng)計運算時間,傳入的target就是pool5磷籍。然后進行backward即訓練過程的評測适荣。grad求相對于所有模型參數(shù)的梯度,這樣就模擬了訓練過程院领。最后執(zhí)行主函數(shù):

    # Run the forward benchmark.
        time_tensorflow_run(sess, pool5, "Forward")

    # Add a simple objective so we can calculate the backward pass.
        objective = tf.nn.l2_loss(pool5)
    # Compute the gradient with respect to all the parameters.
        grad = tf.gradients(objective, parameters)
    # Run the backward benchmark.
        time_tensorflow_run(sess, grad, "Forward-backward")
run_benchmark()

應(yīng)用CNN的主要瓶頸還是在訓練弛矛,用CNN做預(yù)測問題不大。
VGGNet
VGGNet論文中全部使用了3x3的卷積核和2x2的池化核比然,通過不斷加深網(wǎng)絡(luò)結(jié)構(gòu)來提升性能丈氓。其中經(jīng)常出現(xiàn)多個完全一樣的3x3卷積層,兩個3x3的卷積層串聯(lián)相當于1個5x5的卷積層强法,即一個像素會跟5x5的像素產(chǎn)生關(guān)聯(lián)万俗,可以說感受野5x5。
VGG訓練的時候有小技巧饮怯,先訓練級別A的簡單網(wǎng)絡(luò)闰歪,再復用A網(wǎng)絡(luò)的權(quán)重來初始化后面的幾個復雜模型,這樣訓練模型的收斂速度更快蓖墅。
作者總結(jié)了一下結(jié)論:
①LRN層作用不大库倘;
②越深的網(wǎng)絡(luò)效果越好;
③1x1的卷積也是很有效的置媳,但沒有3x3的卷積好于樟,大一些的卷積核可以學習更大的空間特征
(下面僅記錄和其他模型不一樣的,或者有特點的代碼)
用來創(chuàng)建卷積層并把本層的參數(shù)存入?yún)?shù)列表拇囊。get_shape()[-1].value獲取輸入input_op的通道數(shù)迂曲。

def conv_op(input_op, name, kh, kw, n_out, dh, dw, p):
    n_in = input_op.get_shape()[-1].value

    with tf.name_scope(name) as scope:
        kernel = tf.get_variable(scope+"w",
                                 shape=[kh, kw, n_in, n_out],
                                 dtype=tf.float32, 
                                 initializer=tf.contrib.layers.xavier_initializer_conv2d())
        conv = tf.nn.conv2d(input_op, kernel, (1, dh, dw, 1), padding='SAME')
        bias_init_val = tf.constant(0.0, shape=[n_out], dtype=tf.float32)
        biases = tf.Variable(bias_init_val, trainable=True, name='b')
        z = tf.nn.bias_add(conv, biases)
        activation = tf.nn.relu(z, name=scope)
        p += [kernel, biases]
        return activation

下面是全連接層創(chuàng)建函數(shù)fc_op()。先獲取輸入input_op的通道數(shù)寥袭,再使用tf.get_variable創(chuàng)建全連接層的參數(shù):

def fc_op(input_op, name, n_out, p):
    n_in = input_op.get_shape()[-1].value

    with tf.name_scope(name) as scope:
        kernel = tf.get_variable(scope+"w",
                                 shape=[n_in, n_out],
                                 dtype=tf.float32, 
                                 initializer=tf.contrib.layers.xavier_initializer())
        biases = tf.Variable(tf.constant(0.1, shape=[n_out], dtype=tf.float32), name='b')
        activation = tf.nn.relu_layer(input_op, kernel, biases, name=scope)
        p += [kernel, biases]
        return activation

我們將第5段卷積網(wǎng)絡(luò)的輸出結(jié)果進行扁平化路捧,使用tf.reshape函數(shù)將每個樣本化為長度為 7x7x512=25088的一維向量:

shp = pool5.get_shape()
    flattened_shape = shp[1].value * shp[2].value * shp[3].value
    resh1 = tf.reshape(pool5, [-1, flattened_shape], name="resh1")

下面定義評測的主函數(shù)run_benchmark,我們的目標依然是僅評測forward和backward的運算性能传黄,并不進行實質(zhì)的訓練和預(yù)測杰扫。首先生成224x224的隨機圖片,方法和AlexNet中一樣膘掰,通過tf.random_normal函數(shù)生成標準差為0.1的正態(tài)分布的隨機數(shù):

def run_benchmark():
    with tf.Graph().as_default():
        image_size = 224
        images = tf.Variable(tf.random_normal([batch_size,
                                               image_size,
                                               image_size, 3],
                                               dtype=tf.float32,
                                               stddev=1e-1))

接下來創(chuàng)建keep_prob的placeholder章姓,并調(diào)用inference_op函數(shù)構(gòu)建VGGNet-16的網(wǎng)絡(luò)結(jié)構(gòu)佳遣,獲得predictions、softmax凡伊、fc8和參數(shù)列表p:

        keep_prob = tf.placeholder(tf.float32)
        predictions, softmax, fc8, p = inference_op(images, keep_prob)

Google Inception Net
Inception V1降低參數(shù)量的目的有兩點零渐,第一:參數(shù)越多模型越龐大,需要供模型學習的數(shù)據(jù)量就越大系忙;第二:參數(shù)越多诵盼,耗費的計算資源也會更大。Inception V1參數(shù)少但效果好的原因除了模型層數(shù)更深银还、表達能力更強外风宁,還有兩點。一是除了最后的全連接層蛹疯,用全局平均池化層來取代他戒财。二是Inception V1中精心設(shè)計的Inception Module提高了參數(shù)的利用效率。
Inception V1比NIN更進一步的是增加了分支網(wǎng)絡(luò)苍苞,NIN則主要是級聯(lián)的卷積層和MLPConv層固翰。
IM的基本結(jié)構(gòu)有4個分支狼纬。第一個分支是1x1卷積羹呵,是一個非常優(yōu)秀的結(jié)構(gòu)。它可以對輸出通道升維和降維疗琉。第二個分支線使用1x1卷積冈欢,然后連接3x3卷積,相當于進行了兩次特征變換盈简。第三個分支類似凑耻。
因為1x1的卷積性價比高,用很小的計算量就能增加一層特征變換和非線性化柠贤。IM中的4個分支在最后通過一個聚合操作合并香浩。IM中包含看3個不同尺寸的卷積和1個最大池化,增加了網(wǎng)絡(luò)對不同尺度的適應(yīng)性臼勉。
如果數(shù)據(jù)集的概率分布可以被一個很大很稀疏的神經(jīng)網(wǎng)絡(luò)所表達邻吭,那么構(gòu)筑這個網(wǎng)絡(luò)的最佳方法是逐層構(gòu)筑網(wǎng)絡(luò):將上一層高度相關(guān)的節(jié)點聚類,并將聚類出來的每一個小簇連接到一起宴霸。
Inception V2學習了VGGNet囱晴,用兩個3x3的卷積代替5x5的大卷積(可以降低參數(shù)量并且減輕過擬合)。BN在用于神經(jīng)網(wǎng)絡(luò)的某層時瓢谢,會對mini-batch內(nèi)部進行標準化處理畸写,使輸出規(guī)范化到N(0,1)的正態(tài)分布,減少Internal Covariate Shift(內(nèi)部神經(jīng)元的改變)氓扛。
單純使用BN獲得的增益還不明顯枯芬,還需要一些相應(yīng)的調(diào)整:增大學習速率并加快學習衰減以適應(yīng)BN規(guī)范化后的數(shù)據(jù);去除Dropout并減輕L2正則;去除LRN千所;更徹底的進行shuffle翅楼;減少數(shù)據(jù)增強中的光學畸變。
Inception V3網(wǎng)絡(luò)則主要是兩方面的改造真慢,一是引入Factorization into small convolutions的思想毅臊,將一個較大的二維卷積拆成兩個較小的一維卷積。一方面節(jié)約了大量參數(shù)黑界,加速運算并減輕了過擬合管嬉。同時增加了一層非線性擴展模型表達能力。
另一方面朗鸠,Inception V3優(yōu)化了Inception Module的結(jié)構(gòu)蚯撩。
Inception V4相比V3主要是結(jié)合了微軟的ResNet。
下面僅記錄不同的代碼烛占。
首先介紹tf.contrib.slim胎挎。

slim = tf.contrib.slim

他可以給函數(shù)的參數(shù)自動賦予某些默認值。例如weights_regularizer=slim.l2_regularizer(weight_decay))會對[slim.conv2d, slim.fully_connected]這兩個函數(shù)的參數(shù)自動賦值忆家,將參數(shù)weights_regularizer的值默認設(shè)為slim.l2_regularizer(weight_decay)犹菇。使用slim.arg_scope后就不需要每次都重復設(shè)置參數(shù)了,只要在有修改時設(shè)置芽卿。接下來嵌套一個slim.arg_scope揭芍,對卷積層生成函數(shù)slim.sonv2d的參數(shù)賦予默認值。

  with slim.arg_scope([slim.conv2d, slim.fully_connected],
                      weights_regularizer=slim.l2_regularizer(weight_decay)):
    with slim.arg_scope(
        [slim.conv2d],
        weights_initializer=trunc_normal(stddev),
        activation_fn=tf.nn.relu,
        normalizer_fn=slim.batch_norm,
        normalizer_params=batch_norm_params) as sc:
      return sc

同時卸例,Inception V3論文中也提出了Factorization into Module思想称杨,利用兩個一維卷積模擬大尺寸的二維卷積,減少參數(shù)量同時是增加非線性筷转。前面幾層姑原,卷積中還有一層1x1卷積,這也是前面提到的Inception Module中經(jīng)常使用的結(jié)構(gòu)之一呜舒,可以低成本的跨通道的對特征進行組合锭汛。
ResNet
Residual Neural Network由微軟研究院Kaiming He等4名華人提出。ResNet的結(jié)構(gòu)可以極快的加速超神神經(jīng)網(wǎng)絡(luò)的訓練阴绢,模型的準確率也有非常大的提升店乐。Highway Network的目標就是解決極深的神經(jīng)網(wǎng)絡(luò)難以訓練的問題。前一層的信息呻袭,有一定比例可以不經(jīng)過矩陣乘法和非線性變換眨八,直接傳輸?shù)较乱粚印esNet最初的靈感出自問題:在不斷加深神經(jīng)網(wǎng)絡(luò)深度時左电,會出現(xiàn)Degradation的問題廉侧,即準確率會先上升然后達到飽和页响,再持續(xù)增加深度則會導致準確率下降。這并不是過擬合的問題段誊,因為不光在測試集上誤差增大闰蚕,訓練集本身也會增大。假設(shè)某段神經(jīng)網(wǎng)絡(luò)的輸入是x连舍,期望輸出是H(x)没陡,如果我們直接把輸入x傳到輸出作為初始結(jié)果,那么此時我們需要學習的目標就是F(x)=H(x)-x索赏。
傳統(tǒng)的卷積層或全連接層在信息傳遞時盼玄,或多或少會存在信息丟失、損耗等問題潜腻。ResNet在某種程度上解決了這個問題埃儿,通過直接將輸入信息繞道到輸出,保護信息的完整性融涣,這個網(wǎng)絡(luò)則只需要學習輸入童番、輸出差別的那一部分,簡化學習目標和難度威鹿。
以下同只記錄與眾不同的代碼剃斧。

class Block(collections.namedtuple('Block', ['scope', 'unit_fn', 'args'])):

使用collections.namedtuple設(shè)計ResNet基本Block模塊組的named tuple,并用它創(chuàng)建Block類专普,但只包含數(shù)據(jù)結(jié)構(gòu)悯衬,不包含具體方法。
下面定義一個降采樣subsample的方法檀夹,參數(shù)包括inputs(輸入),factor(采樣因子)和scope策橘。如果factor是1炸渡,則不做修改直接返回inputs;如果不為1丽已,則使用slim.max_pool2d最大池化實現(xiàn):

def subsample(inputs, factor, scope=None):
 if factor == 1:
   return inputs
 else:
   return slim.max_pool2d(inputs, [1, 1], stride=factor, scope=scope)

接下來定義堆疊Blocks的函數(shù)蚌堵,參數(shù)中net即為輸入,而outputs_collections則是用來收集各個end_points的collections沛婴。下面使用兩層循環(huán)吼畏,逐個Block,逐個Residual Unit地堆疊嘁灯,先使用兩個tf.variable_scope將殘差學習單元命名為block/unit_1的形式泻蚊。在第二層循環(huán)中,我們拿到每個Block中每個Residual Unit的args丑婿,并展開為depth性雄、depth_bottleneck和stribe没卸,其含義在前面定義Blocks類時已經(jīng)講解過。然后使用unit_fn函數(shù)(即殘差學習單元的生成函數(shù))順序地創(chuàng)建并連接所有殘差單元:

@slim.add_arg_scope
def stack_blocks_dense(net, blocks,
                      outputs_collections=None):
 for block in blocks:
   with tf.variable_scope(block.scope, 'block', [net]) as sc:
     for i, unit in enumerate(block.args):

       with tf.variable_scope('unit_%d' % (i + 1), values=[net]):
         unit_depth, unit_depth_bottleneck, unit_stride = unit
         net = block.unit_fn(net,
                             depth=unit_depth,
                             depth_bottleneck=unit_depth_bottleneck,
                             stride=unit_stride)
     net = slim.utils.collect_named_outputs(outputs_collections, sc.name, net)
 return net
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秒旋,一起剝皮案震驚了整個濱河市约计,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌迁筛,老刑警劉巖煤蚌,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異细卧,居然都是意外死亡铺然,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門酒甸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來魄健,“玉大人,你說我怎么就攤上這事插勤」潦荩” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵农尖,是天一觀的道長析恋。 經(jīng)常有香客問我,道長盛卡,這世上最難降的妖魔是什么助隧? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮滑沧,結(jié)果婚禮上并村,老公的妹妹穿的比我還像新娘。我一直安慰自己滓技,他們只是感情好哩牍,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著令漂,像睡著了一般膝昆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上叠必,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天荚孵,我揣著相機與錄音,去河邊找鬼纬朝。 笑死收叶,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的玄组。 我是一名探鬼主播滔驾,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼谒麦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了哆致?” 一聲冷哼從身側(cè)響起绕德,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎摊阀,沒想到半個月后耻蛇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡胞此,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年臣咖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漱牵。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡夺蛇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酣胀,到底是詐尸還是另有隱情刁赦,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布闻镶,位于F島的核電站甚脉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏铆农。R本人自食惡果不足惜牺氨,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望墩剖。 院中可真熱鬧猴凹,春花似錦、人聲如沸涛碑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒲障。三九已至,卻和暖如春瘫证,著一層夾襖步出監(jiān)牢的瞬間揉阎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工背捌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留毙籽,地道東北人。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓毡庆,卻偏偏與公主長得像坑赡,于是被迫代替她去往敵國和親烙如。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

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