机器学习-吴恩达

前言

  • 本文内容来自b站吴恩达机器学习视频的总结,按知识点进行总结,并标注出知识点在哪个视频
  • 目的是进行复习使用,争取达到不看视频就能回想起视频里的内容
  • 视频链接:吴恩达机器学习


监督学习与无监督学习(P3-P4)

  • 监督学习

    • “right answer” given, 即在房价数据集中的每个样本,都给出正确的房价。也被称为回归问题(regression problem),房价虽然是一个离散值,但是可以预测其连续的属性。简而言之就是我们知道某组离散的数据对(x,y),然后去预测这个函数的图像,从而预测其他x所对应的y。
      监督学习
  • 无监督学习

    • 我们只被告知这里有一组数据集,尝试在其中找到某种结构。也叫做分类问题。


      无监督学习


代价函数(P5-P8)

  • 模型描述


    监督学习模型
  • 代价函数
    • 首先是H函数,也就是预测(x,y)数据对的函数;
    • 其中\theta_0\theta_1是参数,我们要做的是找到合适的参数\theta_0\theta_1,从而找到合适的H函数;
    • 需要对参数构造一个函数,这个关于参数的函数就叫做代价函数;
    • 当代价函数取最小值时,这时的参数往往是所要求的参数值。
      简而言之,代价函数是辅助我们找到最合适的参数的一个函数
代价函数


梯度下降(P9-P11)

  • 下图已经很好的解释了什么是梯度下降


    梯度下降
  • 而梯度下降是什么原理?(首先从单个参数的情况解释)
    • 如下图,\alpha是学习率,即下降的速率。我们的目的是下降到曲线的最低点,这时\alpha后面的偏导项为0(理想情况下),那么\theta_1就不会更新,也就得到了我们需要的参数(理想情况下)。
单参数的原理
  • 当有两个参数时,同时更新参数\theta_0\theta_1,那么和一个参数的情况类似(之前代价函数是一个二维曲线,更新到到达最低点为止),这里的是一个三维曲面,目的是到达曲面最低点,这是的偏导项都为0,两个参数也不再更新。
    注意一点,梯度下降算法的参数是同时更新的
    两个参数梯度下降


多元梯度下降(P18-P19)

  • 下图是多元特征的表示方法:其中n是指特征的个数4;x^{(i)}中的 i 是指第i行,是包含四个特征值的向量;j 则是第 j 列,x^{(i)}_j 指第i行第j列的特征。
    表示方法
  • 当有多个特征时,依次对每个特征所对应的参数进行更新即可,之前是同时更新。


    多元梯度下降


特征缩放(P20)

  • 一般是将特征值缩放到 -1至1之间(只要不是与这个区间相差很大都能接收),视觉上的作用是让轮廓图更圆,实际的作用是加快收敛速度
Mean normalization(均值归一化)
  • 实际上是一种更标准的特征缩放,具体公式如下:
    x_{i}=\frac{x_{i}-\mu_{i}}{s_{i}}
    其中x_{i}是第i个特征值,\mu_{i}是第i个特征值的平均值,s_{i}是特征值取值范围的长度,例如对房价进行预测,其中包含特征值x_{1}是房子的大小,范围为\left [ 60, 140\right ]m^{2}。那么\mu_{1}=(60+140)/2=100s_{1}=140-60=80,所以x_{1}的取值范围变为了\left [ -0.5, 0.5\right ],即完成了特征缩放。


学习速率(P22)

  • 梯度下降算法中趋势都是向下的,当学习速率\alpha很小时,则收敛的速率比较慢;当很大时会出现下面的情况:
    当学习速率太大时出现异常

    此时只需适当调小\alpha即可。


特征多项式回归(P22)

特征多项式回归公式如下:
h_{\theta} =\theta_{0}+\theta_{1}x_{1}+\theta_{2}x_{2}^{2}+\theta_{3}x_{3}^{3}+...+\theta_{n}x_{n}^{n}即这里的参数不再是一阶的,含有高次项。



