pytorch里optimizer作用、自动求导autograd,from_numpy、numpy()等函数声明变量时候的浅拷贝、显卡内存 out of memory

news/2024/7/23 8:40:28

1、其中optimizer的作用,其主要起到的作用就是进行权重的更新,如下:

net=models.resnet50(pretrained=False)
learning_rate=0.01
# 权重更新 如果使用自带的optimizer函数进行梯度更新,效率更好,因为其还可以引入梯度
#下降的方法,例如动量等方法
for f in net.parameters():
    f.data.sub_(f.grad.data*learning_rate)

# 使用optimizer进行更新的方法
import torch.optim as optim
inputdata=[1,2,3]
criterion=torch.nn.CrossEntropyLoss()
optimizer=optim.SGD(net.parameters(),lr=0.01)
optimizer.zero_grad()
output=net(inputdata)
loss=criterion(output,inputdata)
# 进行反向梯度计算
loss.backward()
# 进行权重更新
optimizer.step()

注意:如果想在权重更新时加入权重衰减(weight_decay)、动量(momentum)功能,则可以在声明optimizer时如下定义:

    optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.03, momentum=0.9)

2、自动求导autograd函数功能

A、

# 自动求导
# 自动求导
from torch.autograd import Variable

x = torch.ones(1)
x = Variable(x, requires_grad=True)
y = x * 2

y.backward()
print(x.grad)

其输出结果为:

tensor([2.])

在pytorch里的每个变量都有一个标记:requires_grad,允许从梯度计算中细分排除子图,并可以提高效率。

如果一个输入变量定义requires_grad,那么他的输出也可以哦那个requires_grad;相反,只有所有的输入变量都不定义requires_grad梯度,才不会输出梯度。如果其中所有的变量都不需要计算梯度,在子图中则不会执行向后操作计算。如下:

x=Variable(torch.randn(2,2))
y=Variable(torch.randn(2,2))
z=Variable(torch.randn(2,2),requires_grad=True)
a=x+y
print(a.requires_grad)
b=x+z
print(b.requires_grad)

其输出结果为:

False
True

 注意:从断点可以看出,当有梯度计算的时候其后面有个grad_fn参数,如果要是没有这个参数,例如a拿去进行方向梯度计算backward则会报错,如下:

RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

此时只要把损失值加上一个requires_grad参数即可,如下:

out_selected_a = Variable(torch.from_numpy(out_a.cpu().data.numpy()[hard_triplets]).cuda(),requires_grad=True)
out_selected_p = Variable(torch.from_numpy(out_p.cpu().data.numpy()[hard_triplets]).cuda(),requires_grad=True)
out_selected_n = Variable(torch.from_numpy(out_n.cpu().data.numpy()[hard_triplets]).cuda(),requires_grad=True)
triplet_loss = TripletMarginLoss(args.margin).forward(out_selected_a, out_selected_p,  out_selected_n).cuda()                                                           
 triplet_loss.backward()

既可以正确的进行反向梯度计算。

B、

当使用预训练的模型时,这个标志特别有用,其可以用来冻结部分层,这个需要事先知道有哪些层,哪些层需要冻结。

例如:如果想调整预训练的CNN,只要设置requires_grad标志即可。如下:
 

model = models.resnet50(pretrained=True)
# 冻结部分的层的权重
for params in model.parameters():
    params.requres_grad = False
# 替换最后的全连层,新的网路构造层的requires_grad默认是True
model.fc = torch.nn.Linear(512, 1000)
# 定义优化器,这里虽然传了全部模型的参数,但是其由于上面冻结了一些层,所以这里只会更新最后的全连层
optomizer = torch.optim.SGD(model.parameters(), lr=1e-2, momentum=0.9)

另外一种只更新特定层的权重参数方法为:

# 另一种冻结模型的方法:传给优化器需要更新的网络参数即可
model=models.resnet50(pretrained=True)
optomizer=torch.optim.SGD(model.fc.parameters(),lr=1e-2,momentum=0.9)

3、关于numpy与torch里的数据类型转换问题:

n1 = np.array([1., 2.], dtype=np.float32)
n2 = np.array([1., 2.], dtype=np.int32)
# 其中from_numpy不会进行数据的深拷贝
t1 = torch.from_numpy(n1)
# 这里的是把float型转换为torch里的float型,由于数据类型相同不会进行深拷贝
t2 = torch.FloatTensor(n1)
#这里把int型转换为torch里的float型,由于数据类型不同会进行深拷贝
t3 = torch.FloatTensor(n2)
print("n1:", n1)
print("n2", n2)
print("t1", t1)
print("t2", t2)
print("t3", t3)
n1[0] = 5.
print("t1_size:", t1.size())
print("n2:", n2)
print("t1:", t1)
print("t2:", t2)
print("t3", t3)
print("计算完成")

   注意:这里的如果数据类型相同则不会进行深拷贝,如果不同则会进行深拷贝。

 b、关于tensor转换成numpy,其情况主要分为两类:

如果当tensor是在GPU上使用的指令是:

#其中data主要是为了再train模式不报错。而在valid模式下要不要data都无所谓,所以统一都加data.
 data1=out_a.cpu().data.numpy()

如果上面的在train模式下不加data,则会报如下错误:

