第六周:机器学习周报

news2024/11/27 18:38:02

机器学习周报

  • 摘要
  • Abstract
  • 机器学习——类神经网络训练不起来怎么办?
    • 1. 自动调整学习率(learning rate)
      • 1.1 特制化的Learning Rate——parameter dependent
        • 1.1.1 Root Mean Square(RMS,均方根)
        • 1.1.2 RMSProp
        • 1.1.3 Adam
      • 1.2 Learning Rate Scheduling(学习率调整策略)
        • 1.2.1 learning rate decay(学习率衰减)
        • 1.2.2 Warm up(学习率预热)
      • 1.3 Optimization的总结
  • Pytorch学习
    • 1. torchvision中数据集的使用
    • 2. DataLoader的使用
      • 2.1 sampler参数
      • 2.2 drop_last参数
      • 2.3 shuffle参数
  • 总结

摘要

这一周对机器学习进行了学习,其中学会了如何自动调整学习率中调整参数的知识进行了,对RMS与RMSProp的算法进行了学习和理解。此外,还继续学习了Pytorch,学会了torchvision与DataLoader的使用,了解了其中参数的作用。

Abstract

This week, I learned machine learning, learned how to automatically adjust parameters in the learning rate, and learned and understood the algorithms of RMS and RMSProp. In addition, I continued to learn Pytorch, learned how to use torchvision and DataLoader, and understood the role of parameters in them.

机器学习——类神经网络训练不起来怎么办?

1. 自动调整学习率(learning rate)

如下图所示,当我们在训练的过程中loss不再下降时,我们按照之前的经验,常常会以为我们遇到了gradient = 0的情况,即遇到了 local minima 或者 saddle point
在这里插入图片描述
但是事实真的如此吗?
这个loss不再下降的原因,很明显不是gradient 趋于0造成的,因为在iteration(迭代)到300-500次以及600-700次的时候,gradient任然在起伏,而loss也是几乎不怎么变化
就像遇到了local minima,但是实际的情况就是其在一个狭小的山谷中左右跳跃
所以 training stuck(训练卡顿)≠ small gradient
在这里插入图片描述
那么造成这样的原因是什么呢?
首先我们来回顾上一周的知识
如下图所示Minimum ratio表示真正遇到local minima的比率,很明显我们可以知道,我们在在遇到critical point(临界点)时,大多数都是saddle point的问题,因此我们要重视optimization
在这里插入图片描述
但是!!!
我们上面又说道,遇到critical point 未必是saddle point和local minima的问题,那这张图是什么画出来的?
这个图其实用一般的gradient descent其实是做不到的,需要特别方法train,才可以得到这张图
即使没有关键点,训练也可能很困难
其实走到一个critical point,是一件困难的事
多数时候training在还没有走到critical point的时候就已经停止了
这就说明了当用gradient descent来做optimization的时候你真正的魔王往往不是critical point,而是其他的原因。
那么如果不是critical point的问题,为什么我们的training会卡住呢?
我们可以举一个例子来说明。
如下图中,这边有一个非常简单的error surface,下面来大致介绍一下:
1、只有两个参数,这个两个参数值不一样的时候loss值不一样,然后得到了一个error surface。
2、这个error surface的最低点呢在叉叉的地方
3、事实上,这个error surface是convex(凸面)的形状(即它的等高线是椭圆形的)
只是它在横轴的地方gradient非常的小,所以它的坡度的变化非常的小,导致它非常的平滑。
4、所以这个椭圆的长轴非常的长,短轴呢相对之下比较短。
5、而在纵轴的地方gradient的变化很大,所以error surface的这个纵轴坡度非常的陡峭。
在这里插入图片描述
假设我们的黑点为初始点
然后开始做gradient descent
在这里插入图片描述
当我们的Learning Rate设置为

η = 1 0 − 2 {\color{Red} \eta = 10^{-2}} η=102

可以看到,其在上下两端反复横跳
就比如我把上下两端当作是一个峡谷的两臂,叉叉是最低点,然后其在了两臂反复横跳
在这里插入图片描述
所以我们调整Learning Rate设置为

η = 1 0 − 7 {\color{Red} \eta = 10^{-7}} η=107

可以看到这下的gradient descent有点效果了,终于是往最低点的朝向移动
但是到了横向移动时还是停滞了下来(横向很粗的黑线大概进行了100000次update)
在这里插入图片描述
所以显然就算是一个convex的error surface用gradient descent也很难算好

1.1 特制化的Learning Rate——parameter dependent

面对简单的问题的train都做不好,那如果难的问题又怎么有可能做好呢?所以我们需要更好的gradient descent的版本。
在之前的gradient descent里面所有的参数都是设同样的learning rate。这显然是不够的,我们应该要为每一个参数特制化的learning rate

