Pytorch 复习总结 4

news2024/10/6 4:02:43

Pytorch 复习总结,仅供笔者使用,参考教材:

  • 《动手学深度学习》
  • Stanford University: Practical Machine Learning

本文主要内容为:Pytorch 深度学习计算。

本文先介绍了深度学习中自定义层和块的方法,然后介绍了一些有关参数的管理和读写方法,最后介绍了 GPU 的使用方法。


Pytorch 语法汇总:

  • Pytorch 张量的常见运算、线性代数、高等数学、概率论 部分 见 Pytorch 复习总结1;
  • Pytorch 线性神经网络 部分 见 Pytorch 复习总结2;
  • Pytorch 多层感知机 部分 见 Pytorch 复习总结3;
  • Pytorch 深度学习计算 部分 见 Pytorch 复习总结4;
  • Pytorch 卷积神经网络 部分 见 Pytorch 复习总结5;
  • Pytorch 现代卷积神经网络 部分 见 Pytorch 复习总结6;

目录

  • 一. 自定义块
    • 1. 顺序块
    • 2. 自定义前向传播
    • 3. 嵌套块
  • 二. 自定义层
    • 1. 无参数层
    • 2. 有参数层
  • 三. 参数管理
    • 1. 参数访问
    • 2. 参数初始化
    • 3. 延后初始化
  • 四. 文件读写
    • 1. 加载和保存张量
    • 2. 加载和保存模型参数
  • 五. GPU 计算

层是神经网络的基本组成单元,如全连接层、卷积层、池化层等。块是由层组成的更大的功能单元,用于构建复杂的神经网络结构。块可以是一系列相互关联的层,形成一个功能完整的单元,也可以是一组层的重复模式,用于实现重复的结构。下图就是多个层组合成块形成的更大模型:
在这里插入图片描述

在实际应用中,经常会需要自定义层和块。

一. 自定义块

1. 顺序块

nn.Sequential 本质上就是一个顺序块,通过在块中实例化层来创建神经网络。 nn.Module 是 PyTorch 中用于构建神经网络模型的基类,nn.Sequential 和各种层都是继承自 Module,nn.Sequential 维护一个由多个层组成的有序列表,列表中的每个层连接在一起,将每个层的输出作为下一个层的输入。

如果想要自定义一个顺序块,必须要定义以下两个关键函数:

  1. 构造函数:将每个层按顺序逐个加入列表;
  2. 前向传播函数:将每一层按顺序传递给下一层;
import torch
from torch import nn

class MySequential(nn.Module):
    def __init__(self, *args):
        super().__init__()
        for idx, module in enumerate(args):
            self._modules[str(idx)] = module

    def forward(self, X):
        # self._modules的类型是OrderedDict
        for block in self._modules.values():
            X = block(X)
        return X

net = MySequential(
    nn.Linear(20, 256),
    nn.ReLU(),
    nn.Linear(256, 10)
)

X = torch.rand(2, 20)
output = net(X)

上述示例代码中,定义 net 时会自动调用 __init__(self, *args) 函数,实例化 MySequential 对象;调用 net(X) 相当于 net.__call__(X),会自动调用模型类中定义的 forward() 函数,进行前向传播,每一层的传播本质上就是调用 block(X) 的过程。

2. 自定义前向传播

nn.Sequential 类将前向传播过程封装成函数,用户可以自由使用但没法修改传播细节。如果想要自定义前向传播过程中的细节,就需要自定义顺序块及 forward 函数,而不能仅仅依赖预定义的框架。

例如,需要一个计算函数 f ( x , w ) = c ⋅ w T x f(\bold x,\bold w)=c \cdot \bold w ^T \bold x f(x,w)=cwTx 的层,并且在传播过程中引入控制流。其中 x \bold x x 是输入, w \bold w w 是参数, c c c 是优化过程中不需要更新的指定常量。为此,定义 FixedHiddenMLP 类如下:

