DeepLearning(1)

数据操作

numpy数据操作

创建数组

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
import numpy as np

# 给定值创建
x = np.array([1,2,3])
print(x)
> [1,2,3]

# 创建未初始化array 随机值 dtype指定数据类型
x = np.empty([3,2],dtype=int)
print(x)
> [[6917529027641081856,5764616291768666155],[ 6917529027641081859,-5764598754299804209],[ 4497473538,844429428932120]]

## 创建指定形状数组,内容全0,默认浮点数 设置数据类型dtype=np.int
x = np.zeros(shape,dtype=float)

# 同上,内容全1
x = np.ones(shape,dtype=float)

# 将其他类型数组转换为numpy类型的数组
x = [1,2,3]
x = np.asarray(x)
x
> array([1,2,3])

# 按指定范围生成数组 dtype=int设置数据类型
x = np.arange(5)
x
> array([0,1,2,3,4])

数组属性

1
2
3
x = np.array([1,2,3])
print('数组形状:',x.shape,'数组元素个数:',x.size,'数组秩:',x.ndim,'数组元素类型:',x.dtype)
> 数组形状:(1,)数组元素个数:3数组秩:1数组元素类型:int

数组操作

1
2
3
4
5
# 不改变数据内容改变数据形状
x = np.arange(4)
y = x.reshape(2,2)
print(y)
> [[0,1],[2,3]]

数组统计函数

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
'''
numpy.amin() 用于计算数组中的元素沿指定轴的最小值。
numpy.amax() 用于计算数组中的元素沿指定轴的最大值。
numpy.median() 函数用于计算数组 a 中元素的中位数(中值)。
numpy.mean()函数返回数组中元素的算术平均值。 如果提供了轴,则沿其计算。算术平均值是沿轴的元素的总和除以元素的数量。
numpy.average() 函数根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。该函数可以接受一个轴参数。 如果没有指定轴,则数组会被展开。
np.var([1,2,3,4]) 计算所有元素的方差
'''
a = np.array([[3,7,5],[8,4,3],[2,4,9]])
print ('我们的数组是:')
print (a)
print ('\n')
print ('调用 amin() 函数:')
print (np.amin(a,1))
print ('\n')
print ('再次调用 amin() 函数:')
print (np.amin(a,0))
print ('\n')
print ('调用 amax() 函数:')
print (np.amax(a))
print ('\n')
print ('再次调用 amax() 函数:')
print (np.amax(a, axis = 0))

> 我们的数组是:
[[3 7 5]
[8 4 3]
[2 4 9]]


调用 amin() 函数:
[3 3 2]


再次调用 amin() 函数:
[2 4 3]


调用 amax() 函数:
9


再次调用 amax() 函数:
[8 7 9]

tensor数据操作

官方文档

Tensor和tensor的区别

参考: pytorch中Tensor与tensor有什么区别

pytorch搭建神经网络

构建网络层

pytorch是通过模型Module来构建神经网络的层次。

torch.nn.Module

不管是全连接层,还是卷积层等等,都可以通过Module调用,并且可以自动backward。相当于所有网络模型的一个基本支撑,是他们的父类。

Ex:实现LinearModule过程分析与原理

1
2
3
4
5
6
7
8
9
10
import torch

class LinearModule(torch.nn.Module):
def __init__(self):
super(LinearModel,self).__init__()
self.linear = torch.nn.Linear(1,1)

def forward(self,x):
y_pred = self.linear(x)
return y_pred

这是一个线性模型的实现过程,通过继承Module类实现一个linearModule类。实现了构造方法和重写forward方法。