所以特制化的learning rate怎么做呢?
从刚才的例子里面,其实我们可以学习到一个原则
1、如果在某一个方向上我们的gradient的值很小,即在某一个方向上非常的平坦,那我们会希望learning rate调大一点
2、如果在某一个方向上我们的gradient的值很大,即在某一个方向上非常的非常的陡峭,那我们那我们会希望learning rate可以调小一点
在这里插入图片描述
之前我们在gradient descent时候,算一个新的θ参数是用如下公式表示的:
θ i t + 1 ← θ i t − η g i t {\color{Red} \boldsymbol{\theta}_{i}^{\boldsymbol{t}+\boldsymbol{1}} \leftarrow \boldsymbol{\theta}_{i}^{\boldsymbol{t}}-\eta \boldsymbol{g}_{i}^{\boldsymbol{t}}} θit+1θitηgit

因为我们需要使用特制化的learning rate 所以我们需要加一个σ,然后σ与η组合叫做Parameter dependent(参数依赖),如下所示:

θ i t + 1 ← θ i t − η σ i t g i t {\color{Red} \boldsymbol{\theta}_{i}^{\boldsymbol{t}+\boldsymbol{1}} \leftarrow \boldsymbol{\theta}_{i}^{\boldsymbol{t}}-\frac{\eta}{\sigma_{i}^{t}} \boldsymbol{g}_{i}^{\boldsymbol{t}}} θit+1θitσitηgit

其中根据σ的上、下标我们可以看出:
1、σ是parameter dependent,不同的参数我们要给它不同的σ
2、同时σ是iteration(迭代) dependent,不同的iteration,我们也会有不同的σ

在这里插入图片描述
那接下来我们要看这个parameter dependent的有什么常见的计算方式

1.1.1 Root Mean Square(RMS,均方根)

均方根值RMS 的计算公式,是先将一组数值的平方求和,然后除以数值的数量,最后取平方根。
具体来说,如果有一组数值:
x 1 , x 2 , … , x n x_1,x_2,\dots,x_n x1,x2,,xn
那么这组数值可以通过RMS可以通过以下公式计算:
R M S = 1 N ∑ i = 1 N x i 2 {\color{Red} R M S=\sqrt{\frac{1}{N} \sum_{i=1}^{N} x_{i}^{2}}} RMS=N1i=1Nxi2

其中 N 是是数值的数量, ∑ i = 1 N x i 2 是所有数值的平方和。 其中N是是数值的数量,\sum_{i=1}^{N} x_{i}^{2}是所有数值的平方和。 其中N是是数值的数量,i=1Nxi2是所有数值的平方和。

所以将RMS带入到我们gradient计算中就得到了如下结果:
在这里插入图片描述
这种方式被用在AdaGrad中

AdaGrad,全称Adaptive Gradient,又叫自适应梯度算法,是一种具有自适应学习率的梯度下降优化方法。

如下图:
现在我们有两个参数,一个叫θ₁,一个叫θ₂。
θ₁坡度小,θ₂坡度大。
1、θ₁,因为它坡度小的关系,所以在θ₁这个参数上面算出来的gradient值都比较小,因为gradient算出来的值比较小,然后这个σ是gradient的RSM,算出来的σ也就小,所以会导致learning rate比较大。
2、反过来说θ₂是一个比较陡峭的,这个参数在θ₂这个方向上loss变化比较大。所以算出来的gradient都比较大,所以的σ就比较大,所以会导致learning rate比较小。在update的时候参数update的时候的量就比较小。
3、所以有了σ这一项以后呢,你就可以随着每一个参数gradient的不同来自动的调整learning rate的大小。
在这里插入图片描述

1.1.2 RMSProp

那这个版本还有什么样的问题呢?
我们刚才的假设是同一个参数,它的σ的大小会固定是差不多的值。(因为就算gradient突然变化很大,σ基于RMS的运算,会使其看起来反应很“迟钝”,即坡度突然的变化会使得σ反应不过来)

但事实上并不一定是这个样子的
就算是同一个参数,他需要的learning rate也会随着时间而改变

举例来说:
我们来看这个新月形的error surface,如果我们只考虑横轴的水平线的方向
红色箭头的地方坡度比较陡峭,所以我们需要比较小的learning rate
但是走到了中间绿色箭头这一段的时候,坡度又变得平滑了起来,所以我们在这个地方又需要比较大的learning rate

