深度學(xué)習(xí)_BP神經(jīng)網(wǎng)絡(luò)

1. 說(shuō)明

現(xiàn)在使用深度學(xué)習(xí)算法都以調(diào)庫(kù)為主,但在使用庫(kù)之前嚷闭,先用python寫(xiě)一個(gè)最基本的神經(jīng)網(wǎng)絡(luò)的程序,也非常必要,它讓我們對(duì)一些關(guān)鍵參數(shù):學(xué)習(xí)率货矮,批尺寸,激活函數(shù)尘喝,代價(jià)函數(shù)的功能和用法有一個(gè)直觀的了解压昼。

2. 原理

1) BP神經(jīng)網(wǎng)絡(luò)

BP神經(jīng)網(wǎng)絡(luò)是一種按照誤差逆向傳播算法訓(xùn)練的多層前饋神經(jīng)網(wǎng)絡(luò).這又前饋又逆向的把人繞暈了.先看看什么是前饋神經(jīng)網(wǎng)絡(luò),回顧一下《深度學(xué)習(xí)_簡(jiǎn)介》中的圖示:

圖片.png

這是一個(gè)典型的前饋神經(jīng)網(wǎng)絡(luò)钧大,數(shù)據(jù)按箭頭方向數(shù)據(jù)從輸入層經(jīng)過(guò)隱藏層流入輸出層翰撑,因此叫做前饋.前饋網(wǎng)絡(luò)在模型的輸出和模型之間沒(méi)有反饋,如果也包含反饋拓型,則是循環(huán)神經(jīng)網(wǎng)絡(luò)额嘿,將在后續(xù)的RNN部分介紹.
前向網(wǎng)絡(luò)和循環(huán)網(wǎng)絡(luò)的用途不同瘸恼,舉個(gè)例子,比如做玩具狗册养,前饋是用不同材料和規(guī)格訓(xùn)練N次东帅,各次訓(xùn)練之間都沒(méi)什么關(guān)系,只是隨著訓(xùn)練球拦,工人越來(lái)越熟練.而循環(huán)網(wǎng)絡(luò)中靠闭,要求每次做出來(lái)的狗都是前次的加強(qiáng)版,因此前次的結(jié)果也作為一種輸入?yún)⑴c到本次的訓(xùn)練之中.可把循環(huán)網(wǎng)絡(luò)理解成前饋網(wǎng)絡(luò)的升級(jí)版.本篇講到的BP神經(jīng)網(wǎng)絡(luò)坎炼,以及處理圖像常用的卷積神經(jīng)網(wǎng)絡(luò)都是前饋網(wǎng)絡(luò)愧膀,而處理自然語(yǔ)言常用的RNN則是循環(huán)網(wǎng)絡(luò).
誤差逆向傳播是指通過(guò)工人做出的狗(預(yù)測(cè)結(jié)果)與玩具狗規(guī)格(實(shí)際結(jié)果)的誤差來(lái)調(diào)整各個(gè)工人的操作(權(quán)重w),這個(gè)例子具體見(jiàn)前篇《簡(jiǎn)介》谣光,?由于誤差的傳播的順序是:輸出層->隱藏層2->隱藏層1檩淋,所以叫逆向傳播.
綜上,前饋指的是數(shù)據(jù)流向萄金,逆向指的是誤差流向.

2) 訓(xùn)練過(guò)程