RuntimeError: Can't call numpy() on Variable that requires grad.
 Use var.detach().numpy() instead.

如果当tensor是在CPU上的指令是即可以使用上面的也可以使用下面的:

 data1=out_a.numpy()

注意:由于网络是再GPU上运行的其输出数据也是在GPU上,要先使用cpu()拷贝到CPU上,

4、模型训练的时候报cuda rumtime error(2): out of memory

如错误消息所示,您的GPU上的内存不足。由于我们经常在PyTorch中处理大量数据,因此小错误可能会迅速导致程序耗尽所有 GPU;幸运的是,这些情况下的修复通常很简单。这里有几个常见的事情要检查:

不要在训练循环中累积历史记录。默认情况下,当计算涉及到有需要梯度的变量时,此计算过程将保留运算的历史记录。这意味着您应该避免在计算中使用这些变量,这些变量的生存期将超出您的训练循环(例如在跟踪统计数据时)。您应该分离该变量或访问其底层数据。

有时,当可微分变量可能发生时,它可能并不明显。考虑以下训练循环(从源代码节选):

total_loss = 0
for i in range(10000):
    optimizer.zero_grad()
    output = model(input)
    loss = criterion(output)
    #进行反向传播的时候要用具有历史记录的loss进行传播
    loss.backward()
    optimizer.step()
    #这里记录的total_loss是为了计算平均损失的,所有这里要改为total_loss += float(loss)
    total_loss += loss

在本例中,由于 loss 是具有 autograd 历史记录的可微分变量,所以 total_loss 将在整个训练循环中累积历史记录。你可以替换成 total_loss + = float(loss) 来解决这个问题。为什么这个方法可以进行减少内存,因为其通过float后转换的类型是不具有历史记录的可微分变量。

这个问题的另一个例子:1

删除你不需要的张量和变量。如果将一个张量或变量分配到一个局部栈,在局部栈超出作用域之前,Python 都不会将其释放。您可以使用 del x 释放该引用。同样,如果将一个张量或变量赋值给对象的成员变量,直到该对象超出作用域之前,它将不会释放。如果你及时删除你不需要的临时变量,你将获得最佳的内存使用率。

作用域的范围可能比你想象的要大。例如:

for i in range(5):
    intermdeiate = f(input[i])
    result += g(intermediate)
output = h(result)
return output

在本段代码中,即使当 h 在执行时,intermediate 仍然存在,因为它的作用域延伸出了循环的末尾。为了尽早释放它,当你不需要它时,你应该用 del intermediate 删除这个中间值。

 

 

 

 

 

 

 


http://www.niftyadmin.cn/n/1691427.html

相关文章

git 常用指令、重获得远程所有的分支、本地分支关联远程分支并且在本地添加远程仓库。代码的pull融合、解决冲突,ignore生效条件,把别人仓库代码提交到自己,新仓库。打tag版本、upstream

1、查看本地git add ./指令后查看暂缓区里的文件内容(如果没进行commit操作,这个add会把新旧文件一起放到暂缓区,如果在add后本地删除了某个文件,再进行add,其暂缓区会保留有这个文件的(这个暂缓区是放到.git文件夹下的…

ES6中常用的10个新特性讲解

https://www.jianshu.com/p/ac1787f6c50f https://www.dazhuanlan.com/2020/03/12/5e696e2c65b28/ https://www.manongdao.com/article-856730.html

使用CuDNN进行卷积操作的知识点

参考博客:使用CuDNN进行卷积运算

FaceNet的一些网络训练评估

1、其中主要的损失triplet loss 原理 triplet loss代码如下: def triplet_loss(anchor, positive, negative, alpha):"""Calculate the triplet loss according to the FaceNet paperArgs:anchor: the embeddings for the anchor images.positive:…

pytorch里cat、stack、unsqueeze、squeeze、自带网络自适应输入大小方法、初始化一个输入获取最后一层特征向量的维度大小,empty、random_初始化Tensor。

1、其中cat是用于拼接矩阵数据: 参考:pytorch中的cat、stack、tranpose、permute、unsqeeze #把数据1跟数据2进行按行拼接,其中0,表示按行,如果1则表示按列 outputssum torch.cat((outputs1, outputs2), 0) outputs…

如何使的VS在re‘lease模式下能够调试。能实现debug下大部分功能,使用低版本VS调用高版本的VS打包的动态库、格式化代码快捷键。

1、如何使的VS在release模式下能够调试。能实现debug下大部分功能; 因为release模式下调试速度比在debug模式快很多。很多刚装的VS一般使无法在release模式下打断点的,断电一般会提示:“无法命中次断点”;下面就是设置如何在relea…

@submit.native.prevent作用

<el-form :inline"true" :model"geCarManageData" class"demo-form-inline" v-if"!orderId" submit.native.prevent></el-form>submit.native.prevent .native 表示对一个组件绑定系统原生事件 .prevent 表示提交以后不刷…

使用debugView进行调试代码,这样子就省了控制log文件的问题

介绍&#xff1a;debugview 可以捕获程序中由TRACE(debug版本)和OutputDebugString输出的信息。支持Debug、Release模式编译的程序。其还支持输出信息过滤&#xff0c;可以过滤掉很多无用的输出信息&#xff0c;它这个过滤不是过滤已经输出的信息&#xff0c;而是过滤接下来会接…