《神经网络与机器学习》笔记(四)

第六章 循环神经网络

循环神经网络(Recurrent Neural Network,RNN)是一类具有短期记忆能力的神经网络。循环神经网络的参数学习可以通过随时间反向传播算法来学习。随时间反向传播算法即按照时间的逆序将错误信息一步步地往前传递。当输入序列比较长时,会存在梯度爆炸和消失问题,也称为长程依赖问题。为了解决这个问题,人们对循环神经网络进行了很多的改进,其中最有效的改进方式引入门控机制。

循环神经网络可以很容易地扩展到两种更广义的记忆网络模型:递归神经网络和图网络。

给网络增加记忆能力

延时神经网络

一种简单的利用历史信息的方法是建立一个额外的延时单元,用来存储网络的历史信息(可以包括输入、输出、隐状态等)。比较有代表性的模型是延时神经网络

延时神经网络在时间维度上共享权值,以降低参数数量。因此对于序列输入来讲,延时神经网络就相当于卷积神经网络。

实现方式:延时神经网络是在前馈网络中的非输出层都添加一个延时器,记录最近几次神经元的输出。在第t 个时刻,第l + 1 层神经元和第l 层神经元的最近p 次输出相关,即:\boldsymbol{h}_{t}^{(l+1)}=f\left(\boldsymbol{h}_{t}^{(l)}, \boldsymbol{h}_{t-1}^{(l)}, \cdots, \boldsymbol{h}_{t-p}^{(l)}\right),通过延时器,前馈网络就具有了短期记忆的能力。

有外部输入的非线性自回归模型

自回归模型(AutoRegressive Model,AR)是统计学上常用的一类时间序列模型,用一个变量y_t的历史信息来预测自己。

\begin{align*}&\boldsymbol{y}_{t}=w_{0}+\sum_{i=1}^{p} w_{i} \boldsymbol{y}_{t-i}+\epsilon_{t}\end{align*}
其中p 为超参数,w_0,\cdots ,w_p为可学习参数,\epsilon_{t} \sim \mathcal{N}\left(0, \sigma^{2}\right)为第t 个时刻的噪声,方差\sigma^{2}和时间无关。

有外部输入的非线性自回归模型(NARX)是自回归模型的扩展,在每个时刻t 都有一个外部输入xt,产生一个输出yt。NARX通过一个延时器记录最近几次的外部输入和输出,第t 个时刻的输出yt 为:

\begin{align*} \boldsymbol{y}_{t}=f\left(\boldsymbol{x}_{t}, \boldsymbol{x}_{t-1}, \cdots, \boldsymbol{x}_{t-p}, \boldsymbol{y}_{t-1}, \boldsymbol{y}_{t-2}, \cdots, \boldsymbol{y}_{t-q}\right) \end{align*}
其中f(·) 表示非线性函数,可以是一个前馈网络,p 和q 为超参数。

循环神经网络

循环神经网络(Recurrent Neural Network,RNN)通过使用带自反馈的神经元,能够处理任意长度的时序数据。

给定一个输入序列x_{1:T}=(x_1,x_2,\dots,x_t,\dots,x_T),循环神经网络通过公式h_t=f(h_{t-1},x_t)更新带反馈边的隐藏层的活性值ht。其中h0 = 0,f(·) 为一个非线性函数,也可以是一个前馈网络。

理论上,循环神经网络可以近似任意的非线性动力系统。

简单循环网络

简单循环网络(Simple Recurrent Network,SRN) 是一个非常简单的循环神经网络,只有一个隐藏层的神经网络。

按时间展开的循环神经网络

h_t=f(Uh_{t-1}+Wx_t+b)

循环神经网络的计算能力

由于循环神经网络具有短期记忆能力,相当于存储装置,因此其计算能力十分强大。前馈神经网络可以模拟任何连续函数,而循环神经网络可以模拟任何程序。

我们先定义一个完全连接的循环神经网络,其输入为xt,输出为yt

h_t=f(Uh_{t-1}+Wx_t+b),y_t=Vh_t

循环神经网络的通用近似定理

一个完全连接的循环网络是任何非线性动力系统的近似器。

图灵完备

