PyTorch学习笔记(七):模型构造、初始化、自定义层、保存与加载、GPU计算
PyTorch学习笔记(七):模型构造、初始化、自定义层、保存与加载、GPU计算
- 模型构造
- 继承`Module`类来构造模型
- `Module`的子类
- `Sequential`类
- `ModuleList`类
- `ModuleDict`类
- 构造复杂的模型
- 小结
- 模型参数的访问、初始化和共享
- 访问模型参数
- 自定义初始化方法
- 共享模型参数
- 小结
- 模型参数的延后初始化
- 自定义层
- 不含模型参数的自定义层
- 含模型参数的自定义层
- 小结
- 读取和存储
- 读写模型
- `state_dict`
- 保存和加载模型
- 1. 保存和加载`state_dict`(推荐方式)
- 2. 保存和加载整个模型
- 小结
- GPU计算
- 计算设备
- `Tensor`的GPU计算
- 模型的GPU计算
- 小结
- 参考
模型构造
回顾一下在多层感知机中含单隐藏层的多层感知机的实现方法。我们首先构造Sequential
实例,然后依次添加两个全连接层。其中第一层的输出大小为256,即隐藏层单元个数是256;第二层的输出大小为10,即输出层单元个数是10。我们曾使用了Sequential
类构造模型。这里我们介绍另外一种基于Module
类的模型构造方法:它让模型构造更加灵活。
继承Module
类来构造模型
Module
类是nn
模块里提供的一个模型构造类,是所有神经网络模块的基类,我们可以继承它来定义我们想要的模型。下面继承Module
类构造多层感知机。这里定义的MLP
类重载了Module
类的__init__
函数和forward
函数。它们分别用于创建模型参数和定义前向计算。前向计算也即正向传播。
import torch
from torch import nnclass MLP(nn.Module):# 声明带有模型参数的层,这里声明了两个全连接层def __init__(self, **kwargs):# 调用MLP父类Module的构造函数来进行必要的初始化。这样在构造实例时还可以指定其他函数# 参数,如“模型参数的访问、初始化和共享”将介绍的模型参数paramssuper(MLP, self).__init__(**kwargs)self.hidden = nn.Linear(784, 256) # 隐藏层self.act = nn.ReLU()self.output = nn.Linear(256, 10) # 输出层# 定义模型的前向计算,即如何根据输入x计算返回所需要的模型输出def forward(self, x):a = self.act(self.hidden(x))return self.output(a)
以上的MLP
类中无须定义反向传播函数。系统将通过自动求梯度而自动生成反向传播所需的backward
函数。
我们可以实例化MLP
类得到模型变量net
。下面的代码初始化net
并传入输入数据X
做一次前向计算。其中,net(X)
会调用MLP
继承自Module
类的__call__
函数,这个函数将调用MLP
类定义的forward
函数来完成前向计算。
X = torch.rand(2, 784)
net = MLP()
print(net)
net(X)
MLP((hidden): Linear(in_features=784, out_features=256, bias=True)(act): ReLU()(output): Linear(in_features=256, out_features=10, bias=True)
)tensor([[ 0.4814, 0.0513, 0.0467, 0.0359, -0.0420, 0.1709, 0.1622, 0.1273,-0.1703, -0.1033],[ 0.4090, 0.1921, 0.0406, 0.0263, 0.0262, -0.0621, 0.1327, 0.1324,-0.0828, -0.2278]], grad_fn=<AddmmBackward>)
注意,这里并没有将
Module
类命名为Layer
(层)或者Model
(模型)之类的名字,这是因为该类是一个可供自由组建的部件。它的子类既可以是一个层(如PyTorch提供的Linear
类),又可以是一个模型(如这里定义的MLP
类),或者是模型的一个部分。我们下面通过两个例子来展示它的灵活性。
Module
的子类
我们刚刚提到,Module
类是一个通用的部件。事实上,PyTorch还实现了继承自Module
的可以方便构建模型的类: 如Sequential
、ModuleList
和ModuleDict
等等。
Sequential
类
当模型的前向计算为简单串联各个层的计算时,Sequential
类可以通过更加简单的方式定义模型。这正是Sequential
类的目的:它可以接收一个子模块的有序字典(OrderedDict)或者一系列子模块作为参数来逐一添加Module
的实例,而模型的前向计算就是将这些实例按添加的顺序逐一计算。
下面我们实现一个与Sequential
类有相同功能的MySequential
类。这或许可以帮助读者更加清晰地理解Sequential
类的工作机制。
class MySequential(nn.Module):from collections import OrderedDictdef __init__(self, *args):super(MySequential, self).__init__()if len(args) == 1 and isinstance(args[0], OrderedDict): # 如果传入的是一个OrderedDictfor key, module in args[0].items():self.add_module(key, module) # add_module方法会将module添加进self._modules(一个OrderedDict)else: # 传入的是一些Modulefor idx, module in enumerate(args):self.add_module(str(idx), module)def forward(self, input):# self._modules返回一个 OrderedDict,保证会按照成员添加时的顺序遍历成员for module in self._modules.values():input = module(input)return input
用MySequential
类来实现前面描述的MLP
类,并使用随机初始化的模型做一次前向计算。
net = MySequential(nn.Linear(784, 256),nn.ReLU(),nn.Linear(256, 10), )
print(net)
net(X)
MySequential((0): Linear(in_features=784, out_features=256, bias=True)(1): ReLU()(2): Linear(in_features=256, out_features=10, bias=True)
)tensor([[ 0.0546, -0.1507, 0.0864, -0.1637, 0.0396, -0.0302, 0.1983, -0.0609,0.0281, 0.0837],[-0.0969, -0.1144, 0.0817, -0.2249, 0.0333, -0.0127, 0.1532, 0.0163,-0.0206, 0.0781]], grad_fn=<AddmmBackward>)
观察到这里MySequential
类的使用跟多层感知机中Sequential
类的使用没什么区别。
ModuleList
类
ModuleList
接收一个子模块的列表作为输入,然后也可以类似List那样进行append和extend操作
net = nn.ModuleList([nn.Linear(784, 256), nn.ReLU()])
net.append(nn.Linear(256, 10)) # # 类似List的append操作
print(net[-1]) # 类似List的索引访问
print(net)
# net(torch.zeros(1, 784)) # 会报NotImplementedError
Linear(in_features=256, out_features=10, bias=True)
ModuleList((0): Linear(in_features=784, out_features=256, bias=True)(1): ReLU()(2): Linear(in_features=256, out_features=10, bias=True)
)
既然Sequential
和ModuleList
都可以进行列表化构造网络,那二者区别是什么呢。ModuleList
仅仅是一个储存各种模块的列表,这些模块之间没有联系也没有顺序(所以不用保证相邻层的输入输出维度匹配),而且没有实现forward
功能需要自己实现,所以上面执行net(torch.zeros(1, 784))
会报NotImplementedError
;而Sequential
内的模块需要按照顺序排列,要保证相邻层的输入输出大小相匹配,内部forward
功能已经实现。
ModuleList
的出现只是让网络定义前向传播时更加灵活,见下面官网的例子。
class MyModule(nn.Module):def __init__(self):super(MyModule, self).__init__()self.linears = nn.ModuleList([nn.Linear(10, 10) for i in range(10)])def forward(self, x):# ModuleList can act as an iterable, or be indexed using intsfor i, l in enumerate(self.linears):x = self.linears[i // 2](x) + l(x)return x
另外,ModuleList
不同于一般的Python的list
,加入到ModuleList
里面的所有模块的参数会被自动添加到整个网络中,下面看一个例子对比一下。
class Module_ModuleList(nn.Module):def __init__(self):super(Module_ModuleList, self).__init__()self.linears = nn.ModuleList([nn.Linear(10, 10)])class Module_List(nn.Module):def __init__(self):super(Module_List, self).__init__()self.linears = [nn.Linear(10, 10)]net1 = Module_ModuleList() # ModuleList
net2 = Module_List() # Python的listprint("net1:")
for p in net1.parameters():print(p.size())print("net2:")
for p in net2.parameters():print(p)
net1:
torch.Size([10, 10])
torch.Size([10])
net2:
ModuleDict
类
ModuleDict
接收一个子模块的字典作为输入, 然后也可以类似字典那样进行添加访问操作:
net = nn.ModuleDict({'linear': nn.Linear(784, 256),'act': nn.ReLU(),
})
# 类似字典那样进行添加访问操作
net['output'] = nn.Linear(256, 10) # 添加
print(net['linear']) # 访问
print(net.output)
print(net)
# net(torch.zeros(1, 784)) # 会报NotImplementedError
Linear(in_features=784, out_features=256, bias=True)
Linear(in_features=256, out_features=10, bias=True)
ModuleDict((linear): Linear(in_features=784, out_features=256, bias=True)(act): ReLU()(output): Linear(in_features=256, out_features=10, bias=True)
)
和ModuleList
一样,ModuleDict
实例仅仅是存放了一些模块的字典,并没有定义forward
函数需要自己定义。同样,ModuleDict
也与Python的Dict
有所不同,ModuleDict
里的所有模块的参数会被自动添加到整个网络中。
构造复杂的模型
虽然上面介绍的这些类可以使模型构造更加简单,且不需要定义forward
函数,但直接继承Module
类可以极大地拓展模型构造的灵活性。下面我们构造一个稍微复杂点的网络FancyMLP
。在这个网络中,我们通过get_constant
函数创建训练中不被迭代的参数,即常数参数。在前向计算中,除了使用创建的常数参数外,我们还使用Tensor
的函数和Python的控制流,并多次调用相同的层。
class FancyMLP(nn.Module):def __init__(self, **kwargs):super(FancyMLP, self).__init__(**kwargs)self.rand_weight = torch.rand((20, 20), requires_grad=False) # 不可训练参数(常数参数)self.linear = nn.Linear(20, 20)def forward(self, x):x = self.linear(x)# 使用创建的常数参数,以及nn.functional中的relu函数和mm函数x = nn.functional.relu(torch.mm(x, self.rand_weight.data) + 1)# 复用全连接层。等价于两个全连接层共享参数x = self.linear(x)# 控制流,这里我们需要调用item函数来返回标量进行比较while x.norm().item() > 1:x /= 2if x.norm().item() < 0.8:x *= 10return x.sum()
在这个FancyMLP
模型中,我们使用了常数权重rand_weight
(注意它不是可训练模型参数)、做了矩阵乘法操作(torch.mm
)并重复使用了相同的Linear
层。下面我们来测试该模型的前向计算。
X = torch.rand(2, 20)
net = FancyMLP()
print(net)
net(X)
FancyMLP((linear): Linear(in_features=20, out_features=20, bias=True)
)tensor(-2.6561, grad_fn=<SumBackward0>)
因为FancyMLP
和Sequential
类都是Module
类的子类,所以我们可以嵌套调用它们。
class NestMLP(nn.Module):def __init__(self, **kwargs):super(NestMLP, self).__init__(**kwargs)self.net = nn.Sequential(nn.Linear(40, 30), nn.ReLU()) def forward(self, x):return self.net(x)net = nn.Sequential(NestMLP(), nn.Linear(30, 20), FancyMLP())X = torch.rand(2, 40)
print(net)
net(X)
Sequential((0): NestMLP((net): Sequential((0): Linear(in_features=40, out_features=30, bias=True)(1): ReLU()))(1): Linear(in_features=30, out_features=20, bias=True)(2): FancyMLP((linear): Linear(in_features=20, out_features=20, bias=True))
)tensor(1.8402, grad_fn=<SumBackward0>)
小结
- 可以通过继承
Module
类来构造模型。 Sequential
、ModuleList
、ModuleDict
类都继承自Module
类。- 与
Sequential
不同,ModuleList
和ModuleDict
并没有定义一个完整的网络,它们只是将不同的模块存放在一起,需要自己定义forward
函数。 - 虽然
Sequential
等类可以使模型构造更加简单,但直接继承Module
类可以极大地拓展模型构造的灵活性。
模型参数的访问、初始化和共享
在线性回归中,我们通过init
模块来初始化模型的参数。我们也介绍了访问模型参数的简单方法。下面讲解如何访问和初始化模型参数,以及如何在多个层之间共享同一份模型参数。
我们先定义一个与上面中相同的含单隐藏层的多层感知机。我们依然使用默认方式初始化它的参数,并做一次前向计算。与之前不同的是,在这里我们从nn
中导入了init
模块,它包含了多种模型初始化方法。
import torch
from torch import nn
from torch.nn import initnet = nn.Sequential(nn.Linear(4, 3), nn.ReLU(), nn.Linear(3, 1)) # pytorch已进行默认初始化print(net)
X = torch.rand(2, 4)
Y = net(X).sum()
Sequential((0): Linear(in_features=4, out_features=3, bias=True)(1): ReLU()(2): Linear(in_features=3, out_features=1, bias=True)
)
访问模型参数
上面提到的Sequential
类与Module
类的继承关系。对于Sequential
实例中含模型参数的层,我们可以通过Module
类的parameters()
或者named_parameters
方法来访问所有参数(以迭代器的形式返回),后者除了返回参数Tensor
外还会返回其名字。下面,访问多层感知机net
的所有参数:
print(type(net.named_parameters()))
for name, param in net.named_parameters():print(name, param.size())
<class 'generator'>
0.weight torch.Size([3, 4])
0.bias torch.Size([3])
2.weight torch.Size([1, 3])
2.bias torch.Size([1])
可见返回的名字自动加上了层数的索引作为前缀。
我们再来访问net
中单层的参数。对于使用Sequential
类构造的神经网络,我们可以通过方括号[]
来访问网络的任一层。索引0表示隐藏层为Sequential
实例最先添加的层。
for name, param in net[0].named_parameters():print(name, param.size(), type(param))
weight torch.Size([3, 4]) <class 'torch.nn.parameter.Parameter'>
bias torch.Size([3]) <class 'torch.nn.parameter.Parameter'>
因为这里是单层的所以没有了层数索引的前缀。另外返回的param
的类型为torch.nn.parameter.Parameter
,其实这是Tensor
的子类,和Tensor
不同的是如果一个Tensor
是Parameter
,那么它会自动被添加到模型的参数列表里,来看下面这个例子。
class MyModel(nn.Module):def __init__(self, **kwargs):super(MyModel, self).__init__(**kwargs)self.weight1 = nn.Parameter(torch.rand(20, 20))self.weight2 = torch.rand(20, 20)def forward(self, x):passn = MyModel()
for name, param in n.named_parameters():print(name)
weight1
weight1
在参数列表中但是weight2
却没在参数列表中。
因为Parameter
是Tensor
,即Tensor
拥有的属性它都有,比如可以根据data
来访问参数数值,用grad
来访问参数梯度。
weight_0 = list(net[0].parameters())[0]
print(weight_0.data)
print(weight_0.grad) # 反向传播前梯度为None
Y.backward()
print(weight_0.grad)
tensor([[-0.4248, 0.2388, 0.4786, -0.4371],[-0.1042, -0.0575, -0.1473, -0.4037],[ 0.3261, -0.0399, -0.4394, -0.3868]])
None
tensor([[-0.0264, -0.0247, -0.0290, -0.0312],[ 0.0000, 0.0000, 0.0000, 0.0000],[ 0.0000, 0.0000, 0.0000, 0.0000]])
在数值稳定性和模型初始化中提到了PyTorch中nn.Module
的模块参数都采取了较为合理的初始化策略(不同类型的layer具体采样的哪一种初始化方法的可参考源代码)。但我们经常需要使用其他方法来初始化权重。PyTorch的init
模块里提供了多种预设的初始化方法。在下面的例子中,我们将权重参数初始化成均值为0、标准差为0.01的正态分布随机数,并依然将偏差参数清零。
for name, param in net.named_parameters():if 'weight' in name:init.normal_(param, mean=0, std=0.01)print(name, param.data)
0.weight tensor([[ 0.0021, -0.0111, -0.0036, 0.0073],[-0.0072, -0.0027, 0.0041, -0.0068],[ 0.0020, 0.0164, -0.0145, -0.0016]])
2.weight tensor([[-0.0043, -0.0113, -0.0104]])
使用常数来初始化权重参数。
for name, param in net.named_parameters():if 'bias' in name:init.constant_(param, val=0)print(name, param.data)
0.bias tensor([0., 0., 0.])
2.bias tensor([0.])
自定义初始化方法
有时候我们需要的初始化方法并没有在init
模块中提供。这时,可以实现一个初始化方法,从而能够像使用其他初始化方法那样使用它。在这之前我们先来看看PyTorch是怎么实现这些初始化方法的,例如torch.nn.init.normal_
:
def normal_(tensor, mean=0, std=1):with torch.no_grad():return tensor.normal_(mean, std)
可以看到这就是一个inplace改变Tensor
值的函数,而且这个过程是不记录梯度的。
类似的我们来实现一个自定义的初始化方法。在下面的例子里,我们令权重有一半概率初始化为0,有另一半概率初始化为[−10,−5][-10,-5][−10,−5]和[5,10][5,10][5,10]两个区间里均匀分布的随机数。
def init_weight_(tensor):with torch.no_grad():tensor.uniform_(-10, 10)tensor *= (tensor.abs() >= 5).float()for name, param in net.named_parameters():if 'weight' in name:init_weight_(param)print(name, param.data)
0.weight tensor([[ 9.6562, -8.8501, -5.5881, -5.0146],[ 7.5690, -9.0724, -7.8028, -8.8028],[-7.9102, -8.8607, -0.0000, 0.0000]])
2.weight tensor([[-0., 0., -0.]])
可以通过改变这些参数的data
来改写模型参数值同时不会影响梯度:
for name, param in net.named_parameters():if 'bias' in name:param.data += 1print(name, param.data)
0.bias tensor([1., 1., 1.])
2.bias tensor([1.])
共享模型参数
在有些情况下,我们希望在多个层之间共享模型参数。如何共享模型参数: Module
类的forward
函数里多次调用同一个层。此外,如果我们传入Sequential
的模块是同一个Module
实例的话参数也是共享的,下面来看一个例子:
linear = nn.Linear(1, 1, bias=False)
net = nn.Sequential(linear, linear)
print(net)
for name, param in net.named_parameters():init.constant_(param, val=3)print(name, param.data)
Sequential((0): Linear(in_features=1, out_features=1, bias=False)(1): Linear(in_features=1, out_features=1, bias=False)
)
0.weight tensor([[3.]])
在内存中,这两个线性层其实一个对象:
print(id(net[0]) == id(net[1]))
print(id(net[0].weight) == id(net[1].weight))
True
True
因为模型参数里包含了梯度,所以在反向传播计算时,这些共享的参数的梯度是累加的:
x = torch.ones(1, 1)
y = net(x).sum()
print(y)
y.backward()
print(net[0].weight.grad) # 单次梯度是3,两次所以就是6
tensor(9., grad_fn=<SumBackward0>)
tensor([[6.]])
小结
- 有多种方法来访问、初始化和共享模型参数。
- 可以自定义初始化方法。
模型参数的延后初始化
由于使用MXNet-Gluon创建的全连接层的时候不需要指定输入个数。所以当调用initialize
函数时,由于隐藏层输入个数依然未知,系统也无法得知该层权重参数的形状。只有在当形状已知的输入X
传进网络做前向计算net(X)
时,系统才推断出该层的权重参数形状为多少,此时才进行真正的初始化操作。但是使用PyTorch在定义模型的时候就要指定输入的形状,所以也就不存在这个问题了。
自定义层
深度学习的一个魅力在于神经网络中各式各样的层,例如全连接层和卷积层、池化层与循环层。虽然PyTorch提供了大量常用的层,但有时候我们依然希望自定义层。如何使用Module
来自定义层,从而可以被重复调用。
不含模型参数的自定义层
我们先介绍如何定义一个不含模型参数的自定义层。事实上,这和模型构造中介绍的使用Module
类构造模型类似。下面的CenteredLayer
类通过继承Module
类自定义了一个将输入减掉均值后输出的层,并将层的计算定义在了forward
函数里。这个层里不含模型参数。
import torch
from torch import nnclass CenteredLayer(nn.Module):def __init__(self, **kwargs):super(CenteredLayer, self).__init__(**kwargs)def forward(self, x):return x - x.mean()
可以实例化这个层,然后做前向计算。
layer = CenteredLayer()
# CenteredLayer类通过继承Module类自定义了一个将输入减掉均值后输出的层,并将层的计算定义在了forward函数里。这个层里不含模型参数。
layer(torch.tensor([1, 2, 3, 4, 5], dtype=torch.float))
tensor([-2., -1., 0., 1., 2.])
可以用它来构造更复杂的模型。
net = nn.Sequential(nn.Linear(8, 128), CenteredLayer())
下面打印自定义层各个输出的均值。因为均值是浮点数,所以它的值是一个很接近0的数。
y = net(torch.rand(4, 8))
y.mean().item()
1.862645149230957e-09
含模型参数的自定义层
我们还可以自定义含模型参数的自定义层。其中的模型参数可以通过训练去学习。
在模型参数的访问、初始化和共享中介绍了Parameter
类其实是Tensor
的子类,如果一个Tensor
是Parameter
,那么它会自动被添加到模型的参数列表里。所以在自定义含模型参数的层时,我们应该将参数定义成Parameter
,除了直接定义成Parameter
类外,还可以使用ParameterList
和ParameterDict
分别定义参数的列表和字典。
ParameterList
接收一个Parameter
实例的列表作为输入然后得到一个参数列表,使用的时候可以用索引来访问某个参数,另外也可以使用append
和extend
在列表后面新增参数。
class MyDense(nn.Module):def __init__(self):super(MyDense, self).__init__()self.params = nn.ParameterList([nn.Parameter(torch.randn(4, 4)) for i in range(3)])self.params.append(nn.Parameter(torch.randn(4, 1)))def forward(self, x):for i in range(len(self.params)):x = torch.mm(x, self.params[i])return x
net = MyDense()
print(net)
MyDense((params): ParameterList((0): Parameter containing: [torch.FloatTensor of size 4x4](1): Parameter containing: [torch.FloatTensor of size 4x4](2): Parameter containing: [torch.FloatTensor of size 4x4](3): Parameter containing: [torch.FloatTensor of size 4x1])
)E:\Users\TFX\Anaconda3\envs\tensorflow24\lib\site-packages\torch\nn\modules\container.py:434: UserWarning: Setting attributes on ParameterList is not supported.warnings.warn("Setting attributes on ParameterList is not supported.")
而ParameterDict
接收一个Parameter
实例的字典作为输入然后得到一个参数字典,然后可以按照字典的规则使用了。例如使用update()
新增参数,使用keys()
返回所有键值,使用items()
返回所有键值对等等,可参考PyTorch官方文档。
class MyDictDense(nn.Module):def __init__(self):super(MyDictDense, self).__init__()self.params = nn.ParameterDict({'linear1': nn.Parameter(torch.randn(4, 4)),'linear2': nn.Parameter(torch.randn(4, 1))})self.params.update({'linear3': nn.Parameter(torch.randn(4, 2))}) # 新增def forward(self, x, choice='linear1'):return torch.mm(x, self.params[choice])net = MyDictDense()
print(net)
MyDictDense((params): ParameterDict((linear1): Parameter containing: [torch.FloatTensor of size 4x4](linear2): Parameter containing: [torch.FloatTensor of size 4x1](linear3): Parameter containing: [torch.FloatTensor of size 4x2])
)E:\Users\TFX\Anaconda3\envs\tensorflow24\lib\site-packages\torch\nn\modules\container.py:550: UserWarning: Setting attributes on ParameterDict is not supported.warnings.warn("Setting attributes on ParameterDict is not supported.")
可以根据传入的键值来进行不同的前向传播:
x = torch.ones(1, 4)
print(net(x, 'linear1'))
print(net(x, 'linear2'))
print(net(x, 'linear3'))
tensor([[ 0.1074, -2.3616, 1.3592, -4.9695]], grad_fn=<MmBackward>)
tensor([[-5.9639]], grad_fn=<MmBackward>)
tensor([[2.9479, 0.9011]], grad_fn=<MmBackward>)
可以使用自定义层构造模型。它和PyTorch的其他层在使用上很类似。
net = nn.Sequential(MyDictDense(),MyDense()
)
print(net)
print(net(x))
Sequential((0): MyDictDense((params): ParameterDict((linear1): Parameter containing: [torch.FloatTensor of size 4x4](linear2): Parameter containing: [torch.FloatTensor of size 4x1](linear3): Parameter containing: [torch.FloatTensor of size 4x2]))(1): MyDense((params): ParameterList((0): Parameter containing: [torch.FloatTensor of size 4x4](1): Parameter containing: [torch.FloatTensor of size 4x4](2): Parameter containing: [torch.FloatTensor of size 4x4](3): Parameter containing: [torch.FloatTensor of size 4x1]))
)
tensor([[-2.5538]], grad_fn=<MmBackward>)
小结
- 可以通过
Module
类自定义神经网络中的层,从而可以被重复调用。
读取和存储
到目前为止,我们介绍了如何处理数据以及如何构建、训练和测试深度学习模型。然而在实际中,我们有时需要把训练好的模型部署到很多不同的设备。在这种情况下,我们可以把内存中训练好的模型参数存储在硬盘上供后续读取使用。
可以直接使用save
函数和load
函数分别存储和读取Tensor
。save
使用Python的pickle实用程序将对象进行序列化,然后将序列化的对象保存到disk,使用save
可以保存各种对象,包括模型、张量和字典等。而load
使用pickle unpickle工具将pickle的对象文件反序列化为内存。
下面的例子创建了Tensor
变量x
,并将其存在文件名同为x.pt
的文件里。
import torch
from torch import nnx = torch.ones(3)
torch.save(x, 'x.pt')
将数据从存储的文件读回内存。
x2 = torch.load('x.pt')
x2
tensor([1., 1., 1.])
还可以存储一个Tensor
列表并读回内存。
y = torch.zeros(4)
torch.save([x, y], 'xy.pt')
xy_list = torch.load('xy.pt')
xy_list
[tensor([1., 1., 1.]), tensor([0., 0., 0., 0.])]
存储并读取一个从字符串映射到Tensor
的字典。
torch.save({'x': x, 'y': y}, 'xy_dict.pt')
xy = torch.load('xy_dict.pt')
xy
{'x': tensor([1., 1., 1.]), 'y': tensor([0., 0., 0., 0.])}
读写模型
state_dict
在PyTorch中,Module
的可学习参数(即权重和偏差),模块模型包含在参数中(通过model.parameters()
访问)。state_dict
是一个从参数名称隐射到参数Tesnor
的字典对象。
class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.hidden = nn.Linear(3, 2)self.act = nn.ReLU()self.output = nn.Linear(2, 1)def forward(self, x):a = self.act(self.hidden(x))return self.output(a)net = MLP()
net.state_dict()
OrderedDict([('hidden.weight',tensor([[ 0.5744, 0.3470, 0.1873],[ 0.1400, -0.0541, -0.3312]])),('hidden.bias', tensor([ 0.0379, -0.2148])),('output.weight', tensor([[ 0.4280, -0.6259]])),('output.bias', tensor([0.3837]))])
注意,只有具有可学习参数的层(卷积层、线性层等)才有
state_dict
中的条目。优化器(optim
)也有一个state_dict
,其中包含关于优化器状态以及所使用的超参数的信息。
optimizer = torch.optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
optimizer.state_dict()
{'state': {},'param_groups': [{'lr': 0.001,'momentum': 0.9,'dampening': 0,'weight_decay': 0,'nesterov': False,'params': [0, 1, 2, 3]}]}
保存和加载模型
PyTorch中保存和加载训练模型有两种常见的方法:
- 仅保存和加载模型参数(
state_dict
); - 保存和加载整个模型。
1. 保存和加载state_dict
(推荐方式)
保存:
torch.save(model.state_dict(), PATH) # 推荐的文件后缀名是pt或pth
加载:
model = TheModelClass(*args, **kwargs)
model.load_state_dict(torch.load(PATH))
2. 保存和加载整个模型
保存:
torch.save(model, PATH)
加载:
model = torch.load(PATH)
我们采用推荐的方法一来实验一下:
X = torch.randn(2, 3)
Y = net(X)
print(Y)
PATH = "./net.pt"
torch.save(net.state_dict(), PATH)net2 = MLP()
net2.load_state_dict(torch.load(PATH))
Y2 = net2(X)
print(Y2)
Y2 == Y
tensor([[0.9775],[0.6055]], grad_fn=<AddmmBackward>)
tensor([[0.9775],[0.6055]], grad_fn=<AddmmBackward>)tensor([[True],[True]])
因为这net
和net2
都有同样的模型参数,那么对同一个输入X
的计算结果将会是一样的。上面的输出也验证了这一点。
此外,还有一些其他使用场景,例如GPU与CPU之间的模型保存与读取、使用多块GPU的模型的存储等等,使用的时候可以参考PyTorch官方文档。
小结
- 通过
save
函数和load
函数可以很方便地读写Tensor
。 - 通过
save
函数和load_state_dict
函数可以很方便地读写模型的参数。
GPU计算
到目前为止,我们一直在使用CPU计算。对复杂的神经网络和大规模的数据来说,使用CPU来计算可能不够高效。我们将介绍如何使用单块NVIDIA GPU来计算。所以需要确保已经安装好了PyTorch GPU版本。准备工作都完成后,下面就可以通过nvidia-smi
命令来查看显卡信息了。
!nvidia-smi # 对Linux/macOS用户有效
Invalid combination of input arguments. Please run 'nvidia-smi -h' for help.
计算设备
PyTorch可以指定用来存储和计算的设备,如使用内存的CPU或者使用显存的GPU。默认情况下,PyTorch会将数据创建在内存,然后利用CPU来计算。
用torch.cuda.is_available()
查看GPU是否可用:
import torch
from torch import nntorch.cuda.is_available() # 输出 True
True
查看GPU数量:
torch.cuda.device_count() # 输出 1
1
查看当前GPU索引号,索引号从0开始:
torch.cuda.current_device() # 输出 0
0
根据索引号查看GPU名字:
torch.cuda.get_device_name(0) # 输出 'GeForce GTX 1050'
'GeForce GTX 1050'
Tensor
的GPU计算
默认情况下,Tensor
会被存在内存上。因此,之前我们每次打印Tensor
的时候看不到GPU相关标识。
x = torch.tensor([1, 2, 3])
x
tensor([1, 2, 3])
使用.cuda()
可以将CPU上的Tensor
转换(复制)到GPU上。如果有多块GPU,我们用cuda(i)
来表示第 iii 块GPU及相应的显存(iii从0开始)且cuda(0)
和cuda()
等价。
x = x.cuda(0)
x
tensor([1, 2, 3], device='cuda:0')
可以通过Tensor
的device
属性来查看该Tensor
所在的设备。
x.device
device(type='cuda', index=0)
可以直接在创建的时候就指定设备。
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 指定设备方法一
x = torch.tensor([1, 2, 3], device=device)
# 指定设备方法二
x = torch.tensor([1, 2, 3]).to(device)
x
tensor([1, 2, 3], device='cuda:0')
对在GPU上的数据进行运算,那么结果还是存放在GPU上。
y = x**2
y
tensor([1, 4, 9], device='cuda:0')
需要注意的是,存储在不同位置中的数据是不可以直接进行计算的。即存放在CPU上的数据不可以直接与存放在GPU上的数据进行运算,位于不同GPU上的数据也是不能直接进行计算的。
z = y + x.cpu()
---------------------------------------------------------------------------RuntimeError Traceback (most recent call last)<ipython-input-50-85d1b72f695e> in <module>
----> 1 z = y + x.cpu()RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!
模型的GPU计算
同Tensor
类似,PyTorch模型也可以通过.cuda
转换到GPU上。我们可以通过检查模型的参数的device
属性来查看存放模型的设备。
net = nn.Linear(3, 1)
list(net.parameters())[0].device
device(type='cpu')
模型在CPU上,将其转换到GPU上:
net.cuda()
list(net.parameters())[0].device
device(type='cuda', index=0)
同样的,我么需要保证模型输入的Tensor
和模型都在同一设备上,否则会报错。
x = torch.rand(2,3).cuda()
net(x)
tensor([[-0.4014],[-0.3703]], device='cuda:0', grad_fn=<AddmmBackward>)
小结
- PyTorch可以指定用来存储和计算的设备,如使用内存的CPU或者使用显存的GPU。在默认情况下,PyTorch会将数据创建在内存,然后利用CPU来计算。
- PyTorch要求计算的所有输入数据都在内存或同一块显卡的显存上。
参考
[1] 阿斯顿·张(Aston Zhang),李沐(Mu Li),[美] 扎卡里·C.立顿(Zachary C.Lipton) 等. 动手学深度学习. 北京: 人民邮电出版社,2019
[2] PyTorch官方文档
[3] https://github.com/ShusenTang/Dive-into-DL-PyTorch
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- Java从零码起10-模拟双色球系统
import java.util.Arrays; import java.util.Random; import java.util.Scanner;/* 模拟双色球系统:1。随机生成一组中奖号码(双色球中6个红球(1-33,不重复),一个蓝球(1-16)2.用户输…...
2024/4/13 17:39:12 - 敲打干净的建筑
> Clean Architecture? :) 干净的建筑,六角形的建筑,洋葱的建筑,尖叫的建筑! 这么多名字,那么短时间! 围绕这些提出的理论的概念有些相似,我认为尝试破解其中一种也会使您对其他理论有所了解…...
2024/5/4 13:49:01 - 网上被骗怎么报警?110网上报警平台中心
一、理财骗局有哪些 简单来说说两种较为典型的理财骗局:1、虚假平台骗局 这种骗局往往打着投资理财的名义,构建虚假网站、APP,发布虚构的交易或产品,在骗取投资后,操纵平台用控制涨跌、限制提现、暂停运营、关闭网站…...
2024/4/24 9:03:47 - 秘密共享者:神经网络中无意识记忆的评价与测试
本周粗略阅读了论文《The Secret Sharer: Evaluating and Testing Unintended Memorization in Neural Networks》,并参考了陈老师实验室发布的翻译,记录个人的阅读笔记,侵删。 本文主要内容总结: 深度神经网络模型的无意识记忆…...
2024/5/3 18:38:39 - 零声学院 音视频高级教程 ubuntu16.04 ffmpeg开发环境搭建
配置环境 ubuntu desktop 16.04 ffmpeg 4.2.1 建议在《编译与安装》一节,都使用源码的方式编译和安装,本编译安装方式最终生成的皆为静态库。 部分命令说明: git -C [git-command] 指定其它路径的仓库 执行命令 注意,-C 要在命…...
2024/4/13 17:39:07 - New Year Concert (性质+二分+st表)
New Year Concert [Link](Problem - D - Codeforces) 题意 给你一个序列你可以将更改其中的数变成任意一个数,问你最少更改几个数使得该序列的任意一个子区间的gcdgcdgcd都不等于该区间长度。 思路 首先我们从左到右来看这个序列,按照以每个位置结尾…...
2024/4/13 17:39:02 - BugBounty—我如何能够绕过防火墙进行RCE并获取root用户权限
前言 嗨,大家好, 此篇文章是关于Apache struts2 CVE-2013-2251的病毒式传播并由于其能导致执行远程命令而被高度利用的漏洞。 简而言之,通过操纵以"action:"/"redirect:"/"redirectAction:"为前缀的参数引入的…...
2024/4/27 0:23:51 - 十余年Android开发分享:Android 开发现状与未来,android开发游戏app
Kotlin Kotlin已经成为Android开发的官方语言,Android的新的文档和Sample代码都开始转向 Kotlin,在未来Java将加速被 Kotlin替代。 https://developer.android.google.cn/kotlin KTX KTX是Kotlin与Android之间无缝衔接的粘合剂,是Kotlin和An…...
2024/4/29 2:12:22 - 『题解』Luogu-P3312 [SDOI2014]数表
P3312 [SDOI2014]数表 Description 多测,QQQ 组数据。有一张 nmn\times mnm 的数表,其第 iii 行第 jjj 列(1≤i≤n,1≤j≤m1\le i\le n, 1\le j\le m1≤i≤n,1≤j≤m)的数值为能同时整除 iii 和 jjj 的所有自然数之和。给定 aaa…...
2024/4/13 17:39:12 - 2125 银行中的激光束数量
题目描述: 银行内部的防盗安全装置已经激活。给你一个下标从 0 开始的二进制字符串数组 bank ,表示银行的平面图,这是一个大小为 m x n 的二维矩阵。 bank[i] 表示第 i 行的设备分布,由若干 ‘0’ 和若干 ‘1’ 组成。‘0’ 表示单…...
2024/5/3 12:50:34 - python库:matplotlib.pyplot(二)
文章目录1. pyplot.imshow()2. pyplot.colorbar()1. pyplot.imshow() pyplot.imshow(X, cmapNone, normNone, interpolationNone)X:要绘制的图像或数组,shape(n,m) 或者(n,m,3)或者(n,m,4) MxN - 用来作图的类数组值:float类型 / INT类型 Mx…...
2024/4/13 17:39:17 - 观察者模式
观察者模式 Subject:登记注册、移除和通知 1)registerObserver 注 册 2)removeObserver 移 除 3)notifyObservers() 通知所有的注册的用户,根据不同需求,可以是更新数据,让用户来取,也可能是实施推送, 看…...
2024/5/3 14:23:05 - 前端开发:JS中查找数组的目标元素方法find()、findIndex()的使用
//空置类型选择 onConfirm1(value) { this.currentItem.VacancyID this.columns2.find((a)>a.Name value).ID; }, 2.获取数组中选择的item中的ProjectName和ProjectNewNo,和数组中对应的一致的第一个元素 projectDetail() { if (this.value) { return th…...
2024/4/15 23:23:12 - 字节输入流对象的读数据方法-----java
需求: 把文件fos.txt中的内容读取出来在控制台输出 FileInputStream:从文件系统中的文件获取输入字节 FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名…...
2024/4/22 8:14:20 - Pytorch:全连接神经网络-MLP分类
Pytorch: 全连接神经网络-多层感知机解决分类问题 copyright: Jingmin Wei, Automation 1801, School of Artificial and Intelligence, Huazhong University of Science and Technology 文章目录Pytorch: 全连接神经网络-多层感知机解决分类问题[toc]MLP 垃圾邮件分类数据准备…...
2024/4/13 17:39:02 - 力扣剑指offer第18天 树
53)二叉搜索树中的中序后继 class Solution { public:TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {TreeNode* res nullptr;TreeNode* cur root;while(cur){if(cur->val > p->val){res cur;cur cur->left;}else{cur cur->right;…...
2024/4/13 17:38:52 - Java for循环遍历求和与增强型遍历求和
1.非增强型遍历求和: package a;public class a1 {public static void main(String[] args) {// TODO Auto-generated method stubint sum0;int [] a {34,67,78,56,90,98,76};for(int i : a) {sumi;}System.out.print(sum);}} 2.增强型遍历求和: impo…...
2024/4/15 16:19:41 - esp8266的安装及点亮LED灯
用esp8266点亮led arduinoIDE1.装好arduino和CH3402.esp8266的安装安装失败3.选择开发板4.编译上传空程序![在这里插入图片描述](https://img-blog.csdnimg.cn/283eaa695a084959a9536bed5515e123.png?x-oss-processimage/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETi…...
2024/5/3 12:17:48 - POJ - 3585 Accumulation Degree(二次扫描与换根法)
POJ - 3585 Accumulation Degree(二次扫描与换根法) #include<cstdio> #include<cstring> #include<vector> using namespace std;typedef pair<int,int> PII; const int N 200010, INF 0x3f3f3f3f;vector<PII> g[N]; i…...
2024/5/3 12:17:03 - OpenCV学习(29)
图像处理(2): 非线性滤波(1):中值滤波、双边滤波 一,非线性滤波概述;二,中值滤波;三,双边滤波; 一,非线性滤波概述 我们所考虑的滤…...
2024/4/17 22:52:42
最新文章
- Rust入门篇:数据类型
文章目录 前言整数类型浮点数类型布尔类型字符类型字符串字面量元组类型数组类型切片类型枚举类型结构体类型指针类型最后 前言 你好,我是醉墨居士,前面我们学习了如何使用rust在控制台进行输出,接下来我将带给大家一些关于计算机的基础知识…...
2024/5/4 16:01:28 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - Django实现的登录注册功能
1 前言 在Web开发中,用户登录和注册是最基本且必不可少的功能。Django,作为一个高级的Python Web框架,为我们提供了强大的工具和库来快速实现这些功能。下面,我将详细介绍如何使用Django来实现用户登录和注册功能。 2 功能介绍 …...
2024/5/1 13:23:09 - app上架-您的应用存在最近任务列表隐藏风险活动的行为,不符合华为应用市场审核标准。
上架提示 您的应用存在最近任务列表隐藏风险活动的行为,不符合华为应用市场审核标准。 修改建议:请参考测试结果进行修改。 请参考《审核指南》第2.19相关审核要求:https://developer.huawei.com/consumer/cn/doc/app/50104-02 造成原因 …...
2024/5/4 2:29:45 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/1 17:30:59 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/2 16:16:39 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/29 2:29:43 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/3 23:10:03 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/27 17:58:04 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/28 1:28:33 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/30 9:43:09 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/27 17:59:30 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/2 15:04:34 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/28 1:34:08 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/29 20:46:55 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/30 22:21:04 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/1 4:32:01 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/5/4 2:59:34 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/28 5:48:52 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/30 9:42:22 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/2 9:07:46 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/30 9:42:49 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57