1. 基础知识
1. 张量
1.初始化
torch.rand(col, row) # 使用(0~1)均匀分布随机初始化二维数组
torch.ones(col, row) # 填充1初始化
torch.zero(col, row) # 填充0初始化
torch.eye(col, row) # 对角线为一,其它为0初始化
2.基本类型
tensor = torch.tensor([3.1433223])
torch.DoubleTensor(col, row) # 64位浮点
torch.FloatTensor(col, row) # 32位浮点
torch.HalfTensor(col, row) # 16位浮点
torch.LongTensor(col, row) # 64位整数
torch.IntTensor(col, row) # 32位整数
torch.ShortTensor(col, row) # 16位整数
torch.CharTensor(col, row) # 8位整数(带符号)
torch.ByteTensor(col, row) # 8位整数(无符号)
#转换
tensor.long() # 64位整数
tensor.int() # 32位整数
tensor.short() # 16位整数
tensor.double() # 64位浮点
tensor.float() # 32位浮点
tensor.half() # 16位浮点
tensor.cahr() # 8位整数(带符号)
tensor.byte() # 8位整数(无符号)
3.Numpy转换
torch.XXX(col, row).numpy() # tensor转换为numpy
torch.from_numpy(numpy.XXX((col, row))) # numpy转换为tensor
4.设备间转换
gpu_a=cpu_a.cuda() # cup转gpu
cpu_a=gpu_a.cpu() # gpu转cpu
5.常用方法
max_value, max_idx = torch.max(input, dim=0) # max_value最大值,max_idx最大值索引,dim 1为行、0为列
sum_x = torch.sum(input, dim=1) # sum_x求和,dim 1为行、0为列
x.add_(y) # 将y加到a中
2.Autograd
在张量创建时,通过设置 requires_grad 标识为Ture来告诉Pytorch需要对该张量进行自动求导。
当计算完成后调用.backward()方法自动计算梯度并且将计算结果保存到grad属性中。
使用with torch.no_grad()上下文管理器临时禁止对已设置requires_grad=True的张量进行自动求导
x = torch.rand(5, 5, requires_grad=True)
y = torch.rand(5, 5, requires_grad=True)
z=torch.sum(x+y)
z.backward()
print(x.grad,y.grad)
with torch.no_grad()
print((x +y*2).requires_grad) # False
3.神经网络包nn和优化器optm
1. 定义一个网络
class Net(nn.Module):
def __init__(self):
# nn.Module子类的函数必须在构造函数中执行父类的构造函数
super(Net, self).__init__()
# 卷积层 '1'表示输入图片为单通道, '6'表示输出通道数,'3'表示卷积核为3*3
self.conv1 = nn.Conv2d(1, 6, 3)
#线性层,输入1350个特征,输出10个特征
self.fc1 = nn.Linear(1350, 10) #这里的1350是如何计算的呢?这就要看后面的forward函数
#正向传播
def forward(self, x):
print(x.size()) # 结果:[1, 1, 32, 32]
# 卷积 -> 激活 -> 池化
x = self.conv1(x) #根据卷积的尺寸计算公式,计算结果是30,具体计算公式后面第二章第四节 卷积神经网络 有详细介绍。
x = F.relu(x)
print(x.size()) # 结果:[1, 6, 30, 30]
x = F.max_pool2d(x, (2, 2)) #我们使用池化层,计算结果是15
x = F.relu(x)
print(x.size()) # 结果:[1, 6, 15, 15]
# reshape,‘-1’表示自适应
#这里做的就是压扁的操作 就是把后面的[1, 6, 15, 15]压扁,变为 [1, 1350]
x = x.view(x.size()[0], -1)
print(x.size()) # 这里就是fc1层的的输入1350
x = self.fc1(x)
return x
net = Net()
print(net)
input = torch.randn(1, 1, 32, 32) # 这里的对应前面forward的输入是32
out = net(input)
# 在反向传播前,先要将所有参数的梯度清零
net.zero_grad()
out.backward(torch.ones(1,10)) # 反向传播的实现是PyTorch自动实现的,我们只要调用这个函数即可
2.损失函数
在nn中PyTorch还预制了常用的损失函数
nn.L1Loss L1损失函数
l
o
s
s
(
x
i
,
y
i
)
=
v
m
a
t
r
i
x
x
i
−
y
i
∣
loss(x_i,y_i) = vmatrixx_i-y_i|
loss(xi,yi)=vmatrixxi−yi∣
nn.MSELoss L2损失函数
l
o
s
s
(
x
i
,
y
i
)
=
(
x
i
−
y
i
)
2
loss(x_i,y_i) = (x_i-y_i)^2
loss(xi,yi)=(xi−yi)2
nn.SmoothL1Loss Huber Loss损失函数
l
o
s
s
(
x
i
,
y
i
)
=
{
1
2
(
x
i
−
y
i
)
2
i
f
∣
x
i
−
y
i
∣
<
1
∣
x
i
−
y
i
∣
−
1
2
otherwise
loss(x_i,y_i) = \begin{cases} \frac{1}{2}(x_i-y_i)^2& {if|x_i-y_i|<1}\\ |x_i-y_i| - \frac{1}{2}& \text{otherwise} \end{cases}
loss(xi,yi)={21(xi−yi)2∣xi−yi∣−21if∣xi−yi∣<1otherwise
nn.BCELoss 二分类交叉熵损失函数
l
o
s
s
(
x
i
,
y
i
)
=
−
ω
i
[
y
i
l
o
g
x
i
+
(
1
−
y
i
)
l
o
g
(
1
−
x
i
)
]
loss(x_i,y_i)=-\omega_i[y_ilogx_i+(1-y_i)log(1-x_i)]
loss(xi,yi)=−ωi[yilogxi+(1−yi)log(1−xi)]
y = torch.arange(0,10).view(1,10).float()
criterion = nn.MSELoss()
loss = criterion(out, y)
#loss是个scalar,我们可以直接用item获取到他的python类型的数值
3.优化器
在反向传播计算完所有参数的梯度后,还需要使用优化方法来更新网络的权重和参数
-
SGD
torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0, nesterov=False)
-
AdaGrad
torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0, initial_accumulator_value=0)
-
RMSProp
torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)
-
Adam
torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False)
import torch.optim out = net(input) # 这里调用的时候会打印出我们在forword函数中打印的x的大小 criterion = nn.MSELoss() loss = criterion(out, y) # 新建一个优化器,SGD只需要要调整的参数和学习率 optimizer = torch.optim.SGD(net.parameters(), lr = 0.01) # 先梯度清零(与net.zero_grad()效果一样) optimizer.zero_grad() loss.backward() # 更新参数 optimizer.step()
4.数据的加载和预处理
1.Dataset
Dataset是一个抽象类,为了能够方便的读取,需要将要使用的数据包装为Dataset类。
from torch.utils.data import Dataset
import pandas as pd
#定义一个数据集
class BulldozerDataset(Dataset):
""" 数据集演示 """
def __init__(self, csv_file):
"""实现初始化方法,在初始化的时候将数据读载入"""
self.df=pd.read_csv(csv_file)
def __len__(self):
'''
返回df的长度
'''
return len(self.df)
def __getitem__(self, idx):
'''
根据 idx 返回一行数据
'''
return self.df.iloc[idx].SalePrice
ds_demo= BulldozerDataset('median_benchmark.csv')
#实现了 __len__ 方法所以可以直接使用len获取数据总数
len(ds_demo)
#用索引可以直接访问对应的数据,对应 __getitem__ 方法
ds_demo[0]
2. Dataloader
对Dataset的读取操作,常用参数有:batch_size(每个batch的大小)、 shuffle(是否进行shuffle操作)、 num_workers(加载数据的时候使用几个子进程)。
dl = torch.utils.data.DataLoader(ds_demo, batch_size=10, shuffle=True, num_workers=0)
idata=iter(dl) # 获得dl一批数据
3.torchvision 包
PyTorch中专门用来处理图像的库
1.torchvision.datasets
PyTorch团队自定义的dataset,这些dataset帮我们提前处理好了很多的图片数据集
MNIST,COCO,Captions,Detection,LSUN,ImageFolder,Imagenet-12,CIFAR,STL10,SVHN,PhotoTour
import torchvision.datasets as datasets
trainset = datasets.MNIST(root='./data', # 表示 MNIST 数据的加载的目录
train=True, # 表示是否加载数据库的训练集,false的时候加载测试集
download=True, # 表示是否自动下载 MNIST 数据集
transform=None) # 表示是否需要对数据进行预处理,none为不进行预处理
2.torchvision.models
不仅提供了常用图片数据集,还提供了训练好的模型
AlexNet,VGG,ResNet,SqueezeNet,DenseNet
import torchvision.models as models
resnet18 = models.resnet18(pretrained=True)
3.torchvision.transforms
提供了一般的图像转换操作类,用作数据处理和数据增强
2.基础及数学原理
1. 监督学习和无监督学习
- 监督学习:通过已有的训练样本去训练得到一个最优模型。
- 无监督学习:直接对数据进行建模。
- 半监督学习:在训练阶段结合了大量未标记的数据和少量标签数据。
- 强化学习:设定一个回报函数(reward function),通过这个函数来确认否越来越接近目标
2.线性回归
性回归分析:自变量与因变量关系可用一条线近似表示
3. 损失函数(Loss Function)
常见(PyTorch内置)的损失函数:
1. nn.L1Loss:
l o s s ( x , y ) = 1 / n ∑ ∣ x i − y i ∣ loss(x,y)=1/n\sum|x_i-y_i| loss(x,y)=1/n∑∣xi−yi∣
2. 负对数似然损失函数nn.NLLLoss:
用于多分类的负对数似然损失函数
l
o
s
s
(
x
,
c
l
a
s
s
)
=
−
x
[
c
l
a
s
s
]
loss(x, class) = -x[class]
loss(x,class)=−x[class]
如果传递了weights参数,会对损失进行加权
l
o
s
s
(
x
,
c
l
a
s
s
)
=
−
w
e
i
g
h
t
s
[
c
l
a
s
s
]
∗
x
[
c
l
a
s
s
]
loss(x, class) = -weights[class] * x[class]
loss(x,class)=−weights[class]∗x[class]
3. 均方损失函数nn.MSELoss:
l o s s ( x , y ) = 1 / n ∑ ( x i − y i ) 2 loss(x,y)=1/n\sum(x_i-y_i)^2 loss(x,y)=1/n∑(xi−yi)2
4. 多分类用的交叉熵损失函数nn.CrossEntropyLoss:
多分类用的交叉熵损失函数,LogSoftMax和NLLLoss集成到一个类中,会调用nn.NLLLoss函数,我们可以理解为CrossEntropyLoss()=log_softmax() + NLLLoss()
l
o
s
s
(
x
,
c
l
a
s
s
)
=
−
log
e
x
p
(
x
[
c
l
a
s
s
]
)
∑
j
e
x
p
(
x
[
j
]
)
)
=
−
x
[
c
l
a
s
s
]
+
l
o
g
(
∑
j
e
x
p
(
x
[
j
]
)
)
\begin{aligned} loss(x, class) &= -\text{log}\frac{exp(x[class])}{\sum_j exp(x[j]))}\ &= -x[class] + log(\sum_j exp(x[j])) \end{aligned}
loss(x,class)=−log∑jexp(x[j]))exp(x[class]) =−x[class]+log(j∑exp(x[j]))
5. nn.BCELoss:
计算 x 与 y 之间的二进制交叉熵。
l
o
s
s
(
o
,
t
)
=
−
1
n
∑
i
(
t
[
i
]
∗
l
o
g
(
o
[
i
]
)
+
(
1
−
t
[
i
]
)
∗
l
o
g
(
1
−
o
[
i
]
)
)
loss(o,t)=-\frac{1}{n}\sum_i(t[i]* log(o[i])+(1-t[i])* log(1-o[i]))
loss(o,t)=−n1i∑(t[i]∗log(o[i])+(1−t[i])∗log(1−o[i]))
与NLLLoss类似,也可以添加权重参数
l
o
s
s
(
o
,
t
)
=
−
1
n
∑
i
w
e
i
g
h
t
s
[
i
]
∗
(
t
[
i
]
∗
l
o
g
(
o
[
i
]
)
+
(
1
−
t
[
i
]
)
∗
l
o
g
(
1
−
o
[
i
]
)
)
loss(o,t)=-\frac{1}{n}\sum_iweights[i]* (t[i]* log(o[i])+(1-t[i])* log(1-o[i]))
loss(o,t)=−n1i∑weights[i]∗(t[i]∗log(o[i])+(1−t[i])∗log(1−o[i]))
4. 梯度下降
1. 梯度:
几何上讲,梯度就是函数变化增加最快的地方,沿着梯度向量的方向,更加容易找到函数的最大值。反过来说,沿着梯度向量相反的方向梯度减少最快,也就是更加容易找到函数的最小值。
2. Mini-batch的梯度下降法
如果训练数据集很大的时候处理速度会很慢,而且也不可能一次的载入到内存或者显存中,所以我们会把大数据集分成小数据集,一部分一部分的训练,这个训练子集即称为Mini-batch。
- 如果训练样本的大小比较小时,能够一次性的读取到内存中,那我们就不需要使用Mini-batch,
- 如果训练样本的大小比较大时,一次读入不到内存或者现存中,那我们必须要使用 Mini-batch来分批的计算
3. torch.optim
一个实现了各种优化算法的库。
1. 随机梯度下降算法SGD
不推荐
torch.optim.SGD(params,lr=<requiredparameter>,momentum=0,dampening=0,weight_decay=0,nesterov=False)
2. 随机平均梯度下降ASGD
很少见
torch.optim.ASGD(params, lr=0.01, lambd=0.0001, alpha=0.75, t0=1000000.0, weight_decay=0)
3. AdaGrad算法
优点:它可以自动调节学习率,不需要人为调节
缺点:仍依赖于人工设置一个全局学习率,随着迭代次数增多,学习率会越来越小,最终会趋近于0
不推荐
torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0)
4. AdaDelta算法
是Adagard的改进版,对学习率进行自适应约束,但是进行了计算上的简化,加速效果不错,训练速度快
优点:避免在训练后期,学习率过小;初期和中期,加速效果不错,训练速度快
缺点:还是需要自己手动指定初始学习率,初始梯度很大的话,会导致整个训练过程的学习率一直很小,在模型训练的后期,模型会反复地在局部最小值附近抖动,从而导致学习时间变长
可以试一试更好的
torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e-06, weight_decay=0)
5. Rprop(弹性反向传播)
不推荐优化方法适用于full-batch,不适用于mini-batch,因此基本上没什么用
torch.optim.Rprop(params, lr=0.01, etas=(0.5, 1.2), step_sizes=(1e-06, 50))
6. RMSProp均方根传递
RProp的改进版,也是Adagard的改进版
优点:可缓解Adagrad学习率下降较快的问题,并且引入均方根,可以减少摆动,适合处理非平稳目标,对于RNN效果很好
缺点:依然依赖于全局学习率
推荐
torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)
7. Adam
将Momentum算法和RMSProp算法结合起来使用的一种算法
基本上是最最常用的优化方法
torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)
8. Adamax
Adam的改进版,对Adam增加了一个学习率上限的概念
是Adam的一个变种,差不了多少
torch.optim.Adamax(params, lr=0.002, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)
9. SparseAdam
针对稀疏张量的一种“阉割版”Adam优化方法
推荐,在处理稀疏张量的时候尤其推荐
torch.optim.SparseAdam(params,lr=0.001,betas=(0.9,0.999),eps=1e-08)
10. AdamW
Adam的进化版,是目前训练神经网络最快的方式
优点:比Adam收敛得更快
缺点:只有fastai使用,缺乏广泛的框架,而且也具有很大的争议性
torch.optim.AdamW(params,lr=0.001,betas=(0.9,0.999),eps=1e-08,weight_decay=0.01,amsgrad=False)
11. L-BFGS
torch.optim.LBFGS(params, lr=1, max_iter=20, max_eval=None, tolerance_grad=1e-05, tolerance_change=1e-09, history_size=100,line_search_fn=None)
5. 方差/偏差
- 偏差度量了学习算法的期望预测与真实结果的偏离程序,即刻画了学习算法本身的拟合能力
- 方差度量了同样大小的训练集的变动所导致的学习性能的变化,即模型的泛化能力
高偏差:(错误值过多)欠拟合。
增加网络结构,如增加隐藏层数目。
训练更长时间。
寻找合适的网络架构,使用更大的NN结构。
高方差:(将偏离过多的量拟合)过拟合。
使用更多的数据。
正则化( regularization)。
寻找合适的网络结构。
6. 正则化
减小方差的策略。
torch.optim集成的`优化器只有L2正则化方法
3 神经网络简介
1. 神经网络的表示
将神经元拼接起来,两层神经元,即输入层+输出层(M-P神经元),构成感知机。输入层与输出层之间的所有层神经元,称为隐藏层
![](https://i-blog.csdnimg.cn/blog_migrate/024c30c242963ea7f8b997c11182afc5.jpeg)
2. 激活函数
激活函数都是非线性的
1. sigmoid 函数
a = 1 1 + e − z a=\frac{1}{1+e^{-z}} a=1+e−z1 导数 : a ′ = a ( 1 − a ) a^\prime =a(1 - a) a′=a(1−a)
![sigmoid_函数](https://i-blog.csdnimg.cn/blog_migrate/8e6fd8cae4a807c0107f9348280d27c3.png)