【吴恩达机器学习】第六周—机器学习系统设计

31.jpg

1. 应用机器学习的建议

1.1 下一步做什么

仍然使用预测房价的学习例子,假如你已经完成了正则化线性回归,也就是最小化代价函数J的值,假如,在你得到你的学习参数以后,如果你要将你的假设函数放到一组新的房屋样本上进行测试,假如说你发现在预测房价时产生了巨大的误差,现在你的问题是要想改进这个算法,接下来应该怎么办?

获得更多的训练实例——通常是有效的, 但代价较大, 下面的方法也可能有效, 可考虑先采用下面的几种方法。
1.尝试减少特征的数量
2.尝试获得更多的特征
3.尝试增加多项式特征
4.尝试减少正则化程度λ
5.尝试增加正则化程度λ

总结一下,我们可以采取的手段主要在这些方面:数据集、特征、多项式特征、正则化项。我们不应该随机选择上面的某种方法来改进我们的算法,而是运用一些机器学习诊断法(Machine learning dignostic)来帮助我们知道上面哪些方法对我们的算法是有效的。
诊断法的意义:你通过执行这种测试,能够深入了解某种算法到底是否有用。这通常也能够告诉你,要想改进一种算法的效果,什么样的尝试,才是有意义的。

1.2 评估假设函数(Evaluating a Hypothesis)

我们不能仅仅通过模型训练时的损失来判断一个假设函数是好是坏,因为存在过拟合的可能,如图所示:
image.png

过拟合时,模型对训练数据能完美预测和拟合,但是对于新给定的数据则效果很差,怎么办?对于这个简单的例子,我们可以对假设函数ℎ(x)画图,观察图形趋势,但更一般地做法:将数据分为训练集和测试集,用测试集来评估假设函数的拟合程度和模型的效果。

为了检验算法是否过拟合,我们将数据分成训练集和测试集,通常用 70%的数据作为训练集,用剩下 30%的数据作为测试集。很重要的一点是训练集和测试集均要含有各种类型的数据, 通常我们要对数据进行“洗牌”, 然后再分成训练集和测试集。
image.png

测试集评估在通过训练集让我们的模型学习得出其参数后,对测试集运用该模型,我们有两种方式计算误差:
1.对于线性回归模型,我们利用测试集数据计算损失函数

2.对于逻辑回归模型,我们不仅可以利用测试集数据计算其损失函数,我们还可以计算其错误划分的损失,即误分类损失。
image.png

1.3 模型选择和交叉验证

1.3.1 交叉验证集的意义

假设我们要在 10 个不同次数的二项式模型之间进行选择:
1.h_\theta(x) = \theta_0 + \theta_1x
2.h_\theta(x) = \theta_0 + \theta_1x + \theta_2x^2
3.h_\theta(x) = \theta_0 + \theta_1x + \theta_2x^2 + \theta_3x^3
...
10.h_\theta(x) = \theta_0 + \theta_1x + ...+ \theta_{10}x^{10}

显然越高次数的多项式模型越能够适应我们的训练数据集,但是适应训练数据集并不代表着能推广至一般情况。具体来说,我们先用训练集训练得到这10个模型(假设函数)的参数矩阵\Theta^{(1)},\Theta^{(2)}...\Theta^{(10)}然后用测试集来评估和测试这些参数矩阵的对测试集样本的损失函数。

但,问题来了,即使我们用测试集取到了损失函数J(θ)最低的一个模型,譬如第10个,那么我们也不敢肯定,这个模型在新的数据上的泛化能力。因为,测试集在计算其损失函数J(θ)时,已经拟合了一个比较隐蔽的东西—即多项式的最高次幂d(dgree of polynomial)。式子1拟合了d = 1...式子10拟合了d = 10

怎么解决这个问题 ? 我们需要引入交叉验证集。譬如:使用 60%的数据作为训练集,使用 20%的数据作为交叉验证集,使用 20%的数据作为测试集。引入了交叉验证集后,这三组数据可以分别计算出训练损失、交叉验证损失、测试损失:
image.png

