(Python) 使用numpy實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)

使用numpy實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)
使用numpy實(shí)現(xiàn)MLP(多層感知機(jī))
手寫神經(jīng)網(wǎng)絡(luò)
手寫反向傳播
手寫梯度下降盲再、隨機(jī)梯度下降

代碼都在https://github.com/wushangbin/tripping/blob/master/Python/MLP_with_numpy.py
看了GitHub代碼氓英,別忘了star哦馅扣!

1 前向傳播

1.1 前向傳播理論

先看前向傳播過(guò)程,還是很簡(jiǎn)單的。
u^{[l]}=\theta^{[l]}o^{[l-1]}+b^{[l]}
這里:
設(shè)這一層輸出的維度為d_{2}, 這也是本層的結(jié)點(diǎn)個(gè)數(shù),而上一層輸出維度為d_{1}
一次性輸入網(wǎng)絡(luò)的樣本個(gè)數(shù)為n (即batch_size的大小)

o^{[l-1]} :上一層的輸出,如果上一層是輸入層孵坚,那就是x. 它的shape:(d_{1}, n)
\theta^{[l]}: 權(quán)重矩陣,在訓(xùn)練中調(diào)整窥淆,它的shape:(d_{2}, d_{1}
b^{[l]}: 偏置卖宠,shape:(d_{2}, 1)
u^{[l]}: 這一層的輸出(未經(jīng)激活函數(shù)),shape: (d_{2}, n)

最后這個(gè)輸出u^{[l]}要經(jīng)過(guò)激活函數(shù)變?yōu)?img class="math-inline" src="https://math.jianshu.com/math?formula=o%5E%7B%5Bl%5D%7D" alt="o^{[l]}" mathimg="1">,即:
o^{[l]} = \phi(u^{[l]}) = \phi(\theta^{[l]}o^{[l-1]}+b^{[l]})
其中忧饭,\phi 為激活函數(shù)扛伍,可以是sigmoid、tanh词裤、relu等等蜒秤。

1.2 前向傳播代碼

在前向傳播前汁咏,首先要把參數(shù)進(jìn)行隨機(jī)初始化:

import numpy as np
class MLPnet:
    def __init__(self, x, y, lr=0.005):
        """
        :param x: data
        :param y: labels
        :param lr: learning rate
        yh: predicted labels
        """
        self.X = x
        self.Y = y
        self.yh = np.zeros((1, self.Y.shape[1]))
        self.lr = lr
        self.dims = [12, 20, 1]  # 不同層的結(jié)點(diǎn)個(gè)數(shù)

        self.param = {}  # 需要訓(xùn)練的參數(shù)
        self.ch = {}  # 將一些結(jié)果存在這里亚斋,以便在反向傳播時(shí)使用
        self.loss = []  # 存放每個(gè)epoch的loss
        self.batch_size = 64

    def nInit(self):
        """對(duì)神經(jīng)網(wǎng)絡(luò)中的參數(shù)進(jìn)行隨機(jī)初始化"""
        np.random.seed(1)
        self.param['theta1'] = np.random.randn(self.dims[1], self.dims[0]) / np.sqrt(self.dims[0])
        self.param['b1'] = np.zeros((self.dims[1], 1))
        self.param['theta2'] = np.random.randn(self.dims[2], self.dims[1]) / np.sqrt(self.dims[1])
        self.param['b2'] = np.zeros((self.dims[2], 1))

然后需要注意的是作媚,我們?cè)谇跋騻鞑ブ校枰獙?shí)現(xiàn)激活函數(shù)帅刊,這里纸泡,我們實(shí)現(xiàn)Relu和Tanh:
Relu:
o = \phi(u) = max(0,u)
Tanh:
o = \phi(u) = tanh(u) = \frac{e^{u} - e^{-u}}{e^{u} + e^{-u}}
這個(gè)實(shí)現(xiàn)起來(lái)還是很簡(jiǎn)單的:

    def Relu(self, u):
        return np.maximum(0, u)

    def Tanh(self, u):
        return (np.exp(u) - np.exp(-u)) / (np.exp(u) + np.exp(-u))

