PyTorch深度學(xué)習(xí)60分鐘(一)

寫(xiě)在前面的話:這是跟著ApacheCN團(tuán)隊(duì)學(xué)習(xí)pytorch的學(xué)習(xí)筆記媳否,主要資源來(lái)自pytorch官網(wǎng)和ApacheCN社區(qū)


一想鹰、PyTorch 是什么?

它是一個(gè)基于 Python 的科學(xué)計(jì)算包, 其主要是為了解決兩類(lèi)場(chǎng)景:

  • NumPy 的替代品, 以使用 GPU 的強(qiáng)大加速功能
  • 一個(gè)深度學(xué)習(xí)研究平臺(tái), 提供最大的靈活性和速度

個(gè)人感覺(jué)石咬,其實(shí)無(wú)論是pytorch還是tensorflow其實(shí)都是幫忙解決了在GPU上的自動(dòng)求導(dǎo)問(wèn)題花颗,這是對(duì)我們這些深度學(xué)習(xí)使用者來(lái)說(shuō)最關(guān)鍵的。也就是說(shuō)西傀,通過(guò)這些框架斤寇,我們不用去過(guò)多地操心反向求導(dǎo)的過(guò)程,而是可以更多地專(zhuān)注于神經(jīng)網(wǎng)絡(luò)(或者說(shuō)深度學(xué)習(xí))的結(jié)構(gòu)等問(wèn)題拥褂。當(dāng)然娘锁,它們也提供了相應(yīng)的封裝來(lái)滿足一些基本需求。


二饺鹃、新手入門(mén)

對(duì)于深度學(xué)習(xí)來(lái)說(shuō)莫秆,一個(gè)比較重要的概念就是張量。數(shù)學(xué)上的定義是張量(Tensor)是一個(gè)定義在的一些向量空間和一些對(duì)偶空間的笛卡兒積上的多重線性映射悔详。而簡(jiǎn)單來(lái)說(shuō)其實(shí)就是矢量的推廣镊屎。在同構(gòu)的意義下,第零階張量為標(biāo)量茄螃,第一階張量為向量 (Vector)缝驳, 第二階張量則成為矩陣 (Matrix)。對(duì)我們來(lái)說(shuō)归苍,常用的其實(shí)也就3階和4階的張量(這里沒(méi)有把矩陣它們當(dāng)成張量)用狱,更高階張量其實(shí)也很難遇到。例如一張圖片就是3階張量拼弃,包括長(zhǎng)夏伊、寬和通道(通常是RGB3通道)。在使用時(shí)也會(huì)變成4階張量吻氧,因?yàn)闀?huì)有batch的值溺忧。(也就是有很多3階張量堆在一起)。

1.初識(shí)張量

Tensors 與 NumPy 的 ndarrays 非常相似, 除此之外還可以在 GPU 上使用張量來(lái)加速計(jì)算盯孙。

from __future__ import print_function
import torch

# 構(gòu)建一個(gè) 5x3 的矩陣
# 張量只是創(chuàng)建了鲁森,但是未初始化
# 可以看出,其實(shí)這里就是生成了一個(gè)5行3列的矩陣
x = torch.Tensor(5, 3)
print(x)

>>tensor([[ 0.0000, -2.0000,  0.0000],
          [-2.0000,  0.0000,  0.0000],
          [ 0.0000,  0.0000,  0.0000],
          [ 0.0000,  0.0000,  0.0000],
          [ 0.0000,  0.0000,  0.0000]])
        

# 獲取 size振惰,注:torch.Size 實(shí)際上是一個(gè) tuple(元組)歌溉,所以它支持所有 tuple 的操作。
print(x.size())

>>torch.Size([5, 3])

#PS:torch.Size 實(shí)際上是一個(gè) tuple(元組), 所以它支持所有 tuple(元組)的操作.

2.基本操作

加操作:

#第一種寫(xiě)法
y = torch.rand(5, 3)
print(x + y)

>>tensor([[ 0.8042, -1.5267,  0.5508],
          [-1.0805,  0.2719,  0.9532],
          [ 0.8435,  0.5595,  0.8556],
          [ 0.6867,  0.8612,  0.7824],
          [ 0.9080,  0.1819,  0.2504]])