所以就算是相同参数相同的方向,我们期待的learning rate是可以动态的调整的。
在这里插入图片描述
那我们需要怎么实现呢?
我们使用对RMSProp的改良版
即添加一个α(认为设置大小),控制之前的gradient之和与新的gradient的权重。
下面来详细探讨一下过程:
1、它的第一步跟刚才讲的算RSM的方法是一模一样的,所以就不赘诉了。
2、第二步有什么不同呢?
一样要算出σ₁,只是我们现在算出σ₁的方法,跟刚才算RSM的时候不一样。
刚才在算RSM的时候,每一个gradient都有同等的重要性,但在RSMprop里面,你可以自己调整现代的这个gradient有多重要。
之前的σ₀,算出来σ₀里面就是有g₀,这个σ₀就代表了这个g₀的大小,所以它是σ₀的平方乘上α加上(1-α)现在我们刚算出来的gradient就是g₁的平方,用公式表示为:
σ i 1 = α ( σ i 0 ) 2 + ( 1 − α ) ( g i 1 ) 2 {\color{Red} \sigma_{i}^{1}=\sqrt{\alpha\left(\sigma_{i}^{0}\right)^{2}+(1-\alpha)\left(g_{i}^{1}\right)^{2}} } σi1=α(σi0)2+(1α)(gi1)2

3、以此类推,我们可以知道,到第t+1步update时候我们就可以求得σ等于:
σ i t + 1 = α ( σ i t − 1 ) 2 + ( 1 − α ) ( g i t ) 2 {\color{Red} \sigma_{i}^{t+1}=\sqrt{\alpha\left(\sigma_{i}^{t-1}\right)^{2}+(1-\alpha)\left(g_{i}^{t}\right)^{2}} } σit+1=α(σit1)2+(1α)(git)2
其实就是跟前面的RMS差不多,只不过多了α控制以往的grading之和和如今的gradient权重罢了。
在这里插入图片描述
那用上RMSProp会怎么样呢?
如下图所示:
1、设从这个地方开始,这个黑线是我们的error surface,从这个地方开始update参数
这个球就从这边走走,走到这边那会一路上都很平坦就代表gradient很小,也就代表说这个σ算很小,σ很小,就代表现在update参数的时候,我们会走比较大的步伐。

2、接下来继续滚,滚到gradient突然变大了
如果是原来的RMS计算的话,它反应比较慢。
但如果你用RMSProp,把α设小一点,也就是让新的gradient影响比较大的话,那就可以很快的让σ的值变大。那可以很快的让你的步伐呢变小,也就是踩一个刹车,把learning rate变小。
那如果没有踩刹车的话,你走到这个地方learning rate太大了,那gradient又很大,两个很大的东西乘起来,你可能就啪的一下,就飞到很远的地方

在这里插入图片描述
3、那如果继续走走走,又走到平滑的地方了,因为现在你可以调整α,让他比较看重于最近算出来的gradient。
所以你gradient一变小,σ可能就反应很快它的值就变小了,然后走的步伐呢就变大了
在这里插入图片描述

1.1.3 Adam

其实如今最常用的optimization的策略呢就是Adam
也就是RMSProp + Momentum(第五周周的笔记-1.1处,点击进入)
其实简而言之就是一个在learning rate上进行优化;一个在移动距离上增加动量进行优化
在这里插入图片描述
复习Momentum
在这里插入图片描述

1.2 Learning Rate Scheduling(学习率调整策略)

那么如果用上AdaGrad去优化Learning rate会是怎么样呢?
相比与之前的静态的学习率,我们可以看到我们在原来卡住的地方有所前进了。
因为这个左右的方向的这个gradient很小,所以会自动调整左右这个方向learning rate让其变大,所以step变大,就可以不断的前进。
在这里插入图片描述
接下来的问题就是为什么走到这边突然爆炸了呢?
在这里插入图片描述
因为我们是把过去所有看到的gradient都拿来做平均,所以这个纵轴的方向虽然在初始的这个地方感觉gradient很大,但是这边走了很长一段路以后这个纵轴的方向gradient算出来都很小,因为我们在这个y轴的方向后续的gradient很小,所以我们就累积了很小的σ,累积到一个地步以后,这个step就变很大。
然后就暴走就喷出去了。
但喷出去以后有办法修正回来
因为喷出去以后就走到了这个gradient比较大的地方,走到gradient比较大的地方以后,σ又慢慢的变大,update的这个步伐大小又慢慢的变小。
如此往复
在这里插入图片描述

1.2.1 learning rate decay(学习率衰减)