正规方程(P23)

  • 标准方程法是一种一次就求得所有参数的方法,例如只含单个参数\theta_{1}时,代价函数J(\theta_{1}) =a\theta_{1}^{2}+b\theta_{1}+c所以很容易由一阶导为0得到\theta=-b/2a时,代价函数取最小值
    同理,对于含有多个参数的回归方程,分别求出所有参数的偏导,并令所有偏导为0,得到\theta=(X^{T}X)^{-1}X^{T}y其中X是一个包含所有特征值的矩阵。且第一列赋值为1,因为参数里有个常数项\theta_{0};y矩阵为实际结果组成的列向量。
  • 梯度下降法与标准方程法的比较

梯度下降法:适合特征值很多的情况;需要选择\alpha的值,有时拟合过程会比较慢
标准方程法:操作很方便;但是当特征值很多时,矩阵转置的算法复杂度很高,约为O(n^{3})

  • 所以当参数较少时选用标准方程法,大概一万参数以上可以考虑使用梯度下降算法。


正规方程不可逆(P24)

  • X^{T}X矩阵不可逆的问题
  • 通常不可逆有两种原因

redundant features : 存在线性相关的特征值
Too many features : m\leqslant n,m是训练数据的组数,n是特征值的个数



Octive基本操作(P26)

下载Octave,以下是Octive的一些基本操作

>>1==2
ans = 0
>>1~=2    %不等于是~=,而不是!=
ans = 1
>>1&&0    %与
ans = 0
>>1||0    %或
ans = 1
>>xor(1,0)    %异或
ans = 1
>>PS1('>>');    %命令提示行会变简洁
>>a=3     %赋值并打印
a =  3
>>a=3;    %加分号则不会打印
>>b='hi';
>>b     %打印b
b = hi
>>a=pi;
>>disp(a);     %另一种打印方法
 3.1416
>>disp(a)     %发现这里加不加分号都一样
 3.1416
>>disp(sprintf('2 decimals: %0.2f', a))     %打印,有点像c语言,但是用的是单引号
2 decimals: 3.14
>>format long     %打印长度为long
>>a
a =  3.141592653589793
>>format short    %打印长度为short
>>a
a =  3.1416
>>A=[1 2;3 4;5 6]     %输出一个3*2的矩阵
A =
   1   2
   3   4
   5   6
>>A=[1 2;     %另外一种输入方法
3 4;
5 6]
A =
   1   2
   3   4
   5   6
>>A=1:0.2:2    %以0.2的步长从1到2打印矩阵,是一个行矩阵
A =
    1.0000    1.2000    1.4000    1.6000    1.8000    2.0000
>>ones(2,3)     %打印一个2*3的矩阵,其中所有值都是1
ans =
   1   1   1
   1   1   1
>>A=2*ones(2,3)     %将上面的矩阵所有值乘2,赋给A
A =
   2   2   2
   2   2   2
>>A=rand(2,3)     %随机打印0-1之间的数
A =
   0.393924   0.046474   0.309188
   0.109174   0.188602   0.628519
>>A=randn(2,3)    %随机打印标准正态分布产生的数,均值为0,方差为1
A =
  -0.23444  -0.35377   0.36930
  -0.78721   0.57167   1.22516
>>hist(A)    %打印直方图
>>A=-6+sqrt(pi)*(randn(1,10000)); 
>>hist(A,100)     %将A按照100条的直方图打印出来
>> A=eye(3)      %eye命令打印单位矩阵
A =
Diagonal Matrix
   1   0   0
   0   1   0
   0   0   1
>> size(A)     %返回A的大小
ans =
   3   3


Octive移动数据(P27)

  • 还是一些Octive的操作命令,这里是移动数据的命令
>> load featuresX.dat     %将数据导入Octive
>> who      %显示当前有哪些变量
Variables in the current scope:
a
>> whos             %显示当前变量的详细信息
Variables in the current scope:
   Attr Name        Size                     Bytes  Class
   ==== ====        ====                     =====  =====
        a           1x1                          8  double