引入了交叉验证集后,我们的流程也发生了一点改变:
1.训练集训练模型得到参数矩阵\Theta^{(1)},\Theta^{(2)}...\Theta^{(10)}
2.用交叉验证集计算交叉验证集的损失J(θ)
3.挑选最小的模型来用测试集测试,评估其泛化能力,计算验证集的损失J(θ)

image.png

如上图,采用新方式后,我们用交叉验证集合测试得到损失最小的模型是式子4. 故我们决定采用4.来对其进行测试,用测试集的数据来计算其损失J_{test}(\theta^{(4)})

1.4 诊断和偏差、方差

当你运行一个学习算法时,如果这个算法的表现不理想,那么多半是出现两种情况:要么是偏差比较大,要么是方差比较大。换句话说,出现的情况要么是欠拟合,要么是过拟合问题。那么这两种情况,哪个和偏差有关,哪个和方差有关,或者是不是和两个都有关?搞清楚这一点非常重要,因为能判断出现的情况是这两种情况中的哪一种。
下面看一个例子:

image.png

图中左边的模型对数据拟合不够,导致高偏差;右边的对数据拟合过度,虽然偏差较低但对新数据的预测能力查,泛化能力不够,导致高方差。中间的模型是比较适中的。
P.S.这里偏差的概念比较好懂,误差即指数据集中数据和模型计算出的估计值之间的差值,方差即描述样本和平均值之间的偏离程度,所以看图理解也很直观。

损失和多项式维度d之间的关系

image.png

上图展示了模型训练集、交叉验证集/测试集跑出的损失和多项式维度d之间的关系,
粉线表明:在训练集中d越高,损失越小,拟合程度越高(但不代表模型足够好,反而其泛化能力差);
红线表明:在测试集/交叉验证集跑出来的模型上,损失有个先下降后上升的过程,在d = 2处取到最优。最开始其损失高,是因为模型欠拟合,高偏差,最后其损失高是因为模型过拟合,高方差。

1.4 正则化和偏差、方差

在我们在训练模型的过程中,一般会使用一些正则化方法来防止过拟合。但是我们可能会正则化的程度太高或太小了, 即我们在选择 λ 的值时也需要思考与刚才选择多项式模型次数类似的问题。
关于正则化的概念,请参考第三周的内容

image.png

我们选择一系列的想要测试的λ值,通常是 0-10 之间的呈现 2 倍关系的值(如:0,0.01,0.02,0.04,0.08,0.15,0.32,0.64,1.28,2.56,5.12,10共 12 个)。我们同样把数据分为训练集、交叉验证集和测试集。
image.png

然后,针对这12组模型,我们得到他们的参数矩阵θ,通过交叉验证集来计算交叉验证损失,取最小的模型5来做最后的测试,测试集的损失即为:J_{test}(\theta^{(5)})
对于同一个模型,正则化参数λ和损失的关系图如下:

image.png

可见,对于训练集,λ = 0时的损失是最小的,随着λ增大,整个损失越来越大;对于交叉验证集/测试集,损失随着λ 增加,先减小后增加

1.5 学习曲线

学习曲线Learning Curves是将训练集误差和交叉验证集误差作为训练集实例数量(m)的函数绘制的图表。可以用其判断模型是否处于高方差、高偏差状态,从而改进模型。

1.5.1 正常学习曲线

这里假设m = 100,则学习曲线是从m = 1时的模型损失坐标开始绘制到m = 100时的模型损失曲线。我们看一下训练集和交叉验证集的损失函数,此时暂时不考虑正则化项:

8.png
8.png
然后,假设我们的假设函数如下:

下面我们开始绘制训练集的学习曲线:
9.png
9.png
可以看出,m = 1和2时,方程能完美拟合数据,即损失为0,m = 3以后随着数据量增大,出现不拟合数据的情况增大,即平均损失增加。(这里需要说明,即使假设函数不是二次项的,而是一次项的,对于m = 1,m = 2时一样可以做到完美拟合0误差)汇总起来,学习曲线如下:
10.png
10.png

