PyTorch深度学习实战(3)——使用PyTorch构建神经网络

news2024/11/21 0:27:14

PyTorch深度学习实战(3)——使用PyTorch构建神经网络

    • 0. 前言
    • 1. PyTorch 构建神经网络初体验
      • 1.1 使用 PyTorch 构建神经网络
      • 1.2 神经网络数据加载
      • 1.3 模型测试
      • 1.4 获取中间层的值
    • 2. 使用 Sequential 类构建神经网络
    • 3. PyTorch 模型的保存和加载
      • 3.1 模型保存所需组件
      • 3.2 模型状态
      • 3.3 模型保存
      • 3.4 模型加载
    • 小结
    • 系列链接

0. 前言

我们已经学习了如何从零开始构建神经网络,神经网络通常包括输入层、隐藏层、输出层、激活函数、损失函数和学习率等基本组件。在本节中,我们将学习如何在简单数据集上使用 PyTorch 构建神经网络,利用张量对象操作和梯度值计算更新网络权重。

1. PyTorch 构建神经网络初体验

1.1 使用 PyTorch 构建神经网络

为了介绍如何使用 PyTorch 构建神经网络,我们将尝试解决两个数字的相加问题。

(1) 初始化数据集,定义输入 (x) 和输出 (y) 值:

import torch
x = [[1,2],[3,4],[5,6],[7,8]]
y = [[3],[7],[11],[15]]

在初始化的输入和输出变量中,输入中的每个列表的值之和就是输出列表中对应的值。

(2) 将输入列表转换为张量对象:

X = torch.tensor(x).float()
Y = torch.tensor(y).float()

在以上代码中,将张量对象转换为浮点对象。此外,将输入 ( X ) 和输出 ( Y ) 数据点注册到 device 中:

device = 'cuda' if torch.cuda.is_available() else 'cpu'
X = X.to(device)
Y = Y.to(device)

(3) 定义神经网络架构。

导入 torch.nn 模块用于构建神经网络模型:

from torch import nn

创建神经网络架构类 MyNeuralNet,继承自 nn.Modulenn.Module 是所有神经网络模块的基类:

class MyNeuralNet(nn.Module):

在类中,使用 __init__ 方法初始化神经网络的所有组件,调用 super().__init__() 确保类继承 nn.Module

    def __init__(self):
        super().__init__()

使用以上代码,通过指定 super().__init__() 可以利用为 nn.Module 编写的所有预构建函数,初始化的组件将用于 MyNeuralNet 类中的不同方法。

定义神经网络中的网络层:

        self.input_to_hidden_layer = nn.Linear(2,8)
        self.hidden_layer_activation = nn.ReLU()
        self.hidden_to_output_layer = nn.Linear(8,1)

在以上代码中,指定了神经网络的所有层——一个全连接层 (self.input_to_hidden_layer),使用 ReLU 激活函数 (self.hidden_layer_activation),最后仍是一个全连接层 (self.hidden_to_output_layer)。

将初始化后的神经网络组件连接在一起,并定义网络的前向传播方法 forward

    def forward(self, x):
        x = self.input_to_hidden_layer(x)
        x = self.hidden_layer_activation(x)
        x = self.hidden_to_output_layer(x)
        return x

必须使用 forward 作为前向传播的函数名,因为 PyTorch 保留此函数作为执行前向传播的方法,使用其他名称都会引发错误。

通过打印 nn.Linear 方法的输出了解函数作用:

print(nn.Linear(2, 7))
# Linear(in_features=2, out_features=8, bias=True)

在以上代码中,全连接层以 2 个值作为输入并输出 7 个值,且包含与之关联的偏置参数。

(4) 通过执行以下代码访问每个神经网络组件的初始权重。

创建 MyNeuralNet 类对象的实例并将其注册到 device

mynet = MyNeuralNet().to(device)

可以通过类似代码访问每一层的权重和偏置:

print(mynet.input_to_hidden_layer.weight)

代码输出结果如下:

Parameter containing:
tensor([[ 0.0984,  0.3058],
        [ 0.2913, -0.3629],
        [ 0.0630,  0.6347],
        [-0.5134, -0.2525],
        [ 0.2315,  0.3591],
        [ 0.1506,  0.1106],
        [ 0.2941, -0.0094],
        [-0.0770, -0.4165]], device='cuda:0', requires_grad=True)