构造方法使用继承父类的构造函数,并实现Linear类,forward函数实现了前向传播计算方法,说到Linear类我们可以点进去分析一下他的源码是怎么实现的:

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
class Linear(Module):
r"""Applies a linear transformation to the incoming data: :math:`y = xA^T + b`
在这里的注释我们可以看到linear里面就是的是一个一次线性函数 ,简单来说就是 y = x*W + b / W^T*x + b
W权重(A的转置)是取自输入x的尺寸的倒数再开方后的正负值之间的均匀分布

Args:
输入样本的维度
in_features: size of each input sample
输出的维度,也就是最后的输出结果,如果是分类就是分类种类
out_features: size of each output sample
偏差,就是b
bias: If set to ``False``, the layer will not learn an additive bias.
Default: ``True``

Shape:
- Input: :math:`(N, *, H_{in})` where :math:`*` means any number of
additional dimensions and :math:`H_{in} = \text{in\_features}`
- Output: :math:`(N, *, H_{out})` where all but the last dimension
are the same shape as the input and :math:`H_{out} = \text{out\_features}`.

Attributes:
weight: the learnable weights of the module of shape
:math:`(\text{out\_features}, \text{in\_features})`. The values are
initialized from :math:`\mathcal{U}(-\sqrt{k}, \sqrt{k})`, where
:math:`k = \frac{1}{\text{in\_features}}`
bias: the learnable bias of the module of shape :math:`(\text{out\_features})`.
If :attr:`bias` is ``True``, the values are initialized from
:math:`\mathcal{U}(-\sqrt{k}, \sqrt{k})` where
:math:`k = \frac{1}{\text{in\_features}}`

Examples: 这个例子很好的表明了使用方法,过程就是通过矩阵乘法将输入特征转换为输出特征

输入样本为20维特征大小,输出样本大小为30
>>> m = nn.Linear(20, 30)
用(128,20)的tensor模拟128个20维特征的数据集
>>> input = torch.randn(128, 20)
将数据输入module并获取输出样本output
>>> output = m(input)
输出样本形状
>>> print(output.size())
128个30维的数据
torch.Size([128, 30])
"""
__constants__ = ['in_features', 'out_features']
in_features: int
out_features: int
# 注意这里的weight是一个Tensor类型
weight: Tensor

def __init__(self, in_features: int, out_features: int, bias: bool = True) -> None:
super(Linear, self).__init__()
self.in_features = in_features
self.out_features = out_features
# 这里定义weight是一个[in_features,out_features]的矩阵,然后与input做矩阵相乘输出结果为[n,outfeatures]形状
self.weight = Parameter(torch.Tensor(out_features, in_features))
if bias:
self.bias = Parameter(torch.Tensor(out_features))
else:
self.register_parameter('bias', None)
self.reset_parameters()

def reset_parameters(self) -> None:
init.kaiming_uniform_(self.weight, a=math.sqrt(5))
if self.bias is not None:
fan_in, _ = init._calculate_fan_in_and_fan_out(self.weight)
bound = 1 / math.sqrt(fan_in)
init.uniform_(self.bias, -bound, bound)

# 这里注意forward返回值为Tensor类型
def forward(self, input: Tensor) -> Tensor:
# 这里对应上面的y_pred = self.linear(x),可以看到是调用了F(torch.nn.functional).linear方法,将返回一个通过线性计算后的值也就是y_pred,如果需要自定义函数可以自己通过重写forward函数,不过也需要在functional中实现,并且实现梯度下降backward!
return F.linear(input, self.weight, self.bias)

def extra_repr(self) -> str:
return 'in_features={}, out_features={}, bias={}'.format(
self.in_features, self.out_features, self.bias is not None
)

Loss-Function and optimizer

Loss-Function

网络层模型构建完,接下来就是选择损失函数与优化器,损失函数作为衡量输出值与实际值偏差的大小,是根据模型进行选择。

在这里线性模型使用的是mse_loss 均方损失函数,这个函数常用在回归问题中:

$$
Loss = (\frac1N)\displaystyle\sum^N_iloss_i|\begin{bmatrix}\hat{loss_1}\\hat{loss_2}\\hat{loss_3}\\vdots \end{bmatrix} = ( \begin{bmatrix}\hat{y_1}\\hat{y_2}\\hat{y_3}\\vdots \end{bmatrix} - \begin{bmatrix}{y_1}\{y_2}\{y_3}\\vdots \end{bmatrix})^2
$$

这1/N可有可无,就是对所有损失做一个均值,这个在使用函数中有参数选择:

1
2
3
4
# size_average 是否求均值,默认为True		reduce 是否求和,默认为True
criterion = torch.nn.MSELoss(size_average=True,reduce=True)
# 使用时需要两个参数 输出值 和 实际值 -> Tensor
criterion(y_perd,y)

还有很多常用的损失函数:

  1. CrossEntropyLoss-交叉熵:交叉熵损失函数,刻画的是实际输出(概率)与期望输出(概率)分布的距离,也就是交叉熵的值越小,两个概率分布就越接近,多用在多分类问题中。
  2. BCELoss-二分类交叉熵:二分类交叉熵把 y , 1 − y {y, 1-y}y,1−y 当做两项分布,计算出来的loss就比交叉熵大(因为包含了正类和负类的交叉熵了)