那么我们怎么解决这个问题呢?
就要用到我们的Learning Rate Scheduling(学习率调整策略)
那这个是什么呢?
我们刚才这边还有一项η,这个η是一个固定的值。
我们有一个策略如果η是跟时间有关的会不会更好呢?
那learning rate怎么让它跟时间有关呢?
最常见的策略啊,叫做learning rate decay(学习率衰减)
随着时间不断的进行,随着参数不断的update,让η越来越小。
这个也是合理的
因为一开始我们距离终点很远。随着参数不断update,我们距离终点越来越近,所以我们把learning rate减小,让参数的更新踩一个刹车,让我们参数的更新能够慢下来。
在这里插入图片描述
刚刚的情况,如果加上learning rate decay,我们就可以很平顺的走到终点
在这里插入图片描述

1.2.2 Warm up(学习率预热)

除了learning rate decay以外,还有另外一个也非常常用的learning rate scheduling的方式叫做Warm up(学习率预热)
Warm up这个方法听起来有点匪夷所思

因为Warm up的方法是说我们这个learning rate要先变大再后变小。
在这里插入图片描述
这个方法出现在一个很老的论文中
写道我们用learning rate 0.01去warm up,再把learning rate改成0.1
它还特别加个注解说一开始用0.1就测不好,也没解释为什么
在这里插入图片描述
在transformer里面也用一个式子提了warm up这个黑科技
它遵守这一个神奇的function来设定它的learning rate,而这个函数的图像画出来实际就是warm up的图像(先增后减)
在这里插入图片描述
那为什么要用 warm up呢?
有一个可能的解释是:
1、当我们在用AdaGrad、RMSProp或Adam的时候。我们需要计算σ,这个σ其实就是告诉我们某一个方向它到底有多陡,或者是多平滑,那这个统计的结果要看的够多以后才精准

2、所以一开始我们的σ是不精准的,因此开始的时候不要让我们的参数离初始的地方太远。
所以初始的learning rate比较小的目的是让它探索,收集一些有关error surface的情报和有关σ的统计数据等。

3、等到σ统计的比较精准,以后再把让learning rate慢慢的爬升。

1.3 Optimization的总结

我们这一小节所将讲的是当我们的error surface崎跷的时候,我们需要一些比较好的方法来做optimization

我们从最原始的规定design进化到这个版本。
那这个版本我们改进了什么东西呢?
1、第一个是momentum,就是不完全顺着gradient decent的方向更新参数,而是把过去所有算出来的规律的方向做一个求和当做update方向

2、那接下来到底应该要update多大的步伐呢?我们算要除掉gradient的RMS

3、那总结到这里我就很困惑:
这个momentum是考虑过去所有的gradient。σ也是考虑过去所有的gradient。
一个在分子,一个在分母,都考虑过去所有的gradient 不就是正好抵消了吗?
但是其实momentum跟这σ他们在使用过去所有gradient的方式是不一样的。
①、moment是直接把所有的gradient通通都加起来,所以他有考虑方向,他有考虑gradient的正负号,要考虑gradient是往左走还是往右走。
②、但是这个RMS,它就不考虑gradient的方向了,它只考虑gradient的大小,取得是平方然后开根号。我们是把平方的结果加起来,所以我们只考虑gradient的大小不考虑gradient的方向,
所以momentum跟这个σ算出来的结果并不会互相抵消。

4、最后我们还会加上一个learning rate scheduling
在这里插入图片描述
在这里插入图片描述

Pytorch学习

1. torchvision中数据集的使用

在这里插入图片描述
我们点入处理视觉部分即Torchvision在这里插入图片描述
介绍为:
The torchvision package consists of popular datasets, model architectures, and common image transformations for computer vision.
(该软件包由流行的数据集、模型组成 体系结构,以及计算机视觉的常见图像转换。)

点击dataset模块我们可以看到:
在这里插入图片描述
其中数据集的类型如下:
在这里插入图片描述
点开MNIST可以查看其说明介绍,下图为翻译后内容
在这里插入图片描述
下面我们会使用CIFAR-10数据集用来完成代码实操:CIFAR主要用于图像识别

除了Dataset模块,我们可以看一下models(模型)模块,也是经常使用的模块
主要是提供一些比较常见的神经网络(有些已经预训练好的神经网络)
其中包括

  1. 分类模型
  2. 语义分割模型
  3. 物体检测模型等
    在这里插入图片描述
    下面进行dataset与transform的联合代码实战
    我们使用CIFAR的dataset完成。使用之前,首先来看看CIFAR的用法,以及参数
    1、root(string型):表示我们的数据集的位置
    2、train(布尔型):如果为true则为训练集。否则为测试集
    3、transform(Callable是一种可调用类型,‌它允许外部程序通过动态链接库被调用执行):上一周所学的内容(我的第五周博客),可以在这里进行使用
    4、target_transform:对target进行一个transform。
    5、download(布尔型):如果为true,则自动下载数据集到root中(如果已经下载则不会再重复下载)
    在这里插入图片描述
    知道大概怎么使用后,就进行代码实战
    创建一个新的py文件,然后输入如下代码,并运行:
import torchvision

# 使用CIFAR10数据集
# 训练集设置
train_set = torchvision.datasets.CIFAR10(root='./dataset', train=True, download=True)
# 测试集设置
test_set = torchvision.datasets.CIFAR10(root='./dataset', train=False, download=True)

运行过后可以看到我们的数据集正在下载:
在这里插入图片描述
等待其下载完毕,我们就可以看到我们的项目目录多了一个datasets的文件夹,里面就是我们下载下来的数据集压缩包和一些文件
在这里插入图片描述
在这里插入图片描述
注意:如果下载十分慢。数据集可以复制链接或者用其他方式下载,下载好压缩包再创建一个文件夹(同root一致),然后再拖进去,也可以完成

下载好后,我们就可以查看数据集,继续输入如下代码,然后运行:

# 查看数据集
print(test_set[0])

该数据集由两部分组成分别是(image,target)
可以看到这是一张32*32大小的图片格式是PIL其中3表示target
在这里插入图片描述
那么target为3是什么呢?
target就是标签。
我们打一个断点(鼠标左键到print指令的行数那里),然后debug(再点击虫子标志),就可以看到变量的详情。
这个数据集是分好类别的,比如:0代表airplane、1代表automobile、2代表bird等等
我们这里的3表示的就是cat
在这里插入图片描述
因为其结构是img,target所以我们可以使用如下方式来查看:

import torchvision

# 使用CIFAR10数据集
# 训练集设置
train_set = torchvision.datasets.CIFAR10(root='./datasets', train=True, download=True)
# 测试集设置
test_set = torchvision.datasets.CIFAR10(root='./datasets', train=False, download=True)

# 查看数据集
print(test_set[0])
# 查看数据集的类别
print(train_set.classes)

# 查看格式
img, target = test_set[0]
print(img)
print(target)
print(test_set.classes[target])
#展示图片
img.show()

在这里插入图片描述
图片隐约能看出是一只猫
在这里插入图片描述
接下来我们再详细的了解一下CIFAR-10的数据集的内容
如下图:
可以看到共有10类,每个类有6000张图
其中有50000张为训练图片、10000张为测试图片
在这里插入图片描述

大概了解了dataset模块的使用后,我们就需用dataset与transform进行联动代码实战了
因为之前我们使用transform时候,都需要转换为tensor类型,所以我们需要用到transform的totensor工具箱完成类别的转换。

import torchvision