每次执行时输出的值并不相同,因为神经网络每次都使用随机值进行初始化。如果希望每次在执行相同代码时保持相同输出,则需要在创建类对象的实例之前使用 Torch 中的 manual_seed 方法指定随机种子 torch.manual_seed(0)

(5) 可以通过以下代码获得神经网络的所有参数:

mynet.parameters()

以上代码会返回一个生成器对象,最后通过生成器循环获取参数:

for param in mynet.parameters():
    print(param)

代码输出结果如下:

Parameter containing:
tensor([[ 0.2955,  0.3231],
        [ 0.5153,  0.1734],
        [-0.6359, -0.1406],
        [ 0.3820, -0.1085],
        [ 0.2816, -0.2283],
        [ 0.4633,  0.6564],
        [-0.1605, -0.4450],
        [ 0.0788, -0.0147]], device='cuda:0', requires_grad=True)
Parameter containing:
tensor([[ 0.2955,  0.3231],
        [ 0.5153,  0.1734],
        [-0.6359, -0.1406],
        [ 0.3820, -0.1085],
        [ 0.2816, -0.2283],
        [ 0.4633,  0.6564],
        [-0.1605, -0.4450],
        [ 0.0788, -0.0147]], device='cuda:0', requires_grad=True)
Parameter containing:
tensor([-0.4761,  0.6370,  0.6744, -0.4103, -0.3714,  0.1491, -0.2304,  0.5571],
       device='cuda:0', requires_grad=True)
Parameter containing:
tensor([[-0.0440,  0.0028,  0.3024,  0.1915,  0.1426, -0.2859, -0.2398, -0.2134]],
       device='cuda:0', requires_grad=True)
Parameter containing:
tensor([-0.3238], device='cuda:0', requires_grad=True)

该模型已将这些张量注册为跟踪前向和反向传播所必需的特殊对象,在 __init__ 方法中定义 nn 神经网络层时,它会自动创建相应的张量并同时进行注册,也可以使用 nn.parameter(<tensor>) 函数手动注册这些参数。因此,本节定义的神经网络类 myNeuralNet 等价于以下代码:

class MyNeuralNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.input_to_hidden_layer = nn.parameter(torch.rand(2,8))
        self.hidden_layer_activation = nn.ReLU()
        self.hidden_to_output_layer = nn.parameter(torch.rand(8,1))
    def forward(self, x):
        x = x @ self.input_to_hidden_layer
        x = self.hidden_layer_activation(x)
        x = x @ self.hidden_to_output_layer
        return x

(6) 定义损失函数,由于需要预测连续输出,因此使用均方误差作为损失函数:

loss_func = nn.MSELoss()

通过将输入值传递给神经网络对象,然后计算给定输入的损失函数值:

_Y = mynet(X)
loss_value = loss_func(_Y,Y)
print(loss_value)
# tensor(127.4498, device='cuda:0', grad_fn=<MseLossBackward>)

在以上代码中,mynet(X) 根据给定输入通过神经网络计算输出值,loss_func 函数计算对应于神经网络预测 (_Y) 和实际值 (Y) 的 MSELoss 值。需要注意的是,根据 PyTorch 约定,在计算损失时,我们总是首先传入预测结果,然后传入实际标记值。

(7) 定义用于降低损失值的优化器,优化器的输入是与神经网络相对应的参数(权重和偏差)以及更新权重时的学习率。本节,我们使用随机梯度下降 (Stochastic Gradient Descent, SGD)。从 torch.optim 模块中导入 SGD 方法,然后将神经网络对象 (mynet) 和学习率 (lr) 作为参数传递给 SGD 方法:

from torch.optim import SGD
opt = SGD(mynet.parameters(), lr = 0.001)

(8) 一个 epoch 训练过程包含以下步骤:

  • 计算给定输入和输出对应的损失值
  • 计算参数对应的梯度
  • 根据参数的学习率和梯度更新权重
  • 更新权重后,确保在下一个 epoch 计算梯度之前刷新上一步中计算的梯度
    opt.zero_grad()
    loss_value = loss_func(mynet(X),Y)
    loss_value.backward()
    opt.step()

使用 for 循环重复执行上述步骤。在以下代码中,执行 50epoch,此外,在 loss_history 列表中存储每个 epoch 中的损失值:

loss_history = []
for _ in range(50):
    opt.zero_grad()
    loss_value = loss_func(mynet(X),Y)
    loss_value.backward()
    opt.step()
    loss_history.append(loss_value)

绘制损失随 epoch 的变化情况:

import matplotlib.pyplot as plt
plt.plot(loss_history)
plt.title('Loss variation over increasing epochs')
plt.xlabel('epochs')
plt.ylabel('loss value')
plt.show()

损失值变化情况

1.2 神经网络数据加载

批大小 (batch size) 是神经网络中的重要超参数,批大小是指计算损失值或更新权重时考虑的数据样本数。假设数据集中有数百万个数据样本,一次将所有数据点用于一次权重更新并非最佳选择,因为内存可能无法容纳如此多数据。使用抽样样本可以充分代表数据,批大小可以用于获取具有足够代表性的多个数据样本。在本节中,我们指定计算权重梯度时要考虑的批大小以更新权重,然后计算更新后的损失值。

(1) 导入用于加载数据和处理数据集的方法:

from torch.utils.data import Dataset, DataLoader
import torch
import torch.nn as nn

(2) 导入数据,将数据转换为浮点数,并将它们注册到相应设备中:

x = [[1,2],[3,4],[5,6],[7,8]]
y = [[3],[7],[11],[15]]

X = torch.tensor(x).float()
Y = torch.tensor(y).float()

device = 'cuda' if torch.cuda.is_available() else 'cpu'
X = X.to(device)
Y = Y.to(device)

(3) 创建数据集类 MyDataset

class MyDataset(Dataset):

MyDataset 类中,存储数据信息以便可以将一批 (batch) 数据点捆绑在一起(使用 DataLoader),并通过一次前向和反向传播更新权重。

定义 __init__ 方法,该方法接受输入和输出对并将它们转换为 Torch 浮点对象:

    def __init__(self,x,y):
        self.x = x.clone().detach() # torch.tensor(x).float()
        self.y = y.clone().detach() # torch.tensor(y).float()

指定输入数据集的长度 (__len__):

    def __len__(self):
        return len(self.x)

__getitem__ 方法用于获取指定数据样本:

    def __getitem__(self, ix):
        return self.x[ix], self.y[ix]

在以上代码中,ix 表示要从数据集中获取的数据索引。

(4) 创建自定义类的实例:

ds = MyDataset(X, Y)

(5) 通过 DataLoader 传递数据集实例,从原始输入输出张量对象中获取 batch_size 个数据点:

dl = DataLoader(ds, batch_size=2, shuffle=True)

在以上代码中,指定从原始输入数据集 (ds) 中获取两个 (batch_size=2) 随机样本 (shuffle=True)数据点。

循环遍历 dl 获取批数据信息:

for x, y in dl:
    print(x, y)

输出结果如下所示:

tensor([[3., 4.],
        [5., 6.]], device='cuda:0') tensor([[ 7.],
        [11.]], device='cuda:0')
tensor([[1., 2.],
        [7., 8.]], device='cuda:0') tensor([[ 3.],
        [15.]], device='cuda:0')

可以看到以上代码生成了两组输入-输出对,因为原始数据集中共有 4 个数据点,而指定的批大小为 2

(6) 定义神经网络类:

class MyNeuralNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.input_to_hidden_layer = nn.Linear(2,8)
        self.hidden_layer_activation = nn.ReLU()
        self.hidden_to_output_layer = nn.Linear(8,1)
    def forward(self, x):
        x = self.input_to_hidden_layer(x)
        x = self.hidden_layer_activation(x)
        x = self.hidden_to_output_layer(x)
        return x

(7) 定义模型对象 (mynet)、损失函数 (loss_func) 和优化器 (opt):

mynet = MyNeuralNet().to(device)
loss_func = nn.MSELoss()
from torch.optim import SGD
opt = SGD(mynet.parameters(), lr = 0.001)

(8) 最后,循环遍历批数据点以最小化损失值:

import time
loss_history = []
start = time.time()
for _ in range(50):
    for data in dl:
        x, y = data
        opt.zero_grad()
        loss_value = loss_func(mynet(x),y)
        loss_value.backward()
        opt.step()
        loss_history.append(loss_value)
end = time.time()
print(end - start)
# 0.08548569679260254

虽然以上代码与上一小节中使用的代码非常相似,但与上一小节相比,每个 epoch 更新权重的次数变为原来的 2 倍,因为本节中使用的批大小为 2,而上一小节中的批大小为 4 (即一次使用全部数据点)。