Total is 1 element using 8 bytes
>> clear  a     %删除a变量
>> clear         %删除所有变量
>> A= 1:0.1:2;
>> save hello.mat A;       %存入磁盘,clear无法删除该变量
>> clear
>> whos      %clear无法删除磁盘中的变量
Variables in the current scope:
   Attr Name        Size                     Bytes  Class
   ==== ====        ====                     =====  =====
        A           1x11                        24  double
Total is 11 elements using 24 bytes
>> A=[1 2;3 4;5 6]
A =
   1   2
   3   4
   5   6
>> A(3,2)      %输出矩阵中的当个值
ans =  6
>> A(2,:)       %:表示该行或者该列所有数据
ans =
   3   4
>> A([1 3],:)     %输出第1,3行
ans =
   1   2
   5   6
>> A(:,2)=[10;11;12]      %可以用:直接对第二列直接赋值
A =
    1   10
    3   11
    5   12
>> A=[A,[11;12;13]]       %在A的右边新加一列
A =
    1   10   11
    3   11   12
    5   12   13
>> A(:)     %按列输出A
ans =
    1
    3
    5
   10
   11
   12
   11
   12
   13
>> A=[1 2;3 4;5 6];
>> B=[11 12;13 14;15 16];
>> C=[A B]              %将AB合并
C =
    1    2   11   12
    3    4   13   14
    5    6   15   16
>> C=[A;B]             %将AB合并,加分号为列合并
C =
    1    2
    3    4
    5    6
   11   12
   13   14
   15   16


计算数据(P28)

>> A.*B     %点表示对每个元素进行操作
ans =
   11   24
   39   56
   75   96
>> A'         %单引号表示转置
ans =
   1   3   5
   2   4   6
>> A=[1 2;3 4;5 6];
>> [r,c]=find(A<3)        %找出A矩阵中小于3的数
r =                       %返回行
   1
   1
c =                       %返回列
   1
   2
%find有其他更多的功能,可以通过help find来查询
>> a=[1:0.2:2];
>> sum(a)          %求和,若是二维矩阵,则返回每一列的和
ans =  9
>> prod(a)         %求乘积,若是二维矩阵,则返回每一列的乘积
ans =  9.6768
>> floor(a)        %向下四舍五入
ans =
   1   1   1   1   1   2
>> ceil(a)        %向上四舍五入
ans =
   1   2   2   2   2   2
>> M=magic(3)          %magic生成一个数独矩阵
M =
   8   1   6
   3   5   7
   4   9   2
>> max(M,[],1)          %这里的1表示维度,1是列
ans =
   8   9   7
>> max(M,[],2)           %同理,2也是代表维度,表示行
ans =
   8
   7
   9
>> max(M,[],3)          %3以及3以上则会输出整个矩阵
ans =
   8   1   6
   3   5   7
   4   9   2
>> max(max(M))      %输出二维矩阵中的最大的一个数
ans =  9
>> max(M(:));          %也是输出最大的一个数,这里是先变为列向量再找最大值
>> flipud(eye(3));     %flipud为矩阵的转置命令
>> pinv(A);          %求伪逆矩阵


数据绘制(P29)

