Pytorch-損失函數(shù)

在深度學(xué)習(xí)中要用到各種各樣的損失函數(shù)(loss function)锌奴,這些損失函數(shù)可看作是一種特殊的 layer ,PyTorch也將這些損失函數(shù)實(shí)現(xiàn)為 nn.Module 的子類(lèi)椅挣。然而在實(shí)際使用中通常將這些 loss function 專(zhuān)門(mén)提取出來(lái)项戴,和主模型互相獨(dú)立三痰。

我們所說(shuō)的優(yōu)化腰懂,即優(yōu)化網(wǎng)絡(luò)權(quán)值使得損失函數(shù)值變小。但是隅津,損失函數(shù)值變小是否能代表模型的分類(lèi)/回歸精度變高呢诬垂?那么多種損失函數(shù),應(yīng)該如何選擇呢伦仍?要解答這些就首先要了解Pytorch中的損失函數(shù)都有哪些和他們的機(jī)制结窘,來(lái)看一下吧。

值得注意的是呢铆,很多的 loss 函數(shù)都有 size_average 和 reduce 兩個(gè)布爾類(lèi)型的參數(shù)晦鞋,需要解釋一下。因?yàn)橐话銚p失函數(shù)都是直接計(jì)算 batch 的數(shù)據(jù)棺克,因此返回的 loss 結(jié)果都是維度為 (batch_size, ) 的張量悠垛。

  • 如果 reduce = False,那么 size_average 參數(shù)失效娜谊,直接返回張量形式的 loss确买;(與下文中的size_average=None, reduce=None, reduction='none'一致)

  • 如果 reduce = True,那么 loss 返回的是標(biāo)量;
    1)如果 size_average = True纱皆,返回 loss.mean(); (與下文中的size_average=None, reduce=None, reduction='mean'一致)
    2)如果 size_average = False湾趾,返回 loss.sum();(與下文中的size_average=None, reduce=None, reduction='sum'一致)

1、L1范數(shù)損失 L1Loss

class torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')
  • reduction有三個(gè)取值派草,分別為'none'搀缠、'mean''sum'近迁;
    reduction'none'艺普,則返回 與預(yù)測(cè)值或者真實(shí)值形狀一致的 張量;
    reduction不取'mean'或者'sum',則返回 一個(gè)標(biāo)量值歧譬。

  • size_averagereduce都取None岸浑,不作更改,這是推薦的方式瑰步;
    size_averagereduce兩者中有一個(gè)不為None矢洲,則會(huì)重寫(xiě)reduction

  • 總之缩焦,推薦的方式是:1)size_averagereduce都取None读虏;2)同時(shí),更改reduction的值以達(dá)到不同的目標(biāo)

1.1 功能

計(jì)算預(yù)測(cè)值 x and 真實(shí)值 y之間的平均絕對(duì)值誤差(MAE)(mean absolute error).

1.2 公式

1)當(dāng)reduction = 'none':
\ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = \left| x_n - y_n \right|
其中舌界,N為批量大小batch size掘譬。

2)當(dāng)reduction = 'mean'或者reduction = 'sum'
L = \{l_1,\dots,l_N\}^\top, \quad l_n = \left| x_n - y_n \right|

\ell(x, y) = \begin{cases} \operatorname{mean}(L), & \text{if reduction} = \text{'mean';}\\ \operatorname{sum}(L), & \text{if reduction} = \text{'sum'.} \end{cases}

3)默認(rèn)情況(即reduction='mean'):
\ell(x,y) = \frac{1}{N} \sum_{n=1}^{N} |x_n - y_n|

1.3 代碼

input_ = torch.empty(2, 3, dtype=torch.float).random_(0, 4)
target = torch.empty(2, 3, dtype=torch.float).random_(0, 4)
print(input_); print(target);
print(input_.size(), target.size())

print('=== mean ===')
loss_fn = torch.nn.L1Loss(reduce=None, size_average=None, reduction='mean')
loss = loss_fn(input_, target)
print(loss)
print(loss.size())

print('=== sum ===')
loss_fn = torch.nn.L1Loss(reduce=None, size_average=None, reduction='sum')
loss = loss_fn(input_, target)
print(loss)
print(loss.size())

print('=== none ===')
loss_fn = torch.nn.L1Loss(reduce=None, size_average=None, reduction='none')
loss = loss_fn(input_, target)
print(loss)
print(loss.size())

輸出結(jié)果如下:

tensor([[3., 0., 3.],
        [3., 0., 3.]])
tensor([[2., 0., 3.],
        [2., 0., 0.]])
torch.Size([2, 3]) torch.Size([2, 3])
=== mean ===
tensor(0.8333)
torch.Size([])
=== sum ===
tensor(5.)
torch.Size([])
=== none ===
tensor([[1., 0., 0.],
        [1., 0., 3.]])
torch.Size([2, 3])
  • mean和sum方式下泰演,loss值為一個(gè)標(biāo)量呻拌;
  • none方式下,loss值為張量睦焕,形狀與input_或者target一致藐握;
  • 以mean為例計(jì)算,(|3-2| + |0-0| + |3-3| + |3-2| + |0-0| + |3-0|) / 6 = 5 / 6 = 0.8333

2垃喊、均方誤差損失 MSELoss

class torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')
  • reduction有三個(gè)取值猾普,分別為'none''mean'本谜、'sum'初家;
    reduction'none',則返回 與預(yù)測(cè)值或者真實(shí)值形狀一致的 張量乌助;
    reduction不取'mean'或者'sum'溜在,則返回 一個(gè)標(biāo)量值。

  • size_averagereduce都取None他托,不作更改掖肋,這是推薦的方式;
    size_averagereduce兩者中有一個(gè)不為None赏参,則會(huì)重寫(xiě)reduction志笼。

  • 總之,推薦的方式是:1)size_averagereduce都取None把篓;2)同時(shí)纫溃,更改reduction的值以達(dá)到不同的目標(biāo)

2.1 功能

計(jì)算預(yù)測(cè)值 x and 真實(shí)值 y之間的均方誤差(MSE)(mean squared error (squared L2 norm)).

2.2 公式