1.3 模型测试

在上一小节中,我们学习了如何在已知数据点上拟合模型。在本节中,我们将学习如何利用上一小节训练的 mynet 模型中定义的前向传播方法 forward 来预测模型没有见过的数据点(测试数据)。

(1) 创建用于测试模型的数据点:

val_x = [[10,11]]

新数据集 (val_x) 与输入数据集相同,也是由列表数据组成的列表。

(2) 将新数据点转换为张量浮点对象并注册到 device 中:

val_x = torch.tensor(val_x).float().to(device)

(3) 通过训练好的神经网络 (mynet) 传递张量对象,与通过模型执行前向传播的用法相同:

print(mynet(val_x))
# tensor([[20.0105]], device='cuda:0', grad_fn=<AddmmBackward>)

以上代码返回模型对输入数据点的预测输出值。

1.4 获取中间层的值

在实际应用中,我们可能需要获取神经网络的中间层值,例如风格迁移和迁移学习等,PyTorch 提供了两种方式获取神经网络中间值。

一种方法是直接调用神经网络层,将它们当做函数使用:

print(mynet.hidden_layer_activation(mynet.input_to_hidden_layer(X)))

需要注意的是,我们必须安装模型输入、输出顺序调用相应神经网络层,例如,在以上代码中 input_to_hidden_layer 的输出是 hidden_layer_activation 层的输入。

另一种方法是在 forward 方法中指定想要查看的网络层,虽然以下代码与上一小节中的 MyNeuralNet 类基本相同,但 forward 方法不仅返回输出,还返回激活后的隐藏层值 (hidden2):

class MyNeuralNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.input_to_hidden_layer = nn.Linear(2,8)
        self.hidden_layer_activation = nn.ReLU()
        self.hidden_to_output_layer = nn.Linear(8,1)
    def forward(self, x):
        hidden1 = self.input_to_hidden_layer(x)
        hidden2 = self.hidden_layer_activation(hidden1)
        x = self.hidden_to_output_layer(hidden2)
        return x, hidden2

通过使用以下代码访问隐藏层值,mynet 的第 0 个索引输出是网络前向传播的最终输出,而第 1 个索引输出是隐藏层激活后的值:

print(mynet(X)[1])

2. 使用 Sequential 类构建神经网络

我们已经学习了如何通过定义一个类来构建神经网络,在该类中定义了层以及层之间的连接方式。然而,除非需要构建一个复杂的网络,否则,只需要利用 Sequential 类并指定层和层堆叠的顺序即可搭建神经网络,本节继续使用简单数据集训练神经网络。

(1) 导入相关库并定义使用的设备:

import torch
import torch.nn as nn
import numpy as np
from torch.utils.data import Dataset, DataLoader
device = 'cuda' if torch.cuda.is_available() else 'cpu'

(2) 定义数据集与数据集类 (MyDataset):

x = [[1,2],[3,4],[5,6],[7,8]]
y = [[3],[7],[11],[15]]

class MyDataset(Dataset):
    def __init__(self, x, y):
        self.x = torch.tensor(x).float().to(device)
        self.y = torch.tensor(y).float().to(device)
    def __getitem__(self, ix):
        return self.x[ix], self.y[ix]
    def __len__(self): 
        return len(self.x)

(3) 定义数据集 (ds) 和数据加载器 (dl) 对象:

ds = MyDataset(x, y)
dl = DataLoader(ds, batch_size=2, shuffle=True)

(4) 使用 nn 模块中 Sequential 类定义模型架构:

model = nn.Sequential(
    nn.Linear(2, 8),
    nn.ReLU(),
    nn.Linear(8, 1)
).to(device)

在以上代码中,我们定义了与上小节相同的网络架构,nn.Linear 接受二维输入并为每个数据点提供八维输出,nn.ReLU 在八维输出之上执行 ReLU 激活,最后,使用 nn.Linear 接受八维输入并得到一维输出。

(5) 打印模型的摘要 (summary),查看模型架构信息。

为了查看模型摘要,需要使用 pip 安装 torchsummary 库:

pip install torchsummary

安装完成后,导入库 torchsummary

from torchsummary import summary

打印模型摘要,函数接受模型名称及模型输入大小(需要使用整数元组)作为参数:

print(summary(model, (2,)))

输出结果如下所示:

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Linear-1                    [-1, 8]              24
              ReLU-2                    [-1, 8]               0
            Linear-3                    [-1, 1]               9
================================================================
Total params: 33
Trainable params: 33
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 0.00
Params size (MB): 0.00
Estimated Total Size (MB): 0.00
----------------------------------------------------------------

以第一层输出为例,其形状为 (-1, 8),其中 -1 表示 batch size8 表示对于每个数据点会得到一个 8 维输出,得到形状为 batch size x 8 的输出。

(6) 接下来,定义损失函数 (loss_func) 和优化器 (opt) 并训练模型:

loss_func = nn.MSELoss()
from torch.optim import SGD
opt = SGD(model.parameters(), lr = 0.001)
import time
loss_history = []
start = time.time()
for _ in range(50):
    for ix, iy in dl:
        opt.zero_grad()
        loss_value = loss_func(model(ix),iy)
        loss_value.backward()
        opt.step()
        loss_history.append(loss_value)
end = time.time()
print(end - start)

(7) 训练模型后,在验证数据集上预测值。

定义验证数据集:

val = [[8,9],[10,11],[1.5,2.5]]

将验证数据转换为浮点数,然后将它们转换为张量对象并将它们注册到 device 中,通过模型传递验证数据预测输出:

val = torch.tensor(val).float()
print(model(val.to(device)))
"""
tensor([[16.7774],
        [20.6186],
        [ 4.2415]], device='cuda:0', grad_fn=<AddmmBackward>)
"""

3. PyTorch 模型的保存和加载

神经网络模型处理的一个重要方面是在训练后保存和加载模型,保存模型后,我们可以利用已经训练好的模型中进行推断,只需要加载已经训练过的模型,而无需再次对其进行训练。

3.1 模型保存所需组件

首先了解保存神经网络模型所需的完整组件:

  • 每个张量(参数)的唯一名称(键)
  • 网络中张量间的连接的方式
  • 每个张量的值(权重/偏置值)

第一个组件是在定义的 __init__ 阶段处理的,而第二个组件是在前向计算方法定义期间处理的。默认情况下,张量中的值在 __init__ 阶段随机初始化,但加载预训练模型时我们需要加载一组在训练模型时学习到的固定权重值,并将每个值与特定名称相关联。

3.2 模型状态

model.state_dict() 可以用于了解保存和加载 PyTorch 模型的工作原理,model.state_dict() 中的字典 (OrderedDict) 对应于模型的参数名称(键)及其值(权重和偏置值),state 指的是模型的当前快照,返回的输出中,键是模型网络层的名称,值对应于这些层的权重:

print(model.state_dict())
"""
OrderedDict([('0.weight', tensor([[-0.4732,  0.1934],
        [ 0.1475, -0.2335],
        [-0.2586,  0.0823],
        [-0.2979, -0.5979],
        [ 0.2605,  0.2293],
        [ 0.0566,  0.6848],
        [-0.1116, -0.3301],
        [ 0.0324,  0.2609]], device='cuda:0')), ('0.bias', tensor([ 0.6835,  0.2860,  0.1953, -0.2162,  0.5106,  0.3625,  0.1360,  0.2495],
       device='cuda:0')), ('2.weight', tensor([[ 0.0475,  0.0664, -0.0167, -0.1608, -0.2412, -0.3332, -0.1607, -0.1857]],
       device='cuda:0')), ('2.bias', tensor([0.2595], device='cuda:0'))])
"""

3.3 模型保存

使用 torch.save(model.state_dict(), 'mymodel.pth') 可以将模型以 Python 序列化格式保存在磁盘上,其中 mymodel.pth 表示文件名。在调用 torch.save 之前最好将模型传输到 CPU 中,将张量保存为 CPU 张量有助于将模型加载到任意机器上:

save_path = 'mymodel.pth'
torch.save(model.state_dict(), save_path)

3.4 模型加载

加载模型首先需要初始化模型,然后从 state_dict 中加载权重:

(1) 使用与训练时相同的代码创建一个空模型:

model = nn.Sequential(
    nn.Linear(2, 8),
    nn.ReLU(),
    nn.Linear(8, 1)
).to(device)

(2) 从磁盘加载模型并反序列化以创建一个 OrderedDict 值:

state_dict = torch.load('mymodel.pth')