這里兩個(gè)函數(shù)的輸入u實(shí)際上可以是任意維度的
然后就是前向傳播的整體過(guò)程了,實(shí)際上就是把之前的乘法和加法用代碼實(shí)現(xiàn)就好:

    def forward(self, x):
        if self.param == {}:
            self.nInit()
        u1 = np.matmul(self.param['theta1'], x) + self.param['b1']
        o1 = self.Tanh(u1)
        u2 = np.matmul(self.param['theta2'], o1) + self.param['b2']
        o2 = self.Relu(u2)

        self.ch['X'] = x
        self.ch['u1'], self.ch['o1'] = u1, o1
        self.ch['u2'], self.ch['o2'] = u2, o2
        return o2

要注意赖瞒,這里我們要把x, u1, o1, u2, o2進(jìn)行保存女揭,是為了在反向傳播時(shí)使用

2 反向傳播

2.1 損失函數(shù)

在前向傳播之后,模型實(shí)際上就已經(jīng)輸出了一個(gè)預(yù)測(cè)結(jié)果栏饮,當(dāng)然了吧兔,這個(gè)預(yù)測(cè)結(jié)果可能并不好,我們需要根據(jù)預(yù)測(cè)結(jié)果調(diào)整模型中參數(shù)的權(quán)重袍嬉。
所以這里需要一個(gè)損失函數(shù)境蔼,來(lái)評(píng)價(jià)我們的預(yù)測(cè)結(jié)果,損失函數(shù)的值越小伺通,說(shuō)明我們的預(yù)測(cè)結(jié)果與真實(shí)值差距越小箍土,在這里,我們使用的損失函數(shù)是MSE(Mean Square Error)
MSE = \frac{1}{2N}\sum\limits_{i=1}^{N}\left(y_{i} - \hat{y_{i}}\right)^{2}
其中

y_{i}: 真實(shí)值
\hat{y_{i}}: 預(yù)測(cè)值

這里應(yīng)注意罐监,我們y和yh的形狀吴藻,都是2維的,所以在計(jì)算的時(shí)候弓柱,應(yīng)該y[0][i] - yh[0][i]
而且沟堡,因?yàn)槲覀儁的形狀是(1, n) 所以我們不能用len(y)來(lái)表示樣本數(shù)量,要把樣本數(shù)量顯示地提取出來(lái)
代碼:

    def nloss(self,y, yh):
        """
        :param y: 1*n, 列表
        :param yh: 1*N, 列表
        :return: 1*1 標(biāo)量
        """
        n = y.shape[1]
        error = []
        squaredError = []
        for i in range(n):
            error.append(y[0][i] - yh[0][i])
        for val in error:
            squaredError.append(val * val)
        result = sum(squaredError) / (2 * n)
        return result

2.2 反向傳播理論

