当前位置: 首页 > article >正文

PyTorch基本功能与实现代码

PyTorch是一个开源的深度学习框架,提供了丰富的函数和工具,以下为其主要功能的归纳:

  1. 核心数据结构:

• 张量(Tensor):类似于Numpy的ndarray,是PyTorch中基本的数据结构,用于表示数据,可以在GPU上加速计算。
在PyTorch中,基本的数据结构张量(Tensor)有多种类型,包括:

零维张量(标量)

  • 如 torch.tensor(5) ,用于表示单个数值。

一维张量

  • 类似向量,例如 torch.tensor([1, 2, 3]) 。

二维张量

  • 很像矩阵,如 torch.tensor([[1, 2], [3, 4]]) 。

三维张量及更高维张量

  • 可以用于表示如彩色图像序列(图像数量、通道数、高度、宽度)等更复杂的数据结构。例如,一个简单的三维张量可以是 torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) 。

以下是在GPU上加速计算的PyTorch代码示例:

import torch

# 检查GPU是否可用
if torch.cuda.is_available():
    device = torch.device("cuda")
else:
    device = torch.device("cpu")
print("Using device:", device)

# 创建一个张量并将其移动到GPU上
x = torch.tensor([1., 2., 3.]).to(device)
y = torch.tensor([4., 5., 6.]).to(device)
z = x + y
print(z)

在这个示例中,首先检查GPU是否可用,然后将张量 x 和 y 移动到GPU设备上进行加法运算。如果GPU不可用,代码会在CPU上运行。

  1. 神经网络构建:

• 提供多种神经网络结构和组件,如torch.nn中包含了常见的神经网络层和成本函数,方便用户构建深度学习模型。

神经网络层(torch.nn)

  • 线性层(nn.Linear):这是最基本的全连接层。例如 nn.Linear(in_features = 10, out_features = 5) ,表示输入维度是10,输出维度是5的全连接层,用于将输入数据进行线性变换。
  • 卷积层(nn.Conv2d):用于处理具有网格结构的数据,如图像。例如 nn.Conv2d(in_channels = 3, out_channels = 16, kernel_size = 3, stride = 1, padding = 1) ,输入通道为3(如RGB图像),输出通道为16,卷积核大小为3x3,步长为1,填充为1。
  • 池化层(nn.MaxPool2d、nn.AvgPool2d):用于对数据进行下采样,减少数据维度。如 nn.MaxPool2d(kernel_size = 2, stride = 2) 是一个最大池化层,以2x2的窗口进行池化,步长为2。
  • 循环层(nn.LSTM、nn.GRU):用于处理序列数据。以 nn.LSTM(input_size = 10, hidden_size = 20, num_layers = 2) 为例,输入维度是10,隐藏层维度是20,有2层LSTM。
    激活函数(torch.nn)
  • ReLU(nn.ReLU): nn.ReLU() 是最常用的激活函数之一,它将所有负输入值映射为0,正输入值保持不变,例如 y = nn.ReLU()(x) ,其中 x 是输入张量, y 是经过ReLU激活后的张量。
  • Sigmoid(nn.Sigmoid): nn.Sigmoid() 将输入值映射到0 - 1之间,常用于二分类问题的输出层,如 y = nn.Sigmoid()(x) 。
  • Tanh(nn.Tanh): nn.Tanh() 将输入值映射到 - 1到1之间,在某些神经网络架构中有应用。
    损失函数(torch.nn)
  • 均方误差损失(nn.MSELoss):用于回归问题,计算预测值和真实值之间的均方误差。例如, criterion = nn.MSELoss(),loss = criterion(prediction, target) ,其中 prediction 是模型的预测张量, target 是真实值张量。
  • 交叉熵损失(nn.CrossEntropyLoss):常用于分类问题。如果有 criterion = nn.CrossEntropyLoss() , output 是模型输出的未经过softmax激活的对数概率张量, labels 是真实标签张量,那么 loss = criterion(output, labels) 。
    构建深度学习模型的示例代码
import torch
import torch.nn as nn

# 定义一个简单的神经网络模型
class SimpleNet(nn.Module):
    def __init__(self):
        super(SimpleNet, self).__init__()
        self.fc1 = nn.Linear(10, 5)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(5, 2)
    def forward(self, x):
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x

# 创建模型实例
model = SimpleNet()
# 随机生成输入数据
input_data = torch.randn(3, 10)
# 前向传播得到输出
output = model(input_data)
print(output)

在这个示例中,定义了一个简单的神经网络 SimpleNet ,它有两个全连接层 fc1 和 fc2 ,中间使用ReLU激活函数。在 forward 方法中定义了数据的前向传播路径。最后创建模型实例,生成随机输入数据并进行前向传播得到输出。

  1. 训练和优化:

• 包含各种优化算法,如torch.optim中提供的SGD、Adam等,以及训练技巧,帮助模型优化。以下是常见优化算法和训练技巧的代码示例:

  1. 优化算法示例

SGD(随机梯度下降)

import torch
import torch.nn as nn
import torch.optim as optim

# 定义一个简单的模型
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc = nn.Linear(10, 1)

    def forward(self, x):
        return self.fc(x)

model = SimpleModel()
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

# 训练循环
for epoch in range(100):
    data = torch.randn(100, 10)
    target = torch.randn(100, 1)

    optimizer.zero_grad()
    output = model(data)
    loss = criterion(output, target)
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 10 == 0:
        print(f'Epoch {epoch + 1}, Loss: {loss.item()}')