蓝色部分是训练集的学习曲线,粉色部分是交叉验证集的学习曲线。m很小时,往往假设函数能较好地模拟,
使得损失很低,随着m增加,损失会逐渐上升直到一定范围。交叉验证集m很小时,模型往往泛化能力较差,故对于新的数据,不能很好拟合,损失较大,随着m上升,模型趋于稳定,此时交叉验证集的数据往往也能较好预测了,损失降低,最终趋于收敛(最终往往大于训练集的损失)

1.5.2 高偏差学习曲线

上面的例子,是正常情况下的学习曲线,那么如果假设函数不当,高方差或高偏差下的拟合曲线是怎样的呢?
image.png

高偏差bias时,即模型欠拟合,对数据不能较好预测,故在一定范围内m越大误差越大,且最后收敛到一个较高的水平。
启发:增大训练集m的尺寸对于降低模型在交叉验证集上的损失没有任何帮助。

1.5.3 高方差学习曲线

image.png

可以看到,交叉验证集和训练集的损失变化较为平缓,且中间有较大的距离,这意味着增加m对于模型在交叉验证集上降低损失有较好效果。
启发:高方差时,即过拟合,增加m数量会减轻模型过拟合程度,从而使预测未知数据能力变好,反映在交叉验证集上的表现,即损失降低。

1.6 下一步做什么?

我们已经介绍了怎样评价一个学习算法,我们讨论了模型选择问题,偏差和方差的问题。那么这些诊断法则怎样帮助我们判断,哪些方法可能有助于改进学习算法的效果,而哪些可能是徒劳的呢?
让我们再次回到最开始的例子,在那里寻找答案,这就是我们之前的例子。回顾 1.1中提出的六种可选的下一步,让我们来看一看我们在什么情况下应该怎样选择:
1. 获得更多的训练实例——解决高方差
2. 尝试减少特征的数量——解决高方差
3. 尝试获得更多的特征——解决高偏差
4. 尝试增加多项式特征——解决高偏差
5.尝试减少正则化程度 λ——解决高偏差
6.尝试增加正则化程度 λ——解决高方差

神经网络的方差和偏差:
使用较小的神经网络,类似于参数较少的情况,容易导致高偏差和欠拟合,但计算代价较小使用较大的神经网络,类似于参数较多的情况,容易导致高方差和过拟合,虽然计算代价比较大,但是可以通过正则化手段来调整而更加适应数据。通常选择较大的神经网络并采用正则化处理会比采用较小的神经网络效果要好。

image.png

对于神经网络中的隐藏层的层数的选择,通常从一层开始逐渐增加层数,为了更好地作选择,可以把数据分为训练集、交叉验证集和测试集,针对不同隐藏层层数的神经网络训练神经网络, 然后选择交叉验证集代价最小的神经网络。

2. 机器学习系统的设计

2.1 首先做什么

系统设计是个需要实际动手和采坑累计经验的活,好的设计能节约时间,优化模型和算法。本节内容建议阅读视频,因为没有很多公式和理论,有大量的文字和需要理解的东西。
本周以一个垃圾邮件分类器算法为例进行讨论。
为了解决这样一个问题,我们首先要做的决定是如何选择并表达特征向量x,我们可以选择一个由 100 个最常出现在垃圾邮件中的词所构成的列表,根据这些词是否有在邮件中出现,来获得我们的特征向量(出现为 1,不出现为 0),尺寸为 100×1。
为了构建这个分类器算法,我们可以做很多事,例如:
1.收集更多的数据,让我们有更多的垃圾邮件和非垃圾邮件的样本

  1. 基于邮件的路由信息开发一系列复杂的特征
  2. 基于邮件的正文信息开发一系列复杂的特征,包括考虑截词的处理
  3. 为探测刻意的拼写错误(把 watch 写成 w4tch)开发复杂的算法
    在上面这些选项中,非常难决定应该在哪一项上花费时间和精力,作出明智的选择,比随着感觉走要更好。 当我们使用机器学习时, 总是可以“头脑风暴”一下, 想出一堆方法来试试。实际上,当你需要通过头脑风暴来想出不同方法来尝试去提高精度的时候,你可能已经超越了很多人了。