1)當(dāng)reduction = 'none':
\ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = \left( x_n - y_n \right)^2,
其中,N為批量大小batch size韧掩。

2)當(dāng)reduction = 'mean'或者reduction = 'sum'
\ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = \left( x_n - y_n \right)^2,

\ell(x, y) = \begin{cases} \operatorname{mean}(L), & \text{if reduction} = \text{'mean';}\\ \operatorname{sum}(L), & \text{if reduction} = \text{'sum'.} \end{cases}

3)默認(rèn)情況(即reduction='mean'):
\ell(x, y) = \frac{1}{N} \sum_{n=1}^{N} (x_n - y_n)^{2}

2.3 代碼

input_ = torch.empty(2, 3, dtype=torch.float).random_(0, 4)
target = torch.empty(2, 3, dtype=torch.float).random_(0, 4)
print(input_); print(target);
print(input_.size(), target.size())

print('=== mean ===')
loss_fn = torch.nn.MSELoss(reduce=None, size_average=None, reduction='mean')
loss = loss_fn(input_, target)
print(loss)
print(loss.size())

print('=== sum ===')
loss_fn = torch.nn.MSELoss(reduce=None, size_average=None, reduction='sum')
loss = loss_fn(input_, target)
print(loss)
print(loss.size())

print('=== none ===')
loss_fn = torch.nn.MSELoss(reduce=None, size_average=None, reduction='none')
loss = loss_fn(input_, target)
print(loss)
print(loss.size())

輸出結(jié)果如下:

tensor([[2., 0., 3.],
        [3., 0., 1.]])
tensor([[2., 0., 0.],
        [0., 3., 0.]])
torch.Size([2, 3]) torch.Size([2, 3])
=== mean ===
tensor(4.6667)
torch.Size([])
=== sum ===
tensor(28.)
torch.Size([])
=== none ===
tensor([[0., 0., 9.],
        [9., 9., 1.]])
torch.Size([2, 3])
  • mean和sum方式下紊浩,loss值為一個(gè)標(biāo)量;
  • none方式下,loss值為張量郎楼,形狀與input_或者target一致万伤;
  • 以none為例計(jì)算,
    [[(2-2)^2, (0-0)^2, (3-0)^2], \\ [(3-0)^2, (0-3)^2, (1-0)^2]] \\ =[[0, 0, 9], \\ [9, 9, 1]]

3呜袁、交叉熵?fù)p失 CrossEntropyLoss

class torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')

3.1 功能

該方法將nn.LogSoftmax()nn.NLLLoss()進(jìn)行了結(jié)合敌买。嚴(yán)格意義上的交叉熵?fù)p失函數(shù)應(yīng)該是nn.NLLLoss()。在類(lèi)別分布不平衡的數(shù)據(jù)集中尤其有用阶界。

其中虹钮,nn.LogSoftmax()公式如下:
\text{LogSoftmax}(x_{i}) = \log\left(\frac{\exp(x_i) }{ \sum_j \exp(x_j)} \right)
nn.NLLLoss()公式參見(jiàn)下文。

3.2 公式

1)當(dāng)不指明權(quán)重時(shí):

\text{loss}(x, class) = -\log\left(\frac{\exp(x[class])}{\sum_j \exp(x[j])}\right) = -x[class] + \log\left(\sum_j \exp(x[j])\right)

2)當(dāng)指明權(quán)重時(shí):
\text{loss}(x, class) = weight[class] \left(-x[class] + \log\left(\sum_j \exp(x[j])\right)\right)

3.3 代碼

import torch
import torch.nn as nn
import numpy as np
import math

# ----------------------------------- CrossEntropy loss: base
loss_f = nn.CrossEntropyLoss(weight=None, size_average=True, reduce=False)
# 生成網(wǎng)絡(luò)輸出 以及 目標(biāo)輸出
output = torch.ones(2, 3, requires_grad=True) * 0.5      # 假設(shè)一個(gè)三分類(lèi)任務(wù)膘融,batchsize=2芙粱,假設(shè)每個(gè)神經(jīng)元輸出都為0.5
target = torch.from_numpy(np.array([0, 1])).type(torch.LongTensor)

loss = loss_f(output, target)

print('--------------------------------------------------- CrossEntropy loss: base')
print('loss: ', loss)
print('由于reduce=False,所以可以看到每一個(gè)樣本的loss氧映,輸出為[1.0986, 1.0986]')

# 熟悉計(jì)算公式春畔,手動(dòng)計(jì)算第一個(gè)樣本
output = output[0].detach().numpy()
output_1 = output[0]              # 第一個(gè)樣本的輸出值
target_1 = target[0].numpy()

# 第一項(xiàng)
x_class = output[target_1]
# 第二項(xiàng)
exp = math.e
sigma_exp_x = pow(exp, output[0]) + pow(exp, output[1]) + pow(exp, output[2])
log_sigma_exp_x = math.log(sigma_exp_x)
# 兩項(xiàng)相加
loss_1 = -x_class + log_sigma_exp_x
print('---------------------------------------------------  手動(dòng)計(jì)算')
print('第一個(gè)樣本的loss:', loss_1)

# ----------------------------------- CrossEntropy loss: weight

weight = torch.from_numpy(np.array([0.6, 0.2, 0.2])).float()
loss_f = nn.CrossEntropyLoss(weight=weight, size_average=True, reduce=False)
output = torch.ones(2, 3, requires_grad=True) * 0.5  # 假設(shè)一個(gè)三分類(lèi)任務(wù),batchsize為2個(gè)岛都,假設(shè)每個(gè)神經(jīng)元輸出都為0.5
target = torch.from_numpy(np.array([0, 1])).type(torch.LongTensor)
loss = loss_f(output, target)
print('\n\n--------------------------------------------------- CrossEntropy loss: weight')
print('loss: ', loss)  #
print('原始loss值為1.0986, 第一個(gè)樣本是第0類(lèi)律姨,weight=0.6,所以輸出為1.0986*0.6 =', 1.0986*0.6)

# ----------------------------------- CrossEntropy loss: ignore_index

loss_f_1 = nn.CrossEntropyLoss(weight=None, size_average=False, reduce=False, ignore_index=1)
loss_f_2 = nn.CrossEntropyLoss(weight=None, size_average=False, reduce=False, ignore_index=2)