Adam

import torch
import torch.nn as nn
import torch.optim as optim

model = SimpleModel()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练循环
for epoch in range(100):
    data = torch.randn(100, 10)
    target = torch.randn(100, 1)

    optimizer.zero_grad()
    output = model(data)
    loss = criterion(output, target)
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 10 == 0:
        print(f'Epoch {epoch + 1}, Loss: {loss.item()}')

Adagrad

import torch
import torch.nn as nn
import torch.optim as optim

model = SimpleModel()
criterion = nn.MSELoss()
optimizer = optim.Adagrad(model.parameters(), lr=0.001)

# 训练循环
for epoch in range(100):
    data = torch.randn(100, 10)
    target = torch.randn(100, 1)

    optimizer.zero_grad()
    output = model(data)
    loss = criterion(output, target)
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 10 == 0:
        print(f'Epoch {epoch + 1}, Loss: {loss.item()}')

Adadelta

import torch
import torch.nn as nn
import torch.optim as optim

model = SimpleModel()
criterion = nn.MSELoss()
optimizer = optim.Adadelta(model.parameters(), lr=1.0)

# 训练循环
for epoch in range(100):
    data = torch.randn(100, 10)
    target = torch.randn(100, 1)

    optimizer.zero_grad()
    output = model(data)
    loss = criterion(output, target)
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 10 == 0:
        print(f'Epoch {epoch + 1}, Loss: {loss.item()}')

RMSprop

import torch
import torch.nn as nn
import torch.optim as optim

model = SimpleModel()
criterion = nn.MSELoss()
optimizer = optim.RMSprop(model.parameters(), lr=0.001, alpha=0.99)

# 训练循环
for epoch in range(100):
    data = torch.randn(100, 10)
    target = torch.randn(100, 1)

    optimizer.zero_grad()
    output = model(data)
    loss = criterion(output, target)
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 10 == 0:
        print(f'Epoch {epoch + 1}, Loss: {loss.item()}')
  1. 训练技巧示例

学习率调整(StepLR)

import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR

model = SimpleModel()
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)

# 训练循环
for epoch in range(100):
    data = torch.randn(100, 10)
    target = torch.randn(100, 1)

    optimizer.zero_grad()
    output = model(data)
    loss = criterion(output, target)
    loss.backward()
    optimizer.step()
    scheduler.step()

    if (epoch + 1) % 10 == 0:
        print(f'Epoch {epoch + 1}, Loss: {loss.item()}, LR: {optimizer.param_groups[0]["lr"]}')

梯度裁剪

import torch
import torch.nn as nn
import torch.optim as optim

model = SimpleModel()
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.001)

# 训练循环
for epoch in range(100):
    data = torch.randn(100, 10)
    target = torch.randn(100, 1)

    optimizer.zero_grad()
    output = model(data)
    loss = criterion(output, target)
    loss.backward()
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
    optimizer.step()

    if (epoch + 1) % 10 == 0:
        print(f'Epoch {epoch + 1}, Loss: {loss.item()}')

以上代码示例展示了PyTorch中常见的优化算法和训练技巧,你可以根据实际需求选择合适的优化算法和技巧来训练模型。

• 自动微分和自动求导功能,能够自动计算模型参数的梯度,无需手动编写反向传播代码。

在PyTorch中,自动微分(autograd)是一个强大的功能,它允许自动计算张量操作的梯度。以下是一些关于自动微分、自动求导以及计算模型参数梯度的代码示例:

  1. 简单张量的自动求导
import torch

# 创建一个需要计算梯度的张量
x = torch.tensor(3.0, requires_grad=True)
y = x**2 + 2 * x + 1

# 计算y关于x的梯度
y.backward()

print(x.grad)  # 输出: tensor(8.)

在这个例子中,我们创建了一个张量 x 并设置 requires_grad=True 表示需要计算它的梯度。然后我们定义了一个关于 x 的函数 y ,并调用 y.backward() 来计算 y 关于 x 的梯度。最终, x.grad 包含了计算得到的梯度。

  1. 多个张量的自动求导
import torch

x = torch.tensor(2.0, requires_grad=True)
y = torch.tensor(3.0, requires_grad=True)

z = x**2 * y + 3 * y - 1

z.backward()

print(x.grad)  # 输出: tensor(12.)
print(y.grad)  # 输出: tensor(7.)

这里我们有两个需要计算梯度的张量 x 和 y ,定义了一个关于它们的函数 z ,并通过 z.backward() 计算 z 关于 x 和 y 的梯度。

  1. 使用 nn.Module 计算模型参数的梯度
import torch
import torch.nn as nn

# 定义一个简单的线性模型
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.linear = nn.Linear(1, 1)  # 输入维度1,输出维度1

    def forward(self, x):
        return self.linear(x)

# 创建模型实例
model = LinearModel()

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# 训练数据
x = torch.tensor([[1.0]])
y = torch.tensor([[2.0]])

# 前向传播
output = model(x)
loss = criterion(output, y)

# 反向传播并更新参数
optimizer.zero_grad()  # 梯度清零
loss.backward()  # 计算梯度
optimizer.step()  # 更新参数

print(model.linear.weight.grad)  # 输出权重的梯度
print(model.linear.bias.grad)  # 输出偏置的梯度