>> t=[0:0.01:0.98];
>> y1=sin(2*pi*4*t);            
>> plot(t,y1);              %将y1函数绘图
>> y2=cos(2*pi*4*t);
>> plot(t,y2);
%将y2函数绘图,但y1函数图像会消失
>> plot(t,y1);
>> hold on;               %hold on命令会让y1图像不会消失
>> plot(t,y2,'r');          %然后在y1的基础上再画y2的图像,且这里用红色绘制y2
>> xlabel('time');        %标明横坐标为time
>> ylabel('value');      %标明纵坐标为value
>> legend('sin','cos');      %标明那个是sin曲线,哪个是cos曲线
>> title('my plot');         %取标题名字
>> cd 'C:\Users\Administrator\Desktop', print -dpng 'my plot.png'
%将绘制的图像保存至桌面,这里的路径可以改变
>> cd F:\Octaveprint         %也可以在F盘下创建一个Octaveprint文件夹,先用cd切换到该文件夹
>> print -dpng 'my plot.png'      %然后使用打印命令
>> figure(1); plot(t,y1);       %单独绘制图一
>> figure(2); plot(t,y2);       %单独绘制图二,这时会同时出现两个图
%不会像之前一样绘制图2时图1消失
>> subplot(1,2,1);        %分为一行两列来绘图,先绘制第一列
>> plot(t,y1);                %第一列绘制图1
>> subplot(1,2,2);        %第二列绘制图2
>> plot(t,y2);
>> axis([0.5 1 -1 1])      %改变坐标刻度,横轴改为[0.5,1],纵轴改为[-1,1]
>> A=magic(5);
>> imagesc(A)              %将矩阵可视化
>> imagesc(A),colorbar,colormap gray
>> close      %关闭绘图工具


控制语句(P30)

>> V=zeros(5,1)
V =
   0
   0
   0
   0
   0
>> for i=1:5,        %for循环语句,从1到5
      V(i)=2^i;
   end
>> V
V =
      2
      4
      8
     16
     32
>> i=1;
>> while i<=3,       %while循环
     V(i)=100;
     i=i+1;
   end;
>> V
V =
    100
    100
    100
    16
    32
%在F盘的function文件夹下创建一个函数
%function y =squareThisNumber(x);
%y=x^2;
>> cd F:\octave\function     %必须先切换到该文件夹下,才能调用该函数
>> squareThisNumber(5)    %调用该函数,可以求出函数值
ans =  25
%也可以添加默认路径,也就是配置环境变量,以后不用切换到指定的文件夹下也可以操作
>> addpath('F:\octave\function');
%再创建一个函数,注意Octive可以一个变量输出多个函数值
%此外可以用Windows自带的写字板创建函数,定义好之后保存到function文件夹下,注意加上后缀名 .m 
>> [y1,y2]=squareAndCubeThisNumber(5);     
>> y1
y1 =  25
>> y2
y2 =  125
%下面定义一个代价函数
%function J = costFunctionJ(X,y,theta);
%m=size(X,1);
%predictions=X*theta;
%sqrErrors=(prediction-y).^2;
%J=1/(2*m)*sum(sqrErrors);
>> X=[1 1;1 2;1 3];            %特征值矩阵
>> y=[1;2;3];          %实际取值
>> theta=[0;1];        %参数theta的取值
>>  j=costFunctionJ(X,y,theta)       %代价函数的值
j = 0
>> theta=[1;1];         %调整参数theta
>> j=costFunctionJ(X,y,theta)       
j =  0.50000              %代价函数值发生改变


向量化(P31)

  • 因为Octave含有线性代数的函数库,且实现了高度的优化,所以将一组值转化成向量,会使用更少的代码实现更快的计算速度


假设陈述(P33)

  • 在分类问题中用什么函数来表达假设?
  • 二分类中希望最终得到一个0,1值的结果,所以就需要一个这样的函数来表示
  • 线性回归中的假设函数形式是h_{\theta}(x)=\theta^{T}x,但是这种假设函数是线性的,当有一个值很大时就会很影响分类:
    线性的假设函数

    上图的粉红色线为较好的分类;当出现一个很大的值时,就会出现蓝色线的情况,出现较差的分类
  • 所以引入S型函数,进行更好的分类(也叫Sigmoid function/logistic function),S型函数的表达式为g(z)=\frac{1}{1+e^{-z}},然后h_{\theta}(x)=g(\theta^{T}x)。所以最终的假设函数是h_{\theta}(x)=\frac{1}{1+e^{-\theta^{T}x}}
    其图像如下:
    二分类最终的假设函数:S型函数

    这里会给出一个概率,假设h_{\theta}(x)=0.7,那么患病的概率为0.7,给出的y=1时的概率
    引入S函数的目的是为了二分类,因为S函数的特性:输入可以取所有值,输出在0-1之间