(3) 加载 state_dict 到模型中,并将其注册到 device 中,执行预测任务:

model.load_state_dict(state_dict)
model.to(device)

val = [[8,9],[10,11],[1.5,2.5]]
val = torch.tensor(val).float()
model(val.to(device))

小结

在本节中,我们使用 PyTorch 在简单数据集上构建了一个神经网络,训练神经网络来映射输入和输出,并通过执行反向传播来更新权重值以最小化损失值,并利用 Sequential 类简化网络构建过程;介绍了获取网络中间值的常用方法,以及如何使用 saveload 方法保存和加载模型,以避免再次训练模型。

系列链接

PyTorch深度学习实战(1)——神经网络与模型训练过程详解
PyTorch深度学习实战(2)——PyTorch基础

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

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

相关文章

【框架源码】Spring源码解析之Bean生命周期流程

观看本文前&#xff0c;我们先思考一个问题&#xff0c;什么是Spring的bean的生命周期&#xff1f;这也是我们在面试的时候&#xff0c;面试官常问的一个问题。 在没有Spring之前&#xff0c;我们创建对象的时候&#xff0c;采用new的方式&#xff0c;当对象不在被使用的时候&…

【网络】UDP/TCP网络程序

目录 UDP网络程序 简单通信版本(UDP) 准备工作&#xff08;接口学习、分析&#xff09; 整体代码&#xff08;Server.hpp/Server.cpp/Client.hpp/Client.cpp&#xff09; 添加“婴儿版”业务逻辑 英译汉翻译 my_shell 聊天室 linux和windows通信 TCP网络程序 简单通…

AB32VG1:SDK_AB53XX_V061(3)IO口复用功能的补充资料

文章目录 1.IO口功能复用表格2.功能映射寄存器 FUNCTION03.功能映射寄存器 FUNCTION14.功能映射寄存器 FUNCTION2 AB5301A的官方数据手册很不完善&#xff0c;没有开放出来。我通过阅读源码补充了一些关于IO口功能复用寄存器的资料。 官方寄存器文档&#xff1a;《 AB32VG1_Re…

chatgpt赋能python:Python怎么截屏Windows

Python怎么截屏Windows Python是一种高级编程语言&#xff0c;具有快速开发、易于学习、可移植性强等优点&#xff0c;因此在实现Windows屏幕截图方面也是一种非常强大的工具。 什么是Windows屏幕截图&#xff1f; Windows屏幕截图是将当前屏幕或窗口的图像保存成文件或剪贴…

Android BlueToothBLE入门(二)——设备的连接和通讯(附Demo源码地址)

学更好的别人&#xff0c; 做更好的自己。 ——《微卡智享》 本文长度为7870字&#xff0c;预计阅读12分钟 前言 接《Android BlueToothBLE入门&#xff08;一&#xff09;——低功耗蓝牙介绍》上篇&#xff0c;这篇文章主要就是来做Demo实现Android两台设备的数据通讯。 实现效…

chatgpt赋能python:Python如何快速处理数据

Python如何快速处理数据 在当今数据爆炸的时代&#xff0c;数据处理已经成为一项非常重要的任务。因此&#xff0c;如何快速、高效地处理数据就成为了每个数据科学家、数据工程师以及数据分析师的必备技能之一。而Python正是其中的佼佼者。 为什么选择Python进行数据处理 Py…

Spring事物失效的八大场景

1.方法内的自调用&#xff1a;spring事物是基于aop的&#xff0c;只要使用代理对象调用某个方法时&#xff0c;spring事物才能生效&#xff0c;而在一个方法内使用this.xxx()时。this并不是代理对象&#xff0c;所以会失效&#xff08;实际上是transaction注解失效&#xff09;…

用程序控制对文本的复制和粘贴pyperclip模块

【小白从小学Python、C、Java】 【等级考试500强双证书考研】 【Python-数据分析】 用程序控制对文本的复制和粘贴 pyperclip模块 选择题 关于下列代码说法错误的是&#xff1f; import pyperclip print(【执行】pyperclip.copy("Python 太强大了&#xff01;")) p…

读发布!设计与部署稳定的分布式系统(第2版)笔记01_生产环境的生存法则