output = torch.ones(3, 3, requires_grad=True) * 0.5  # 假設(shè)一個(gè)三分類(lèi)任務(wù),batchsize為2個(gè)臼疫,假設(shè)每個(gè)神經(jīng)元輸出都為0.5
target = torch.from_numpy(np.array([0, 1, 2])).type(torch.LongTensor)

loss_1 = loss_f_1(output, target)
loss_2 = loss_f_2(output, target)

print('\n\n--------------------------------------------------- CrossEntropy loss: ignore_index')
print('ignore_index = 1: ', loss_1)     # 類(lèi)別為1的樣本的loss為0
print('ignore_index = 2: ', loss_2)     # 類(lèi)別為2的樣本的loss為0

輸出結(jié)果:

--------------------------------------------------- CrossEntropy loss: base
loss:  tensor([1.0986, 1.0986], grad_fn=<NllLossBackward>)
由于reduce=False择份,所以可以看到每一個(gè)樣本的loss,輸出為[1.0986, 1.0986]
---------------------------------------------------  手動(dòng)計(jì)算
第一個(gè)樣本的loss: 1.0986122886681098
--------------------------------------------------- CrossEntropy loss: weight
loss:  tensor([0.6592, 0.2197], grad_fn=<NllLossBackward>)
原始loss值為1.0986, 第一個(gè)樣本是第0類(lèi)烫堤,weight=0.6,所以輸出為1.0986*0.6 = 0.65916
--------------------------------------------------- CrossEntropy loss: ignore_index
ignore_index = 1:  tensor([1.0986, 0.0000, 1.0986], grad_fn=<NllLossBackward>)
ignore_index = 2:  tensor([1.0986, 1.0986, 0.0000], grad_fn=<NllLossBackward>)

3.4 其他

交叉熵?fù)p失(cross-entropy Loss) 又稱(chēng)為對(duì)數(shù)似然損失(Log-likelihood Loss)荣赶、對(duì)數(shù)損失;二分類(lèi)時(shí)還可稱(chēng)之為邏輯斯諦回歸損失(Logistic Loss)鸽斟。pytroch這里不是嚴(yán)格意義上的交叉熵?fù)p失函數(shù)拔创,而是先將input經(jīng)過(guò)softmax激活函數(shù),將向量“歸一化”成概率形式湾盗,然后再與target計(jì)算嚴(yán)格意義上交叉熵?fù)p失伏蚊。 在多分類(lèi)任務(wù)中,經(jīng)常采用softmax激活函數(shù)+交叉熵?fù)p失函數(shù)格粪,因?yàn)榻徊骒孛枋隽藘蓚€(gè)概率分布的差異躏吊,然而神經(jīng)網(wǎng)絡(luò)輸出的是向量,并不是概率分布的形式帐萎。所以需要softmax激活函數(shù)將一個(gè)向量進(jìn)行“歸一化”成概率分布的形式比伏,再采用交叉熵?fù)p失函數(shù)計(jì)算loss。 再回顧PyTorch的CrossEntropyLoss()疆导,官方文檔中提到時(shí)將nn.LogSoftmax()和 nn.NLLLoss()進(jìn)行了結(jié)合赁项,nn.LogSoftmax() 相當(dāng)于激活函數(shù) , nn.NLLLoss()是損失函數(shù),將其結(jié)合悠菜,完整的是否可以叫做softmax+交叉熵?fù)p失函數(shù)呢舰攒?

4、負(fù)對(duì)數(shù)似然損失 NLLLoss

class torch.nn.NLLLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')
  • size_average悔醋、reduce摩窃、reduction這個(gè)三個(gè)參數(shù)不再贅述,與L1Loss芬骄、MSELoss一致猾愿;
  • weight: 如果提供,則應(yīng)該是 由每個(gè)類(lèi)別的權(quán)重組成的一維張量账阻,例如有A蒂秘、B、C三個(gè)類(lèi)別淘太,則weight可為weight=[0.6, 0.3, 0.1]姻僧,其中weight的長(zhǎng)度與類(lèi)別數(shù)相等;如果沒(méi)有提供琴儿,所有權(quán)重置為1段化;
  • ignore_index:忽略某一類(lèi)別,不計(jì)算其loss造成,其loss會(huì)為0,并且雄嚣,在采用size_average時(shí)晒屎,不會(huì)計(jì)算那一類(lèi)的loss,除的時(shí)候的分母也不會(huì)統(tǒng)計(jì)那一類(lèi)的樣本缓升;
  • NLLLoss的輸入是每一類(lèi)別的log-probabilities鼓鲁,該log-probabilities可以通過(guò)LogSoftmax網(wǎng)絡(luò)層獲得,如果不想讓網(wǎng)絡(luò)的最后一層是 log_softmax 層的話(huà)港谊,就可以采用 CrossEntropyLoss 完全代替此函數(shù)骇吭,因?yàn)镃rossEntropyLoss 中就有這些步驟

4.1 功能

類(lèi)別分布不平衡的數(shù)據(jù)集中尤其有用歧寺。

4.2 公式

1)當(dāng)reduction = 'none':
\ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = - w_{y_n} x_{n,y_n}, \quad w_{c} = \text{weight}[c] \cdot \mathbb{1}\{c \not= \text{ignore_index}\},
其中燥狰,N為批量大小batch size;n \in (1, 2, ..., N)表示一個(gè)批量中的第n個(gè)樣本斜筐;l_n表示第n個(gè)樣本的損失值龙致;y_n表示第n個(gè)樣本的真實(shí)標(biāo)簽(例如是類(lèi)別2,則y_n=2)顷链;w_{y_n}表示類(lèi)別y_n的權(quán)重目代。

2)當(dāng)reduction = 'mean'或者reduction = 'sum'
l_n = - w_{y_n} x_{n,y_n}, \quad w_{c} = \text{weight}[c] \cdot \mathbb{1}\{c \not= \text{ignore_index}\},

\ell(x, y) = \begin{cases} \sum_{n=1}^N \frac{1}{\sum_{n=1}^N w_{y_n}} l_n, & \text{if reduction} = \text{'mean';}\\ \sum_{n=1}^N l_n, & \text{if reduction} = \text{'sum'.} \end{cases}