在这个例子中,我们定义了一个简单的线性模型 LinearModel ,使用均方误差损失函数 MSELoss 和随机梯度下降优化器 SGD 。在训练过程中,我们通过 loss.backward() 计算损失关于模型参数的梯度,然后使用 optimizer.step() 更新参数。 optimizer.zero_grad() 用于在每次反向传播前清零梯度,以避免梯度累加。

  1. 模型保存和加载:

• 支持模型的保存和加载,方便实验记录和复现。

在PyTorch中,模型的保存和加载主要有两种方式:保存和加载整个模型,以及只保存和加载模型的参数。以下是具体的代码示例:

  1. 保存和加载整个模型
import torch
import torch.nn as nn


# 定义一个简单的模型
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc = nn.Linear(10, 1)

    def forward(self, x):
        return self.fc(x)


# 初始化模型和优化器
model = SimpleModel()
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)

# 保存整个模型
torch.save(model, 'entire_model.pth')

# 加载整个模型
loaded_model = torch.load('entire_model.pth')
loaded_model.eval()
  1. 保存和加载模型参数(推荐)

这种方式更轻量级,并且在不同结构但参数名称相同的模型间转移参数时更灵活。

import torch
import torch.nn as nn


# 定义一个简单的模型
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc = nn.Linear(10, 1)

    def forward(self, x):
        return self.fc(x)


# 初始化模型和优化器
model = SimpleModel()
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)

# 保存模型参数
torch.save(model.state_dict(),'model_params.pth')

# 加载模型参数
new_model = SimpleModel()
new_model.load_state_dict(torch.load('model_params.pth'))
new_model.eval()
  1. 保存和加载带有优化器状态的模型
    在训练过程中,保存模型的同时保存优化器的状态,可以在恢复训练时继续使用之前的优化器参数。
import torch
import torch.nn as nn


# 定义一个简单的模型
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc = nn.Linear(10, 1)

    def forward(self, x):
        return self.fc(x)


# 初始化模型和优化器
model = SimpleModel()
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)

# 训练模型几步(示例)
for epoch in range(5):
    # 假设这里有数据和前向/反向传播步骤
    loss = 0.1  # 示例损失值
    loss.backward()
    optimizer.step()
    optimizer.zero_grad()

# 保存模型和优化器状态
checkpoint = {
  'model_state_dict': model.state_dict(),
    'optimizer_state_dict': optimizer.state_dict(),
}
torch.save(checkpoint, 'checkpoint.pth')

# 加载模型和优化器状态
new_model = SimpleModel()
new_optimizer = torch.optim.SGD(new_model.parameters(), lr=0.001)

checkpoint = torch.load('checkpoint.pth')
new_model.load_state_dict(checkpoint['model_state_dict'])
new_optimizer.load_state_dict(checkpoint['optimizer_state_dict'])

new_model.eval()
  1. 数据处理和转换:

• 提供数据的预处理和转换功能,包括torchvision等库中的图像变换等,以提升模型性能。

在PyTorch中, torchvision 库提供了丰富的数据预处理和转换功能,特别是针对图像数据。以下是一些常见的用于提升模型性能的预处理和转换操作及其代码示例:

  1. 图像变换基础

首先,导入必要的库:

import torch
from torchvision import transforms, datasets
from torch.utils.data import DataLoader
  1. 常见图像变换

调整大小

resize_transform = transforms.Resize((224, 224))

裁剪

  • 中心裁剪:
center_crop = transforms.CenterCrop(224)
  • 随机裁剪:
random_crop = transforms.RandomCrop(224)

翻转

  • 随机水平翻转:
random_horizontal_flip = transforms.RandomHorizontalFlip()
  • 随机垂直翻转:
random_vertical_flip = transforms.RandomVerticalFlip()

旋转

random_rotation = transforms.RandomRotation(10)  # 随机旋转角度在 -10 到 10 度之间

归一化

normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])

转换为张量

to_tensor = transforms.ToTensor()
  1. 组合变换

可以将多个变换组合在一起:

transform = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
  1. 使用变换加载数据集

以加载CIFAR - 10数据集为例:

train_dataset = datasets.CIFAR10(root='./data', train=True,
                                 download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)

test_dataset = datasets.CIFAR10(root='./data', train=False,
                                download=True, transform=transform)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)
  1. 自定义变换

如果 torchvision 提供的变换不能满足需求,可以自定义变换。例如,定义一个简单的图像反色变换:

class InvertColor(object):
    def __call__(self, img):
        img = torch.from_numpy(np.array(img))
        return 255 - img

invert_color = InvertColor()
custom_transform = transforms.Compose([
    transforms.Resize((224, 224)),
    invert_color,
    transforms.ToTensor()
])

以上代码展示了如何使用 torchvision 库中的各种图像变换功能来预处理数据,以提升模型性能。不同的数据集和模型可能需要不同的预处理组合,需要根据实际情况进行调整。

  1. 函数式接口:

• 提供函数式编程接口,方便用户编写简洁的代码。

PyTorch中有许多函数式编程接口,下面列举一些常见的示例:

张量操作

创建张量

import torch

# 创建一个常量张量
tensor = torch.tensor([1, 2, 3])
print(tensor)

# 使用函数式接口创建全零张量
zeros_tensor = torch.zeros(3)
print(zeros_tensor)

# 创建全一张量
ones_tensor = torch.ones(3)
print(ones_tensor)
 
 
张量运算