2.2 误差分析Error Analysis

在本次课程中,我们将会讲到误差分析(Error Analysis)的概念。这会帮助你更系统地做出决定。如果你准备研究机器学习的东西,或者构造机器学习应用程序,最好的实践方法不是建立一个非常复杂的系统,拥有多么复杂的变量;而是构建一个简单的算法,这样你可以很快地实现它。

每当我研究机器学习的问题时,我最多只会花一天的时间,就是字面意义上的 24 小时,来试图很快的把结果搞出来,即便效果不好。坦白的说,就是根本没有用复杂的系统,但是只是很快的得到的结果。即便运行得不完美,但是也把它运行一遍,最后通过交叉验证来检验数据。一旦做完,你可以画出学习曲线,通过画出学习曲线,以及检验误差,来找出你的算法是否有高偏差和高方差的问题,或者别的问题。在这样分析之后,再来决定用更多的数据训练,或者加入更多的特征变量是否有用。这么做的原因是:这在你刚接触机器学习问题时是一个很好的方法,你并不能提前知道你是否需要复杂的特征变量,或者你是否需要更多的数据,还是别的什么。提前知道你应该做什么,是非常难的,因为你缺少证据,缺少学习曲线。因此,你很难知道你应该把时间花在什么地方来提高算法的表现。但是当你实践一个非常简单即便不完美的方法时,你可以通过画出学习曲线来做出进一步的选择。你可以用这种方式来避免一种电脑编程里的过早优化问题,这种理念是:我们必须用证据来领导我们的决策,怎样分配自己的时间来优化算法,而不是仅仅凭直觉,凭直觉得出的东西一般总是错误的。除了画出学习曲线之外,一件非常有用的事是误差分析,我的意思是说:当我们在构造垃圾邮件分类器时,我会看一看我的交叉验证数据集,然后亲自看一看哪些邮件被算法错误地分类。因此,通过这些被算法错误分类的垃圾邮件与非垃圾邮件,你可以发现某些系统性的规律:什么类型的邮件总是被错误分类。经常地这样做之后,这个过程能启发你构造新的特征变量,或者告诉你:现在这个系统的短处,然后启发你如何去提高它。