4.3 shape

  • Input: (N, C) where C = number of classes or (N, C, d_1, d_2, ..., d_K) with K \geq 1 in the case of K- dimensional loss.

  • Target: (N) where each value is 0 \leq \text{targets}[i] \leq C-1 or (N, d_1, d_2, ..., d_K) with K \geq 1 in the case of K- dimensional loss.

  • Output: scalar.
    If reduction is 'none', then the same size as the target: (N) or (N, d_1, d_2, ..., d_K) with K \geq 1 in the case of K- dimensional loss.

  • 會(huì)發(fā)現(xiàn)Target 與 Output的形狀一致,但I(xiàn)nput要比前兩者多一個(gè)類(lèi)別通道(C)

4.4 理解f(x, class) = -x[class]

以三分類(lèi)任務(wù)為例,類(lèi)別標(biāo)號(hào)為0榛了、1在讶、2。NLLLoss 的輸入input=[-1.233, 2.657, 0.534]霜大, 真實(shí)標(biāo)簽為2(class=2)真朗,則loss = f(x, class) = -x[class] = -input[2] = -0.534(有點(diǎn)列表切片的意思)。

4.5 舉例

1) 當(dāng)reduction = 'none'僧诚,

  • 理論計(jì)算

使用如下公式:
\ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = - w_{y_n} x_{n,y_n}, \quad w_{c} = \text{weight}[c] \cdot \mathbb{1}\{c \not= \text{ignore_index}\},

以三分類(lèi)任務(wù)為例遮婶,類(lèi)別標(biāo)號(hào)為0、1湖笨、2旗扑。NLLLoss 的輸入input為[[0.6, 0.2, 0.2], [0.4, 1.2, 0.4]](即兩個(gè)樣本分別在三個(gè)類(lèi)別的預(yù)測(cè)概率值),真實(shí)標(biāo)簽target= [0, 1]慈省,不指定權(quán)重(則權(quán)重全為1)臀防。

這個(gè)批量有兩個(gè)樣本(N=2),所以L = \{l_1, l_2\}^\top边败;

真實(shí)標(biāo)簽列表為target= [0, 1]袱衷,即第一個(gè)樣本的真實(shí)標(biāo)簽為類(lèi)別0,第二個(gè)樣本的真實(shí)標(biāo)簽為類(lèi)別1笑窜,所以y_1 = 0致燥、y_2= 1

權(quán)重沒(méi)有指定(則weight = [1, 1, 1])排截,所以w_{y_1} = w_0 = \text {weight}[0] = 1嫌蚤,同理,w_{y_2} = w_1 = \text {weight}[1] = 1断傲;

x_{1, y_1} 表示第一個(gè)樣本中y_1對(duì)應(yīng)的值脱吱,即x_{1, y_1}= [0.6, 0.2, 0.2][y_1]=[0.6, 0.2, 0.2][0]=0.6,同理认罩,x_{2, y_2}=1.2;

所以 l_1 = - w_{y_1} x_{1,y_1} = - 1 * 0.6 = -0.6箱蝠,同理,l_2 = -1 * 1.2 = -1.2

因此垦垂,\ell(x, y) = L = \{-0.6, -1.2\} ^\top宦搬。

  • 代碼實(shí)現(xiàn):
import torch
import torch.nn as nn
import numpy as np

# ----------------------------------- log likelihood loss
# 生成網(wǎng)絡(luò)輸出 以及 目標(biāo)輸出
output = torch.from_numpy(np.array([[0.6, 0.2, 0.2], [0.4, 1.2, 0.4]])).float()  
output.requires_grad = True
target = torch.from_numpy(np.array([0, 1])).type(torch.LongTensor)

loss_f = nn.NLLLoss(weight=None, size_average=None, reduce=None, reduction='none')
loss = loss_f(output, target)

print('\nloss: \n', loss)
print('\n第一個(gè)樣本是0類(lèi),loss = -(1*0.6)={}'.format(loss[0]))
print('\n第二個(gè)樣本是1類(lèi)乔外,loss = -(1*1.2)={}'.format(loss[1]))

輸出結(jié)果:

loss: 
 tensor([-0.6000, -1.2000], grad_fn=<NllLossBackward>)
第一個(gè)樣本是0類(lèi)床三,loss = -(1*0.6)=-0.6000000238418579
第二個(gè)樣本是1類(lèi),loss = -(1*1.2)=-1.2000000476837158

2)當(dāng)reduction = 'mean'杨幼,且?guī)蠙?quán)重

  • 理論計(jì)算

l_n = - w_{y_n} x_{n,y_n}, \quad w_{c} = \text{weight}[c] \cdot \mathbb{1}\{c \not= \text{ignore_index}\},

\ell(x, y) = \begin{cases} \sum_{n=1}^N \frac{1}{\sum_{n=1}^N w_{y_n}} l_n, & \text{if reduction} = \text{'mean';}\\ \sum_{n=1}^N l_n, & \text{if reduction} = \text{'sum'.} \end{cases}

以三分類(lèi)任務(wù)為例撇簿,類(lèi)別標(biāo)號(hào)為0聂渊、1、2四瘫。NLLLoss 的輸入input為[[0.6, 0.2, 0.2], [0.4, 1.2, 0.4]](即兩個(gè)樣本分別在三個(gè)類(lèi)別的預(yù)測(cè)概率值)汉嗽,真實(shí)標(biāo)簽target= [0, 1],指定權(quán)值weight = [0.6, 0.2, 0.2]找蜜。

則有饼暑,
l_1 = - 0.6 * 0.6 = -0.36
l_2 = - 0.2 * 1.2 = -0.24

因?yàn)?code>reduction = 'mean'洗做,所以\ell(x, y)=\frac{1}{0.6 + 0.2} * (-0.36) + \frac{1}{0.6 + 0.2} * (-0.24) = -0.75弓叛。

  • 代碼實(shí)現(xiàn)
import torch
import torch.nn as nn
import numpy as np

# ----------------------------------- log likelihood loss
# 各類(lèi)別權(quán)重
weight = torch.from_numpy(np.array([0.6, 0.2, 0.2])).float()