是指一种数据操作规则,比如一种计算机编程语言,可以实现图灵机(Turing Machine)的所有功能,解决所有的可计算问题,目前主流的编程语言(比如C++、Java、Python 等)都是图灵完备的。

一个完全连接的循环神经网络可以近似解决所有的可计算问题。

应用到机器学习

序列到类别模式

序列到类别模式主要用于序列数据的分类问题:输入为序列,输出为类别。比如在文本分类中,输入数据为单词的序列,输出为该文本的类别。

同步的序列到序列模式

主要用于序列标注(Sequence Labeling)任务,即每一时刻都有输入和输出,输入序列和输出序列的长度相同。比如词性标注(Partof-Speech Tagging)中,每一个单词都需要标注其对应的词性标签。

异步的序列到序列模式

也称为编码器-解码器(Encoder-Decoder)模型,即输入序列和输出序列不需要有严格的对应关系,也不需要保持相同的长度。比如在机器翻译中,输入为源语言的单词序列,输出为目标语言的单词序列。

参数学习

可以通过梯度下降方法来进行学习。

以随机梯度下降为例,给定一个训练样本(x, y),其中x_{1:T}=(x_1,x_2,\dots,x_t,\dots,x_T)为长度是T 的输入序列,y_{1:T}=(y_1,y_2,\dots,y_t,\dots,y_T)是长度为T 的标签序列。即在每个时刻t,都有一个监督信息yt,我们定义时刻t 的损失函数为:\mathcal{L}_{t}=\mathcal{L}\left(y_{t}, g\left(h_{t}\right)\right),其中g(ht) 为第t 时刻的输出,\mathcal{L}为可微分的损失函数,比如交叉熵。那么整个序
列的损失函数为:\mathcal{L}=\sum_{t=1}^{T} \mathcal{L}_{t},整个序列的损失函数\mathcal{L}关于参数U 的梯度为:\frac{\partial \mathcal{L}}{\partial U}=\sum_{t=1}^{T} \frac{\partial \mathcal{L}_{t}}{\partial U},即每个时刻损失\mathcal{L}_{t}对参数U 的偏导数之和。

在循环神经网络中主要有两种计算梯度的方式:随时间反向传播(BPTT)算法和实时循环学习(RTRL)算法。

随时间反向传播算法

BPTT算法的主要思想是通过类似前馈神经网络的错误反向传播算法来计算梯度。

BPTT 算法将循环神经网络看作是一个展开的多层前馈网络,其中“每一层”对应循环网络中的“每个时刻”。这样,循环神经网络就可以按照前馈网络中的反向传播算法计算参数梯度。在“展开”的前馈网络中,所有层的参数是共享的,因此参数的真实梯度是所有“展开层”的参数梯度之和。

计算第t 时刻损失对参数U 的偏导数\frac{\partial \mathcal{L}_t}{\partial U}

误差项随时间反向传播算法示例


所以整个序列的损失函数关于参数U的梯度是:

同理可得,整个序列的损失函数关于权重W 和偏置b 的梯度为:\frac{\partial \mathcal{L}}{\partial W}=\sum^T_{t=1}\sum_{k=1}^{t} \delta_{t, k} x_{k}^T\frac{\partial \mathcal{L}}{\partial U}=\sum^T_{t=1}\sum_{k=1}^{t} \delta_{t, k}

实时循环学习算法

与反向传播的BPTT算法不同的是,实时循环学习(Real-Time Recurrent Learning,RTRL)是通过前向传播的方式来计算梯度。

假设循环神经网络中第t + 1时刻的状态ht+1为:h_{t+1}=f\left(z_{t+1}\right)=f\left(U h_{t}+W x_{t+1}+b\right)