import torch
from torch import nn
from torch.nn import functional as F

class FixedHiddenMLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.rand_weight = torch.rand((20, 20), requires_grad=False)    # 优化过程中不需要更新的指定常量
        self.linear = nn.Linear(20, 20)

    def forward(self, X):
        X = self.linear(X)
        X = F.relu(torch.mm(X, self.rand_weight) + 1)
        X = self.linear(X)          # 两个全连接层共享参数
        while X.abs().sum() > 1:    # 控制流
            X /= 2
        return X

3. 嵌套块

多个层可以组合成块,多个块还可以嵌套形成更大的模型:

import torch
from torch import nn
from torch.nn import functional as F

class FixedHiddenMLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.rand_weight = torch.rand((20, 20), requires_grad=False)    # 优化过程中不需要更新的指定常量
        self.linear = nn.Linear(20, 20)

    def forward(self, X):
        X = self.linear(X)
        X = F.relu(torch.mm(X, self.rand_weight) + 1)
        X = self.linear(X)          # 两个全连接层共享参数
        while X.abs().sum() > 1:    # 控制流
            X /= 2
        return X.sum()

class NestMLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(nn.Linear(20, 64), nn.ReLU(),
                                 nn.Linear(64, 32), nn.ReLU())
        self.linear = nn.Linear(32, 16)

    def forward(self, X):
        return self.linear(self.net(X))

net = nn.Sequential(
    NestMLP(), 
    nn.Linear(16, 20), 
    FixedHiddenMLP()
)

X = torch.rand(2, 20)
output = net(X)

二. 自定义层

和自定义块一样,自定义层也需要实现构造函数和前向传播函数。

1. 无参数层

import torch
from torch import nn

class CenteredLayer(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, X):
        return X - X.mean()

net = nn.Sequential(nn.Linear(8, 128), CenteredLayer())
X = torch.rand(4, 8)
output = net(X)
print(output.mean())	# tensor(0., grad_fn=<MeanBackward0>)

2. 有参数层

import torch
from torch import nn
import torch.nn.functional as F

class MyLinear(nn.Module):
    def __init__(self, in_units, out_units):
        super().__init__()
        self.weight = nn.Parameter(torch.randn(in_units, out_units))
        self.bias = nn.Parameter(torch.randn(out_units,))
    def forward(self, X):
        linear = torch.matmul(X, self.weight.data) + self.bias.data
        return F.relu(linear)

net = nn.Sequential(
    MyLinear(64, 8), 
    MyLinear(8, 1)
)
X = torch.rand(2, 64)
output = net(X)
print(output)       # tensor([[11.9497], [13.9729]])

三. 参数管理

在实验过程中,有时需要提取参数,以便检查或在其他环境中复用。本节将介绍参数的访问方法和参数的初始化。

1. 参数访问

  • net.state_dict() / net[i].state_dict():返回模型或某一层参数的状态字典;
  • net[i].weight.data / net[i].bias.data:返回某一层的权重 / 偏置参数;
  • net[i].weight.grad:返回某一层的权重参数的梯度属性。只有调用了 backward() 方法后才能访问到梯度值,否则为 None;
import torch
from torch import nn

net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1))
X = torch.rand(size=(2, 4))
output = net(X)