# 生成網(wǎng)絡(luò)輸出 以及 目標(biāo)輸出
output = torch.from_numpy(np.array([[0.6, 0.2, 0.2], [0.4, 1.2, 0.4]])).float()  
output.requires_grad = True
target = torch.from_numpy(np.array([0, 1])).type(torch.LongTensor)

loss_f = nn.NLLLoss(weight=weight, size_average=None, reduce=None, reduction='mean')
loss = loss_f(output, target)

print('\nloss: \n', loss)

輸出結(jié)果:

loss: 
 tensor(-0.7500, grad_fn=<NllLossBackward>)

5、目標(biāo)值為泊松分布的負(fù)對(duì)數(shù)似然損失PoissonNLLLoss

class torch.nn.PoissonNLLLoss(log_input=True, full=False, size_average=None, eps=1e-08, reduce=None, reduction='mean')
  • log_input (bool, optional): 如果為T(mén)rue诚纸,使用\exp(\text{input}) - \text{target}*\text{input}撰筷;如果為False,使用\text{input} - \text{target}*\log(\text{input}+\text{eps})
  • full (bool, optional): 是否計(jì)算全部的loss畦徘。例如毕籽,當(dāng)采用斯特林公式近似階乘項(xiàng)時(shí),階乘項(xiàng)近似為\text{target}*\log(\text{target}) - \text{target} + 0.5 * \log(2\pi\text{target})
  • eps(float): 當(dāng)log_input = False時(shí)井辆,用來(lái)防止計(jì)算log(0)关筒,而增加的一個(gè)修正項(xiàng),即 loss(input,target)=input - target * log(input+eps)杯缺。默認(rèn)為1e^{-8}

5.1 功能

目標(biāo)值為泊松分布的負(fù)對(duì)數(shù)似然損失

5.2 公式

\text{target} \sim \mathrm{Poisson}(\text{input})

\text{loss}(\text{input}, \text{target})= \text{input} - \text{target} * \log(\text{input})+ \log(\text{target!})

其中蒸播,上式的最后一項(xiàng)能被省略或者使用Stirling formula近似。當(dāng)target的值大于1時(shí)夺谁,使用該近似廉赔;當(dāng)小于或等于1時(shí),將該最后一項(xiàng)加到損失中匾鸥,不近似。
\text{target}*\log(\text{target}) - \text{target} + 0.5 * \log(2\pi\text{target})

5.3 代碼

import torch
import torch.nn as nn
import numpy as np

# ----------------------------------- Poisson NLLLoss
# 生成網(wǎng)絡(luò)輸出 以及 目標(biāo)輸出
log_input = torch.randn(5, 2, requires_grad=True)
target = torch.randn(5, 2)

loss_f = nn.PoissonNLLLoss()
loss = loss_f(log_input, target)
print('\nloss: \n', loss)

輸出結(jié)果:

loss: 
 tensor(1.1533, grad_fn=<MeanBackward0>)

6碉纳、KL 散度損失 KLDivLoss

class torch.nn.KLDivLoss(size_average=None, reduce=None, reduction='mean')

注意:

  • reduction的選項(xiàng)增加了batchmean勿负;
  • reduction = 'mean' doesn't return the true kl divergence value;除 loss總個(gè)數(shù)劳曹;
  • reduction = 'batchmean' which aligns with KL math definition.(目前是這樣的奴愉,后續(xù)版本可能會(huì)改進(jìn));除 batch size 铁孵。

6.1 功能

計(jì)算input和target之間的KL散度( Kullback–Leibler divergence) 锭硼。 KL 散度,又叫做相對(duì)熵蜕劝,算的是兩個(gè)分布之間的距離檀头,越相似則越接近零轰异。KL散度是連續(xù)分布的有用距離度量,在對(duì)連續(xù)輸出分布的空間進(jìn)行直接回歸時(shí)通常很有用暑始。

6.2 公式

1)當(dāng)reduction = 'none'
l(x,y) = L = \{ l_1,\dots,l_N \}, \quad l_n = y_n \cdot \left( \log y_n - x_n \right)

2)當(dāng)reduction不為 'none'搭独,默認(rèn)為'mean'

L = \{ l_1,\dots,l_N \}, \quad l_n = y_n \cdot \left( \log y_n - x_n \right)

\ell(x, y) = \begin{cases} \operatorname{mean}(L), & \text{if reduction} = \text{'mean';} \\ \operatorname{sum}(L), & \text{if reduction} = \text{'sum'}. \\ \end{cases}

6.3 代碼

import torch
import torch.nn as nn
import numpy as np

# -----------------------------------  KLDiv loss
loss_f = nn.KLDivLoss(size_average=False, reduce=False)
loss_f_mean = nn.KLDivLoss(size_average=True, reduce=True)
loss_f_mean_1 = nn.KLDivLoss(reduction='mean')
loss_f_mean_2 = nn.KLDivLoss(reduction='batchmean')

# 生成網(wǎng)絡(luò)輸出 以及 目標(biāo)輸出
output = torch.from_numpy(np.array([[0.1132, 0.5477, 0.3390], [0.1132, 0.5477, 0.3390]])).float()
output.requires_grad = True
target = torch.from_numpy(np.array([[0.8541, 0.0511, 0.0947], [0.1132, 0.5477, 0.3390]])).float()

loss_1 = loss_f(output, target)
loss_mean = loss_f_mean(output, target)
loss_mean_1 = loss_f_mean_1(output, target)
loss_mean_2 = loss_f_mean_2(output, target)

print('\nloss: ', loss_1)
print('\nloss_mean: ', loss_mean)
print('\nloss_mean_1: ', loss_mean_1)  # 除 總損失個(gè)數(shù)
print('\nloss_mean_2: ', loss_mean_2)  # 這是真正數(shù)學(xué)上KL散度的定義,除 batch size
print(torch.sum(loss_1) / 6)  # 所以 與 loss_mean_1相等
print(torch.sum(loss_1) / 2)  # 所以 與 loss_mean_2相等

# 熟悉計(jì)算公式廊镜,手動(dòng)計(jì)算樣本的第一個(gè)元素的loss牙肝,注意這里只有一個(gè)樣本,是 element-wise計(jì)算的