# 使用transform转换为tensor类型,compose可以配合裁剪和resize等操作
dataset_transforms = torchvision.transforms.Compose([
    torchvision.transforms.ToTensor()
]
# 使用CIFAR10数据集
# 加上transform参数
# 训练集设置
train_set = torchvision.datasets.CIFAR10(root='./datasets', train=True, transform=dataset_transforms, download=True)
# 测试集设置
test_set = torchvision.datasets.CIFAR10(root='./datasets', train=False, transform=dataset_transforms, download=True)
# 查看数据集
print(test_set[0])

可以看到数据集已经变为tensor类型了。
在这里插入图片描述
那变为tensor类型,我们就可以使用tensorboard进行显示(正好可以复习一下之前的内容)

import torchvision
from torch.utils.tensorboard import SummaryWriter

# 使用transform转换为tensor类型,compose可以配合裁剪和resize等操作
dataset_transforms = torchvision.transforms.Compose([
    torchvision.transforms.ToTensor()
])

# 使用CIFAR10数据集
# 训练集设置
train_set = torchvision.datasets.CIFAR10(root='./datasets', train=True, transform=dataset_transforms, download=True)
# 测试集设置
test_set = torchvision.datasets.CIFAR10(root='./datasets', train=False, transform=dataset_transforms, download=True)

# 使用tensorboard进行显示
# 创建writer实例
writer = SummaryWriter("logs_dataset_transform")
# 显示测试集中前10张图片,每个setp代表一张图
for i in range(10):
    img, target = test_set[i]
    writer.add_image("test_set", img, i)
# 关闭writer
writer.close()

在terminal中启动tensorboard

 tensorboard --logdir=logs_dataset_transform --port=6007

效果如下:
在这里插入图片描述
在这里插入图片描述
大致的演示就完成了。
但是dataset模块除了CIFAR10之外,还有CoCo数据集(比较庞大30多G)
可以看到其使用方式,其实跟CIFAR10差不多,具体怎么使用要多看官方文档
在这里插入图片描述

2. DataLoader的使用

上一部分我们学习了dataset如何使用,这一小节我们学习DataLoader的使用
那么它们的区别是什么呢?
我们可以用一张图形象的表示出来
我们的datastet就是一副扑克牌,里面一张一张的牌就是我们的data。
比如上一小节中的test_set就是一副扑克牌,test_set[0]就是其中的一副牌,每一张牌都有对应的数字与含义。
dataloader,loader顾名思义就是加载器,就是对数据进行加载
类似与右图里面的手,从一副扑克牌中取出一张张的牌
dataloader就是需要数据的时候就要去dataset里面取。

那么怎么取和取多少就是由dataloader里面的参数进行控制的
(比如我们想一下取4张牌,是一只手抓还是两只手抓)
大概有了了解之后,我们可以进入Pytorch官网查看DataLoader的使用
打开官网,根据下图顺序操作就可以找到dataloader的说明文档了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从下图的说明中可以看到,dataloader的参数比较多
但是除了dataset外(此dataset就是上一小节所学习的),其余参数都有默认值。
在这里插入图片描述
接下来我们可以认识一下一些常见的参数:
在这里插入图片描述
接下来进行我们dataloader的代码实战
创建一个新的py文件,输入如下代码:

在这之前我们可以用一个图示的过程了解一下运作原理

dataset里有一个getitem()方法,其就是返回img,target
在这里插入图片描述
比如我们的batch size = 4
就会以上述格式提取出4份,然后封装成一个imgs,targets中,再return回去
在这里插入图片描述
接下来我们用代码去体验:
我们依旧使用上以小结的数据集CIFAR10

import torchvision
from torch.utils.data import DataLoader

# 准备的测试数据集
test_data = torchvision.datasets.CIFAR10(root='./datasets', train=False, transform=torchvision.transforms.ToTensor())

# dataloader
test_loader = DataLoader(dataset=test_data, batch_size=4, shuffle=True, num_workers=0, drop_last=False)

# 查看测试集第一张图片的数据
img, target = test_data[0]
print(img.shape)
print(target)

for data in test_loader:
    imgs, targets = data
    print(imgs.shape)
    print(targets)

结果如下:
可以看到基本上符合我们上面的流程图
在这里插入图片描述
我们可以配合tensorboard,让其在上面展示更加的直观
把batch size设置为64

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

# 准备的测试数据集
test_data = torchvision.datasets.CIFAR10(root='./datasets', train=False, transform=torchvision.transforms.ToTensor())

# dataloader
test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=True, num_workers=0, drop_last=False)

# 查看测试集第一张图片的数据
img, target = test_data[0]
print(img.shape)
print(target)

writer = SummaryWriter('./logs_dataloader')
step = 0
for data in test_loader:
    imgs, targets = data
    # print(imgs.shape)
    # print(targets)
    writer.add_images('test_data', imgs, step)
    step += 1

# 关闭SummaryWriter
writer.close()

在这里插入图片描述

2.1 sampler参数

在上面的输出中细心的我们可以看到
我们test_data[0]与这里的第一个data不是同一个?
这是为什么呢?难道分类是不是从一个开始分吗?
在这里插入图片描述
这是因为我们的sampler的方式时随机采样的
如下图所示:
我们添加了断点,可以看到其采样方式为RandomSampler(即batch size 为4时,在数据集中随机抓取4张图片)
在这里插入图片描述

2.2 drop_last参数

在最后一个step中(就是batch),很明显与其他step不同,这是因为10000/64 等于156余16
余数为16,所以只有16张图,而其他step都有8*8=64张图。
这是由于我们的drop_last设置为False导致的
在这里插入图片描述

在这里插入图片描述
我们将drop_last设置为True看看结果:

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

# 准备的测试数据集
test_data = torchvision.datasets.CIFAR10(root='./datasets', train=False, transform=torchvision.transforms.ToTensor())

# dataloader
test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=True, num_workers=0, drop_last=True)

# 查看测试集第一张图片的数据
img, target = test_data[0]
print(img.shape)
print(target)

writer = SummaryWriter('./logs_dataloader')
step = 0
for data in test_loader:
    imgs, targets = data
    # print(imgs.shape)
    # print(targets)
    writer.add_images('test_data_drop_last', imgs, step)
    step += 1

# 关闭SummaryWriter
writer.close()

刷新tensorboard后:
在这里插入图片描述

2.3 shuffle参数

shuffle用于再下一次epoch的时候打乱数据
每轮完所有的个batch就为一次epoch,每轮完一次epoch就进行shuffle
我们先把shuffle设置为False
我们输入如下代码:

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

# 准备的测试数据集
test_data = torchvision.datasets.CIFAR10(root='./datasets', train=False, transform=torchvision.transforms.ToTensor())