等等…

这篇博客介绍了pytorch中的loss函数,可做参考,这里不再一一列举。

pytorch-Loss function

optimizer

接下来就是优化器选择,它不属于.nn包下,它在 torch.optim. 下,下面是在定义loss后的优化器代码。

这段代码是实例化一个SGD的类,lr表示学习率,也称为步长,momentum表示动量。

1
optimizer = torch.optim.SGD(module.parameters(),lr=0.01,momentum=0.5)

这里我们看到SGD这个类传入了三个参数,一个是module的parameters方法返回值,还有两个是学习率和动量,这个module.parameters()我们也可以点进去看一下它的源码到底是什么:

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
def parameters(self, recurse: bool = True) -> Iterator[Parameter]:
r"""Returns an iterator over module parameters.

This is typically passed to an optimizer.

Args:
recurse (bool): if True, then yields parameters of this module
and all submodules. Otherwise, yields only parameters that
are direct members of this module.

Yields:
Parameter: module parameter

Example::

>>> for param in model.parameters():
>>> print(type(param), param.size())
<class 'torch.Tensor'> (20L,)
<class 'torch.Tensor'> (20L, 1L, 5L, 5L)

"""
for name, param in self.named_parameters(recurse=recurse):
yield param

def named_parameters(self, prefix: str = '', recurse: bool = True) -> Iterator[Tuple[str, Tensor]]:
r"""Returns an iterator over module parameters, yielding both the
name of the parameter as well as the parameter itself.

Args:
prefix (str): prefix to prepend to all parameter names.
recurse (bool): if True, then yields parameters of this module
and all submodules. Otherwise, yields only parameters that
are direct members of this module.

Yields:
(string, Parameter): Tuple containing the name and parameter

Example::

>>> for name, param in self.named_parameters():
>>> if name in ['bias']:
>>> print(param.size())

"""
gen = self._named_members(
lambda module: module._parameters.items(),
prefix=prefix, recurse=recurse)
for elem in gen:
yield elem

可以看到注释介绍了parameter是表示组成module的参数,在linear模型中就表示w和b,它的特点是默认requires_grad=True,就是在训练过程中的反向传播,在反向传播过程中调整w和b。pytoch中有很多优化器模型,这里使用的SGD是随机梯度下降,可以选择动量。

pytoch常用的优化器有:

  1. SGD-随机梯度下降
  2. Momentum-标准动量优化算法
  3. RMSProp算法
  4. Adam

优化器算法对比参考

实现

1
2
3
4
5
6
7
8
9
for epoch in range(10000):
y_pred = module(x_data)
loss = criterion(y_pred,y_data)
print('\tepoch:',epoch+1,'loss value:',loss.item())

# 这一步必须将优化器梯度清零
optimizer.zero_grad()
loss.backward()
optimizer.step()

zero_grad()作用:

根据pytorch中backward()函数的计算,当网络参量进行反馈时,梯度是累积计算而不是被替换,但在处理每一个batch时并不需要与其他batch的梯度混合起来累积计算,因此需要对每个batch调用一遍zero_grad()将参数梯度置0.

​ 另外,如果不是处理每个batch清除一次梯度,而是两次或多次再清除一次,相当于提高了batch_size,对硬件要求更高,更适用于需要更高batch_size的情况

完整模型

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
import torch
import torch.nn.functional as F

x_data = torch.Tensor([[1.0],[2.0],[3.0],[4.0]])
y_data = torch.Tensor([[0],[0],[1],[1]])


class LinearModule(torch.nn.Module):
def __init__(self):
super(LinearModule,self).__init__()
# Linear(rank,kinds)
self.linear = torch.nn.Linear(1,1)

#
def forward(self,x):
# sigmoid激活函数,把通过linear线性变化的数据做非线性变化,为了更好的降维和拟合
y_pred = F.sigmoid(self.linear(x))
return y_pred
module = LinearModule()

'''
criterion is : the value of y_data[i] and the y_pred in model counted by a specific loss_function
ex :
return (y_pred - y) ** 2

optimizer is:
'''
criterion = torch.nn.BCELoss(size_average=False)
optimizer = torch.optim.SGD(module.parameters(),lr=0.01)

for epoch in range(10000):
y_pred = module(x_data)
loss = criterion(y_pred,y_data)
print('\tepoch:',epoch+1,'loss value:',loss.item())

optimizer.zero_grad()
loss.backward()
optimizer.step()
0%