1. 系统“应该”做什么 1.1. 添加所需特性 2. 系统“不应该”做什么 2.1. 崩溃 2.2. 停止响应 2.3. 丢失数据 2.4. 侵犯隐私 2.5. 损失金钱 2.6. 摧毁公司 2.7. “杀死”客户 3. QA部门的测试 3.1. 团队的大部分工作是想方设法地通过测试 3.2. 做了敏捷、务实和自动…

【设计模式与范式:行为型】57 | 观察者模式(下):如何实现一个异步非阻塞的EventBus框架?

上一节课中&#xff0c;我们学习了观察者模式的原理、实现、应用场景&#xff0c;重点介绍了不同应用场景下&#xff0c;几种不同的实现方式&#xff0c;包括&#xff1a;同步阻塞、异步非阻塞、进程内、进程间的实现方式。 同步阻塞是最经典的实现方式&#xff0c;主要是为了…

GreenPlum分布式集群部署实战

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

GC演变过程、三色标记法、大白话讲解G1

文章目录 GC演变过程并发垃圾回收需要解决的问题怎么确定一个垃圾?并发收集存在的问题 三色标记法CMS垃圾收集器G1垃圾收集器介绍,主要特点优点使用注意点 GC演变过程 在Java中,垃圾收集一直是一个非常重要的组成部分, 到目前为止,垃圾收集器已经有十种了, 在不停的优化. 那为…

GoogleTest之Actions的用法

目录 返回值Actions的组合验证复杂参数mock副作用改变mock对象的行为设置返回类型的默认值使用自定义函数作为Actions 通用示例 namespace mock_action { class Foo { public:virtual ~Foo() {}virtual int& GetBar() 0; // 1virtual int GetPointerValue() 0; //…

Linux CentOS7虚拟机配置静态IP并允许上网的配置方法

文章目录 前言一、开启本地电脑VMnet8二、Linux配置静态IP1. NAT模式设置2. 开启虚拟机登录root用户3. 执行命令设置静态IP4. 重启网卡① 重启网卡 (正常)② 重启网卡 (异常)③ 解决方式&#xff1a;禁用NetworkManager 5. 查看ip6. 本地电脑cmd窗口ping虚拟机7. 虚拟机ping本地…

Golang每日一练(leetDay0095) 第一个错误的版本、完全平方数

目录 278. 第一个错误的版本 First Bad Version &#x1f31f; 279. 完全平方数 Perfect Squares &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日…

springboot的数据访问和数据视图

当使用 Spring Boot 进行数据访问时&#xff0c;我们可以选择使用 MyBatis 或 JPA&#xff08;Java Persistence API&#xff09;来实现增删改查操作。下面我将分别给出使用这两种方式整合数据访问的详细步骤和示例&#xff0c;同时结合 Thymeleaf 实现数据展现。 方式一: 使用…

AI实战营:语义分割与MMSegmentation

目录 OpenMMLab图像分割算法库MMSegmentation 深度学习下的语义分割模型 全卷积网络Fully Convolutional Network 201 ​编辑 上下文信息与PSPNet模型 空洞卷积与DeepLab模型 语义分割算法总结 语义分割 前沿算法 SegFormer K-Net MaskFormer Mask2Former Seg…

PySide2 or PyQt5???该如何抉择???

1. 区别 Qt库里面有非常强大的图形界面开发库&#xff0c;但是Qt库是C语言开发的&#xff0c;PySide2、PyQt5可以让我们通过Python语言使用Qt。 但是 PySide2、PyQt5 这两者有什么区别呢&#xff1f; 可以形象地这样说&#xff1a; PySide2 是Qt的 亲儿子 &#xff0c; PyQt5 …

面向对象程序设计|静态友元

题目一&#xff1a;复数运算 题目描述&#xff1a; 复数类的声明如下 要求如下&#xff1a; 1. 实现复数类和友元函数addCom和outCom&#xff1b; 2. 参考addCom函数为复数类增加一个友元函数minusCom&#xff0c;用于实现两个复数的减法&#xff1b; 3. 在main函数中&…

待办事项JS:DHTMLX To Do List 1.2 cRACK

DHTMLX To Do List用于有效任务管理的DHTMLX JavaScript 待办事项列表 使用 JavaScript/HTML 5 中的待办事项列表来管理您的任务并确定其优先级。将组件连接到 DHTMLX 甘特图&#xff0c;并允许用户以简单直观的方式快速组织他们的业务流程。 DHTMLX JavaScript 待办事项列表的…