# dataloader
test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=False, num_workers=0, drop_last=True)

# 查看测试集第一张图片的数据
img, target = test_data[0]
print(img.shape)
print(target)

writer = SummaryWriter('./logs_dataloader')
step = 0
# 设置epoch,每轮完156个batch(因为此时drop_last=True,所以共有156个batch)就为一次epoch
for epoch in range(2):
    for data in test_loader:
        imgs, targets = data
        # print(imgs.shape)
        # print(targets)
        # "Epoch:{}".format(epoch),即当epoch = 1时,就为Epoch_1;当epoch = 2时,就为Epoch_2
        writer.add_images("Epoch:{}".format(epoch), imgs, step)
        step += 1
    epoch = epoch + 1

# 关闭SummaryWriter
writer.close()

在这里插入图片描述

再把shuffle设置为True

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

# 准备的测试数据集
test_data = torchvision.datasets.CIFAR10(root='./datasets', train=False, transform=torchvision.transforms.ToTensor())

# dataloader
test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=True, num_workers=0, drop_last=True)

# 查看测试集第一张图片的数据
img, target = test_data[0]
print(img.shape)
print(target)

writer = SummaryWriter('./logs_dataloader')
# 设置epoch,每轮完156个batch(因为此时drop_last=True,所以共有156个batch)就为一次epoch
for epoch in range(2):
    step = 0
    for data in test_loader:
        imgs, targets = data
        # print(imgs.shape)
        # print(targets)
        # "Epoch:{}".format(epoch),即当epoch = 1时,就为Epoch_1;当epoch = 2时,就为Epoch_2
        writer.add_images("Epoch:{}".format(epoch), imgs, step)
        step += 1
    epoch = epoch + 1

# 关闭SummaryWriter
writer.close()

在这里插入图片描述

总结

这一周对机器学习继续进行了探究,学习了自动调整学习率与Loss的知识,当我们的error surface崎跷的时候,我们需要一些比较好的方法来做optimization。其中学会了RMS与RMSProp的算法,以及学会对η进行策略优化,还复习了momentum算法。此外,还对Pytorch进行了更进一步的学习,其中学会了使用torchvision的dataset模块,以及结合之前的transform与tensorboard一同进行联动的代码实践。然后还学会了如何使用DataLoader,其中学会了dataloader中batch size与shuffle以及drop_last的应用,明白了dataloader与dataset的关系。
下一周计划继续对李宏毅的机器学习视频进行学习,开始学习神经卷积网络,然后Pytorch要进入CNN的学习阶段。争取实现理论与代码的协同性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1961830.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python】基础语法(下)

本篇文章将接着上篇文章继续讲解基础语法: (4)变量 (5)注释 (6)输入 (7)条件语句 四:变量 变量其实就是我们生活中起别名和外号。让变量名指向某个值&a…

旅游卡,免费,旅游是真的吗?真相是……

但这种包来回大交通,一旦成本大于利润,他们就会以各种理由推卸责任。这就是我在“揭秘:共享旅游卡免费旅游,包来回路费,这背后的3大真相!”这篇文章里面讲到那个大妈的惨痛教训。 以上这5点真相&#xff0…

Python 中的@符号:如何用装饰器改变你的编程方式?

Python 是一种强大且灵活的编程语言,其中有许多独特的语法元素和概念。 符号通常用于装饰器。它看起来可能有些神秘,但实际上它的工作原理非常简单。 什么是装饰器? 在了解 符号之前,我们首先需要理解什么是装饰器。简单来说&am…

C++设计模式笔记(内附可运行代码示例)

持续更新, 欢迎关注....... 前言 设计目的 高内聚,低耦合 设计原则 1、开放封闭原则 类的改动是通过增加代码进行,而不是修改源代码。 2、单一职责原则 职责单一,对外只提供一种功能,引起类变化的原因都应该只有一个。 3…

【中项】系统集成项目管理工程师-第9章 项目管理概论-9.1PMBOK的发展与9.2项目基本要素

前言:系统集成项目管理工程师专业,现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试,全称为“全国计算机与软件专业技术资格(水平)考试”&…

数据库设计效率提高的5大注意事项

数据库设计效率和质量的提高对项目影响深远,能够显著提升数据访问速度,确保数据一致性和完整性,减少应用开发和维护成本,同时提升系统稳定性和用户体验。如果数据库设计不佳会导致项目性能低下,数据访问缓慢&#xff0…

Java7.0标准之重要特性及用法实例(十八)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列…

APDL(ANSYS Parametric Design Language)初识