我們?cè)谟?jì)算出loss之后矢空,下一步就是根據(jù)loss調(diào)整模型中的參數(shù)
具體怎么調(diào)整呢航罗?
這個(gè)原理其實(shí)很簡(jiǎn)單:我們的輸入是固定的,像\theta妇多, b這樣的參數(shù)是可訓(xùn)練的(可變的)伤哺,因此我們現(xiàn)在就可以得到一個(gè)這樣的函數(shù),函數(shù)的輸出值者祖,取決于參數(shù):
Loss = f(w)
我們把整個(gè)網(wǎng)絡(luò)看作一個(gè)函數(shù)f, 其中的所有的參數(shù)表示為w立莉,那么接下來(lái),我們就是要找到這個(gè)函數(shù)的最小值(Loss的最小值)七问,以及Loss取最小值時(shí)的w的值蜓耻。
在線性回歸中,我們可以直接通過(guò)數(shù)學(xué)方法直接求出最優(yōu)解械巡,但是現(xiàn)在模型復(fù)雜刹淌,我們要采用梯度下降法饶氏。
梯度下降法中,我們需要知道在w取一個(gè)確定值時(shí)有勾,Loss對(duì)w的導(dǎo)數(shù)值疹启,這個(gè)導(dǎo)數(shù)值即為下降方向,也就是說(shuō)蔼卡,我們把w沿著這個(gè)方向調(diào)整喊崖,w就會(huì)離最小值的點(diǎn)更近。而學(xué)習(xí)率(learning rate)即為我們調(diào)整的幅度雇逞,如果調(diào)整幅度過(guò)大荤懂,可能會(huì)錯(cuò)過(guò)最小值的點(diǎn)。具體到我們模型中的4個(gè)參數(shù)上塘砸,參數(shù)更新公式分別是:
\theta^{[2]} = \theta^{[2]} - lr \times \frac{\partial l}{\partial \theta^{[2]}} \\ b^{[2]} = b^{[2]} - lr \times \frac{\partial l}{\partial b^{[2]}} \\ \theta^{[1]} = \theta^{[1]} - lr \times \frac{\partial l}{\partial \theta^{[1]}} \\ b^{[1]} = b^{[1]} - lr \times \frac{\partial l}{\partial b^{[1]}}
這其中节仿,參數(shù)的值是隨機(jī)初始化好的,lr是提前設(shè)定好的掉蔬,需要計(jì)算4個(gè)偏導(dǎo)數(shù)的值廊宪。
那么我們?nèi)绾吻筮@4個(gè)偏導(dǎo)數(shù)呢?直接求比較困難眉踱,因?yàn)槲覀儾⒉恢?img class="math-inline" src="https://math.jianshu.com/math?formula=Loss" alt="Loss" mathimg="1">與其中每個(gè)參數(shù)的函數(shù)關(guān)系式挤忙,但是我們知道每一層的函數(shù)(u^{[l]}=\theta^{[l]}o^{[l-1]}+b^{[l]}),所以要根據(jù)鏈?zhǔn)椒▌t
\frac{\partial l}{\partial \theta^{[2]}} = \frac{\partial l}{\partial o^{[2]}}\frac{\partial o^{[2]}}{\partial u^{[2]}}\frac{\partial u^{[2]}}{\partial \theta^{[2]}} \\ \frac{\partial l}{\partial b^{[2]}} = \frac{\partial l}{\partial o^{[2]}}\frac{\partial o^{[2]}}{\partial u^{[2]}}\frac{\partial u^{[2]}}{\partial b^{[2]}} \\ \frac{\partial l}{\partial \theta^{[1]}} = \frac{\partial l}{\partial o^{[2]}}\frac{\partial o^{[2]}}{\partial u^{[2]}}\frac{\partial u^{[2]}}{\partial o^{[1]}} \frac{\partial o^{[1]}}{\partial u^{[1]}} \frac{\partial u^{[1]}}{\partial \theta^{[1]}} \\ \frac{\partial l}{\partial b^{[1]}} = \frac{\partial l}{\partial o^{[2]}}\frac{\partial o^{[2]}}{\partial u^{[2]}}\frac{\partial u^{[2]}}{\partial o^{[1]}} \frac{\partial o^{[1]}}{\partial u^{[1]}} \frac{\partial u^{[1]}}{\partial b^{[1]}}
不必被這一長(zhǎng)串公式嚇到谈喳,我們接下來(lái)求出其中等號(hào)右邊的每一項(xiàng)册烈,然后就可以算出等號(hào)左邊的偏導(dǎo)數(shù)了
那么對(duì)于等號(hào)右邊的每一項(xiàng),其實(shí)都是很好求的婿禽,我們舉個(gè)例子:
對(duì)于\frac{\partial l}{\partial o ^{[2]}}, 因?yàn)橛?br> l = MSE = \frac{1}{2N}(o^{[2]} - y)^{2}
我們這里赏僧,o_{2} = \hat{y_{i}},第二層的輸出過(guò)了激活函數(shù)即為模型的輸出結(jié)果扭倾,然后y是真實(shí)值淀零,注意這里沒(méi)有求和,因?yàn)槲疫@里的yo_{2}都是矢量膛壹。那么\frac{\partial l}{\partial o ^{[2]}}就很好求了驾中,它就是:
\frac{\partial l}{\partial o ^{[2]}} = \frac{1}{n}(o^{[2]} - y)
類似地,o ^{[2]}o ^{[2]}的關(guān)系模聋,就是一層激活函數(shù)的關(guān)系肩民,所以它們之間的偏導(dǎo)數(shù),就是對(duì)激活函數(shù)求偏導(dǎo)即可.
Tanh的偏導(dǎo):
o' = \phi'(u) = 1 - {\left(\frac{e^{u} - e^{-u}}{e^{u} + e^{-u}}\right)}^{2} = 1 - o^{2}
Relu的偏導(dǎo):
o' = \phi'(u) = \begin{cases} &0& u \leq 0 \\ &1& u > 0 \end{cases}