print(net.state_dict())
'''
OrderedDict([('0.weight', tensor([[ 0.2178, -0.3286,  0.4875, -0.0347],
        [-0.0415,  0.0009, -0.2038, -0.1813],
        [-0.2766, -0.4759, -0.3134, -0.2782],
        [ 0.4854,  0.0606,  0.1070,  0.0650],
        [-0.3908,  0.2412, -0.1348,  0.3921],
        [-0.3044, -0.0331, -0.1213, -0.1690],
        [-0.3875, -0.0117,  0.3195, -0.1748],
        [ 0.1840, -0.3502,  0.4253,  0.2789]])), ('0.bias', tensor([-0.2327, -0.0745,  0.4923, -0.1018,  0.0685,  0.4423, -0.2979,  0.1109])), ('2.weight', tensor([[ 0.1006,  0.2959, -0.1316, -0.2015,  0.2446, -0.0158,  0.2217, -0.2780]])), ('2.bias', tensor([0.2362]))])
'''
print(net[2].state_dict())
'''
OrderedDict([('weight', tensor([[ 0.1006,  0.2959, -0.1316, -0.2015,  0.2446, -0.0158,  0.2217, -0.2780]])), ('bias', tensor([0.2362]))])
'''
print(net[2].bias)
'''
Parameter containing:
tensor([0.2362], requires_grad=True)
'''
print(net[2].bias.data)
'''
tensor([0.2362])
'''

如果想一次性访问所有参数,可以使用 for 循环递归遍历:

import torch
from torch import nn

net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1))
X = torch.rand(size=(2, 4))
output = net(X)

print(*[(name, param.data) for name, param in net[0].named_parameters()])
'''
('weight', tensor([[-0.0273, -0.4942, -0.0880,  0.3169],
        [ 0.2205,  0.3344, -0.4425, -0.0882],
        [ 0.1726, -0.0007, -0.0256, -0.0593],
        [-0.3854, -0.0934, -0.4641,  0.1950],
        [ 0.2358, -0.4820, -0.2315,  0.1642],
        [-0.2645,  0.2021,  0.3167, -0.0042],
        [ 0.1714, -0.2201, -0.3326, -0.2908],
        [-0.3196,  0.0584, -0.1059,  0.0256]])) ('bias', tensor([ 0.3285,  0.4167, -0.2343,  0.3099,  0.1576, -0.0397, -0.2190, -0.3854]))
'''
print(*[(name, param.shape) for name, param in net.named_parameters()])
'''
('0.weight', torch.Size([8, 4])) ('0.bias', torch.Size([8])) ('2.weight', torch.Size([1, 8])) ('2.bias', torch.Size([1]))
'''

如果网络是由多个块相互嵌套的,可以按块索引后再访问参数:

import torch
from torch import nn

def block1():
    return nn.Sequential(nn.Linear(4, 8), nn.ReLU(),
                         nn.Linear(8, 4), nn.ReLU())

def block2():
    net = nn.Sequential()
    for i in range(4):
        net.add_module(f'block {i}', block1())
    return net

net = nn.Sequential(block2(), nn.Linear(4, 1))
X = torch.rand(size=(2, 4))
output = net(X)

print(net)
'''
Sequential(
  (0): Sequential(
    (block 0): Sequential(
      (0): Linear(in_features=4, out_features=8, bias=True)
      (1): ReLU()
      (2): Linear(in_features=8, out_features=4, bias=True)
      (3): ReLU()
    )
    (block 1): Sequential(
      (0): Linear(in_features=4, out_features=8, bias=True)
      (1): ReLU()
      (2): Linear(in_features=8, out_features=4, bias=True)
      (3): ReLU()
    )
    (block 2): Sequential(
      (0): Linear(in_features=4, out_features=8, bias=True)
      (1): ReLU()
      (2): Linear(in_features=8, out_features=4, bias=True)
      (3): ReLU()
    )
    (block 3): Sequential(
      (0): Linear(in_features=4, out_features=8, bias=True)
      (1): ReLU()
      (2): Linear(in_features=8, out_features=4, bias=True)
      (3): ReLU()
    )
  )
  (1): Linear(in_features=4, out_features=1, bias=True)
)
'''
print(net[0][1][0].bias.data)
'''
tensor([-0.0083,  0.2490,  0.1794,  0.1927,  0.1797,  0.1156,  0.4409,  0.1320])
'''

2. 参数初始化