APDL(ANSYS Parametric Design Language)编写涉及使用ANSYS的参数化设计语言来创建、修改和执行有限元分析(FEA)任务。以下是一些关于APDL编写的基本步骤、技巧和示例: 一、基本步骤 了解APDL基础: 熟悉AP…

并发--快速查询死锁信息

使用jstack查看线程堆栈信息 jstack:jdk提供的一个工具,可以查看java进程中线程堆栈信息。 位于:jdk1.8.0_121\bin包下 死锁代码 public class DeadLockDemo {private static String A "A";private static String B "B"…

视频平台麓战奥运经济,谁能接住这“破天的富贵”?

文丨郭梦仪 与巴黎奥运会炸裂开幕式的“松弛感”不同,赛场外的流量之争早已硝烟弥漫。 今年,腾讯、咪咕、快手、抖音与中央广播电视总台达成奥运转播版权合作,长短视频平台各占一半。 而今,获得转播权的视频平台们,…

20240731 每日AI必读资讯

📱苹果AI版iOS首日火爆:聊天秒变高情商,大模型成最强嘴替,Siri华丽变身 - 苹果的Apple Intelligence终于面世!随着iOS 18.1 Beta版的上线,注册开发者从即日起就能体验到苹果AI的部分功能。 - Siri的全面换…

出行方案,智能推荐:用友BIP商旅云6.0推出AI新装备

随着企业业务的不断拓展和员工出行需求的日益复杂化,传统的商旅预订方式已经难以应对,同时企业在商旅成本控制方面也面临着巨大的挑战。为此用友BIP商旅云6.0推出了创新性的AI新装备——智能推荐,以智能分析与精准预测,为企业提供…

基于springboot的大学奖学金评定管理系统表结构调试讲解源码

基于springboot的大学奖学金评定管理系统 赠送自己录的运行教程视频,无经验也可以运行起来。 提供远程调试服务,加钱可远程帮忙运行起来。 项目功能: 二、项目功能介绍 管理员 个人中心:这是管理员的个人工作区域,允许管理员…

vue基础3

1.推荐好用的第三方框架 BootCDN - Bootstrap 中文网开源项目免费 CDN 加速服务 1.moment.js 2.dayjs 2.收集表达数据 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>Document</title><…

MSYS2下载安装和使用

Minimalist GNU&#xff08;POSIX&#xff09;system on Windows&#xff0c;Windows下的GNU环境。 目录 1. 安装 2. pacman命令 3. 配置vim 4. 一些使用示例 4.1 编译代码 4.2 SSH登录远程服务器 1. 安装 官网下载&#xff1a;https://www.msys2.org/ 双击.exe文件&am…

【python】OpenCV—Faster Video File FPS

文章目录 1、需求描述2、正常方法 cv2.read3、加速方法 imutils.video.FileVideoStream4、涉及到的核心库函数4.1、imutils.video.FPS4.2、imutils.video.FileVideoStream 5、参考 1、需求描述 使用线程和队列数据结构将视频文件的 FPS 速率提高 &#xff01; 我们的目标是将…

解决Qt3D程序场景中无法显示创建的立体图形?

有的新手在创建Qt3D程序时&#xff0c;因为不熟练&#xff0c;导致经常遇到无法显示3D图形的情况。 原因其实也简单&#xff0c;就是设置的摄像机的位置不对&#xff0c;或者压根没有设置摄像机。 // CameraQt3DRender::QCamera *cameraEntity view.camera();cameraEntity-&g…

文件未保存后能否恢复?分享实用恢复指南,6个方法

在日常用电脑时文件未保存而导致的数据丢失&#xff0c;是许多人都会遭遇的棘手问题。那么面对这样的情况&#xff0c;文件真的能够恢复吗&#xff1f;本文将深入分析文件恢复的可能性&#xff0c;并提供一系列实用的建议。 一、了解文件恢复的基础 首先我们需要明白文件恢复并…

每一次新建终端固定到某个环境,配置PyCharm终端以自动激活环境

在PyCharm中&#xff0c;即使已经为项目设置了特定的Python解释器&#xff0c;默认情况下&#xff0c;新建的终端可能不会自动激活与项目绑定的Conda虚拟环境。要解决这个问题&#xff0c;可以采取以下步骤&#xff1a; 1. 配置PyCharm终端以自动激活环境 PyCharm支持为每个项…

手把手教你用家用电脑完成图片和视频AI去水印功能

一.效果展示 二.video-subtitle-remover源码地址 soda151314/video-subtitle-remover: 基于AI的图片/视频硬字幕去除、文本水印去除&#xff0c;无损分辨率生成去字幕、去水印后的图片/视频文件。无需申请第三方API&#xff0c;本地实现。AI-based tool for removing hard-cod…