激活函数以及损失函数

sigmoid

sigmoid函数和tanh函数是研究早期被广泛使用的2种激活函数。两者都为S型饱和函数。

  1. 当sigmoid 函数输入的值趋于正无穷或负无穷时,梯度会趋近零,从而发生梯度弥散现象
  2. sigmoid函数的输出恒为正值,不是以零为中心的,这会导致权值更新时只能朝一个方向更新,从而影响收敛速度。

tanh激活函数是sigmoid 函数的改进版,是以零为中心的对称函数,收敛速度快,不容易出现 loss 值晃动,但是无法解决梯度弥散的问题

2个函数的计算量都是指数级的,计算相对复杂。softsign 函数是 tanh 函数的改进版,为 S 型饱和函数,以零为中心,值域为(−1,1)。

公式

更多可以直接看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# -*- coding: utf8 -*-
#
import math

import torch
from torch.functional import F

print('sigmoid'.center(60, '-'))


def sigmoid(x):
return 1 / (1 + math.exp(-x))


print(torch.sigmoid(torch.tensor([1., 2.])))
print([sigmoid(1.), sigmoid(2.)])

print('softmax'.center(60, '-'))


def softmax(xs):
z_exp = [math.exp(x) for x in xs]
sum_z_exp = sum(z_exp)
return [_z_exp / sum_z_exp for _z_exp in z_exp]


print(torch.softmax(torch.tensor([1., 2., 7.]), dim=-1))
print(softmax([1., 2., 7.]))

print('tanh'.center(60, '-'))


def tanh(x):
return (math.exp(x) - math.exp(-x)) / (math.exp(x) + math.exp(-x))


print(torch.tanh(torch.tensor([1., 2.])))
print([tanh(1.), tanh(2.)])

print('cross_entropy'.center(60, '-'))
import torch


def my_cross_entropy(input, target, reduction="mean"):
# input.shape: torch.size([-1, class])
# target.shape: torch.size([-1])
# reduction = "mean" or "sum"
# input是模型输出的结果,与target求loss
# target的长度和input第一维的长度一致
# target的元素值为目标class
# reduction默认为mean,即对loss求均值
# 还有另一种为sum,对loss求和

# 这里对input所有元素求exp
exp = torch.exp(input)
# 根据target的索引,在exp第一维取出元素值,这是softmax的分子
tmp1 = exp.gather(1, target.unsqueeze(-1)).squeeze()
# 在exp第一维求和,这是softmax的分母
tmp2 = exp.sum(1)
# softmax公式:ei / sum(ej)
softmax = tmp1 / tmp2
# cross-entropy公式: -yi * log(pi)
# 因为target的yi为1,其余为0,所以在tmp1直接把目标拿出来,
# 公式中的pi就是softmax的结果
log = -torch.log(softmax)
# 官方实现中,reduction有mean/sum及none
# 只是对交叉熵后处理的差别
if reduction == "mean":
return log.mean()
else:
return log.sum()

# example1
# input = torch.randn(3, 5,)
# target = torch.randint(5, (3,), dtype=torch.int64)
# example2
input = torch.tensor([[0.1, 0.9], [0.9, 0.1]])
target = torch.tensor([1, 0])
# example3
# input = torch.tensor([[0., 1.], [1., 0.]])
# target = torch.tensor([1, 0])
loss1_mean = F.cross_entropy(input, target)
loss2_mean = my_cross_entropy(input, target)
print(loss1_mean)
print(loss2_mean)

loss1_sum = F.cross_entropy(input, target, reduction="sum")
loss2_sum = my_cross_entropy(input, target, reduction="sum")
print(loss1_sum)
print(loss2_sum)


def bce_loss_with_logit(y_pred, y_true, reduction='mean'):
y_pred = sigmoid(y_pred)

loss = -y_true * torch.log(y_pred) - (1 - y_true) * torch.log(1 - y_pred)
if reduction == 'mean':
return torch.mean(loss)
raise NotImplementedError

交叉熵

有木有发现,伯努利分布加上log就是交叉熵。

另外其实可以理解交叉熵就是极大似然估计加上log。

如何解释梯度消失呢?

描述

梯度消失是指模型在反向传播的过程中,更上层模型获取到的梯度值越来越小,导致更上层的权重基本保持不变,导致整个模型无法正常收敛以及训练。

原因?
其出现原因在Xavier Glorot和Yoshua Bengio在2010年的一篇论文中阐述了一些观点,包含像当时流行的sigmoid激活函数以及均值为0标准差为1的权重初始化方案,每层输出的方差远大于输入的方差,随着网络的延伸,方差在每一层之后都会增加,直到激活函数在顶层达到饱和为止。而实际像simoid这种激活函数随x的增大其导数值趋向于0,导致在反向传播的过程中,基本没有什么可以传播回去。

解决方式?

他提出应该在每一层网络的输出的方差等于其输入的方差。但是除非该层具有相等数量的输入和神经元,否则这条条件无法满足,故提出一些这种方案,像Xavier初始化或者Glorot初始化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值