因此链方,類似我們可得:
\frac{\partial u^{[2]}}{\partial \theta^{[2]}} = o^{[1]} \\ \frac{\partial u^{[2]}}{\partial b^{[2]}} = 1 \frac{\partial u^{[2]}}{\partial o^{[1]}} = \theta^{[2]} \\ \frac{\partial o^{[1]}}{\partial u^{[1]}} = 1 - (o^{[1]}) ^ {2}\\ \frac{\partial u^{[1]}}{\partial \theta^{[1]}} = x\\ \frac{\partial u^{[1]}}{\partial b^{[1]}} = 1
把這些式子帶入鏈?zhǔn)椒▌t持痰,可求出Loss對(duì)每個(gè)參數(shù)的偏導(dǎo),然后再把偏導(dǎo)帶入參數(shù)更新公式祟蚀,就可以求出新的參數(shù)了工窍。

2.3 反向傳播代碼

我們先把激活函數(shù)的導(dǎo)數(shù)寫好

    def dRelu(self, u):
        """        
        :param u: u of any dimension
        :return: dRelu(u) """        
        u[u<=0] = 0
        u[u>0] = 1
        return u

    def dTanh(self, u):
        """
        :param u: u of any dimension
        :return: dTanh(u) 
        """
        o = np.tanh(u)
        return 1-o**2

在反向傳播代碼中割卖,有一個(gè)細(xì)節(jié),是需要注意的:

  1. \frac{\partial l}{\partial o ^{[2]}} = \frac{1}{n}(o^{[2]} - y)中患雏,其實(shí)除以n或者不除以n都沒(méi)有很大區(qū)別鹏溯,因?yàn)檫@里說(shuō)到底是影響了學(xué)習(xí)率,不影響梯度下降的方向纵苛,如果你沒(méi)有除以n剿涮,那么就需要在學(xué)習(xí)率上做出調(diào)整;
  2. 后面每一個(gè)操作其實(shí)有類似情況攻人,比如你矩陣相乘后的結(jié)果,融合了所有樣本的悬槽,那么是否需要除以n怀吻,再比如有對(duì)所有樣本loss求和的操作,求和后是否需要除以n等等初婆。我自己親身實(shí)驗(yàn)了下蓬坡,大部分影響不大,有公式的改動(dòng)影響很大磅叛。這里我統(tǒng)一采用:一旦有合并所有樣本的梯度的情況屑咳,就除以n
  3. 這里的yh-y不能搞反,不然梯度下降的方向就錯(cuò)了弊琴,會(huì)導(dǎo)致loss一致不下降
  4. 有的時(shí)候是點(diǎn)乘兆龙,有的時(shí)候是矩陣乘,這一點(diǎn)要注意敲董,時(shí)時(shí)小心紫皇,關(guān)注每一步的維度變化
    def backward(self, y, yh):
        n = y.shape[1]
        dLoss_o2 = (yh - y) / n
        dLoss_u2 = dLoss_o2 * self.dRelu(self.ch['o2'])  # (1,379)
        dLoss_theta2 = np.matmul(dLoss_u2, self.ch['o1'].T) / n
        dLoss_b2 = np.sum(dLoss_u2) / n
        
        dLoss_o1 = np.matmul(self.param["theta2"].T, dLoss_u2)  # (20*1) mul (1*379)
        dLoss_u1 = dLoss_o1 * self.dTanh(self.ch['u1'])  # (20*379)
        dLoss_theta1 = np.matmul(dLoss_u1, self.X.T)  # (20*379) mul (379*13)
        dLoss_b1 = np.sum(dLoss_u1, axis=1, keepdims=True) / n
        # parameters update:
        self.param["theta2"] = self.param["theta2"] - self.lr * dLoss_theta2
        self.param["b2"] = self.param["b2"] - self.lr * dLoss_b2
        self.param["theta1"] = self.param["theta1"] - self.lr * dLoss_theta1
        self.param["b1"] = self.param["b1"] - self.lr * dLoss_b1
        return dLoss_theta2, dLoss_b2, dLoss_theta1, dLoss_b1