簡(jiǎn)單回憶一下(詳見(jiàn)《簡(jiǎn)介》篇)訓(xùn)練過(guò)程:對(duì)于每個(gè)訓(xùn)練樣本蟀悦,BP算法先將輸入樣例提供給給輸入神經(jīng)元,然后逐層將信號(hào)向前傳播氧敢,直到產(chǎn)生輸出層的結(jié)果日戈,然后對(duì)照實(shí)際結(jié)果計(jì)算輸出層的誤差,再將誤差逆向傳播到隱層神經(jīng)元孙乖,然后根據(jù)神經(jīng)元的誤差來(lái)對(duì)連接權(quán)值和與偏置進(jìn)行調(diào)整優(yōu)化浙炼。向前傳數(shù)據(jù)很簡(jiǎn)單,只包含加法乘法和激活函數(shù)(具體計(jì)算見(jiàn)代碼)唯袄,相對(duì)的難點(diǎn)在于逆向傳誤差弯屈,當(dāng)?shù)玫搅溯敵鰧拥恼`差后,調(diào)整w3中各個(gè)w的具體方法是什么呢恋拷?這里用到了梯度下降算法.此處也是代碼中的最理解的部分.
下面先看一下代碼季俩,梯度下降算法見(jiàn)之后的"關(guān)鍵概念"部分.

3. 代碼分析

1) 程序說(shuō)明

程序?qū)崿F(xiàn)了通過(guò)MNIST數(shù)據(jù)集中60000個(gè)實(shí)例訓(xùn)練對(duì)手寫(xiě)數(shù)字的識(shí)別,使用一個(gè)輸入層梅掠,一個(gè)隱藏層酌住,一個(gè)輸出層的方式構(gòu)建BP神經(jīng)網(wǎng)絡(luò).
因代碼較長(zhǎng),把它分成兩塊:算法實(shí)現(xiàn)和處部調(diào)用(運(yùn)行程序時(shí)把它們粘在一起即可)阎抒。注釋有點(diǎn)多哈:p

2) 算法實(shí)現(xiàn)

# -*- coding: utf-8 -*-

import numpy as np
import random
import os, struct
from array import array as pyarray
from numpy import append, array, int8, uint8, zeros
from keras.datasets import mnist
 
class NeuralNet(object):
    # 初始化神經(jīng)網(wǎng)絡(luò)酪我,sizes包含了神經(jīng)網(wǎng)絡(luò)的層數(shù)和每層神經(jīng)元個(gè)數(shù)
    def __init__(self, sizes):
        self.sizes_ = sizes
        self.num_layers_ = len(sizes)  # 三層:輸入層,一個(gè)隱藏層(8個(gè)節(jié)點(diǎn)), 輸出層
        # zip 函數(shù)同時(shí)遍歷兩個(gè)等長(zhǎng)數(shù)組的方法
        self.w_ = [np.random.randn(y, x) for x, y in zip(sizes[:-1], sizes[1:])]  # w_且叁、b_初始化為隨機(jī)數(shù)
        self.b_ = [np.random.randn(y, 1) for y in sizes[1:]]
        # w_是二維數(shù)組都哭,w_[0].shape=(8,784), w_[1].shape=(10, 8),權(quán)值, 供矩陣乘
        # b_是二維數(shù)組,b_[0].shape=(8, 1), b_[1].shape=(10, 1),偏移, 每層間轉(zhuǎn)換的偏移
 
    # Sigmoid函數(shù),激活函數(shù)的一種, 把正負(fù)無(wú)窮間的值映射到0-1之間
    def sigmoid(self, z):
        return 1.0/(1.0+np.exp(-z))

    # Sigmoid函數(shù)的導(dǎo)函數(shù), 不同激活函數(shù)導(dǎo)函數(shù)不同
    def sigmoid_prime(self, z):
        return self.sigmoid(z)*(1-self.sigmoid(z))
 
    # 向前傳播:已知input欺矫,根據(jù)w,b算output纱新,用于預(yù)測(cè)
    def feedforward(self, x):
        for b, w in zip(self.b_, self.w_):
            x = self.sigmoid(np.dot(w, x)+b)
        return x # 此處的x是0-9每個(gè)數(shù)字的可能性
 
    # 單次訓(xùn)練函數(shù),x是本次訓(xùn)練的輸入穆趴,y是本次訓(xùn)練的實(shí)際輸出
    # 返回的是需調(diào)整的w,b值
    def backprop(self, x, y):
        # 存放待調(diào)整的w,b值脸爱,nabla是微分算符
        nabla_b = [np.zeros(b.shape) for b in self.b_] # 與b_大小一樣,初值為0
        nabla_w = [np.zeros(w.shape) for w in self.w_] # 與w_大小一樣未妹,初值為0
 
        activation = x # 存放層的具體值, 供下層計(jì)算 
        activations = [x] # 存儲(chǔ)每層激活函數(shù)之后的值
        zs = [] # 存放每層激活函數(shù)之前的值
        for b, w in zip(self.b_, self.w_):
            z = np.dot(w, activation)+b # dot是矩陣乘法, w是權(quán)值簿废,b是偏移
            zs.append(z)
            activation = self.sigmoid(z) # 激活函數(shù)
            activations.append(activation)
 
        # 計(jì)算輸出層的誤差,cost_derivative為代價(jià)函數(shù)的導(dǎo)數(shù)
        delta = self.cost_derivative(activations[-1], y) * \
            self.sigmoid_prime(zs[-1]) #原理見(jiàn)梯度下降部分
        nabla_b[-1] = delta 
        nabla_w[-1] = np.dot(delta, activations[-2].transpose())
 
        # 計(jì)算隱藏層的誤差
        for l in range(2, self.num_layers_):
            z = zs[-l]
            sp = self.sigmoid_prime(z)
            delta = np.dot(self.w_[-l+1].transpose(), delta) * sp
            nabla_b[-l] = delta
            nabla_w[-l] = np.dot(delta, activations[-l-1].transpose())
        return (nabla_b, nabla_w)
 
    # 對(duì)每批中的len(mini_batch)個(gè)實(shí)例络它,按學(xué)習(xí)率eta調(diào)整一次w,b
    def update_mini_batch(self, mini_batch, eta):
        # 累計(jì)調(diào)整值
        nabla_b = [np.zeros(b.shape) for b in self.b_] # 與b_大小一樣族檬,值為0
        nabla_w = [np.zeros(w.shape) for w in self.w_] # 與w_大小一樣,值為0
        for x, y in mini_batch: # 100個(gè)值,分別訓(xùn)練
            delta_nabla_b, delta_nabla_w = self.backprop(x, y)
            nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
            nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
        # eta是預(yù)設(shè)的學(xué)習(xí)率(learning rate),用來(lái)調(diào)節(jié)學(xué)習(xí)的速度. eta越大化戳,調(diào)整越大
        # 用新計(jì)算出的nable_w調(diào)整舊的w_, b_同理
        self.w_ = [w-(eta/len(mini_batch))*nw for w, nw in zip(self.w_, nabla_w)]
        self.b_ = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.b_, nabla_b)]
 
    # 訓(xùn)練的接口函數(shù)
    # training_data是訓(xùn)練數(shù)據(jù)(x, y);epochs是訓(xùn)練次數(shù);
    # mini_batch_size是每次訓(xùn)練樣本數(shù); eta是學(xué)習(xí)率learning rate
    def SGD(self, training_data, epochs, mini_batch_size, eta, test_data=None):
        if test_data:
            n_test = len(test_data)
 
        n = len(training_data)
        for j in range(epochs): # 用同樣數(shù)據(jù)单料,訓(xùn)練多次
            random.shuffle(training_data) # 打亂順序
            mini_batches = [training_data[k:k+mini_batch_size] for k in range(0, n, mini_batch_size)]
            # 把所有訓(xùn)練數(shù)據(jù)60000個(gè)分成每100個(gè)/組(mini_batch_size=100)
            for mini_batch in mini_batches:
                self.update_mini_batch(mini_batch, eta) # 分批訓(xùn)練
            if test_data:
                print("Epoch {0}: {1} / {2}".format(j, self.evaluate(test_data), n_test))
            else:
                print("Epoch {0} complete".format(j))
 
    # 計(jì)算預(yù)測(cè)的正確率
    def evaluate(self, test_data):
        # argmax(f(x))是使得 f(x)取得最大值所對(duì)應(yīng)的變量x
        test_results = [(np.argmax(self.feedforward(x)), y) for (x, y) in test_data]
        return sum(int(x == y) for (x, y) in test_results)
 
    # 代價(jià)函數(shù)的導(dǎo)數(shù), 對(duì)比實(shí)際輸出與模擬輸出的差異, 此時(shí)y也是個(gè)數(shù)組
    def cost_derivative(self, output_activations, y):
        return (output_activations-y)
 
    # 預(yù)測(cè)
    def predict(self, data):
        value = self.feedforward(data)
        return value.tolist().index(max(value))

3) 外部調(diào)用

外部調(diào)用主要實(shí)現(xiàn)了主函數(shù),load數(shù)據(jù)点楼,以及調(diào)用神經(jīng)網(wǎng)絡(luò)的接口

# 將輸入數(shù)據(jù)轉(zhuǎn)換為神經(jīng)網(wǎng)絡(luò)能處理的格式
def load_samples(image, label, dataset="training_data"):
    X = [np.reshape(x,(28*28, 1)) for x in image] # 手寫(xiě)圖分辨率28x28
    X = [x/255.0 for x in X]   # 灰度值范圍(0-255)看尼,轉(zhuǎn)換為(0-1)
 
    # 把y從一個(gè)值轉(zhuǎn)成一個(gè)數(shù)組,對(duì)應(yīng)輸出層0-9每個(gè)數(shù)字出現(xiàn)的概率
    # 5 -> [0,0,0,0,0,1.0,0,0,0];  1 -> [0,1.0,0,0,0,0,0,0,0]
    def vectorized_Y(y):  
        e = np.zeros((10, 1))
        e[y] = 1.0
        return e
 
    if dataset == "training_data":
        Y = [vectorized_Y(y) for y in label]
        pair = list(zip(X, Y))
        return pair
    elif dataset == 'testing_data':
        pair = list(zip(X, label))
        return pair
    else:
        print('Something wrong')
 
 
if __name__ == '__main__':
    INPUT = 28*28 # 每張圖像28x28個(gè)像素
    OUTPUT = 10 # 0-9十個(gè)分類(lèi)
    net = NeuralNet([INPUT, 8, OUTPUT])

    # 從mnist提供的庫(kù)中裝載數(shù)據(jù)
    (x_train, y_train), (x_test, y_test) = mnist.load_data()
    # 格式轉(zhuǎn)換
    test_set = load_samples(x_test, y_test, dataset='testing_data')
    train_set = load_samples(x_train, y_train, dataset='training_data')

    #訓(xùn)練
    net.SGD(train_set, 13, 100, 3.0, test_data=test_set)
 
    #計(jì)算準(zhǔn)確率
    correct = 0;
    for test_feature in test_set:  
        if net.predict(test_feature[0]) == test_feature[1]:  
            correct += 1  
    print("percent: ", correct/len(test_set))

4. 關(guān)鍵概念

1) 誤差函數(shù)

誤差函數(shù)也叫代價(jià)函數(shù)或損失函數(shù)盟步,它計(jì)算的是實(shí)際結(jié)果和預(yù)測(cè)結(jié)果之間的差異,誤差函數(shù)記作L(Y, f(x)).
上例中代價(jià)函數(shù)用的是方差再取二分之一的方法(SSE):(1/2)*(o-y)^2躏结,它的導(dǎo)數(shù)是o-y却盘,即output_activations-y,其中output_activations為預(yù)測(cè)結(jié)果媳拴,y為實(shí)際結(jié)果黄橘。上面沒(méi)有直接寫(xiě)誤差函數(shù),而是給出了它的導(dǎo)數(shù)(cost_derivative).
誤差函數(shù)還有均方誤差屈溉,絕對(duì)值均差等塞关,具體請(qǐng)見(jiàn)參考中的《目標(biāo)函數(shù)objectives》。

2) 梯度下降

回顧一下導(dǎo)數(shù)的概念子巾,假設(shè)我們有一個(gè)函數(shù) y = f (x)帆赢,這個(gè)函數(shù)的導(dǎo)數(shù)記為f’(x) ,它描述了如何改變x线梗,能在輸出獲得相應(yīng)的變化:
f (x +ε) ≈ f (x) +εf’(x)
此時(shí)我們希望f()向小的方向變化(等號(hào)左側(cè))椰于,則需要對(duì)f(x)加一個(gè)負(fù)數(shù),即ε
f’(x)<=0仪搔,那么ε與f’(x)符號(hào)不同瘾婿。換言之,可以將 x 往導(dǎo)數(shù)的反方向移動(dòng)一小步ε來(lái)減小 f (x)。這種技術(shù)被稱(chēng)為梯度下降.可通過(guò)下圖偏陪,獲得更直觀的理解.

(圖片引自《深度學(xué)習(xí)》"花書(shū)")

梯度下降算法在上例的backprop()部分實(shí)現(xiàn)抢呆,我們想知道如何改變權(quán)重w,能使誤差函數(shù)L變小笛谦,于是求L對(duì)于w的導(dǎo)數(shù)抱虐,然后將w向?qū)?shù)的反方向移動(dòng)一小步,即可使L變芯竞薄.
損失函數(shù)的計(jì)算由下式得出:
L = (1/2)*(g(wx+b) – y)^2梯码,其中y是實(shí)際結(jié)果,g()是激活函數(shù)好啰,wx+b是對(duì)上一步x的線性變換轩娶,對(duì)L求導(dǎo)用到了復(fù)合函數(shù)的鏈試法則,因此有程序中分別使用了激活函數(shù)的導(dǎo)數(shù)(sigmoid_prime)框往,損失函數(shù)的導(dǎo)數(shù)(cost_derivative)鳄抒,再乘以上一步的x(activations).以上就是求權(quán)重w變化的原理,偏置b同理.
另外椰弊,需要注意的是這里求出的nable_w是權(quán)重的梯度许溅,并不是具體的權(quán)重值.

3) 批尺寸

批尺寸是每訓(xùn)練多少個(gè)數(shù)據(jù)調(diào)整一次權(quán)重.上例中由mini_batch指定為每次100個(gè)實(shí)例;如果每訓(xùn)練一次就調(diào)整一次秉版,不但會(huì)增加運(yùn)算量贤重,還會(huì)使w變化波動(dòng)加俱,使其難以收斂清焕;如果一次訓(xùn)練太多并蝗,則會(huì)占用較大內(nèi)存,有時(shí)正負(fù)波相互抵消秸妥,最終使w無(wú)法改進(jìn).因此選擇批尺寸時(shí)滚停,需要在考慮內(nèi)存和運(yùn)算量的情況下盡量加大批尺寸.

4) 學(xué)習(xí)率

學(xué)習(xí)率也叫學(xué)習(xí)因子,簡(jiǎn)單地說(shuō)粥惧,就是每次算出來(lái)的梯度對(duì)權(quán)值的影響的大小键畴。學(xué)習(xí)率大,影響就大突雪。學(xué)習(xí)率決定了參數(shù)移動(dòng)到最優(yōu)值的速度快慢起惕。如果學(xué)習(xí)率過(guò)大,很可能會(huì)越過(guò)最優(yōu)值咏删;反而如果學(xué)習(xí)率過(guò)小疤祭,優(yōu)化的效率可能過(guò)低,使得長(zhǎng)時(shí)間算法無(wú)法收斂饵婆。
學(xué)習(xí)率在上例中是eta數(shù)值.
學(xué)習(xí)率的選擇與誤差函數(shù)相關(guān)勺馆,上例中使用SSE作為誤差函數(shù)戏售,批尺寸越大,梯度數(shù)據(jù)累加后越大草穆,因此在計(jì)算時(shí)除以了批尺寸大泄嘣帧.我們可以選擇一個(gè)不被訓(xùn)練集樣本個(gè)數(shù)影響的誤差函數(shù)(比如MSE).另外,輸入特征的大小也對(duì)學(xué)習(xí)率有影響悲柱,所以處理前最好先歸一化.
還可以在學(xué)習(xí)中動(dòng)態(tài)地調(diào)整學(xué)習(xí)率锋喜,常用的有學(xué)習(xí)率有sgd, adadelta等.具體見(jiàn)參考中的《各種優(yōu)化方法總結(jié)比較》

5) 激活函數(shù)

激活函數(shù)也叫激勵(lì)函數(shù)豌鸡,它的功能是將線性變換轉(zhuǎn)成非線性變換嘿般,以提供非線性問(wèn)題的解決方法.
上例中使用了sigmoid函數(shù)作為激活函數(shù).常用的激活函數(shù)還有tanh,RelU等.其中ReLU是當(dāng)前流行的激活函數(shù)y=max(0,x)涯冠,它將大于0的值留下炉奴,否則一律為0。常用于處理大多數(shù)元素為0的稀疏矩陣蛇更。具體請(qǐng)見(jiàn)參考中的《神經(jīng)網(wǎng)絡(luò)之激活函數(shù)》

5. 參考

  1. 神經(jīng)網(wǎng)絡(luò)入門(mén)之bp算法瞻赶,梯度下降
    http://blog.csdn.net/u013230651/article/details/75909596
  2. 使用Python實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)
    http://blog.csdn.net/u014365862/article/details/53868414
  3. 目標(biāo)函數(shù)objectives
    http://keras-cn.readthedocs.io/en/latest/other/objectives/
  4. 各種優(yōu)化方法總結(jié)比較
    http://blog.csdn.net/luo123n/article/details/48239963
  5. 機(jī)器學(xué)習(xí)中的損失函數(shù)
    http://blog.csdn.net/shenxiaoming77/article/details/51614601
  6. Deep Learning 學(xué)習(xí)隨記(七)Convolution and Pooling --卷積和池化
    http://blog.csdn.net/zhoubl668/article/details/24801103
  7. 神經(jīng)網(wǎng)絡(luò)之激活函數(shù)(sigmoid、tanh派任、ReLU)
    http://blog.csdn.net/suixinsuiyuan33/article/details/69062894?locationNum=4&fps=1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末砸逊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子掌逛,更是在濱河造成了極大的恐慌师逸,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豆混,死亡現(xiàn)場(chǎng)離奇詭異篓像,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)崖叫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拍柒,“玉大人心傀,你說(shuō)我怎么就攤上這事〔鹧叮” “怎么了脂男?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)种呐。 經(jīng)常有香客問(wèn)我宰翅,道長(zhǎng),這世上最難降的妖魔是什么爽室? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任汁讼,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嘿架。我一直安慰自己瓶珊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布耸彪。 她就那樣靜靜地躺著伞芹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蝉娜。 梳的紋絲不亂的頭發(fā)上唱较,一...
    開(kāi)封第一講書(shū)人閱讀 51,737評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音召川,去河邊找鬼南缓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛扮宠,可吹牛的內(nèi)容都是我干的西乖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼坛增,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼获雕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起收捣,我...
    開(kāi)封第一講書(shū)人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤届案,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后罢艾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體楣颠,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年咐蚯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了童漩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡春锋,死狀恐怖矫膨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情期奔,我是刑警寧澤侧馅,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站呐萌,受9級(jí)特大地震影響馁痴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肺孤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一罗晕、第九天 我趴在偏房一處隱蔽的房頂上張望济欢。 院中可真熱鬧,春花似錦攀例、人聲如沸船逮。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)挖胃。三九已至,卻和暖如春梆惯,著一層夾襖步出監(jiān)牢的瞬間酱鸭,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工垛吗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凹髓,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓怯屉,卻偏偏與公主長(zhǎng)得像蔚舀,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锨络,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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