构建一个学习算法的推荐方法为:

  1. 从一个简单的能快速实现的算法开始,实现该算法并用交叉验证集数据测试这个算法

  2. 绘制学习曲线,决定是增加更多数据,或者添加更多特征,还是其他选择

  3. 进行误差分析:人工检查交叉验证集中我们算法中产生预测误差的实例,看看这些实例是否有某种系统化的趋势
    以我们的垃圾邮件过滤器为例
    误差分析要做的既是检验交叉验证集中我们的算法产生错误预测的所有邮件,看:是否能将这些邮件按照类分组。例如医药品垃圾邮件,仿冒品垃圾邮件或者密码窃取邮件等。然后看分类器对哪一组邮件的预测误差最大,并着手优化。

    思考怎样能改进分类器。例如,发现是否缺少某些特征,记下这些特征出现的次数。例如记录下错误拼写出现了多少次,异常的邮件路由情况出现了多少次等等,然后从出现次数最多的情况开始着手优化。误差分析并不总能帮助我们判断应该采取怎样的行动。有时我们需要尝试不同的模型,然后进行比较,在模型比较时,用数值来判断哪一个模型更好更有效,通常我们是看交叉验证集的误差。

    在我们的垃圾邮件分类器例子中,对于 “我们是否应该将discount/discounts/discounted/discounting 处理成同一个词? ”如果这样做可以改善我们算法,我们会采用一些截词软件。误差分析不能帮助我们做出这类判断,我们只能尝试采用和不采用截词软件这两种不同方案,然后根据数值检验的结果来判断哪一种更好。

    因此,当你在构造学习算法的时候,你总是会去尝试很多新的想法,实现出很多版本的学习算法,如果每一次你实践新想法的时候,你都要手动地检测这些例子,去看看是表现差还是表现好,那么这很难让你做出决定。到底是否使用词干提取,是否区分大小写。但是通过一个量化的数值评估,你可以看看这个数字,误差是变大还是变小了。你可以通过它更快地实践你的新想法,它基本上非常直观地告诉你:你的想法是提高了算法表现,还是让它变得更坏,这会大大提高你实践算法时的速度。所以我强烈推荐在交叉验证集上来实施误差分析,而不是在测试集上。但是,还是有一些人会在测试集上来做误差分析。即使这从数学上讲是不合适的。所以我还是推荐你在交叉验证向量上来做误差分析。

    总结一下,当你在研究一个新的机器学习问题时,我总是推荐你实现一个较为简单快速、即便不是那么完美的算法。我几乎从未见过人们这样做。大家经常干的事情是:花费大量的时间在构造算法上,构造他们以为的简单的方法。因此,不要担心你的算法太简单,或者太不完美,而是尽可能快地实现你的算法。当你有了初始的实现之后,它会变成一个非常有力的工具,来帮助你决定下一步的做法。因为我们可以先看看算法造成的错误,通过误差分析,来看看他犯了什么错,然后来决定优化的方式。另一件事是:假设你有了一个快速而不完美的算法实现,又有一个数值的评估数据,这会帮助你尝试新的想法,快速地发现你尝试的这些想法是否能够提高算法的表现,从而你会更快地做出决定,在算法中放弃什么,吸收什么误差分析可以帮助我们系统化地选择该做什么。

2.3 不对称性分类的误差

2.3.1 偏斜类skewed classes

通常情况下,我们在误差分析中,设定某个实数来评估学习算法,并衡量它的表现。但有时仅仅依靠数字并不能解决问题,尤其是遇到偏斜类(skewed classes)的情况看个例子:
还是以预测肿瘤良性/恶心为例,实际样本中,恶性肿瘤占比为0.5%,良性为99.5%,我们要用一个算法来预测肿瘤的良性/恶性情况。
此时有两个算法模型:A.神经网络模型 B.一个错误的模型
在B模型中,每次预测都判断为良性,则对于真实样本来看,其误差在0.5%;A模型经过正常训练的神经网络模型,误差在1%,那么我们就不能仅仅依靠数字来比较算法模型的准确性。因为明显地B是一个错误的模型。

2.3.2 查准率查全率

为了解决上面这个例子,我们需要引入查准率Precision和查全率Recall
引入查准率查全率后,我们将算法的预测情况归为以下四类:
1. 正确肯定(True Positive,TP): 预测为真,实际为真
2. 正确否定(True Negative,TN):预测为假,实际为真
3. 错误肯定(False Positive,FP): 预测为真,实际为假
4. 错误否定(False Negative,FN):预测为假,实际为假
Precision = \frac{TP}{TP+FP} Recall = \frac{TP}{TP+FN}
查准率,即查出来的TP类是准确的和所有预测的类数量的比例(此处以TP,即预测为真的类计算)
查全率,即查出来的TP类占所有实际类的比例

在本例中,查准率的含义:预测出的,且正确判断其为恶性肿瘤患者数量/预测总数;查全率的含义:查出的恶性肿瘤患者数量 / 实际恶性肿瘤患者数量。这样,我们即可通过查准率和查全率来评估模型的准确情况了,很明显的,我们希望查准率和查全率都是越大越好。当然极限值是查准率 = 查全率 = 1,即代表模型能做到0误差预测。

2.4 查准率VS查全率