PyTorch 的 nn.init 模块提供了多种初始化方法:

  • nn.init.constant_(layer.weight, c):将权重参数初始化为指定的常量值;
  • nn.init.zeros_(layer.weight):将权重参数初始化为 0;
  • nn.init.ones_(layer.weight):将权重参数初始化为 1;
  • nn.init.uniform_(layer.weight, a, b):将权重参数按均匀分布初始化;
  • nn.init.xavier_uniform_(layer.weight)
  • nn.init.normal_(layer.weight, mean, std):将权重参数按正态分布初始化;
  • nn.init.orthogonal_(layer.weight):将权重参数初始化为正交矩阵;
  • nn.init.sparse_(layer.weight, sparsity, std):将权重参数初始化为稀疏矩阵;

初始化时,可以直接 net.apply(init_method) 初始化整个网络,也可以 net[i].apply(init_method) 初始化某一层:

import torch
from torch import nn

def init_normal(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, mean=0, std=0.01)
        nn.init.zeros_(m.bias)

def init_constant(m):
    if type(m) == nn.Linear:
        nn.init.constant_(m.weight, 1)
        nn.init.zeros_(m.bias)

net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1))
X = torch.rand(size=(2, 4))
output = net(X)

# net.apply(init_normal)
net[0].apply(init_normal)
net[2].apply(init_constant)

3. 延后初始化

有些情况下,无法提前判断网络的输入维度。为了代码能够继续运行,需要使用延后初始化,即直到数据第一次通过模型传递时,框架才会动态地推断出每个层的大小。由于 PyTorch 的延后初始化功能还处于开发阶段,API 和功能随时可能变化,下面只给出简单示例:

import torch
from torch import nn

net = nn.Sequential(nn.LazyLinear(256), nn.ReLU(), nn.LazyLinear(10))

print(net)
'''
Sequential(
  (0): LazyLinear(in_features=0, out_features=256, bias=True)
  (1): ReLU()
  (2): LazyLinear(in_features=0, out_features=10, bias=True)
)
'''

X = torch.rand(2, 20)
net(X)
print(net)
'''
Sequential(
  (0): Linear(in_features=20, out_features=256, bias=True)
  (1): ReLU()
  (2): Linear(in_features=256, out_features=10, bias=True)
)
'''

四. 文件读写

可以使用 torch.load(file)torch.save(x, file) 函数读写张量和模型参数。

1. 加载和保存张量

只要保证读写格式一致即可:

import torch
from torch import nn
from torch.nn import functional as F

x = torch.arange(4)
y = torch.zeros(4)
torch.save([x, y],'xy.pth')

x2, y2 = torch.load('xy.pth')
print(x2, y2)       # tensor([0, 1, 2, 3]) tensor([0., 0., 0., 0.])

保存张量的文件格式没有要求,甚至可以没有后缀名。因为 torch.save(x, file) 函数本质上是使用 Python 的 pickle 模块来序列化对象并将其保存到文件中的,pickle 模块负责将 Python 对象转换为字节流,而文件的扩展名本身并不影响 pickle 模块的工作。

2. 加载和保存模型参数

因为模型一般是自定义的类,所以加载模型前要先实例化一个相同类别的变量,再将模型参数加载到该变量中:

import torch
from torch import nn
from torch.nn import functional as F

class MLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden = nn.Linear(4, 2)
        self.output = nn.Linear(2, 3)

    def forward(self, x):
        return self.output(F.relu(self.hidden(x)))

net = MLP()
X = torch.randn(size=(2, 4))
Y = net(X)
print(net.state_dict())
'''
OrderedDict([('hidden.weight', tensor([[-0.0154, -0.3586, -0.3653, -0.2950],
        [ 0.2591, -0.2563,  0.3833,  0.1449]])), ('hidden.bias', tensor([0.1884, 0.3998])), ('output.weight', tensor([[-0.4805,  0.4077],
        [-0.0933,  0.0584],
        [ 0.3114,  0.6285]])), ('output.bias', tensor([-0.2552, -0.6520,  0.3290]))])
'''