3 梯度下降

3.1 梯度下降算法

梯度下降這一塊兒,比較簡(jiǎn)單腋寨,現(xiàn)在先說(shuō)最基礎(chǔ)的聪铺,我們把所有數(shù)據(jù)放入模型,跑出結(jié)果萄窜,然后根據(jù)結(jié)果調(diào)用backward函數(shù)铃剔,更新參數(shù)即可,這里我們每一次都跑全部的數(shù)據(jù)查刻,然后設(shè)定一個(gè)參數(shù)iter即為迭代的次數(shù)键兜。
先寫一個(gè)函數(shù),輸入數(shù)據(jù)赖阻,輸出預(yù)測(cè)結(jié)果(其實(shí)就是調(diào)用forward):

    def predict(self, x):
        yh = self.forward(x)
        return yh

然后就是梯度下降:

    def gradient_descent(self, x, y, iter=60000):
        """
        每次跑全部數(shù)據(jù)蝶押,跑iter次,每2000次存儲(chǔ)一次loss
        :param x: data
        :param y: labels
        :param iter: 迭代次數(shù)
        """
        for i in range(iter):
            pre_y = self.predict(x)
            this_loss = self.nloss(y, pre_y)
            self.loss.append(this_loss)
            if i % 2000 == 0:
                print("Loss after iteration", i, ":", this_loss)
            self.backward(y, pre_y)

3.2 批量梯度下降

剛剛的方法火欧,每次都要放全部數(shù)據(jù)棋电,計(jì)算量太大了茎截,現(xiàn)在,我們每次放batch_size個(gè)數(shù)據(jù)赶盔。它的優(yōu)點(diǎn)在于企锌,下降速度更快,每次看少量數(shù)據(jù)就開(kāi)始修改參數(shù)于未,缺點(diǎn)是loss波動(dòng)性大撕攒,因?yàn)樗看螞](méi)有看全部的數(shù)據(jù),很可能這次看了一部分?jǐn)?shù)據(jù)烘浦,改了參數(shù)抖坪,第二次看了另一部分?jǐn)?shù)據(jù),又把參數(shù)改回去了闷叉。因此有一定的波動(dòng)性擦俐。
我們每次選取batch_size個(gè)數(shù)據(jù),進(jìn)行訓(xùn)練握侧,然后再往后選batch_size個(gè)數(shù)據(jù)蚯瞧,這樣就好。

    def batch_gradient_descent(self, x, y, iter=60000):
        """
        這里的迭代次數(shù)品擎,依然是backward的次數(shù)埋合,并非epoch(epoch是看全部數(shù)據(jù)的次數(shù))
        """
        n = y.shape[1]
        begin = 0
        for k in range(iter):
            index_list = [i % n for i in range(begin, begin + self.batch_size)]
            x_batch = x[:, index_list]
            y_batch = y[:, index_list]
            pre_y = self.predict(x_batch)
            self.X = x_batch
            this_loss = self.nloss(y_batch, pre_y)
            if k % 1000 == 0:
                self.loss.append(this_loss)
                print("Loss after iteration", k, ":", this_loss)
            self.backward(y_batch, pre_y)
            begin = begin + self.batch_size

4 實(shí)驗(yàn)結(jié)果

4.1 梯度下降

使用boston數(shù)據(jù)集