其关于参数u_{ij}的偏导数为:
\begin{align} \frac{\partial h_{t+1}}{\partial u_{i j}} &=\left(\frac{\partial^{+} z_{t+1}}{\partial u_{i j}}+\frac{\partial h_{t}}{\partial u_{i j}} U^{\mathrm{T}}\right) \frac{\partial h_{t+1}}{\partial z_{t+1}} \\ &=\left(\mathbb{I}_{i}\left(\left[\boldsymbol{h}_{t}\right]_{j}\right)+\frac{\partial \boldsymbol{h}_{t}}{\partial u_{i j}} U^{\mathrm{T}}\right) \operatorname{diag}\left(f^{\prime}\left(z_{t+1}\right)\right) \\ &=\left(\mathbb{I}_{i}\left(\left[\boldsymbol{h}_{t}\right]_{j}\right)+\frac{\partial \boldsymbol{h}_{t}}{\partial u_{i j}} U^{\mathrm{T}}\right) \odot\left(f^{\prime}\left(z_{t+1}\right)\right)^{\mathrm{T}} \end{align}
两种算法比较:RTRL算法和BPTT算法都是基于梯度下降的算法,分别通过前向模式和反向模式应用链式法则来计算梯度。在循环神经网络中,一般网络输出维度远低于输入维度,因此BPTT算法的计算量会更小,但是BPTT算法需要保存所有时刻的中间梯度,空间复杂度较高。RTRL算法不需要梯度回传,因此非常适合用于需要在线学习或无限序列的任务中。

长程依赖问题

循环神经网络在学习过程中的主要问题是由于梯度消失或爆炸问题,很难建模长时间间隔(Long Range)的状态之间的依赖关系。

在BPTT算法中,将公式\delta_{t, k}=\operatorname{diag}\left(f^{\prime}\left(z_{k}\right)\right) U^{\mathrm{T}} \delta_{t, k+1}展开得到\delta_{t, k}=\prod_{\tau=k}^{t-1}\left(\operatorname{diag}\left(f^{\prime}\left(z_{\tau}\right)\right) U^{\mathrm{T}}\right) \delta_{t, t}

如果定义\gamma \cong\left\|\operatorname{diag}\left(f^{\prime}\left(z_{\tau}\right)\right) U^{\mathrm{T}}\right\|,则\delta_{t, k} \cong \gamma^{t-k} \delta_{t, t}

若γ > 1,当t − k → ∞时,γt−k → ∞。当间隔t − k 比较大时,梯度也变得很大,会造成系统不稳定,称为梯度爆炸问题。

相反,若γ < 1,当t − k → ∞时,γt−k → 0。当间隔t − k 比较大时,梯度也变得非常小,会出现和深层前馈神经网络类似的梯度消失问题,这就是长程依赖问题

由于循环神经网络经常使用非线性激活函数为Logistic函数或Tanh函数作为非线性激活函数,其导数值都小于1,并且权重矩阵∥U∥ 也不会太大,因此如果时间间隔t − k 过大,δt,k 会趋向于0,因而经常会出现梯度消失问题。

改进方案

为了避免梯度爆炸或消失问题,一种最直接的方式就是选取合适的参数,同时使用非饱和的激活函数,尽量使得\operatorname{diag}\left(f^{\prime}\left(z_{k}\right)\right) U^{\mathrm{T}} ≈ 1,这种方式需要足够的人工调参经验,限制了模型的广泛应用。比较有效的方式是通过改进模型或优化方法来缓解循环网络的梯度爆炸和梯度消失问题。

梯度爆炸一般而言,循环网络的梯度爆炸问题比较容易解决,一般通过权重衰减或梯度截断(是一种启发式的解
决梯度爆炸问题的有效方法)来避免。

梯度消失是循环网络的主要问题。除了使用一些优化技巧外,更有效的方式就是改变模型,比如让U=I,同时令为\frac{\partial h_t}{\partial h_{t-1}}=I单位矩阵,即:h_t=h_{t-1}+g(x_t;\theta),其中g(\cdot)是一个非线性函数,θ为参数。

可以看出h_t和h_{t-1}是线性依赖关系,且权重系数为1,这样就不存在梯度爆炸或消失问题。但是,这种改变也丢失了神经元在反馈边上的非线性激活的性质,因此也降低了模型的表示能力。

为了避免这个缺点,我们可以采用一种更加有效的改进策略:h_t=h_{t-1}+g(x_t,h_{t-1};\theta)