理想状态下,查准率和查全率当然都是越高越好,最好都 = 1,但是实际上不可能达到。这时候我们就需要考虑在实际的算法模型中,究竟对于查准率和查全率哪个更看重,分别的目标值是多少。
譬如,一个手机生产商的产线判断屏幕缺陷的算法模型,我希望查全率尽可能高,查全率Recall = 0.999,即我希望在产线上经过总共有1000个缺陷屏幕,那么我只允许放掉1块,将其判断为OK,其余999块缺陷屏幕,则算法必须识别出来。而对于查准率,可能生产商的要求就没有那么严格,查准率可以设置为0.6...
在肿瘤预测的例子里,如果我们希望只在非常确信的情况下预测为真(肿瘤为恶性),即我们希望更高的查
准率,我们可以使用比 0.5 更大的阀值,如 0.7, 0.9。这样做我们会减少错误预测病人为恶性肿瘤的情况,同时却会增加未能成功预测肿瘤为恶性的情况。如果我们希望提高查全率,尽可能地让所有有可能是恶性肿瘤的病人都得到进一步地检查、诊断,我们可以使用比 0.5 更小的阀值,如 0.3。
那么我们怎么衡量之间的关系?

14.png
14.png
假设我有三个算法模型,对应的查准率查全率如图所示,则究竟哪个是我想要的?这里通常有两种方式:
1.求均值 Average = \frac{P+R}{2}

2.求F1值 F_1 Score = 2\frac{P*R}{P+R}
由于第一种方式通常比较粗糙,我们选用第二种方式,第二种方式中如果P或R某一项较大,则F值较小,P和R较为接近和平均,则F值较大。当然我们也可以根据业务需求自己拟定合适的P或R值,或者设定一下系数如P0.2 + R0.8

2.5 机器学习中的数据

虽然算法很重要,但是大量数据面前,可能不同算法模型最后得到的模型都会达到较好的效果。
很多很多年前,我认识的两位研究人员 Michele Banko 和 Eric Brill 进行了一项有趣的研究,他们尝试通过机器学习算法来区分常见的易混淆的单词,他们尝试了许多种不同的算法,并发现数据量非常大时,这些不同类型的算法效果都很好。
比如, 在这样的句子中: 早餐我吃了__个鸡蛋(to,two,too), 在这个例子中, “早餐我吃了 2 个鸡蛋”, 这是一个易混淆的单词的例子。 于是他们把诸如这样的机器学习问题, 当做一类监督学习问题,并尝试将其分类,什么样的词,在一个英文句子特定的位置,才是合适的。他们用了几种不同的学习算法,这些算法都是在他们 2001 年进行研究的时候,都已经被公认是比较领先的。因此他们使用了一个方差,用于逻辑回归上的一个方差,被称作"感知器"(perceptron)。他们也采取了一些过去常用,但是现在比较少用的算法,比如 Winnow算法,很类似于回归问题,在一些方面又有所不同,过去用得比较多,但现在用得不太多。还有一种基于内存的学习算法,现在也用得比较少了,但是我稍后会讨论一点,而且他们用了一个朴素算法。这些具体算法的细节不那么重要, 我们下面希望探讨,什么时候我们会希望获得更多数据,而非修改算法。他们所做的就是改变了训练数据集的大小,并尝试将这些

学习算法用于不同大小的训练数据集中,这就是他们得到的结果:
15.png
15.png
这些趋势非常明显, 首先大部分算法,都具有相似的性能,其次,随着训练数据集的增大,在横轴上代表以百万为单位的训练集大小,从 0.1 个百万到 1000 百万,也就是到了 10亿规模的训练集的样本,这些算法的性能也都对应地增强了。
事实上,如果你选择任意一个算法,可能是选择了一个"劣等的"算法,如果你给这个劣等算法更多的数据,那么从这些例子中看起来的话,它看上去很有可能会其他算法更好,甚至会比"优等算法"更好。由于这项原始的研究非常具有影响力,因此已经有一系列许多不同的研究显示了类似的结果。这些结果表明,许多不同的学习算法有时倾向于表现出非常相似的表现,这还取决于一些细节,但是真正能提高性能的,是你能够给一个算法大量的训练数据。像这样的结果,引起了一种在机器学习中的普遍共识: "取得成功的人不是拥有最好算法的人,而是拥有最多数据的人"。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容