决策边界(P34)

  • 决策边界其实就是分类的那条线,可以是直线,圆,椭圆,不规则的曲线等等。影响决策边界的是参数,可以进行调参来得到更好的分类效果
  • 参数是怎么影响到决策边界的?
    可以从S型函数看出,当\theta^{T}x>0时,g(\theta^{T}x)>0.5;此时可以认为预测结果y=1,反之为0。
    线性的决策边界

    如上图,可以看到x_{1}+x_{2}=3时的决策边界可以有效的进行分类,那么就要使\theta_{0}+\theta_{1}x_{1}+\theta_{2}x_{2}>0,才能得到分类结果y=1,所以此时取参数\theta_{0}=-3,\theta_{1}=1,\theta_{2}=1,这样能得到如图所示的分类
  • 总之,可以通过调节参数\theta^{T},得到更好的边界决策


代价函数(P35)

  • 这一节的主要是讲如何求参数\theta,之前是用梯度下降算法求解,如下:
    J(\theta)=\frac{1}{m}\sum_{i=1}^{m}\frac{1}{2}(h_{\theta}(x^{i})-y^{i})^{2}但是会出现一个问题,因为h_{\theta}(x)是非线性的,所以求得的J(\theta)是一个非凸函数(non-convex),也就是说梯度下降无法保证能到达最低点,所以这种方法就存在一些问题。
    Cost(h_{\theta}(x),y)是指1/m之后的部分,所以需要一个更好的代价函数来替代这一部分,如下:
    Cost(h_{\theta}(x),y)=\left\{\begin{matrix} -log(h_{\theta}(x))\; \; \; \; \; \; \; \; \; \; if \; \; \; y=1 \\ -log(1-h_{\theta}(x)) \; \; \; \; \; \; if \; \; \; y=0 \end{matrix}\right.
    非凸函数与凸函数


简化代价函数和梯度下降(P36)

  • 下面是之前的逻辑回归的代价函数
逻辑回归的代价函数
  • 现在对其进行简化,其实就是加上系数 y 和 y-1,将 y=0 和 y=1 两类情况合并
  • 注意此时用梯度下降方法求参数时,与线性回归的公式相同,但是此处的h_{\theta}(x^{i})是不同的,线性回归中是h_{\theta}(x)=\theta^{T}x,逻辑回归中是h_{\theta}(x)=\frac{1}{1+e^{-\theta^{T}x}},所以对\theta求导之后是不同的结果


多分类(P38)

  • 这里是用二分类的方法解决多分类问题,比如要分三类,那么就设置三个不同的二分类器。实际进行分类时,就将x代入不同的H函数,选择可信度最高的分类器。


    多分类


过拟合(P39)

  • 过拟合就是训练的时候表现很好,但是缺乏泛化能力,预测阶段表现很差。
  • 欠拟合就是训练的模型没训练好。
  • 理想情况是训练数据和预测数据都能很好的和训练出的模型相拟合。
过拟合与欠拟合


正则化(P40-P42)

  • 正则化的目的是防止过拟合的出现

  • 在原有的代价函数后加上调节项,如下图:


    正则化
  • 其中\lambda是起调节作用的正则化参数,参数取平方是为了扩大参数改变后的影响,使结果更平滑

  • 注意正则项中参数是从\theta_{1}开始的



神经网络(P44-P46)

  • 下面是一个简单的神经网络,包含输入层,隐藏层,输出层;其中x_0是偏置单元,值为1;然后每条传输路径是一个参数,在神经网络中也叫权重。

    神经网络

  • a_i^{(j)}的上标 j 表示层数 ,下标表示每一层的第几个单元。下面是具体的计算。

神经网络


多元分类(P49)

  • 多元分类的神经网络有多个输出,可以看做一个向量,具体看那一行的值接近1,那么就是对应的分类结果。


    多元分类


神经网络的代价函数(P50)

神经网络的代价函数


反向传播算法(P51-52)

  • 神经网络在之前曾没落过一段时间,因为单层的神经网络连同或和异或等简单计算都无法完成;而多层的神经网络虽然能够计算,但是因为隐藏层的存在,就无法计算中间层的损失,也就是说不能通过损失函数来进行参数的优化,这也就导致了多层神经网络没有实际作用(无法调参)。直到反向传播算法的出现,神经网络又重新复兴起来。
    简而言之,就是反向传播算法可以实现多层神经网络的调参

  • 反向传播算法的思想是从最后的结果出发,一步一步反向计算每个隐藏层的损失,从而调优。

  • 下图是正向传播的计算过程


    正向传播
  • 反向传播:可以看到是用输出层结果 \delta 减去实际值 y 得到最后一层的误差,然后反向计算隐藏层的误差。

反向传播
  • 下面是整个算法的计算过程


    反向传播


梯度检验(P54)

  • 梯度检验可以验证反向传播算法的实现是否正确。

  • 下图是当只有一个参数时的计算方法gradApprox=[J(\theta+\epsilon)-J(\theta-\epsilon)]/(2*\epsilon)

    单个参数

  • 含多个参数时,这是参数为一个向量


    多个参数
  • 下面是检验过程:

    • 先计算反向传播的导数DVec
    • 然后通过数值计算得到梯度gradApprox
    • 比较二者,若很接近则说明算法没有问题
    • 注意检验后,关闭梯度检验,因为计算过程耗时较多
检验过程


精准率与召回率(P67-P68)

  • 单一的输出概率(比如y=99.2%和99.5%),有时会很接近,并不能很好的反应预测结果,所以引入更多的高阶数据进一步说明结果。
精准率与召回率
  • 其中精准率表达式为:
    Precision=True\;pos /(True \;pos+False\; pos)

  • 其中召回率表达式为:
    Recall=True\;pos /(True \;pos+False\; neg)

  • 以癌症预测为例,其实际的意义分别是:精准率越高表示希望预测癌症的正确率更高;召回率表示希望找到更多的癌症患者

  • 当要取二者之间的平衡时,平均值并不能很好的反应出来,所以又有了F1值

trade off
F1值


SVM(P70-P75)

  • 数学上的定义


    数学图形


反向传播算法


正向chuanbo


迁移学习

迁移学习


端到端的神经网络

端到端


卷积神经网络

  • 卷积运算

    • 左侧是原始矩阵
    • 中间的是一个3*3的过滤器(poling池化)
    • 右侧得到的矩阵
卷积运算
  • 卷积运算的作用
    • 可以看到滤波后可以检测垂直边缘(Vertical edge)
滤波的意义
  • 滤波器的参数学习

    • 通过改变滤波器的参数可以得到完全不同的效果
    • 例如Sobel滤波器,Scharr滤波器
    • 可以通过反向传播算法来计算参数,得到不同角度的边缘感知


      参数学习
  • Padding(填充)

    • 卷积计算存在两个缺点:边缘信息损失;每次卷积计算后矩阵变小
    • 所以对边缘进行填充
padding
  • Valid表示无填充;Same表示填充前后矩阵大小不变
  • p为填充大小,所以可以看出滤波器大小始终为奇数
填充方法
  • 步长
    • 步长就是每次与滤波器相乘后移动的距离
步长
  • 三维卷积
    • 三维计算后是一个二维的,图中是27个数相加后得到一个值
三维卷积计算
  • 若卷积后的是一个三维矩阵,那么第三个维度数是滤波器的数量,如下图442中的2表示有两个滤波器
三维卷积
  • 这里可以看到,当输入矩阵很大时,卷积神经网络很大程度上减少了参数的个数
单层卷积网络
各数据的表示
  • 卷积神经网络layer
    • 包含卷积层
    • 池化层
    • 全连接层
  • 池化层
    • 池化层是为了缩减计算数据量

    • 计算方法(没有权重和参数,只是做一个数学计算)

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

推荐阅读更多精彩内容