这样h_t和h_{t-1}之间既有线性关系,也有非线性关系,并且可以缓解梯度消失问题。但这种改进依然存在两个问题:

  1. 梯度爆炸问题,因为其中存在非线性关系
  2. 记忆容量问题,:随着ht不断累积存储新的输入信息,会发生饱和现象。假设g(·) 为Logistic 函数,则随着时间t 的增长,ht 会变得越来越大,从而导致h变得饱和。也就是说,隐状态ht 可以存储的信息是有限的,随着记忆单元存储的内容越来越多,其丢失的信息也越来越多。

基于门控的循环神经网络

为了改善循环神经网络的长程依赖问题,一种非常好的解决方案是在上一个改进方案的的基础上引入门控机制来控制信息的累积速度,包括有选择地加入新的信息,并有选择地遗忘之前累积的信息。这一类网络可以称为基于门控的循环神经网络(Gated RNN)。本节中,主要介绍两种基于门控的循环神经网络:长短期记忆网络和门控循环单元网络。

长短期记忆网络(LSTM)

是循环神经网络的一个变体,可以有效地解决简单循环神经网络的梯度爆炸或消失问题。

LSTM网络的循环单元结构

LSTM的改进点在两个方面:

  1. LSTM网络引入了一个新的内部状态ct专门进行线性的循环信息传递,同时(非线性地)输出信息给隐藏层的外部状态ht
    \begin{array}{l}{c_{t}=f_{t} \odot c_{t-1}+i_{t} \odot \tilde{c}_{t}} \\ {h_{t}=o_{t} \odot \tanh \left(c_{t}\right)}\end{array}\\ 其中f_{t}、i_t 和o_t 为三个门(gate)来控制信息传递的路径;\odot 为向量元素乘积; c_{t−1} 为上一时刻的记忆单元;\\ \tilde c_t 是通过非线性函数得到的候选状态,内部状态c_t 记录了到当前时刻为止的历史信息。

  2. 门控机制:LSTM网络中的三个“门”是一种“软”门,取值在(0, 1) 之间,表示以一定的比例运行信息通过。

  • 遗忘门ft 控制上一个时刻的内部状态ct−1 需要遗忘多少信息。\dot{i}_{t} =\sigma\left(W_{i} \boldsymbol{x}_{t}+U_{i} \boldsymbol{h}_{t-1}+\boldsymbol{b}_{i}\right)

  • 输入门it 控制当前时刻的候选状态\tilde{c}_t 有多少信息需要保存。\boldsymbol{f}_{t} =\sigma\left(W_{f} \boldsymbol{x}_{t}+U_{f} \boldsymbol{h}_{t-1}+\boldsymbol{b}_{f}\right)

  • 输出门ot 控制当前时刻的内部状态ct 有多少信息需要输出给外部状态ht。\boldsymbol{o}_{t} =\sigma\left(W_{o} \boldsymbol{x}_{t}+U_{o} \boldsymbol{h}_{t-1}+\boldsymbol{b}_{o}\right)

    其中σ(·) 为Logistic 函数,其输出区间为(0, 1)

    上述公式可简洁的描述为:

    \begin{aligned}\left[\begin{array}{c}{\tilde{c}_{t}} \\ {o_{t}} \\ {o_{t}} \\ {i_{t}} \\ {f_{t}}\end{array}\right] &=\left[\begin{array}{c}{\tanh } \\ {\sigma} \\ {\sigma}\end{array}\right]\left(W\left[\begin{array}{c}{x_{t}} \\ {h_{t-1}}\end{array}\right]+b\right) \\ c_{t} &=f_{t} \odot c_{t-1}+i_{t} \odot \tilde{c}_{t} \\ h_{t} &=o_{t} \odot tanh(c_t) \end{aligned}其中x_t \in \mathbb{R}^e 为当前时刻的输入,W \in \mathbb{R}^{4d\times (d+e)} 和b \in \mathbb{R}^{4d} 为网络参数。

记忆循环神经网络中的隐状态h存储了历史信息,可以看作是一种记忆(Memory)。在简单循环网络中,隐状态每个时刻都会被重写,因此可以看作是一种短期记忆(Short-Term Memory)。在神经网络中,长期记忆(Long-Term Memory)可以看作是网络参数,隐含了从训练数据中学到的经验,其更新周期要远远慢于短期记忆。而在LSTM 网络中,记忆单元c 可以在某个时刻捕捉到某个关键信息,并有能力将此关键信息保存一定的时间间隔。记忆单元c 中保存信息的生命周期要长于短期记忆h,但又远远短于长期记忆, 长短期记忆是指长的“短期记忆”。因此称为长短期记忆。