output = output[0].detach().numpy()
output_1 = output[0]           # 第一個(gè)樣本的第一個(gè)元素
target_1 = target[0][0].numpy()

loss_1 = target_1 * (np.log(target_1) - output_1)

print('\n第一個(gè)樣本第一個(gè)元素的loss:', loss_1)

輸出結(jié)果:

loss:  tensor([[-0.2314, -0.1800, -0.2553],
        [-0.2594, -0.6297, -0.4816]], grad_fn=<KlDivBackward>)
loss_mean:  tensor(-0.3396, grad_fn=<KlDivBackward>)
loss_mean_1:  tensor(-0.3396, grad_fn=<KlDivBackward>)
loss_mean_2:  tensor(-1.0187, grad_fn=<DivBackward0>)
tensor(-0.3396, grad_fn=<DivBackward0>)
tensor(-1.0187, grad_fn=<DivBackward0>)
第一個(gè)樣本第一個(gè)元素的loss: -0.23138165

7嗤朴、二進(jìn)制交叉熵?fù)p失 BCELoss

class torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean')

7.1 功能

二分類(lèi)任務(wù)時(shí)的交叉熵計(jì)算函數(shù)配椭。此函數(shù)可以認(rèn)為是 nn.CrossEntropyLoss 函數(shù)的特例。其分類(lèi)限定為二分類(lèi)雹姊,y必須是{0,1}股缸。還需要注意的是,input 應(yīng)該為概率分布的形式容为,這樣才符合交叉熵的應(yīng)用乓序。所以在 BCELoss 之前,input一般為 sigmoid 激活層的輸出坎背,官方例子也是這樣給的替劈。該損失函數(shù)在自編碼器中常用

7.2 公式

1)當(dāng)reduction = 'none'
\ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = - w_n \left[ y_n \cdot \log x_n + (1 - y_n) \cdot \log (1 - x_n) \right],
2)當(dāng)reduction 不為 'none'得滤,默認(rèn)為'mean'
L = \{l_1,\dots,l_N\}^\top, \quad l_n = - w_n \left[ y_n \cdot \log x_n + (1 - y_n) \cdot \log (1 - x_n) \right],

\ell(x, y) = \begin{cases} \operatorname{mean}(L), & \text{if reduction} = \text{'mean';}\\ \operatorname{sum}(L), & \text{if reduction} = \text{'sum'.} \end{cases}

7.3 代碼

import torch.nn.functional as F
loss_fn = torch.nn.BCELoss(reduce=False, size_average=False)
input = torch.autograd.Variable(torch.randn(3, 4))
target = torch.autograd.Variable(torch.FloatTensor(3, 4).random_(2))
loss = loss_fn(F.sigmoid(input), target)
print(input); print(target); print(loss)

輸出結(jié)果

tensor([[-1.8626, -0.1685,  1.3190,  0.4265],
        [ 0.3094, -1.2203, -0.4972, -0.4424],
        [-0.1279,  0.4547,  0.7306,  0.0625]])
tensor([[0., 0., 1., 1.],
        [0., 0., 1., 0.],
        [1., 0., 1., 1.]])
tensor([[0.1443, 0.6125, 0.2370, 0.5025],
        [0.8597, 0.2586, 0.9723, 0.4962],
        [0.7591, 0.9461, 0.3931, 0.6624]])

8陨献、BCEWithLogitsLoss

class torch.nn.BCEWithLogitsLoss(weight=None, size_average=None, reduce=None, reduction='mean', pos_weight=None)

8.1 功能

  • Sigmoid層和BCELoss組合成一個(gè)層;
  • This version is more numerically stable than using a plain Sigmoid
    followed by a BCELoss懂更;
  • 將兩個(gè)操作組合成一個(gè)層眨业, we take advantage of the log-sum-exp trick for numerical stability.

8.2 公式

1)當(dāng)reduction = 'none'
\ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = - w_n \left[ y_n \cdot \log \sigma(x_n) + (1 - y_n) \cdot \log (1 - \sigma(x_n)) \right],

2)當(dāng)reduction 不為 'none',默認(rèn)為'mean'
L = \{l_1,\dots,l_N\}^\top, \quad l_n = - w_n \left[ y_n \cdot \log \sigma(x_n) + (1 - y_n) \cdot \log (1 - \sigma(x_n)) \right],

\ell(x, y) = \begin{cases} \operatorname{mean}(L), & \text{if reduction} = \text{'mean';}\\ \operatorname{sum}(L), & \text{if reduction} = \text{'sum'.} \end{cases}

\ell_c(x, y) = L_c = \{l_{1,c},\dots,l_{N,c}\}^\top, \quad l_{n,c} = - w_{n,c} \left[ p_c y_{n,c} \cdot \log \sigma(x_{n,c}) + (1 - y_{n,c}) \cdot \log (1 - \sigma(x_{n,c})) \right],

8.3 代碼

loss = nn.BCEWithLogitsLoss(reduction='none')
input = torch.randn(3, requires_grad=True)
target = torch.empty(3).random_(2)

output = loss(input, target)
print(input); print(target); print(output)

輸出結(jié)果:

tensor([ 0.1099,  1.3278, -0.2820], requires_grad=True)
tensor([0., 0., 0.])
tensor([0.7496, 1.5629, 0.5620],
       grad_fn=<BinaryCrossEntropyWithLogitsBackward>)

9躏啰、MarginRankingLoss

class torch.nn.MarginRankingLoss(margin=0.0, size_average=None, reduce=None, reduction='mean')

計(jì)算兩個(gè)向量之間的相似度赞厕,當(dāng)兩個(gè)向量之間的距離大于margin,則loss為正聘殖,小于margin,loss為0

9.1 公式

\text{loss}(x1, x2, y) = \max(0, -y * (x1 - x2) + \text{margin})

  • inputs :x1, x2, two 1D mini-batch Tensors行瑞;
  • y: a label 1D mini-batch tensor (containing 1 or -1)奸腺;
  • margin:默認(rèn)為0;
  • 當(dāng)y=1時(shí)血久,x1要比x2大突照,且x1 - x2 > margin,才不會(huì)有損失氧吐;
  • 當(dāng)y=-1時(shí)讹蘑,x2要比x1大末盔,且x2 - x1 > margin,才不會(huì)有損失衔肢。

