总结:今天队伍的进度是第六章 PyTorch进阶训练技巧,主要内容见后,但因为我没打好Pytorch基础,所以我学习了 第二章Pytorch基础知识,同见后。
PyTorch在torch.nn模块为我们提供了许多常用的损失函数,比如:MSELoss,L1Loss,BCELoss… 但是随着深度学习的发展,出现了越来越多的非官方提供的Loss,比如DiceLoss,HuberLoss,SobolevLoss… 这些Loss Function专门针对一些非通用的模型,PyTorch不能将他们全部添加到库中去,因此这些损失函数的实现则需要我们通过自定义损失函数来实现。另外,在科学研究中,我们往往会提出全新的损失函数来提升模型的表现,这时我们既无法使用PyTorch自带的损失函数,也没有相关的博客供参考,此时自己实现损失函数就显得更为重要了。
经过本节的学习,你将收获:
学习率的选择是深度学习中一个困扰人们许久的问题,学习速率设置过小,会极大降低收敛速度,增加训练时间;学习率太大,可能导致参数在最优解两侧来回振荡。但是当我们选定了一个合适的学习率后,经过许多轮的训练后,可能会出现准确率震荡或loss不再下降等情况,说明当前学习率已不能满足模型调优的需求。此时我们就可以通过一个适当的学习率衰减策略来改善这种现象,提高我们的精度。这种设置方式在PyTorch中被称为scheduler,也是我们本节所研究的对象。
经过本节的学习,你将收获:
随着深度学习的发展,模型的参数越来越大,许多开源模型都是在较大数据集上进行训练的,比如Imagenet-1k,Imagenet-11k,甚至是ImageNet-21k等。但在实际应用中,我们的数据集可能只有几千张,这时从头开始训练具有几千万参数的大型神经网络是不现实的,因为越大的模型对数据量的要求越大,过拟合无法避免。
假设我们想从图像中识别出不同种类的椅⼦,然后将购买链接推荐给用户。一种可能的方法是先找出100种常见的椅子,为每种椅子拍摄1000张不同⻆度的图像,然后在收集到的图像数据集上训练一个分类模型。这个椅子数据集虽然可能比Fashion-MNIST数据集要庞⼤,但样本数仍然不及ImageNet数据集中样本数的十分之⼀。这可能会导致适用于ImageNet数据集的复杂模型在这个椅⼦数据集上过拟合。同时,因为数据量有限,最终训练得到的模型的精度也可能达不到实用的要求。
为了应对上述问题,一个显⽽易⻅的解决办法是收集更多的数据。然而,收集和标注数据会花费大量的时间和资⾦。例如,为了收集ImageNet数据集,研究人员花费了数百万美元的研究经费。虽然目前的数据采集成本已降低了不少,但其成本仍然不可忽略。
另外一种解决办法是应用迁移学习(transfer learning),将从源数据集学到的知识迁移到目标数据集上。例如,虽然ImageNet数据集的图像大多跟椅子无关,但在该数据集上训练的模型可以抽取较通用的图像特征,从而能够帮助识别边缘、纹理、形状和物体组成等。这些类似的特征对于识别椅子也可能同样有效。
迁移学习的一大应用场景是模型微调(finetune)。简单来说,就是我们先找到一个同类的别人训练好的模型,把别人现成的训练好了的模型拿过来,换成自己的数据,通过训练调整一下参数。 在PyTorch中提供了许多预训练好的网络模型(VGG,ResNet系列,mobilenet系列…),这些模型都是PyTorch官方在相应的大型数据集训练好的。学习如何进行模型微调,可以方便我们快速使用预训练模型完成自己的任务。
经过本节的学习,你将收获:
————
import torch
x=torch.arange(12)
print(x)
x=torch.rand(4,3)
print(x)
x=torch.zeros(4,3,dtype=torch.long)
print(x)
x=torch.tensor([5.5,3])
print(x)
x=x.new_ones(4,3,dtype=torch.double)
print(x)
x=torch.randn_like(x,dtype=torch.float)
print(x)
print(x.size())
print(x.shape)
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
tensor([[0.0749, 0.0049, 0.8261],
[0.6157, 0.3573, 0.3716],
[0.2893, 0.4511, 0.3119],
[0.3560, 0.4484, 0.1670]])
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
tensor([5.5000, 3.0000])
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=torch.float64)
tensor([[-0.2442, 0.8814, 0.2310],
[ 0.8963, 0.6212, 1.0183],
[-1.5958, -1.7611, 0.0930],
[-0.7085, -0.3020, 1.3215]])
torch.Size([4, 3])
torch.Size([4, 3])
```python
#加法操作
x=torch.zeros(4,3)
print(x)
y=y.new_ones(4,3)
print(y)
# 方式1
print(x+y)
# 方式2
print(torch.add(x,y))
# 方式3 提供一个输出 tensor 作为参数
# 这里的 out 不需要和真实的运算结果保持维数一致,但是会有警告提示!
result = torch.empty(4, 3)
# print(result)
torch.add(x, y, out=result)
print(result)
# 方式4 in-place
y.add_(x)
print(y)
tensor([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_21/4150726505.py in
2 x=torch.zeros(4,3)
3 print(x)
----> 4 y=y.new_ones(4,3)
5 print(y)
6 # 方式1
NameError: name 'y' is not defined
#索引操作
x=torch.rand(4,3)
print(x)
# 取第二列
print(x[:, 1])
# y取X第一列
y = x[0,:]
y += 1#加法运算
print("y:",y)
print(x[0, :]) # !源tensor也被改了了
#改变大小
x = torch.randn(4, 4)
print(x)
y = x.view(16)#展平
print(y)
z = x.view(-1, 8) # -1是指这一维的维数由其他维度决定,16/8=2
print(z)
z = x.view(-1, 2) # -1是指这一维的维数由其他维度决定,16/2=8
print(z)
print(x.size(), y.size(), z.size())
#x,y,z共享内存
#**view**仅仅是改变了对这个张量的观察⻆度
x += 1
print(x)
print(y) # 也加了了1
#clone一个独立的副本
c=torch.clone(x)
print("clone:",c) # 也加了了1
x += 1
print("x:",x)
print("clone:",c) # 也加了了1
#broadcast广播
x = torch.arange(1, 3)
print(x)
x = torch.arange(1, 3).view(1, 2)
print(x)
y = torch.arange(1, 4).view(3, 1)
print(y)
print(x + y)
%config Completer.use_jedi = False