torch.save(net.state_dict(), 'mlp.pth')

net2 = MLP()
net2.load_state_dict(torch.load('mlp.pth'))
print(net2.state_dict())
'''
OrderedDict([('hidden.weight', tensor([[-0.0154, -0.3586, -0.3653, -0.2950],
        [ 0.2591, -0.2563,  0.3833,  0.1449]])), ('hidden.bias', tensor([0.1884, 0.3998])), ('output.weight', tensor([[-0.4805,  0.4077],
        [-0.0933,  0.0584],
        [ 0.3114,  0.6285]])), ('output.bias', tensor([-0.2552, -0.6520,  0.3290]))])
'''

也可以只保存单层参数:

import torch
from torch import nn
from torch.nn import functional as F

class MLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden = nn.Linear(4, 2)
        self.output = nn.Linear(2, 3)

    def forward(self, x):
        return self.output(F.relu(self.hidden(x)))

net = MLP()
X = torch.randn(size=(2, 4))
Y = net(X)
print(net.state_dict())
'''
OrderedDict([('hidden.weight', tensor([[-0.2937,  0.1589,  0.2349,  0.1130],
        [ 0.4170,  0.2699,  0.3760,  0.0201]])), ('hidden.bias', tensor([ 0.3914, -0.1185])), ('output.weight', tensor([[0.0884, 0.2572],
        [0.1547, 0.0164],
        [0.3386, 0.5151]])), ('output.bias', tensor([-0.5032, -0.2515, -0.4531]))])
'''

torch.save(net.hidden.state_dict(), 'mlp.pth')

net2 = MLP()
net2.hidden.load_state_dict(torch.load('mlp.pth'))
print(net2.state_dict())
'''
OrderedDict([('hidden.weight', tensor([[-0.2937,  0.1589,  0.2349,  0.1130],
        [ 0.4170,  0.2699,  0.3760,  0.0201]])), ('hidden.bias', tensor([ 0.3914, -0.1185])), ('output.weight', tensor([[ 0.2318,  0.3837],
        [ 0.2380,  0.6463],
        [-0.6014,  0.3717]])), ('output.bias', tensor([-0.3154, -0.0078, -0.2676]))])
'''

五. GPU 计算