9.2 代碼

loss = nn.MarginRankingLoss(reduction='none')
input1 = torch.randn(3, requires_grad=True)
input2 = torch.randn(3, requires_grad=True) + 0.5
target = torch.empty(3).random_(2)

output = loss(input1, input2, target)
print(input1); print(input2); print(target); print(output)

輸出結(jié)果:

tensor([ 0.2112, -0.0281,  0.5583], requires_grad=True)
tensor([ 1.8994, -0.6425,  0.9355], grad_fn=<AddBackward0>)
tensor([1., 0., 1.])
tensor([1.6882, 0.0000, 0.3772], grad_fn=<ClampMinBackward>)

10庄岖、MultiMarginLoss

多分類(lèi)(multi-class)的 Hinge 損失,

loss(\text{x}, y) = \frac{1}{N} \sum_{i=0, i \neq y}^{n} [\text{max}(0, (\text{margin} - (\text{x}_{y} - \text{x}_i))^{p})]
其中角骤,0 \leq y \leq N -1表示標(biāo)簽隅忿,p默認(rèn)取1,margin默認(rèn)取1邦尊,也可以取別的值背桐。

注意:

  • \text{x}為向量,y為標(biāo)量值蝉揍。

代碼:

loss = nn.MultiMarginLoss()
x = torch.FloatTensor([[0.1, 0.2, 0.4, 0.8]])
y = torch.LongTensor([3])
# 0.25 * ((1 - 0.8 + 0.1) + (1 - 0.8 + 0.2) + (1 - 0.8 + 0.4)) = 0.325
loss(x, y)

11链峭、MultiLabelMarginLoss

class torch.nn.MultiLabelMarginLoss(size_average=None, reduce=None, reduction='mean')

多類(lèi)別(multi-class)多分類(lèi)(multi-classification)的 Hinge 損失,是上面 MultiMarginLoss 在多類(lèi)別上的拓展又沾。同時(shí)限定 p = 1弊仪,margin = 1.

這個(gè)接口有點(diǎn)坑,是直接從 Torch 那里抄過(guò)來(lái)的杖刷,見(jiàn) MultiLabelMarginCriterion 的描述励饵。而 Lua 的下標(biāo)和 Python 不一樣,前者的數(shù)組下標(biāo)是從 1 開(kāi)始的滑燃,所以用 0 表示占位符役听。有幾個(gè)坑需要注意:
loss(\text{x}, \text{y}) = \frac{1}{N} \sum_{i=1, i \neq \text{y}_i}^{n} \sum_{j=1}^{\text{y}_j \neq 0}[\text{max}(0, 1 - (\text{x}_{\text{y}_j} - \text{x}_i))]

  • 這里的 \text{x,y} 都是大小為 N 的向量,如果 \text{y} 不是向量而是標(biāo)量表窘,后面的 \sum_{j=1}就沒(méi)有了典予,因此就退化成上面的MultiMarginLoss;
  • 限制\text{y}的大小為 N乐严,是為了處理多標(biāo)簽中標(biāo)簽個(gè)數(shù)不同的情況瘤袖,用 0 表示占位,該位置和后面的數(shù)字都會(huì)被認(rèn)為不是正確的類(lèi)昂验。如\text{y}=[5,3,0,0,4] 那么就會(huì)被認(rèn)為是屬于類(lèi)別 5 和 3孽椰,而 4 因?yàn)樵诹愫竺妫虼藭?huì)被忽略凛篙。
  • 上面的公式和說(shuō)明只是為了和文檔保持一致,其實(shí)在調(diào)用接口的時(shí)候栏渺,用的是 -1 做占位符呛梆,而 0 是第一個(gè)類(lèi)別。

11.1 公式解析

loss(\text{x}, \text{y}) = \frac{1}{N} \sum_{i=0, i \neq \text{y}_{i}}^{n-1} \sum_{j=0}^{\text{y}_j \neq -1}[\text{max}(0, 1 - (\text{x}_{\text{y}_j} - \text{x}_i))]

  • \text{x,y}形狀相同的向量磕诊,為了維持一致填物,使用-1填充\text{y}纹腌;
  • 對(duì)于真實(shí)標(biāo)簽\text{y},不考慮\text{y}中-1之后的值滞磺;
  • j\text{y}的索引升薯,從0開(kāi)始直到\text{y}_j \neq -1,也就是取\text{y}中-1之前的值击困。例如\text{y} = [3,0,-1,1]涎劈,則j可取0、1阅茶;\text{y}_j可取3蛛枚、0;
  • i\text{x}的索引,i的取值為{0, 1, ..., n-1}中不等于\text{y}_j的值脸哀。

代碼:

loss = nn.MultiLabelMarginLoss()
x = torch.FloatTensor([[0.1, 0.2, 0.4, 0.8]])
# for target y, only consider labels 3 and 0, not after label -1
y = torch.LongTensor([[3, 0, -1, 1]])
# 0.25 * ((1-(0.1-0.2)) + (1-(0.1-0.4)) + (1-(0.8-0.2)) + (1-(0.8-0.4)))
loss(x, y)

代碼中公式:
loss = \frac{1}{4} \sum_{i=1,2} \sum_{j=3,0}[\text{max}(0, 1 - (\text{x}_{j} - \text{x}_i))] = \\ 0.25 * ((1-(0.1-0.2)) + (1-(0.1-0.4)) + (1-(0.8-0.2)) + (1-(0.8-0.4))) = 0.85

12蹦浦、SoftMarginLoss

class nn.SoftMarginLoss(size_average=None, reduce=None, reduction='mean')

多標(biāo)簽二分類(lèi)問(wèn)題,這 N 項(xiàng)都是二分類(lèi)問(wèn)題撞蜂,其實(shí)就是把 N 個(gè)二分類(lèi)的 loss 加起來(lái)盲镶,化簡(jiǎn)一下。其中 \text{y} 只能取 1,?1 兩種蝌诡,代表正類(lèi)和負(fù)類(lèi)溉贿。和下面的其實(shí)是等價(jià)的,只是 \text{y} 的形式不同送漠。