#這里的y就是tensor([[ 0.8042,  0.4733,  0.5508],
#                 [ 0.9195,  0.2719,  0.9532],
#                 [ 0.8435,  0.5595,  0.8556],
#                 [ 0.6867,  0.8612,  0.7824],
#                 [ 0.9080,  0.1819,  0.2504]])
# 
# x是第一部分代碼中的x
#第二種寫(xiě)法
print(torch.add(x, y))

>>tensor([[ 0.8042, -1.5267,  0.5508],
          [-1.0805,  0.2719,  0.9532],
          [ 0.8435,  0.5595,  0.8556],
          [ 0.6867,  0.8612,  0.7824],
          [ 0.9080,  0.1819,  0.2504]])
#第三種寫(xiě)法报账,提供一個(gè)輸出 tensor 作為參數(shù)
result = torch.Tensor(5, 3)
torch.add(x, y, out = result)
print(result)

>>>>tensor([[ 0.8042, -1.5267,  0.5508],
            [-1.0805,  0.2719,  0.9532],
            [ 0.8435,  0.5595,  0.8556],
            [ 0.6867,  0.8612,  0.7824],
            [ 0.9080,  0.1819,  0.2504]])
#第四種寫(xiě)法研底,in-place(就地操作)
# adds x to y
y.add_(x)
print(y)

>>>>>>tensor([[ 0.8042, -1.5267,  0.5508],
              [-1.0805,  0.2719,  0.9532],
              [ 0.8435,  0.5595,  0.8556],
              [ 0.6867,  0.8612,  0.7824],
              [ 0.9080,  0.1819,  0.2504]])

索引(類(lèi)似Numpy的索引):

print(x[:, 1])

>>tensor([-2.0000,  0.0000,  0.0000,  0.0000,  0.0000])

改變大小:

x = torch.randn(4, 4)

>>tensor([[ 0.2755, -0.1519,  0.0257, -0.7659],
          [ 0.7431, -1.0414,  0.5645, -1.0806],
          [ 0.7274, -0.5298, -1.5444, -0.2279],
          [-0.9928, -1.0443,  0.4778, -0.2496]])
          
y = x.view(16)

>>tensor([ 0.2755, -0.1519,  0.0257, -0.7659,  0.7431, -1.0414,  0.5645,
          -1.0806,  0.7274, -0.5298, -1.5444, -0.2279, -0.9928, -1.0443,
           0.4778, -0.2496])
           
z = x.view(-1, 8)  # -1就是根據(jù)情況,由計(jì)算機(jī)自己推斷這個(gè)維數(shù)

>>tensor([[ 0.2755, -0.1519,  0.0257, -0.7659,  0.7431, -1.0414,  0.5645,
           -1.0806],
          [ 0.7274, -0.5298, -1.5444, -0.2279, -0.9928, -1.0443,  0.4778,
           -0.2496]])

3.NumPy Bridge

將一個(gè) Torch Tensor 轉(zhuǎn)換為 NumPy 數(shù)組, 反之亦然透罢。
Torch Tensor 和 NumPy 數(shù)組將會(huì)共享它們的實(shí)際的內(nèi)存位置, 改變一個(gè)另一個(gè)也會(huì)跟著改變榜晦。

#轉(zhuǎn)換一個(gè) Torch Tensor 為 NumPy 數(shù)組
a = torch.ones(5)
print(a)

>>tensor([ 1.,  1.,  1.,  1.,  1.])

b = a.numpy()
print(b)

>>array([1., 1., 1., 1., 1.], dtype=float32)

#盡管轉(zhuǎn)換了,但是兩者依然共享內(nèi)存
a.add_(1)
print(a)
print(b)

>>tensor([ 2.,  2.,  2.,  2.,  2.])
>>[2. 2. 2. 2. 2.]

#轉(zhuǎn)換 NumPy 數(shù)組為 Torch Tensor
import numpy as np
a = np.ones(5)

>>array([1., 1., 1., 1., 1.])

b = torch.from_numpy(a)

>>tensor([ 1.,  1.,  1.,  1.,  1.], dtype=torch.float64)

#同樣兩者共享內(nèi)存
np.add(a, 1, out = a)
print(a)
print(b)

>>[2. 2. 2. 2. 2.]
>>tensor([ 2.,  2.,  2.,  2.,  2.], dtype=torch.float64)
Note:

除了 CharTensor 之外, CPU 上的所有 Tensor 都支持與Numpy進(jìn)行互相轉(zhuǎn)換

4.CUDA Tensors

可以使用 .cuda 方法將 Tensors 在GPU上運(yùn)行.