from sklearn.datasets import load_boston
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
if __name__ == '__main__':
    dataset = load_boston()  # load the dataset
    x, y = dataset.data, dataset.target
    y = y.reshape(-1, 1)
    x = MinMaxScaler().fit_transform(x)  # normalize data
    y = MinMaxScaler().fit_transform(y)
    x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=1)  # split data
    x_train, x_test, y_train, y_test = x_train.T, x_test.T, y_train.reshape(1, -1), y_test  
    nn = MLPnet(x_train, y_train, lr=0.001)  
    nn.gradient_descent(x_train, y_train, iter=60000)  # train
    # create figure
    fig = plt.plot(np.array(nn.loss).squeeze())
    plt.title(f'Training: MLPnet')
    plt.xlabel("Epoch")
    plt.ylabel("Loss")
    plt.show()
Loss after iteration 0 : 0.08998720790406557
Loss after iteration 2000 : 0.07518079881255157
Loss after iteration 4000 : 0.04587554948861338
Loss after iteration 6000 : 0.03592926084683294
Loss after iteration 8000 : 0.03037128839345559
Loss after iteration 10000 : 0.02678080951732856
...
Loss after iteration 48000 : 0.010800052957060184
Loss after iteration 50000 : 0.010534368656369569
Loss after iteration 52000 : 0.010286303319926585
Loss after iteration 54000 : 0.010054283077500703
Loss after iteration 56000 : 0.009836923785315307
Loss after iteration 58000 : 0.009633001471168611
Mean Squared Error (MSE) 0.02512249554701871
梯度下降.png

4.2 批量梯度下降:

把剛剛代碼中的gradient_descent改一下即可:

nn.batch_gradient_descent(x_train, y_train, iter = 60000) #train

實(shí)驗(yàn)結(jié)果:

Loss after iteration 0 : 0.08928835763543144
Loss after iteration 1000 : 0.06964017531640365
Loss after iteration 2000 : 0.08718731719795095
Loss after iteration 3000 : 0.07178114114739374
Loss after iteration 4000 : 0.03668939190963524
...
Loss after iteration 56000 : 0.008814925199710841
Loss after iteration 57000 : 0.006920864366920335
Loss after iteration 58000 : 0.005792226865048128
Loss after iteration 59000 : 0.012028778071099835
Mean Squared Error (MSE) 0.025001722467090818
隨機(jī)梯度下降.png

4.3 實(shí)驗(yàn)結(jié)果分析

在訓(xùn)練中,可以明顯感覺(jué)到

  1. 隨機(jī)梯度下降更快萄传,耗時(shí)更少(我沒(méi)有計(jì)時(shí)甚颂,但是感覺(jué)很明顯)
  2. 隨機(jī)梯度下降地波動(dòng)性更大
    另外要注意,隨機(jī)梯度下降盲再,我們這里的每個(gè)iter的數(shù)據(jù)量遠(yuǎn)遠(yuǎn)小于梯度下降的全量數(shù)據(jù)

代碼在https://github.com/wushangbin/tripping/blob/master/Python/MLP_with_numpy.py
看完代碼有幫助的話記得star哦西设!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市答朋,隨后出現(xiàn)的幾起案子贷揽,更是在濱河造成了極大的恐慌,老刑警劉巖梦碗,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件禽绪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡洪规,警方通過(guò)查閱死者的電腦和手機(jī)印屁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)斩例,“玉大人雄人,你說(shuō)我怎么就攤上這事。” “怎么了础钠?”我有些...
    開(kāi)封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵恰力,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我旗吁,道長(zhǎng)踩萎,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任很钓,我火速辦了婚禮香府,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘码倦。我一直安慰自己企孩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布叹洲。 她就那樣靜靜地躺著柠硕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪运提。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天闻葵,我揣著相機(jī)與錄音民泵,去河邊找鬼。 笑死槽畔,一個(gè)胖子當(dāng)著我的面吹牛栈妆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播厢钧,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鳞尔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了早直?” 一聲冷哼從身側(cè)響起寥假,我...
    開(kāi)封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎霞扬,沒(méi)想到半個(gè)月后糕韧,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡喻圃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年萤彩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斧拍。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡雀扶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肆汹,到底是詐尸還是另有隱情愚墓,我是刑警寧澤予权,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站转绷,受9級(jí)特大地震影響伟件,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜议经,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一斧账、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧煞肾,春花似錦咧织、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蝙昙,卻和暖如春闪萄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奇颠。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工败去, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烈拒。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓圆裕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親荆几。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吓妆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

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