\text{loss}( \text{x}, \text{y}) = \sum_i \frac{\log(1 + \exp(- \text{y} [i]* \text{x} [i]))}{\text{x.nelement}()}

13顽照、MultiLabelSoftMarginLoss

class nn.MultiLabelSoftMarginLoss(
    weight=None,
    size_average=None,
    reduce=None,
    reduction='mean',
)

根據(jù)最大熵的多標(biāo)簽 one-versue-all 損失。

loss(x, y) = - \frac{1}{C} * \sum_i y[i] * \log((1 + \exp(-x[i]))^{-1}) + (1-y[i]) * \log\left(\frac{\exp(-x[i])}{(1 + \exp(-x[i]))}\right)

其中闽寡,i \in \left\{0, \; \cdots , \; \text{x.nElement}() - 1\right\} 代兵;y[i] \in \left\{0, \; 1\right\}

14、CosineEmbeddingLoss

class nn.CosineEmbeddingLoss(
    margin=0.0,
    size_average=None,
    reduce=None,
    reduction='mean',
)

余弦相似度的損失爷狈,目的是讓兩個(gè)向量盡量相近植影。注意這兩個(gè)向量都是有梯度的。

\text{loss}(x, y) = \begin{cases} 1 - \cos(x_1, x_2), & \text{if } y = 1 \\ \max(0, \cos(x_1, x_2) - \text{margin}), & \text{if } y = -1 \end{cases}

margin 可以取 [?1,1]涎永,但是比較建議取 0-0.5 較好思币。

15、HingeEmbeddingLoss

class nn.HingeEmbeddingLoss(
    margin=1.0,
    size_average=None,
    reduce=None,
    reduction='mean',
)

This is usually used for measuring whether two inputs are similar or
dissimilar, e.g. using the L1 pairwise distance as x, and is typically
used for learning nonlinear embeddings or semi-supervised learning.

l_n = \begin{cases} x_n, & \text{if}\; y_n = 1,\\ \max \{0, \Delta - x_n\}, & \text{if}\; y_n = -1, \\ \end{cases}

L = \{l_1,\dots,l_N\}^\top

\ell(x, y) = \begin{cases} \operatorname{mean}(L), & \text{if reduction} = \text{'mean';}\\ \operatorname{sum}(L), & \text{if reduction} = \text{'sum'.} \end{cases}

16羡微、TripleMarginLoss

class nn.TripletMarginLoss(
    margin=1.0,
    p=2.0,
    eps=1e-06,
    swap=False,
    size_average=None,
    reduce=None,
    reduction='mean',
)

L(a, p, n) = \max \{d(a_i, p_i) - d(a_i, n_i) + {\rm margin}, 0\}

d(x_i, y_i) = \left\lVert {\bf x}_i - {\bf y}_i \right\rVert_p

triplet_loss = nn.TripletMarginLoss(margin=1.0, p=2)
anchor = torch.randn(100, 128, requires_grad=True)
positive = torch.randn(100, 128, requires_grad=True)
negative = torch.randn(100, 128, requires_grad=True)
output = triplet_loss(anchor, positive, negative)
output

17谷饿、SmoothL1Loss

class nn.SmoothL1Loss(size_average=None, reduce=None, reduction='mean')

\text{loss}(x, y) = \frac{1}{n} \sum_{i} z_{i}= \begin{cases} 0.5 (x_i - y_i)^2, & \text{if } |x_i - y_i| < 1 \\ |x_i - y_i| - 0.5, & \text{otherwise } \\ \end{cases}

18、CTCLoss

class nn.CTCLoss(blank=0, reduction='mean', zero_infinity=False)

還不要清楚妈倔。博投。。

T = 50      # Input sequence length
C = 20      # Number of classes (including blank)
N = 16      # Batch size
S = 30      # Target sequence length of longest target in batch
S_min = 10  # Minimum target length, for demonstration purposes

# Initialize random batch of input vectors, for *size = (T,N,C)
input = torch.randn(T, N, C).log_softmax(2).detach().requires_grad_()

# Initialize random batch of targets (0 = blank, 1:C = classes)
target = torch.randint(low=1, high=C, size=(N, S), dtype=torch.long)

input_lengths = torch.full(size=(N,), fill_value=T, dtype=torch.long)
target_lengths = torch.randint(low=S_min, high=S, size=(N,), dtype=torch.long)
ctc_loss = nn.CTCLoss()
loss = ctc_loss(input, target, input_lengths, target_lengths)
loss.backward()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盯蝴,一起剝皮案震驚了整個(gè)濱河市毅哗,隨后出現(xiàn)的幾起案子听怕,更是在濱河造成了極大的恐慌,老刑警劉巖虑绵,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尿瞭,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡翅睛,警方通過(guò)查閱死者的電腦和手機(jī)声搁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)宏所,“玉大人酥艳,你說(shuō)我怎么就攤上這事∨乐瑁” “怎么了充石?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)霞玄。 經(jīng)常有香客問(wèn)我骤铃,道長(zhǎng),這世上最難降的妖魔是什么坷剧? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任惰爬,我火速辦了婚禮,結(jié)果婚禮上惫企,老公的妹妹穿的比我還像新娘撕瞧。我一直安慰自己,他們只是感情好狞尔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布丛版。 她就那樣靜靜地躺著,像睡著了一般偏序。 火紅的嫁衣襯著肌膚如雪页畦。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天研儒,我揣著相機(jī)與錄音豫缨,去河邊找鬼。 笑死端朵,一個(gè)胖子當(dāng)著我的面吹牛好芭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播冲呢,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼栓撞,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起瓤湘,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恩尾,沒(méi)想到半個(gè)月后弛说,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翰意,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年木人,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冀偶。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡醒第,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出进鸠,到底是詐尸還是另有隱情稠曼,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布客年,位于F島的核電站霞幅,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏量瓜。R本人自食惡果不足惜司恳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绍傲。 院中可真熱鬧扔傅,春花似錦、人聲如沸烫饼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)枫弟。三九已至邢享,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間淡诗,已是汗流浹背骇塘。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留韩容,地道東北人款违。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像群凶,于是被迫代替她去往敵國(guó)和親插爹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353