# 只要在  CUDA 是可用的情況下, 我們可以運(yùn)行這段代碼
if torch.cuda.is_available():
    x = x.cuda()
    y = y.cuda()
    x + y


三羽圃、自動(dòng)求導(dǎo)

PyTorch 中所有神經(jīng)網(wǎng)絡(luò)的核心是 autograd自動(dòng)求導(dǎo)包. 我們先來(lái)簡(jiǎn)單介紹一下, 然后我們會(huì)去訓(xùn)練我們的第一個(gè)神經(jīng)網(wǎng)絡(luò)乾胶。

autograd 自動(dòng)求導(dǎo)包針對(duì)張量上的所有操作都提供了自動(dòng)微分操作. 這是一個(gè)逐個(gè)運(yùn)行的框架, 這意味著您的反向傳播是由您的代碼如何運(yùn)行來(lái)定義的, 每個(gè)單一的迭代都可以不一樣。

1.Variable(變量)

autograd.Variable 是包的核心類(lèi). 它包裝了張量, 并且支持幾乎所有的操作. 一旦你完成了你的計(jì)算, 你就可以調(diào)用 .backward()方法, 然后所有的梯度計(jì)算會(huì)自動(dòng)進(jìn)行朽寞。

pytorch允許通過(guò) .data 屬性來(lái)訪問(wèn)原始的張量, 而關(guān)于該 variable(變量)的梯度會(huì)被累計(jì)到 .grad 上去识窿。


還有一個(gè)針對(duì)自動(dòng)求導(dǎo)實(shí)現(xiàn)來(lái)說(shuō)非常重要的類(lèi) - Function

VariableFunction 是相互聯(lián)系的, 并且它們構(gòu)建了一個(gè)非循環(huán)的圖, 編碼了一個(gè)完整的計(jì)算歷史信息. 每一個(gè) variable(變量)都有一個(gè) .grad_fn 屬性, 它引用了一個(gè)已經(jīng)創(chuàng)建了 VariableFunction (除了用戶創(chuàng)建的 Variable 之外 - 它們的 grad_fn is None

如果你想計(jì)算導(dǎo)數(shù), 你可以在 Variable 上調(diào)用 .backward() 方法. 如果 Variable 是標(biāo)量的形式(例如, 它包含一個(gè)元素?cái)?shù)據(jù)), 你不必指定任何參數(shù)給 backward(), 但是, 如果它有更多的元素. 你需要去指定一個(gè) grad_output 參數(shù), 該參數(shù)是一個(gè)匹配 shape(形狀)的張量脑融。

import torch
from torch.autograd import Variable

#創(chuàng)建 variable(變量)
x = Variable(torch.ones(2, 2), requires_grad = True)
print(x)

>>tensor([[ 1.,  1.],
          [ 1.,  1.]])
          
#y 由操作創(chuàng)建,所以它有 grad_fn 屬性.
y = x + 2
print(y)

>>tensor([[ 3.,  3.],
          [ 3.,  3.]])
 
z = y * y * 3
out = z.mean()
print(z, out)

>>tensor([[ 27.,  27.],
          [ 27.,  27.]])
>>tensor(27.)        

2.梯度

pytorch之類(lèi)的框架對(duì)于我們學(xué)習(xí)者來(lái)說(shuō)最大的幫助莫過(guò)于反向求導(dǎo)的簡(jiǎn)單化喻频。

我們考慮上述例子的反向求導(dǎo)過(guò)程,首先肘迎,先寫(xiě)出整體的前向過(guò)程:
y = x + 2
z = 3 * y^2
out = \frac{1}{4} \sum_{i}^4{z_{i}}

所以在反向求導(dǎo)時(shí):
\nabla_{z_{i}} = \frac{\partial{out}}{\partial{z_{i}}} = \frac{1}{4}
\nabla_{y} = \frac{\partial{z_{i}}}{\partial{y}} = 6 * y
\nabla_{x} = \frac{\partial{y}}{\partial{x}} = 1

故而:

\nabla_{x} = \frac{\partial{out}}{\partial{x}} = \frac{1}{4} * 6 * y * 1 = 4.5



如果沒(méi)有框架甥温,單純編寫(xiě)這段代碼其實(shí)比較的繁瑣。而在使用了pytorch框架后妓布,只需要調(diào)用out.backward()姻蚓,pytorch就會(huì)自動(dòng)求導(dǎo)其導(dǎo)數(shù),將其存放在.grad中:

out.backward()
print(x.grad)

>>tensor([[ 4.5000,  4.5000],
          [ 4.5000,  4.5000]])

同時(shí)匣沼,梯度的有趣應(yīng)用:

x = torch.randn(3)
x = Variable(x, requires_grad = True)

y = x * 2

gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)

>>tensor([ 0.2000,  2.0000,  0.0002])


四狰挡、實(shí)戰(zhàn)之基本的卷積神經(jīng)網(wǎng)絡(luò)

神經(jīng)網(wǎng)絡(luò)可以使用 torch.nn 包構(gòu)建。

autograd 實(shí)現(xiàn)了反向傳播功能, 但是直接用來(lái)寫(xiě)深度學(xué)習(xí)的代碼在很多情況下還是稍顯復(fù)雜, torch.nn 是專(zhuān)門(mén)為神經(jīng)網(wǎng)絡(luò)設(shè)計(jì)的模塊化接口. nn 構(gòu)建于 Autograd 之上, 可用來(lái)定義和運(yùn)行神經(jīng)網(wǎng)絡(luò). nn.Modulenn 中最重要的類(lèi), 可把它看成是一個(gè)網(wǎng)絡(luò)的封裝, 包含網(wǎng)絡(luò)各層定義以及 forward 方法, 調(diào)用 forward(input) 方法, 可返回前向傳播的結(jié)果释涛。

1.定義一個(gè)網(wǎng)絡(luò)

import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F


class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        # 卷積層 '1'表示輸入圖片為單通道, '6'表示輸出通道數(shù), '5'表示卷積核為5*5
        # 核心
        # 初始化的過(guò)程中其實(shí)沒(méi)有再定義網(wǎng)絡(luò)結(jié)構(gòu)加叁,只是定義了一些函數(shù)
        self.conv1 = nn.Conv2d(1, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        # 仿射層/全連接層: y = Wx + b
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)
        
        # 這里的前向過(guò)程才定義了整個(gè)網(wǎng)絡(luò)結(jié)構(gòu)
    def forward(self, x):
        # 在由多個(gè)輸入平面組成的輸入信號(hào)上應(yīng)用2D最大池化.
        # (2, 2) 代表的是池化操作的步幅
        
        # 這里正是從輸入層,通過(guò)一個(gè)卷積之后枢贿,在經(jīng)過(guò)一個(gè)pool
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        # 如果大小是正方形, 則只能指定一個(gè)數(shù)字
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        
        # 這邊便是將x拉值殉农,以便用于全連接
        x = x.view(-1, self.num_flat_features(x))
        # 接下來(lái)就是普通的兩個(gè)全連接層
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        # 下面是輸出層
        x = self.fc3(x)
        return x

    def num_flat_features(self, x):
        size = x.size()[1:]  # 除批量維度外的所有維度
        num_features = 1
        for s in size:
            num_features *= s
        return num_features


net = Net()
print(net)