在 PyTorch 中,CPU 和 GPU 分别可以用 torch.device('cpu')torch.device('cuda') 表示。如果有多个 GPU,可以使用 torch.device(fcuda:i') 来表示,cuda:0cuda 等价。可以查询所有可用 GPU 也可以指定 GPU:

import torch

def try_gpu(i=0):
    if torch.cuda.device_count() >= i + 1:
        return torch.device(f'cuda:{i}')
    return torch.device('cpu')

def try_all_gpus():
    devices = [torch.device(f'cuda:{i}')
             for i in range(torch.cuda.device_count())]
    return devices if devices else [torch.device('cpu')]

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

张量和网络模型都可以通过 .cuda(device) 函数移动到 GPU 上:

import torch
from torch import nn

net = nn.Sequential(
    nn.Linear(2, 64),
    nn.ReLU(),
    nn.Linear(64, 32)
)
X = torch.randn(size=(4, 2))
loss = nn.MSELoss()

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

net.cuda(device=device)
X.cuda(device=device)
loss.cuda(device=device)

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

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

相关文章

Doccano 修复 spacy.gold 的bug

引言 最初只是想把Doccano标注的数据集转换成BIO(类似conll2003数据集)的标注格式&#xff1b; 按照PR的修改意见实现了修改&#xff0c;但是本人不建议这么做&#xff1b; 应该随着Doccano的升级&#xff0c;Doccano的导出格式发生了变化&#xff0c;而原来的doccano-transfo…

正确认识肠道内脆弱拟杆菌——其在健康的阴暗面和光明面

谷禾健康 脆弱拟杆菌(Bacteroides fragilis)是拟杆菌门拟杆菌属的重要成员。事实上&#xff0c;脆弱拟杆菌因其免疫调节功能而成为该属中研究最多的共生微生物。它是革兰氏阴性、不形成孢子、杆状专性厌氧菌。在人类健康中扮演着复杂而双面的角色。 这种革兰氏阴性专性厌氧菌常…

架构设计方法(4A架构)-信息架构

1、 信息架构&#xff08;IA&#xff09;&#xff1a;现实事物在IT世界的建模体现 2、数据资产目录 3、 识别业务对象&#xff1a;业务对象的设计方法 设计方法 1.基于业务流程识别业务活动。 2. 识别业务流程中每个业务活动的输入、输出等BI&#xff08;Business Item&#…

Zabbix企业运维监控工具

Zabbix企业级监控方案 常见监控软件介绍 Cacti Cacti是一套基于 PHP、MySQL、SNMP 及 RRD Tool 开发的监测图形分析工具&#xff0c;Cacti 是使用轮询的方式由主服务器向设备发送数据请求来获取设备上状态数据信息的,如果设备不断增多,这个轮询的过程就非常的耗时&#xff0…

SpringBoot源码解读与原理分析(三十七)SpringBoot整合WebMvc(二)DispatcherServlet的工作全流程

文章目录 前言12.4 DispatcherServlet的工作全流程12.4.1 DispatcherServlet#service12.4.2 processRequest12.4.3 doService12.4.3.1 isIncludeRequest的判断12.4.3.2 FlashMapManager的设计 12.4.4 doDispatch12.4.4.1 处理文件上传请求12.4.4.2 获取可用的Handler&#xff0…

Vue+SpringBoot打造农村物流配送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统登录、注册界面2.2 系统功能2.2.1 快递信息管理&#xff1a;2.2.2 位置信息管理&#xff1a;2.2.3 配送人员分配&#xff1a;2.2.4 路线规划&#xff1a;2.2.5 个人中心&#xff1a;2.2.6 退换快递处理&#xff1a;…

5G时代对于工业化场景应用有什么改善

5G 不仅仅是 4G 的技术升级&#xff0c;而是将平板电脑和智能手机的技术升级。除了更好的高清视频流和其他高带宽应用&#xff0c;消费者不会注意到很多性能差异。然而&#xff0c;在工业领域&#xff0c;5G 代表着巨大的飞跃。 在工厂和厂房内&#xff0c; 设备的Wi-Fi 网络经…

低功耗运放D722,具有9MHz的高增益带宽积,转换速率为8.5V/μs

D722是低噪声、低电压、低功耗运放&#xff0c;应用广泛。D722具有9MHz的高增益带宽积&#xff0c;转换速率为8.5V/μs&#xff0c;静态电流为1.7mA&#xff08;5V电源电压&#xff09;。D722具有低电压、低噪声的特点&#xff0c;并提供轨到轨输出能力&#xff0c;D722的最大输…

本地maven库缓存导入私库

为了加速编译代码&#xff0c;想将本地maven缓存导入内网私库使用。 脚本网上搜的 #!/bin/bash # copy and run this script to the root of the repository directory containing files # this script attempts to exclude uploading itself explicitly so the script name …

C++指针(二)

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 文章目录 1.数组指针 1.1数组指针的概念 1.2数组指针的用处 1.3数组指针的操作 1.4二维数组如何访问 1.5数组指针访问流程 1.6数组指针的练习题 2.指针数组 2.1指针数组的概念 2.2指针数组的用处 2…

AMEYA360:航顺车规级MCU HK32AUTO39A的汽车侧滑门控制方案

汽车滑门因侧开启方式与传统车门相比&#xff0c;具有易泊车、开启宽度大和方便乘员货物进出的优点&#xff0c;很受消费者的青睐。汽车市场上&#xff0c;无论是面向高端的商务豪华MPV&#xff0c;还是面向城市物流的轻型客车和低端客运微型车都采用了汽车机械滑门系统。 汽车…

韦东山嵌入式Liunx入门驱动开发三

文章目录 一、GPIO和Pinctrl子系统的使用1-1 Pinctrl子系统1-2 GPIO子系统1-3 基于GPIO子系统的LED驱动程序 本人学习完韦老师的视频&#xff0c;因此来复习巩固&#xff0c;写以笔记记之。 韦老师的课比较难&#xff0c;第一遍不知道在说什么&#xff0c;但是坚持看完一遍&…

死记硬背spring bean 的生命周期

1.bean的生命周期 我们平常经常使用类似于new Object()的方式去创建对象&#xff0c;在这个对象没有任何引用的时候&#xff0c;会被gc给回收掉。而对于spring而言&#xff0c;它本身存在一个Ioc容器&#xff0c;就是用来管理对象的&#xff0c;而对象的生命周期也完全由这个容…

为什么软考报名人数越来越多?

2020年软考报名人数404666人&#xff0c;广东省报考人数超过14万人。 ●2021年软考通信考试报名人数突破100万人&#xff0c;估计软考有90多万。 ●2022年软考通信考试共129万人&#xff0c;估计软考占了120多万人。 ●2023年软考具体报名人数没有公布&#xff0c;但工业和信…

three 层级模型

group.remove(mesh1,mesh2);Vector3与模型位置、缩放属性 Group层级模型(树结构) 创建了两个网格模型mesh1、mesh2&#xff0c;通过THREE.Group类创建一个组对象group,然后通过add方法把网格模型mesh1、mesh2作为设置为组对象group的子对象&#xff0c;然后在通过执行scene.a…

ETL数据仓库的使用方式

一、ETL的过程 在 ETL 过程中&#xff0c;数据从源系统中抽取&#xff08;Extract&#xff09;&#xff0c;经过各种转换&#xff08;Transform&#xff09;操作&#xff0c;最后加载&#xff08;Load&#xff09;到目标数据仓库中。以下是 ETL 数仓流程的基本步骤&#xff1a…

猫为什么挑食?改善挑食的主食冻干推荐

现代养猫人士往往把自家的小猫看作是生活中的小宝贝&#xff0c;十分宠爱。然而&#xff0c;这种宠爱有时也会导致猫咪养成挑食的不良习惯。那么&#xff0c;猫为什么挑食&#xff1f;当猫咪拒绝吃猫粮时&#xff0c;我们应该如何应对呢&#xff1f; 今天&#xff0c;我要分享一…

【前端素材】推荐优质后台管理系统 Adminity平台模板(附源码)

一、需求分析 1、系统定义 后台管理系统是一种用于管理网站、应用程序或系统的管理界面&#xff0c;通常由管理员和工作人员使用。它提供了访问和控制网站或应用程序后台功能的工具和界面&#xff0c;使其能够管理用户、内容、数据和其他各种功能。 2、功能需求 后台管理系…

C++利用汇编挖掘编程语言的本质..

1.谬论 很多非一手的资料特别是中文资料其实并不可靠 因为很多作者都是直接通过转载他人的作品 也不管他人作品真与假 而且有一部分的作品中的言论和官方描述相去甚远 有的则是翻译的过程中出现了问题 比如sizeof很多人认为是一个函数 其实他并不是一个函数 而是一个运算符 是…

【Godot4自学手册】第十八节主人公的血量显示

今天&#xff0c;我主要学习主人公的血量显示&#xff0c;在屏幕的左上角&#xff0c;会显示主人公的头像&#xff0c;后面会显示血量进度条&#xff0c;当主人公受到伤害时&#xff0c;血量会实时变动&#xff0c;显示绿色血条减少&#xff0c;后是红色血量逐渐减少到正确位置…