LSTM网络的各种变体

无遗忘门的LSTM网络:即最早提出的LSTM网络,其内部状态的更新为:c_{t} =c_{t-1}+i_{t} \odot \tilde{c}_{t}

没有遗忘门,记忆单元c 会不断增大。当输入序列的长度非常大时,记忆单元的容量会饱和,从而大大降低LSTM模型的性能。

peephole 连接:让三个门不但依赖于输入xt 和上一时刻的隐状态ht−1,也依赖于上一个时刻的记忆单元ct−1
\begin{aligned} \boldsymbol{i}_{t} &=\sigma\left(W_{i} \boldsymbol{x}_{t}+U_{i} \boldsymbol{h}_{t-1}+V_{i} \boldsymbol{c}_{t-1}+\boldsymbol{b}_{i}\right) \\ \boldsymbol{f}_{t} &=\sigma\left(W_{f} \boldsymbol{x}_{t}+U_{f} \boldsymbol{h}_{t-1}+V_{f} \boldsymbol{c}_{t-1}+\boldsymbol{b}_{f})\right.\\ \boldsymbol{o}_{t} &=\sigma\left(W_{o} \boldsymbol{x}_{t}+U_{o} \boldsymbol{h}_{t-1}+V_{o} \boldsymbol{c}_{t}+\boldsymbol{b}_{o}\right)\\&其中V_i,V_f 和V_o 为对角矩阵。 \end{aligned}
耦合输入门和遗忘门:LSTM网络中的输入门和遗忘门有些互补关系,因此同时用两个门比较冗余。为了减少LSTM网络的计算复杂度,将这两门合并为一个门。令f_t=1-i_t

这样,内部状态的更新方式为:c_t=(1-i_t)\odot c_{t-1}+i_t\odot \tilde c_t

门控循环单元网络(GRU)

GRU是是一种比LSTM网络更加简单的循环神经网络。

GRU网络的循环单元结构

GRU网络引入门控机制来控制信息更新的方式。和LSTM 不同,GRU不引入额外的记忆单元,GRU 网络也是在公式h_t=h_{t-1}+g(x_t,h_{t-1};\theta)的基础上引入一个更新门(Update Gate)来控制当前状态需要从历史状态中保留多少信息(不经过非线性变换),以及需要从候选状态中接受多少新信息。

h_t=z_t\odot h_{t-1}+(1-z_t)\odot g(x_t,h_{t-1};\theta)

其中z_t\in[0,1]为更新门,z_t=\sigma(W_zx_t+U_zh_{t-1}+b_z)

在LSTM网络中,输入门和遗忘门是互补关系,具有一定的冗余性。GRU网络直接使用一个门来控制输入和遗忘之间的平衡。当zt = 0 时,当前状态ht 和前一时刻的状态ht−1 之间为非线性函数关系;当zt = 1 时,ht 和ht−1 之间为线性函数关系。

在GRU网络中,函数g(xt,ht−1; θ) 的定义为:\tilde{\boldsymbol{h}}_{t}=\tanh \left(W_{h} \boldsymbol{x}_{t}+U_{h}\left(\boldsymbol{r}_{t} \odot \boldsymbol{h}_{t-1}\right)+\boldsymbol{b}_{h}\right),(这里使用tanh 激活函数是
由于其导数有比较大的值域,能够缓解梯度消失问题。)

其中\tilde h_t表示当前时刻的候选状态,r_t\in[0,1]为重置门,用来控制候选状态\tilde h_t的计算是否依赖上一时刻的状态h_{t-1}

r_t=\sigma(W_rx_t+U_rh_{t-1}+b_r)

当rt = 0 时,候选状态\tilde{\boldsymbol{h}}_{t}=\tanh \left(W_{h} \boldsymbol{x}_{t}+\boldsymbol{b}_{h}\right) 只和当前输入xt 相关,和历史状态无关。当rt = 1 时,候选状态\tilde{\boldsymbol{h}}_{t}=\tanh (W_{h} \boldsymbol{x}_{t}+U_{h}\boldsymbol{h}_{t-1}+\boldsymbol{b}_{h})和当前输入xt 以及历史状态ht−1 相关,和简单循环网络一致。