```python
a = torch.tensor([1.0, 2.0, 3.0])
b = torch.tensor([4.0, 5.0, 6.0])

# 加法
add_result = torch.add(a, b)
print(add_result)

# 乘法
mul_result = torch.mul(a, b)
print(mul_result)

# 矩阵乘法
mat_a = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
mat_b = torch.tensor([[5, 6], [7, 8]], dtype=torch.float32)
matmul_result = torch.matmul(mat_a, mat_b)
print(matmul_result)

自动求导

计算梯度

x = torch.tensor([2.0], requires_grad=True)
y = x ** 2 + 3 * x
z = 2 * y

z.backward(torch.tensor([1.0]))
print(x.grad)

神经网络层

线性层

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

# 创建一个线性层
linear_layer = nn.Linear(10, 5)
input_tensor = torch.randn(1, 10)
output = linear_layer(input_tensor)
print(output)

# 使用函数式接口实现相同功能
weight = torch.randn(5, 10, requires_grad=True)
bias = torch.randn(5, requires_grad=True)
output_functional = F.linear(input_tensor, weight, bias)
print(output_functional)

激活函数

input_tensor = torch.tensor([-1.0, 0.0, 1.0])

# ReLU激活函数
relu_result = F.relu(input_tensor)
print(relu_result)

# Sigmoid激活函数
sigmoid_result = F.sigmoid(input_tensor)
print(sigmoid_result)

损失函数

均方误差损失

prediction = torch.tensor([1.0, 2.0, 3.0])
target = torch.tensor([1.5, 2.5, 3.5])

mse_loss = F.mse_loss(prediction, target)
print(mse_loss)

交叉熵损失

logits = torch.tensor([[0.2, 0.5, 0.3], [0.1, 0.7, 0.2]])
labels = torch.tensor([1, 0])

cross_entropy_loss = F.cross_entropy(logits, labels)
print(cross_entropy_loss)

这些示例展示了PyTorch中丰富的函数式编程接口,通过这些接口,你可以以更简洁的方式进行张量操作、构建神经网络、计算损失等。

  1. 动态计算图:

• 使用动态计算图来表示模型的结构和参数,方便进行模型构建和调试。

在PyTorch中,动态计算图是其核心特性之一,使得模型构建和调试更加灵活。以下是几个不同复杂度的PyTorch代码示例,展示如何使用动态计算图来表示模型结构和参数:

简单线性回归模型

import torch
import torch.nn as nn
import torch.optim as optim


# 定义模型
class LinearRegression(nn.Module):
    def __init__(self, input_dim):
        super(LinearRegression, self).__init__()
        self.linear = nn.Linear(input_dim, 1)

    def forward(self, x):
        out = self.linear(x)
        return out


# 数据准备
input_dim = 1
x = torch.tensor([[1.0], [2.0], [3.0], [4.0]], dtype=torch.float32)
y = torch.tensor([[2.0], [4.0], [6.0], [8.0]], dtype=torch.float32)

# 初始化模型、损失函数和优化器
model = LinearRegression(input_dim)
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 训练模型
for epoch in range(1000):
    # 前向传播
    y_pred = model(x)
    loss = criterion(y_pred, y)

    # 反向传播和优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/1000], Loss: {loss.item():.4f}')

多层感知机(MLP)

import torch
import torch.nn as nn
import torch.optim as optim


# 定义MLP模型
class MLP(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(MLP, self).__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)
        return out


# 数据准备
input_dim = 2
hidden_dim = 10
output_dim = 1
x = torch.randn(100, input_dim)
y = torch.randn(100, output_dim)

# 初始化模型、损失函数和优化器
model = MLP(input_dim, hidden_dim, output_dim)
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练模型
for epoch in range(1000):
    # 前向传播
    y_pred = model(x)
    loss = criterion(y_pred, y)

    # 反向传播和优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/1000], Loss: {loss.item():.4f}')

卷积神经网络(CNN)用于图像分类(简单示例)

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader


# 定义CNN模型
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)
        self.relu1 = nn.ReLU()
        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
        self.fc1 = nn.Linear(16 * 56 * 56, 128)
        self.relu2 = nn.ReLU()
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        out = self.conv1(x)
        out = self.relu1(out)
        out = self.pool1(out)
        out = out.view(-1, 16 * 56 * 56)
        out = self.fc1(out)
        out = self.relu2(out)
        out = self.fc2(out)
        return out


# 数据预处理
transform = transforms.Compose([
    transforms.Resize((112, 112)),
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])

# 加载数据集
train_dataset = datasets.CIFAR10(root='./data', train=True,
                                 download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)

# 初始化模型、损失函数和优化器
model = SimpleCNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

# 训练模型
for epoch in range(10):
    running_loss = 0.0
    for i, data in enumerate(train_loader, 0):
        inputs, labels = data
        optimizer.zero_grad()

        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
    print(f'Epoch {epoch + 1}, Loss: {running_loss / len(train_loader):.4f}')

这些示例展示了如何在PyTorch中使用动态计算图构建不同类型的模型,从简单的线性回归到复杂的卷积神经网络。PyTorch的动态计算图允许在运行时构建计算图,使得代码更易读、调试和灵活扩展。
8. 高级功能:

• 支持高级数据处理和转换功能,以及更高级的网络结构和组件,适合复杂任务。

以下是一些使用PyTorch进行高级数据处理、转换以及构建复杂网络结构的代码示例:

  1. 高级数据处理与转换

自定义数据变换

import torch
from torchvision import transforms, datasets
from torch.utils.data import DataLoader


# 自定义数据变换
class CustomTransform:
    def __init__(self, mean, std):
        self.normalize = transforms.Normalize(mean=mean, std=std)

    def __call__(self, img):
        img = transforms.functional.to_tensor(img)
        img = self.normalize(img)
        return img


# 加载CIFAR - 10数据集并应用自定义变换
mean = [0.4914, 0.4822, 0.4465]
std = [0.2470, 0.2435, 0.2616]
custom_transform = CustomTransform(mean, std)
cifar10_train = datasets.CIFAR10(root='./data', train=True,
                                 download=True, transform=custom_transform)
train_loader = DataLoader(cifar10_train, batch_size=32, shuffle=True)
  1. 复杂网络结构与组件

ResNet - 18网络

import torch
import torch.nn as nn

class BasicBlock(nn.Module):
    expansion = 1

    def __init__(self, in_channels, out_channels, stride=1):
        super(BasicBlock, self).__init__()
        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3,
                               stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3,
                               stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channels)
        self.shortcut = nn.Sequential()
        if stride!= 1 or in_channels!= self.expansion * out_channels:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels, self.expansion * out_channels,
                          kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(self.expansion * out_channels)
            )

    def forward(self, x):
        out = self.relu(self.bn1(self.conv1(x)))
        out = self.bn2(self.conv2(out))
        out += self.shortcut(x)
        out = self.relu(out)
        return out


class ResNet18(nn.Module):
    def __init__(self, num_classes=10):
        super(ResNet18, self).__init__()
        self.in_channels = 64
        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
        self.bn1 = nn.BatchNorm2d(64)
        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        self.layer1 = self._make_layer(BasicBlock, 64, 2, stride=1)
        self.layer2 = self._make_layer(BasicBlock, 128, 2, stride=2)
        self.layer3 = self._make_layer(BasicBlock, 256, 2, stride=2)
        self.layer4 = self._make_layer(BasicBlock, 512, 2, stride=2)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(512 * BasicBlock.expansion, num_classes)

    def _make_layer(self, block, out_channels, num_blocks, stride):
        strides = [stride] + [1] * (num_blocks - 1)
        layers = []
        for stride in strides:
            layers.append(block(self.in_channels, out_channels, stride))
            self.in_channels = out_channels * block.expansion
        return nn.Sequential(*layers)

    def forward(self, x):
        out = self.relu(self.bn1(self.conv1(x)))
        out = self.maxpool(out)
        out = self.layer1(out)
        out = self.layer2(out)
        out = self.layer3(out)
        out = self.layer4(out)
        out = self.avgpool(out)
        out = out.view(out.size(0), -1)
        out = self.fc(out)
        return out


# 创建ResNet - 18实例
resnet18 = ResNet18()

多GPU训练

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader

# 假设已经定义了ResNet18
resnet18 = ResNet18()
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
if torch.cuda.device_count() > 1:
    resnet18 = nn.DataParallel(resnet18)
resnet18.to(device)

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(resnet18.parameters(), lr=0.001, momentum=0.9)

# 加载数据
mean = [0.4914, 0.4822, 0.4465]
std = [0.2470, 0.2435, 0.2616]
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean, std)
])
cifar10_train = datasets.CIFAR10(root='./data', train=True,
                                 download=True, transform=transform)
train_loader = DataLoader(cifar10_train, batch_size=32, shuffle=True)

# 训练循环
for epoch in range(10):
    running_loss = 0.0
    for i, data in enumerate(train_loader, 0):
        inputs, labels = data[0].to(device), data[1].to(device)
        optimizer.zero_grad()
        outputs = resnet18(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
    print(f'Epoch {epoch + 1}, Loss: {running_loss / len(train_loader)}')

这些示例展示了如何在PyTorch中进行自定义数据变换、构建复杂网络结构(如ResNet - 18)以及利用多GPU进行训练。实际应用中,你可以根据具体任务进行调整和扩展。
• 提供模型分析和调试工具,方便用户定位问题。

在PyTorch中,有多种工具可用于模型分析和调试。以下是一些常见工具及其代码示例:

  1. torch.autograd.set_detect_anomaly(True)

这个功能可以帮助检测计算图中的异常,例如梯度计算中的NaN或Inf值。

import torch
import torch.nn as nn

torch.autograd.set_detect_anomaly(True)

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.linear = nn.Linear(10, 1)

    def forward(self, x):
        return self.linear(x)

model = MyModel()
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# 生成一些随机数据
input_data = torch.randn(1, 10)
target = torch.randn(1, 1)

for i in range(10):
    optimizer.zero_grad()
    output = model(input_data)
    loss = criterion(output, target)
    loss.backward()
    optimizer.step()
  1. torch.utils.bottleneck

torch.utils.bottleneck  模块提供了一个分析器,用于识别计算瓶颈。

import torch
import torch.nn as nn
from torch.utils import bottleneck

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.linear1 = nn.Linear(10, 100)
        self.linear2 = nn.Linear(100, 1)

    def forward(self, x):
        x = self.linear1(x)
        x = torch.relu(x)
        return self.linear2(x)

model = MyModel()
input_data = torch.randn(1, 10)

with bottleneck.profile(model) as prof:
    with bottleneck.trace(model, input_data) as t:
        model(input_data)

print(prof.key_averages().table(sort_by="self_cpu_time_total"))
  1. torch.onnx

将PyTorch模型导出为ONNX格式,这有助于在其他框架中可视化模型结构,例如Netron。

import torch
import torch.nn as nn
import torch.onnx as onnx

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.linear = nn.Linear(10, 1)

    def forward(self, x):
        return self.linear(x)

model = MyModel()
input_data = torch.randn(1, 10)
onnx.export(model, input_data, "my_model.onnx")
  1. pdb  调试器

pdb  是Python标准库中的调试器,可以在PyTorch代码中插入断点进行调试。

import torch
import torch.nn as nn
import pdb

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.linear = nn.Linear(10, 1)

    def forward(self, x):
        pdb.set_trace()
        return self.linear(x)

model = MyModel()
input_data = torch.randn(1, 10)
output = model(input_data)

当代码执行到  pdb.set_trace()  时,会暂停执行,你可以在命令行中使用  pdb  命令检查变量、单步执行代码等。

这些工具可以帮助你在不同方面对PyTorch模型进行分析和调试,以确保模型的正确性和性能。

  1. 特殊用途函数和实用工具:

• 提供一些特殊用途的函数和实用工具,方便特定任务的处理。

PyTorch提供了许多特殊用途的函数和实用工具,以方便处理特定任务。以下是一些常见的示例:

  1. 数据加载与预处理

torchvision  库提供了用于计算机视觉任务的数据加载和预处理工具。

import torch
from torchvision import datasets, transforms
from torch.utils.data import DataLoader

# 数据预处理
transform = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

# 加载CIFAR - 10数据集
train_dataset = datasets.CIFAR10(root='./data', train=True,
                                 download=True, transform=transform)
test_dataset = datasets.CIFAR10(root='./data', train=False,
                                download=True, transform=transform)

# 创建数据加载器
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)
  1. 模型初始化

torch.nn.init  模块提供了各种初始化权重的方法。

import torch.nn as nn
import torch.nn.init as init

class SimpleNet(nn.Module):
    def __init__(self):
        super(SimpleNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)
        self.fc1 = nn.Linear(16 * 56 * 56, 128)
        self.fc2 = nn.Linear(128, 10)
        self._initialize_weights()

    def forward(self, x):
        x = nn.functional.relu(self.conv1(x))
        x = x.view(-1, 16 * 56 * 56)
        x = nn.functional.relu(self.fc1(x))
        x = self.fc2(x)
        return x

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:
                    init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                init.normal_(m.weight, 0, 0.01)
                init.constant_(m.bias, 0)
  1. 优化器与学习率调整
     torch.optim  模块提供了各种优化算法, torch.optim.lr_scheduler  用于调整学习率。
import torch.optim as optim
import torch.optim.lr_scheduler as lr_scheduler

model = SimpleNet()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)

for epoch in range(10):
    running_loss = 0.0
    for i, data in enumerate(train_loader, 0):
        inputs, labels = data
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
    scheduler.step()
    print(f'Epoch {epoch + 1}, Loss: {running_loss / len(train_loader)}')
  1. 模型保存与加载
     torch.save  和  torch.load  用于保存和加载模型。
# 保存整个模型
torch.save(model, 'entire_model.pth')
# 保存模型的状态字典
torch.save(model.state_dict(),'model_state_dict.pth')
# 加载整个模型
loaded_model = torch.load('entire_model.pth')
# 加载模型状态字典
new_model = SimpleNet()
new_model.load_state_dict(torch.load('model_state_dict.pth'))
  1. 分布式训练
     torch.distributed  模块用于分布式训练。
import torch.distributed as dist
import torch.multiprocessing as mp
from torch.nn.parallel import DistributedDataParallel as DDP

def setup(rank, world_size):
    os.environ['MASTER_ADDR'] = 'localhost'
    os.environ['MASTER_PORT'] = '12355'
    dist.init_process_group("gloo", rank=rank, world_size=world_size)

def cleanup():
    dist.destroy_process_group()

def train(rank, world_size):
    setup(rank, world_size)
    model = SimpleNet()
    ddp_model = DDP(model, device_ids=[rank])
    optimizer = optim.Adam(ddp_model.parameters(), lr=0.001)
    # 训练循环
    cleanup()

if __name__ == "__main__":
    world_size = 2
    mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)

这些示例展示了PyTorch在数据处理、模型初始化、优化、保存加载以及分布式训练等方面的实用工具和函数。根据具体任务,你可以灵活运用这些工具。
10. 高级数学和统计函数:

  • 支持高级数学和统计函数,方便用户进行复杂计算。
    PyTorch提供了丰富的数学和统计函数库,以下是一些常见的高级数学和统计函数示例:
  1. 数学函数
    1.1 三角函数
import torch

# 正弦函数
x = torch.tensor([0, torch.pi / 2, torch.pi])
y = torch.sin(x)
print(y)

1.2 指数和对数函数
import torch

指数函数

x = torch.tensor([1.0, 2.0, 3.0])
y = torch.exp(x)
print(y)

对数函数

z = torch.log(y)
print(z)

1.3 幂函数

import torch

计算幂

x = torch.tensor([2.0, 3.0, 4.0])
y = torch.pow(x, 2) # x的平方
print(y)

  1. 统计函数

2.1 均值、标准差和方差

import torch

创建一个张量

x = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0])

计算均值

mean_value = torch.mean(x)
print(mean_value)

计算标准差

std_value = torch.std(x)
print(std_value)

计算方差

var_value = torch.var(x)
print(var_value)

2.2 求和与乘积

import torch

创建一个张量

x = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0])

求和

sum_value = torch.sum(x)
print(sum_value)

求乘积

prod_value = torch.prod(x)
print(prod_value)

2.3 百分位数

import torch

创建一个张量

x = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0])

计算第50百分位数(中位数)

percentile_50 = torch.quantile(x, 0.5)
print(percentile_50)

  1. 线性代数函数
    3.1 矩阵乘法
    import torch

创建两个矩阵

a = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
b = torch.tensor([[5.0, 6.0], [7.0, 8.0]])

矩阵乘法

c = torch.mm(a, b)
print©

3.2 矩阵求逆

import torch

创建一个可逆矩阵

a = torch.tensor([[1.0, 2.0], [3.0, 4.0]], dtype=torch.float64)

矩阵求逆

a_inv = torch.inverse(a)
print(a_inv)

这些示例展示了PyTorch中部分常用的高级数学和统计函数,涵盖了三角函数、指数对数函数、统计量计算以及线性代数运算等方面。实际应用中,你可以根据具体需求进一步探索和使用PyTorch的数学函数库。

  1. GPU加速:
  • 支持GPU加速,可以大大提高深度学习模型的训练和推理速度。

以下为你展示在PyTorch中使用GPU加速的常见代码示例,涵盖模型训练和推理的关键步骤:

  1. 检查GPU是否可用

import torch

device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”)
print(device)

这段代码检查CUDA是否可用,如果可用则将设备设置为 cuda ,否则设置为 cpu 。

  1. 张量使用GPU

import torch

device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”)

创建张量并移动到GPU

x = torch.tensor([1.0, 2.0, 3.0]).to(device)
print(x)

通过 .to(device) 方法将张量移动到指定设备(GPU或CPU)。

  1. 模型使用GPU

import torch
import torch.nn as nn

class SimpleNet(nn.Module):
def init(self):
super(SimpleNet, self).init()
self.fc = nn.Linear(10, 1)

def forward(self, x):
    return self.fc(x)

device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”)
model = SimpleNet().to(device)
print(model)

定义模型后,使用 .to(device) 方法将模型移动到GPU。

  1. 训练过程使用GPU

import torch
import torch.nn as nn
import torch.optim as optim

定义设备

device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”)

生成随机数据

input_size = 10
output_size = 1
batch_size = 32
x = torch.randn(batch_size, input_size).to(device)
y = torch.randn(batch_size, output_size).to(device)

定义模型

class SimpleNet(nn.Module):
def init(self):
super(SimpleNet, self).init()
self.fc = nn.Linear(input_size, output_size)

def forward(self, x):
    return self.fc(x)

model = SimpleNet().to(device)
criterion = nn.MSELoss().to(device)
optimizer = optim.SGD(model.parameters(), lr=0.01)

训练模型

for epoch in range(100):
optimizer.zero_grad()
outputs = model(x)
loss = criterion(outputs, y)
loss.backward()
optimizer.step()
if (epoch + 1) % 10 == 0:
print(f’Epoch [{epoch + 1}/100], Loss: {loss.item():.4f}’)

在训练过程中,将数据、模型、损失函数都移动到GPU上,确保整个计算在GPU上执行。

  1. 推理过程使用GPU

import torch
import torch.nn as nn

定义设备

device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”)

定义模型

class SimpleNet(nn.Module):
def init(self):
super(SimpleNet, self).init()
self.fc = nn.Linear(10, 1)

def forward(self, x):
    return self.fc(x)

model = SimpleNet().to(device)

假设模型已训练并加载权重

这里省略加载权重代码

推理数据

input_data = torch.randn(1, 10).to(device)
with torch.no_grad():
output = model(input_data)
print(output)

推理时同样将模型和输入数据移动到GPU上进行计算。

以上代码示例展示了在PyTorch中如何利用GPU加速深度学习模型的不同阶段,从基本的张量操作到完整的训练和推理过程。

  1. 可扩展性:
  • 支持多GPU和多机训练,适应大规模模型和数据。
    在PyTorch中,支持多GPU和多机训练主要通过 torch.nn.parallel.DistributedDataParallel (DDP)来实现。以下是一些示例代码,展示了如何在单节点多GPU和多节点多GPU环境下进行训练。
    单节点多GPU训练
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.utils.data.distributed import DistributedSampler


# 定义一个简单的模型
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc = nn.Linear(10, 1)

    def forward(self, x):
        return self.fc(x)


# 定义数据集
class RandomDataset(Dataset):
    def __init__(self, size, length):
        self.len = length
        self.data = torch.randn(length, size)

    def __getitem__(self, index):
        return self.data[index]

    def __len__(self):
        return self.len


def setup(rank, world_size):
    os.environ['MASTER_ADDR'] = 'localhost'
    os.environ['MASTER_PORT'] = '12355'

    # 初始化进程组
    dist.init_process_group("gloo", rank=rank, world_size=world_size)


def cleanup():
    dist.destroy_process_group()


def train(rank, world_size):
    setup(rank, world_size)
    # 模型初始化
    model = SimpleModel()
    # 将模型移动到对应的GPU上
    model.to(rank)
    ddp_model = DDP(model, device_ids=[rank])

    # 定义损失函数和优化器
    loss_fn = nn.MSELoss()
    optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)

    # 定义数据集和数据加载器
    dataset = RandomDataset(10, 100)
    sampler = DistributedSampler(dataset, num_replicas=world_size, rank=rank)
    dataloader = DataLoader(dataset, batch_size=10, sampler=sampler)

    for epoch in range(2):
        running_loss = 0.0
        for i, data in enumerate(dataloader):
            data = data.to(rank)
            optimizer.zero_grad()
            output = ddp_model(data)
            target = torch.randn_like(output)
            loss = loss_fn(output, target)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()
        print(f'Epoch {epoch}, Rank {rank}, Loss: {running_loss / len(dataloader)}')

    cleanup()


if __name__ == '__main__':
    import os
    import torch.multiprocessing as mp

    world_size = torch.cuda.device_count()
    mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)

多节点多GPU训练

多节点训练的代码和单节点多GPU类似,主要区别在于每个节点需要正确设置 MASTER_ADDR 和 MASTER_PORT ,并且每个节点上的进程需要正确初始化进程组。假设你有两个节点,节点0的IP是 192.168.1.100 ,节点1的IP是 192.168.1.101 。

节点0上的代码

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.utils.data.distributed import DistributedSampler

# 定义模型和数据集,与单节点相同
class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc = nn.Linear(10, 1)

    def forward(self, x):
        return self.fc(x)

class RandomDataset(Dataset):
    def __init__(self, size, length):
        self.len = length
        self.data = torch.randn(length, size)

    def __getitem__(self, index):
        return self.data[index]

    def __len__(self):
        return self.len

def setup(rank, world_size):
    os.environ['MASTER_ADDR'] = '192.168.1.100'
    os.environ['MASTER_PORT'] = '12355'
    dist.init_process_group("gloo", rank=rank, world_size=world_size)

def cleanup():
    dist.destroy_process_group()

def train(rank, world_size):
    setup(rank, world_size)
    model = SimpleModel()
    model.to(rank)
    ddp_model = DDP(model, device_ids=[rank])

    loss_fn = nn.MSELoss()
    optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)

    dataset = RandomDataset(10, 100)
    sampler = DistributedSampler(dataset, num_replicas=world_size, rank=rank)
    dataloader = DataLoader(dataset, batch_size=10, sampler=sampler)

    for epoch in range(2):
        running_loss = 0.0
        for i, data in enumerate(dataloader):
            data = data.to(rank)
            optimizer.zero_grad()
            output = ddp_model(data)
            target = torch.randn_like(output)
            loss = loss_fn(output, target)
            loss.backward()
            optimizer.step()
            running_loss += loss.item()
        print(f'Epoch {epoch}, Rank {rank}, Loss: {running_loss / len(dataloader)}')
    cleanup()

if __name__ == '__main__':
    import os
    import torch.multiprocessing as mp

    world_size = 4  # 假设每个节点有2个GPU,共2个节点
    rank = int(os.environ['SLURM_PROCID'])  # 假设使用SLURM管理作业
    train(rank, world_size)

节点1上的代码
与节点0上的代码基本相同,只是 MASTER_ADDR 需要设置为节点0的IP。

#... (前面的导入和模型定义与节点0相同)
def setup(rank, world_size):
    os.environ['MASTER_ADDR'] = '192.168.1.100'
    os.environ['MASTER_PORT'] = '12355'
    dist.init_process_group("gloo", rank=rank, world_size=world_size)
#... (后面的训练和主函数部分与节点0相同)

这些示例代码展示了如何在PyTorch中进行单节点多GPU和多节点多GPU训练。实际应用中,你可能需要根据具体的模型、数据集和计算资源进行调整。同时,还需要注意不同的分布式训练后端(如nccl用于GPU训练, gloo用于CPU训练)的选择和配置。


http://www.kler.cn/a/509525.html

相关文章:

  • Python操作Excel——openpyxl使用笔记(2)
  • 深入理解 SQL 中的 DATEDIFF 函数
  • 深度学习 Pytorch 张量的线性代数运算
  • 物联网网关Web服务器--Boa服务器移植与测试
  • Python根据图片生成学生excel成绩表
  • Elasticsearch:Jira 连接器教程第二部分 - 6 个优化技巧
  • 浙江安吉成新照明电器:Acrel-1000DP 分布式光伏监控系统应用探索
  • vector迭代器的使用以及迭代器失效
  • 非科班转码第5年零241天
  • STM32 物联网智能家居 (五) 设备子系统之点亮LED灯
  • wireshark 网络分析工具
  • 1.5 GPT 模型家族全解析:从 GPT-1 到 GPT-4 的演进与创新
  • Scrapy 爬取 Bangumi 网站的分页与详情页数据
  • unity——Preject3——摄像机动画
  • Java并发05 - AQS共享模式的数据结构
  • windows 搭建flutter环境,开发windows程序
  • 新星杯-ESP32智能硬件开发--ESP32的I/O组成
  • 《重生到现代之从零开始的C++生活》—— 类和对象1
  • “深入浅出”系列之FFmpeg:(3)音视频开发的学习路线和必备知识
  • Transformer 与注意力机制原理说明与面试笔试题
  • ASP.NET Core 基础知识---依赖注入(DI)---生命周期和作用域
  • 中国数字安全产业年度报告(2024)
  • 智慧家居环境监测与控制系统的研发与应用案例分析
  • Asp .Net Core 实现微服务:集成 Ocelot+Nacos+Swagger+Cors实现网关、服务注册、服务发现
  • Linux下level-ip安装及测试_4
  • SSL配置实验