>>Net(
    (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
    (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
    (fc1): Linear(in_features=400, out_features=120, bias=True)
    (fc2): Linear(in_features=120, out_features=84, bias=True)
    (fc3): Linear(in_features=84, out_features=10, bias=True)
   )

只要在 nn.Module 的子類(lèi)中定義了 forward 函數(shù), backward 函數(shù)就會(huì)自動(dòng)被實(shí)現(xiàn)(利用 autograd )。 在 forward 函數(shù)中可使用任何 Tensor 支持的操作局荚。

并不像tensorflow需要顯式地定義參數(shù)超凳,pytorch在上述過(guò)程中只需要用戶輸入維度信息,參數(shù)的維度便可由計(jì)算機(jī)自動(dòng)給出耀态。網(wǎng)絡(luò)的可學(xué)習(xí)參數(shù)通過(guò) net.parameters() 返回,net.named_parameters 可同時(shí)返回學(xué)習(xí)的參數(shù)以及名稱(chēng)轮傍。

params = list(net.parameters())
print(len(params))
print(params[0].size())  # conv1的weight

>>10
>>torch.Size([6, 1, 5, 5])

向前的輸入是一個(gè) autograd.Variable, 輸出也是如此。注意: 這個(gè)網(wǎng)絡(luò)(LeNet)的預(yù)期輸入大小是 32x32, 使用這個(gè)網(wǎng)上 MNIST 數(shù)據(jù)集, 請(qǐng)將數(shù)據(jù)集中的圖像調(diào)整為 32x32

input = Variable(torch.randn(1, 1, 32, 32))
out = net(input)
print(out)

>>tensor([[-0.0821,  0.1081,  0.0103,  0.1502,  0.0191,  0.0097, -0.0175,
           -0.0804, -0.0055, -0.0382]])
Note:
  • torch.nn 只支持小批量(mini-batches), 不支持一次輸入一個(gè)樣本, 即一次必須是一個(gè) batch
  • nn.Conv2d 的輸入必須是 4 維的, 形如 nSamples x nChannels x Height x Width


2.損失函數(shù)

損失函數(shù)采用 (output, target) 輸入對(duì), 并計(jì)算預(yù)測(cè)輸出結(jié)果與實(shí)際目標(biāo)的距離首装。

在 nn 包下有幾種不同的損失函數(shù)创夜。一個(gè)簡(jiǎn)單的損失函數(shù)是: nn.MSELoss 計(jì)算輸出和目標(biāo)之間的均方誤差

output = net(input)
target = Variable(torch.arange(1, 11))  # 一個(gè)虛擬的目標(biāo)
criterion = nn.MSELoss()

loss = criterion(output, target)
print(loss)

現(xiàn)在, 如果你沿著 loss 反向傳播的方向使用.grad_fn 屬性, 你將會(huì)看到一個(gè)如下所示的計(jì)算圖:

input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
      -> view -> linear -> relu -> linear -> relu -> linear
      -> MSELoss
      -> loss

所以, 當(dāng)我們調(diào)用loss.backward(), 整個(gè)圖與損失是有區(qū)別的, 圖中的所有變量都將用 .grad 梯度累加它們的變量。


3.反向傳播

為了反向傳播誤差, 我們所要做的就是 loss.backward()仙逻。你需要清除現(xiàn)有的梯度, 否則梯度會(huì)累加之前的梯度驰吓。
現(xiàn)在我們使用 loss.backward(), 看看反向傳播之前和之后 conv1 的梯度涧尿。

net.zero_grad()     # 把之前的梯度清零

print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)

>>None

loss.backward()

print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)

>>tensor([ 0.1580, -0.0348, -0.1106,  0.0706, -0.0937, -0.0539])


4.更新權(quán)重

實(shí)踐中使用的最簡(jiǎn)單的更新規(guī)則是隨機(jī)梯度下降( SGD ):

weight = weight - learning\_rate * gradient

可以使用簡(jiǎn)單的 python 代碼來(lái)實(shí)現(xiàn)這個(gè):

learning_rate = 0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * learning_rate)

當(dāng)然,更新權(quán)重的方法pytorch也已經(jīng)做了封裝(torch.optim)檬贰,方便我們調(diào)用:

import torch.optim as optim

# 新建一個(gè)優(yōu)化器, 指定要調(diào)整的參數(shù)和學(xué)習(xí)率
optimizer = optim.SGD(net.parameters(), lr = 0.01)

# 在訓(xùn)練過(guò)程中:
optimizer.zero_grad()   # 首先梯度清零(與 net.zero_grad() 效果一樣)
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()    # 更新參數(shù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末姑廉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子翁涤,更是在濱河造成了極大的恐慌桥言,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件葵礼,死亡現(xiàn)場(chǎng)離奇詭異号阿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)鸳粉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)扔涧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人赁严,你說(shuō)我怎么就攤上這事扰柠。” “怎么了疼约?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵卤档,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我程剥,道長(zhǎng)劝枣,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任织鲸,我火速辦了婚禮舔腾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘搂擦。我一直安慰自己稳诚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布瀑踢。 她就那樣靜靜地躺著扳还,像睡著了一般。 火紅的嫁衣襯著肌膚如雪橱夭。 梳的紋絲不亂的頭發(fā)上氨距,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音棘劣,去河邊找鬼俏让。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的首昔。 我是一名探鬼主播寡喝,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼勒奇!你這毒婦竟也來(lái)了拘荡?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤撬陵,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后网缝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體巨税,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年粉臊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了草添。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扼仲,死狀恐怖远寸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情屠凶,我是刑警寧澤驰后,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站矗愧,受9級(jí)特大地震影響灶芝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜唉韭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一夜涕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧属愤,春花似錦女器、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至只壳,卻和暖如春俏拱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吼句。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工锅必, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓搞隐,卻偏偏與公主長(zhǎng)得像驹愚,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子劣纲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355