综上,GRU网络的状态更新方式为:h_t=z_t\odot h_{t-1}+(1-z_t)\odot \tilde h_t

可以看出,当zt = 0, r = 1 时,GRU网络退化为简单循环网络;若zt =0, r = 0 时,当前状态ht 只和当前输入xt相关,和历史状态ht-1 无关。当zt = 1时,当前状态ht = ht-1 等于上一时刻状态ht−1,和当前输入xt 无关。

深层循环神经网络

如果是长时间序列的神经网络,按时间片段展开,即h_0\rightarrow h_t的路径是很长的,可以说这是个很“深”的神经网络,但是不按时间片段展开,只看同一时刻网络输入到输出的路径,即x_t\rightarrow y_t,这又是一个很“浅”的网络。

深层循环神经网络是通过增加x_t\rightarrow h_t或者h_t\rightarrow y_t之间的路径,从而增强循环神经网络的能力。

堆叠循环神经网络(SRNN)

就是将多个循环网络堆叠起来。一个堆叠的简单循环网络(Stacked SRN)也称为循环多层感知器(RMLP)。

按时间展开的堆叠循环神经网络
双向循环神经网络

假设第1 层按时间顺序,第2 层按时间逆序,在时刻t 时的隐状态定义为h_t^{(1)}h_t^{(2)},则:
\begin{aligned} \boldsymbol{h}_{t}^{(1)} &=f\left(U^{(1)} \boldsymbol{h}_{t-1}^{(1)}+W^{(1)} \boldsymbol{x}_{t}+\boldsymbol{b}^{(1)}\right) \\ \boldsymbol{h}_{t}^{(2)} &=f\left(U^{(2)} \boldsymbol{h}_{t+1}^{(2)}+W^{(2)} \boldsymbol{x}_{t}+\boldsymbol{b}^{(2)}\right) \\ \boldsymbol{h}_{t} &=\boldsymbol{h}_{t}^{(1)} \oplus \boldsymbol{h}_{t}^{(2)} \\&其中\oplus为向量拼接操作\end{aligned}

扩展到图结构

因为同一层级的隐状态,在时间链中,可以构成一条链路,而链式结构是一种特殊的图结构,我们可以比较容易地将这种消息传递(Message Passing)的思想扩展到任意的图结构上。

递归神经网络(RecNN)

是循环神经网络在有向无循环图上的扩展。递归神经网络的一般结构为树状的层次结构。

递归神经网络

以图a中的结构为例,有三个隐藏层h1、h2 和h3,其中h1 由两个输入x1和x2 计算得到,h2 由另外两个输入层x3 和x4 计算得到,h3 由两个隐藏层h1 和h2 计算得到。

对于一个节点hi,它可以接受来自父节点集合πi 中所有节点的消息,并更新自己的状态:h_i=f(h_{\pi_i})

其中h_{\pi_i}表示集合\pi_i中所有节点状态的拼接,f(\cdot)是一个和节点位置无关的非线性函数,可以为一个单层的前馈神经网络。比如图a所示的递归神经网络具体可以写为:
\begin{array}{l}{h_{1}=\sigma\left(W\left[\begin{array}{l}{x_{1}} \\ {x_{2}}\end{array}\right]+b\right)} \\ {h_{2}=\sigma\left(W\left[\begin{array}{l}{x_{3}} \\ {x_{4}}\end{array}\right]+b\right)} \\ {h_{3}=\sigma\left(W\left[\begin{array}{l}{h_{1}} \\ {h_{2}}\end{array}\right]+b\right)}\end{array}
其中,\sigma(\cdot)表示非线性激活函数,W和b是可学习的参数。

同样,输出层y可以为一个分类器,比如:y=g\left(W^{'}\left[\begin{array}{l}{h_{1}} \\ {h_{2}}\end{array}\right]+b^{'}\right)

图网络

图网络(Graph Network,GN)是将消息传递的思想扩展到图结构数据上的神经网络。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容