model.half

 
开启半精度。

直接可以加快运行速度、减少GPU占用,并且只有不明显的accuracy损失。

之前做硬件加速的时候,尝试过多种精度的权重和偏置。
在FPGA里用8位精度和16位精度去处理MNIST手写数字识别,
完全可以达到差不多的准确率,并且可以节省一半的资源消耗。

这一思想用到GPU里也是完全可以行通的。即将pytorch默认的32位浮点型都改成16位浮点型。

    

在CUDA之前设置,且数据入模前也需要设置为半精度

 
model.half()
model.cuda()
model.eval()
    
img = torch.from_numpy(image).float()
img = img.cuda()
img = img.half()
    
res = model(img)
    

 

    

 

    

 


 

  

 


nn.Parameter

 
在 PyTorch 中,当你直接将 `Parameter` 赋值给一个 `nn.Module` 的属性时
(如 `self.weight = Parameter(...)`),PyTorch 会自动将其注册为模型的参数。

这是因为 `nn.Module` 类中定义了 `__setattr__` 方法,
它会在你设置属性时检查该属性是否是 `Parameter` 或者 `nn.Module` 类型,
并相应地进行注册。
    

 
import torch
from torch import nn
torch.manual_seed(73)

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.weight = nn.Parameter(torch.randn(2,5),requires_grad=True)

    def forward(self,x=None):
        return x

        
model = Model()
for param in model.parameters():
    print(param)
        

 
Parameter containing:
tensor([[ 0.0591,  0.4445, -1.2168,  1.3444, -0.4423],
        [-0.5446, -0.6891, -1.2737, -0.3340,  0.5016]], requires_grad=True)
        
    

 

    

 

    

 
import torch
from torch import nn
torch.manual_seed(73)

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.weight = nn.Parameter(torch.randn(2,5))

    def forward(self,x=None):
        return x

        
model = Model()
for param in model.parameters():
    print(param)
    
    

 
Parameter containing:
tensor([[ 0.0591,  0.4445, -1.2168,  1.3444, -0.4423],
        [-0.5446, -0.6891, -1.2737, -0.3340,  0.5016]], requires_grad=True)
        
    

 

    

 

    

 


 

  

 


nn.Module·register_parameter

 
class GraphConvolution(nn.Module):

def __init__(self, in_features, out_features, with_bias=True):
    super(GraphConvolution, self).__init__()
    self.in_features = in_features
    self.out_features = out_features
    self.weight = Parameter(torch.FloatTensor(in_features, out_features))
    if with_bias:
        self.bias = Parameter(torch.FloatTensor(out_features))
    else:
        self.register_parameter('bias', None)
    self.reset_parameters()
    

 
class MyLayer(nn.Module):
    def __init__(self, has_param):
        super().__init__()
        if has_param:
            self.myparam = nn.Parameter(torch.randn(3,3))
        else:
            # 可选:self.myparam = None
            self.register_parameter('myparam', None)
    

Parameter 是什么?

 
torch.nn.Parameter 是 torch.Tensor 的子类,用于标识某个张量是模型中的可训练参数。

当你把一个张量封装成 Parameter,PyTorch 就知道这个张量需要梯度更新,
并且要包含在模型的参数列表中。

为什么要用 register_parameter()

 
虽然 Python 层面能访问到这个变量,
但为了能让 PyTorch 框架正确识别和管理这些参数(如 optimizer 更新、model.parameters() 等),
就需要调用 register_parameter()。

当属性名是动态生成的或条件性的(比如 with_bias=True/False),
更推荐使用 register_parameter() 方法来统一管理。
    

为什么注册 None?

 
在你的代码中,当 with_bias=False 时,bias 不应该存在。

但为了保持接口一致性(例如其他地方可能会检查 self.bias 是否存在),
仍然注册该参数,只不过设置为 None
    

 

    

 

    

要设置为None时通常使用注册

 
import torch
from torch import nn
torch.manual_seed(73)

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.weight = nn.Parameter(torch.randn(2,5),requires_grad=True)

    def forward(self,x=None):
        return x

        
model = Model()
for param in model.parameters():
    print(param)
    

 
Parameter containing:
tensor([[ 0.0591,  0.4445, -1.2168,  1.3444, -0.4423],
        [-0.5446, -0.6891, -1.2737, -0.3340,  0.5016]], requires_grad=True)

 
在 PyTorch 中,当你直接将 `Parameter` 赋值给一个 `nn.Module` 的属性时
(如 `self.weight = Parameter(...)`),PyTorch 会自动将其注册为模型的参数。
这是因为 `nn.Module` 类中定义了 `__setattr__` 方法,
它会在你设置属性时检查该属性是否是 `Parameter` 或者 `nn.Module` 类型,
并相应地进行注册。

因此,在你的例子中,即使没有显式调用 `register_parameter()` 来注册 `self.weight`,
它仍然会被自动添加到模型的参数列表中。

### 注册与不注册的主要区别

1. **显式 vs 隐式:
** 使用 `register_parameter()` 是一种更显式的注册方式,
而直接赋值给模块属性是一种隐式的方式。
显式地使用 `register_parameter()` 可以让你的代码意图更加清晰,
特别是在动态或条件性地创建参数时更为有用。

2. **处理 None 值:
** 当你需要设置某个参数为 `None`(即不存在)时,
使用 `register_parameter('param_name', None)` 是合适的。
这确保了即便该参数未被实例化(即设为 `None`),
它仍然是模块的一个合法属性,不会导致运行时错误。
如果只是简单地跳过这个属性的定义,则访问它可能导致 `AttributeError`。

3. **灵活性和控制:
** 在某些情况下,可能需要对参数的注册过程有更多的控制,
例如根据某些条件动态决定是否注册一个参数,
这时候 `register_parameter()` 提供了更高的灵活性。

4. **维护代码的一致性和可读性:
** 尤其是在大型项目或多人员协作中,
统一使用 `register_parameter()` 可以提高代码的一致性和可读性,
使得其他开发者更容易理解你的意图和代码的工作原理。

总结来说,虽然对于直接赋值给 `nn.Module` 属性的 `Parameter` 实例,
PyTorch 自动为你处理了注册流程,
但 `register_parameter()` 提供了一种额外的方式来更灵活、明确地管理模型参数,
尤其是在处理条件性参数或确保代码健壮性方面。

在大多数情况下,直接赋值的方法已经足够,
但在特定场景下,了解并使用 `register_parameter()` 可以提供额外的便利和控制。

 

    

 


 

  

 


参考