【深度学习:理论篇】--Pytorch进阶教程
目录
1.神经网络
1.1.torch.nn 核心模块
1.2.定义神经网络
1.3.损失函数
1.4.反向传播
1.5.梯度更新
2.图片分类器
2.1.数据加载
2.2.卷积神经网络
2.3.优化器和损失
2.4.训练网络
2.5.测试网络
2.6.GPU上训练
3.数据并行训练--多块GPU
3.1.导入和参数
3.2.构造一个虚拟数据集
3.3.简单的网络
3.4.创建数据并行
3.5.运行模型
1.神经网络
在 PyTorch 中 torch.nn 专门用于实现神经网络。其中 nn.Module 包含了网络层的搭建,以及一个方法-- forward(input) ,并返回网络的输出 outptu .
下面是一个经典的 LeNet 网络,用于对字符进行分类。
对于神经网络来说,一个标准的训练流程是这样的:⭐⭐⭐⭐⭐
- 定义一个多层的神经网络
- 对数据集的预处理并准备作为网络的输入
- 将数据输入到网络
- 计算网络的损失
- 反向传播,计算梯度
- 更新网络的梯度,一个简单的更新规则是 w= w - l* g
1.1.torch.nn
核心模块
基础层:
nn.Module
:所有神经网络模块的基类,自定义网络必须继承此类。
import torch.nn as nnclass MyModel(nn.Module):def __init__(self): # 注意:函数名应为__init__,而不是initsuper().__init__() # 正确调用父类的__init__方法self.layer = nn.Linear(10, 5) # 定义一个线性层,输入x:10,输出:5def forward(self, x): # 定义前向传播函数return self.layer(x) # 输入x通过线性层处理
nn.Sequential
:顺序容器,简化层堆叠。
model = nn.Sequential(nn.Conv2d(1, 20, 5),nn.ReLU(),nn.Flatten()
)
常用层类型
- 线性层:
nn.Linear(in_features, out_features)
- 卷积层:
nn.Conv2d(in_channels, out_channels, kernel_size)
- 循环网络层:
nn.LSTM(input_size, hidden_size, num_layers)
- 归一化层:
nn.BatchNorm2d(num_features)
激活函数
nn.ReLU()
/nn.Sigmoid()
/nn.Softmax(dim=1)
损失函数
- 分类任务:
nn.CrossEntropyLoss()
- 回归任务:
nn.MSELoss()
- 自定义损失:继承
nn.Module
实现forward()
1.2.定义神经网络
首先定义一个神经网络,下面是一个 5 层的卷积神经网络,包含两层卷积层和三层全连接层:
import torch
import torch.nn as nn
import torch.nn.functional as Fclass Net(nn.Module):def __init__(self):super(Net, self).__init__()# 输入图像是单通道,conv1 kenrnel size=5*5,输出通道 6self.conv1 = nn.Conv2d(1, 6, 5)# conv2 kernel size=5*5, 输出通道 16self.conv2 = nn.Conv2d(6, 16, 5)# 全连接层self.fc1 = nn.Linear(16*5*5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):# max-pooling 采用一个 (2,2) 的滑动窗口x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))# 核(kernel)大小是方形的话,可仅定义一个数字,如 (2,2) 用 2 即可x = F.max_pool2d(F.relu(self.conv2(x)), 2)x = x.view(-1, self.num_flat_features(x))x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return xdef num_flat_features(self, x):# 除了 batch 维度外的所有维度size = x.size()[1:]num_features = 1for s in size:num_features *= sreturn num_featuresnet = Net()
print(net)
这里必须实现 forward 函数,而 backward 函数在采用 autograd 时就自动定义好了,在 forward 方法可以采用任何的张量操作。
net.parameters() 可以返回网络的训练参数,使用例子如下:
params = list(net.parameters())
print('参数数量: ', len(params))
# conv1.weight
print('第一个参数大小: ', params[0].size())
然后简单测试下这个网络,随机生成一个 32*32 的输入:
# 随机定义一个变量输入网络
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
input = torch.randn(1, 1, 32, 32)
创建了一个形状为(1, 1, 32, 32)
的张量。这个形状通常表示:
- 第一个维度(1):批次大小(batch size),即一次处理多少个图像。
- 第二个维度(1):通道数(channels),对于灰度图像是1,对于RGB图像是3。
- 第三个维度(32):图像的高度。
- 第四个维度(32):图像的宽度。
因此,这个张量代表了一个批次中包含的单个32x32像素的灰度图像。
接着反向传播需要先清空梯度缓存,并反向传播随机梯度:
# 清空所有参数的梯度缓存,然后计算随机梯度进行反向传播
net.zero_grad()
out.backward(torch.randn(1, 10))
torch.nn 只支持小批量(mini-batches)数据,也就是输入不能是单个样本,比如对于 nn.Conv2d 接收的输入是一个 4 维张量–nSamples * nChannels * Height * Width 。
所以,如果你输入的是单个样本,需要采用 input.unsqueeze(0) 来扩充一个假的 batch 维度,即从 3 维变为 4 维。
1.3.损失函数
损失函数的输入是 (output, target) ,即网络输出和真实标签对的数据,然后返回一个数值表示网络输出和真实标签的差距。
PyTorch 中其实已经定义了不少的损失函数,这里仅采用简单的均方误差:nn.MSELoss ,例子如下:
output = net(input)
# 定义伪标签
target = torch.randn(10)
# 调整大小,使得和 output 一样的 size
target = target.view(1, -1)# 1*10
criterion = nn.MSELoss()loss = criterion(output, target)
print(loss)
这里,整个网络的数据输入到输出经历的计算图如下所示,
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
调用 loss.backward() :
# MSELoss
print(loss.grad_fn)
# Linear layer
print(loss.grad_fn.next_functions[0][0])
# Relu
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])
<MseLossBackward0 object at 0x000001C3A6AAE020>
:
- 这是均方误差损失(MSELoss)的梯度函数。它用于计算损失函数关于其输入的梯度。在反向传播过程中,这个梯度函数会计算损失函数对输入的梯度。
<AddmmBackward0 object at 0x000001C3A70055D0>
:
- 这是线性层(nn.Linear)的梯度函数。线性层的正向操作是
y = Ax + b
,其中A
是权重矩阵,x
是输入,b
是偏置。在反向传播过程中,这个梯度函数会计算关于权重、偏置和输入的梯度。
<AccumulateGrad object at 0x000001C3A6AAE020>
:
- 这是用于累加梯度的梯度函数。在反向传播过程中,模型的参数(如权重和偏置)会累积梯度。这个梯度函数负责将计算出的梯度累加到相应的参数上。
1.4.反向传播
反向传播的实现只需要调用 loss.backward() 即可,当然首先需要清空当前梯度缓存,即.zero_grad() 方法,否则之前的梯度会累加到当前的梯度,这样会影响权值参数的更新。
下面是一个简单的例子,以 conv1 层的偏置参数 bias 在反向传播前后的结果为例:
# 清空所有参数的梯度缓存
net.zero_grad()
print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)loss.backward()print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)
1.5.梯度更新
采用随机梯度下降(Stochastic Gradient Descent, SGD)方法的最简单的更新权重规则如下:
weight = weight - learning_rate * gradient
按照这个规则,代码实现如下所示:
# 简单实现权重的更新例子
learning_rate = 0.01
for f in net.parameters():#网络中所有可训练参数的迭代器,包括权重和偏置。f.data.sub_(f.grad.data * learning_rate)
遍历网络参数:
net.parameters()
返回网络中所有可训练参数的迭代器,包括权重和偏置。更新参数:对于每个参数
f
,其值通过减去f.grad.data * learning_rate
来更新。这里:
f.data
是参数的值。f.grad.data
是参数的梯度,即在反向传播过程中计算出的梯度。sub_()
是一个原地操作,用于直接在参数上减去给定的值,而不需要创建新的张量。
但是这只是最简单的规则,深度学习有很多的优化算法,不仅仅是 SGD,还有 Nesterov-SGD, Adam, RMSProp 等等,为了采用这些不同的方法,这里采用 torch.optim 库,使用例子如下所示:
import torch.optim as optim
# 创建优化器
optimizer = optim.SGD(net.parameters(), lr=0.01)# 在训练过程中执行下列操作
optimizer.zero_grad() # 清空梯度缓存
output = net(input)
loss = criterion(output, target)
loss.backward()
# 更新权重
optimizer.step()
注意,同样需要调用 optimizer.zero_grad() 方法清空梯度缓存。
2.图片分类器
在训练分类器前,当然需要考虑数据的问题。通常在处理如图片、文本、语音或者视频数据的时候,一般都采用标准的 Python 库将其加载并转成 Numpy 数组,然后再转回为 PyTorch 的张量。
·对于图像,可以采用 Pillow, OpenCV 库;
·对于语音,有 scipy 和 librosa;
·对于文本,可以选择原生 Python 或者 Cython 进行加载数据,或者使用 NLTK 和 SpaCy 。
PyTorch 对于计算机视觉,特别创建了一个 torchvision 的库,它包含一个数据加载器(data loader),可以加载比较常见的数据集,比如 Imagenet, CIFAR10, MNIST 等等,然后还有一个用于图像的数据转换器(data transformers),调用的库是 torchvision.datasets 和 torch.utils.data.DataLoader 。
在本教程中,将采用 CIFAR10 数据集,它包含 10 个类别,分别是飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车。数据集中的图片都是 3x32x32。一些例子如下所示:
基础信息
- 全称:Canadian Institute For Advanced Research (CIFAR-10)
- 发布时间:2009年(至今仍是基准测试的黄金标准)
- 数据规模:60,000张32×32像素彩色图像(50k训练+10k测试)
- 类别分布:10类平衡数据,每类6,000张(含飞机、汽车、鸟类等常见物体)
训练流程如下:
- 通过调用 torchvision 加载和归一化 CIFAR10 训练集和测试集;
- 构建一个卷积神经网络;
- 定义一个损失函数;
- 在训练集上训练网络;
- 在测试集上测试网络性能。
2.1.数据加载
由于在pycharm中下载很慢,所以直接去官网下载,
官网下载:https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
import torch
import torchvision
import torchvision.transforms as transforms# 定义数据预处理(含归一化到[-1,1])
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])# 直接指向已下载的cifar-10-python文件夹
data_path = './data/cifar-10-python' # 替换为实际路径trainset = torchvision.datasets.CIFAR10(root=data_path, # 关键修改:指定本地路径train=True,download=False, # 禁用重复下载transform=transform
)
# 定义训练集数据加载器
trainloader = torch.utils.data.DataLoader(trainset,batch_size=4,# 批大小shuffle=True,# 是否打乱顺序num_workers=2# 多线程加载数据
)# 定义测试集数据加载器
testset = torchvision.datasets.CIFAR10(root=data_path, # 关键修改:指定本地路径train=False,download=False, # 禁用重复下载transform=transform)
testloader = torch.utils.data.DataLoader(testset,batch_size=4,shuffle=False,num_workers=2
)
classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')
- transforms.
ToTensor()
:将PIL图像或NumPy数组转换为PyTorch张量(Tensor),格式为(C, H, W)
,自动将像素值从[0, 255]缩放到[0.0, 1.0]- transforms.Normalize
- 参数说明:
(mean_channels, std_channels)
- 计算过程:
normalized = (input - mean) / std
torchvision.datasets.CIFAR10():标准数据集接口
可视化数据:
from datetime import datetime
import matplotlib.pyplot as plt
import torchvision
import numpy as np
from skimage import filtersdef imshow_ultimate(img):# 预处理流程img = img / 2 + 0.5img_np = img.numpy().transpose(1, 2, 0)# 锐化+降噪img_np = filters.unsharp_mask(img_np, radius=1, amount=1.8)# 可视化设置plt.figure(figsize=(15, 15), dpi=500)plt.imshow(img_np,interpolation='hanning',cmap='plasma',vmin=0.1, vmax=0.9)plt.axis('off')plt.title(f"CIFAR-10 Enhanced Preview\n{datetime.now().strftime('%Y-%m-%d %H:%M')}")plt.show()# 执行展示
dataiter = iter(trainloader)
images, labels = next(dataiter)
imshow_ultimate(torchvision.utils.make_grid(images[:4]))
print('清晰化标签:', ' | '.join(classes[labels[j]] for j in range(4)))
远古数据,可真的糊!!!!
2.2.卷积神经网络
import torch.nn as nn
import torch.nn.functional as F class Net(nn.Module):def __init__(self):super(Net, self).__init__() # 调用父类nn.Module的初始化方法 # 第一卷积层:输入通道3(RGB),输出通道6,卷积核5x5(无padding默认valid卷积)self.conv1 = nn.Conv2d(3, 6, 5) # 最大池化层:窗口2x2,步长2(下采样率50%)self.pool = nn.MaxPool2d(2, 2) # 第二卷积层:输入通道6,输出通道16,卷积核5x5 self.conv2 = nn.Conv2d(6, 16, 5) # 全连接层1:将16*5*5=400维特征映射到120维 self.fc1 = nn.Linear(16 * 5 * 5, 120) # 全连接层2:120维到84维 self.fc2 = nn.Linear(120, 84) # 输出层:84维到10维(对应CIFAR-10的10个类别)self.fc3 = nn.Linear(84, 10) def forward(self, x):# 第一卷积块:Conv → ReLU → Pooling x = self.pool(F.relu(self.conv1(x))) # 输出尺寸:6x14x14 # 第二卷积块:Conv → ReLU → Pooling x = self.pool(F.relu(self.conv2(x))) # 输出尺寸:16x5x5 # 展平操作:将三维特征图转为一维向量(batch_size × 400)x = x.view(-1, 16 * 5 * 5) # 全连接层1 + ReLU激活 x = F.relu(self.fc1(x)) # 全连接层2 + ReLU激活 x = F.relu(self.fc2(x)) # 输出层(不接Softmax,因CrossEntropyLoss自带)x = self.fc3(x) return x net = Net()
网络架构图:
2.3.优化器和损失
import torch.optim as optim # 导入优化器模块 criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
# 损失函数:交叉熵损失(适用于多分类任务)
# 特点:内部自动整合Softmax和Negative Log Likelihood# 优化器:带动量的随机梯度下降(SGD)
# 参数说明:
# - net.parameters(): 获取网络所有可训练参数
# - lr=0.001: 学习率(2025年推荐初始值,需根据任务调整)
# - momentum=0.9: 动量因子(加速收敛并减少震荡)
2.4.训练网络
指定需要迭代的 epoch,然后输入数据,指定次数打印当前网络的信息,比如 loss 或者准确率等性能评价标准。
import time
start = time.time()
for epoch in range(2):running_loss = 0.0for i, data in enumerate(trainloader, 0):# 获取输入数据inputs, labels = data# 清空梯度缓存optimizer.zero_grad()# 网络输出outputs = net(inputs)# 计算损失loss = criterion(outputs, labels)# 反向传播loss.backward()# 更新参数optimizer.step()# 打印统计信息running_loss += loss.item()if i % 2000 == 1999:# 每 2000 次迭代打印一次信息print('[%d, %5d] loss: %.3f' % (epoch + 1, i+1, running_loss / 2000))running_loss = 0.0
print('Finished Training! Total cost time in CPU: ', time.time()-start)
2.5.测试网络
训练好一个网络模型后,就需要用测试集进行测试,检验网络模型的泛化能力。对于图像分类任务来说,一般就是用准确率作为评价标准。
首先,我们先用一个 batch 的图片进行小小测试,这里 batch=4 ,也就是 4 张图片,代码如下:
dataiter = iter(testloader)
images, labels = next(dataiter)# 打印图片
imshow_ultimate(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
# 网络输出
outputs = net(images)# 预测结果
_, predicted = torch.max(outputs, 1)
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))
前面三张图片都预测正确了,第四张图片错误预测飞机为船。
接着,让我们看看在整个测试集上的准确率可以达到多少吧!
correct = 0
total = 0
with torch.no_grad():for data in testloader:images, labels = dataoutputs = net(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():for data in testloader:images, labels = dataoutputs = net(images)_, predicted = torch.max(outputs, 1)c = (predicted == labels).squeeze()for i in range(4):label = labels[i]class_correct[label] += c[i].item()class_total[label] += 1for i in range(10):print('Accuracy of %5s : %2d %%' % (classes[i], 100 * class_correct[i] / class_total[i]))
准确率差异:
1. 数据层面问题
- 类别不平衡
- 示例:若
dog
类训练样本仅100张,而ship
类有5000张,模型会倾向预测高频类别。- 证据:
dog
(7%)和bird
(32%)准确率极低,可能样本量不足。- 标注噪声
- 低质量标注(如将
wolf
误标为dog
)会导致模型学习错误特征。- 特征相似性干扰
bird
与plane
(未出现类别)可能因蓝天背景混淆;deer
与horse
因四足形态相似易误判。2. 模型架构局限
- 浅层特征提取不足
- 若使用简单CNN(如LeNet),难以区分
cat
/dog
的细粒度纹理(如毛发vs皮毛)。- 过拟合特定类别
- 高准确率类别(如
ship
81%)可能因训练集背景单一(如海景)导致模型依赖背景而非物体特征。3. 训练策略缺陷
- 损失函数未加权
- 默认交叉熵损失平等对待所有类别,加剧对小类别的忽略。
- 学习率/优化器不适配
- 固定学习率可能使模型快速收敛到主导类别(如
ship
),忽略难样本(如dog
)。
2.6.GPU上训练
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)import time
# 在 GPU 上训练注意需要将网络和数据放到 GPU 上
net.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)start = time.time()
for epoch in range(2):running_loss = 0.0for i, data in enumerate(trainloader, 0):# 获取输入数据inputs, labels = datainputs, labels = inputs.to(device), labels.to(device)# 清空梯度缓存optimizer.zero_grad()outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()# 打印统计信息running_loss += loss.item()if i % 2000 == 1999:# 每 2000 次迭代打印一次信息print('[%d, %5d] loss: %.3f' % (epoch + 1, i+1, running_loss / 2000))running_loss = 0.0
print('Finished Training! Total cost time in GPU: ', time.time() - start)
3.数据并行训练--多块GPU
这部分教程将学习如何使用 DataParallel 来使用多个 GPUs 训练网络。
首先,在 GPU 上训练模型的做法很简单,如下代码所示,定义一个 device 对象,然后用 .to() 方法将网络模型参数放到指定的 GPU 上。
device = torch.device(“cuda:0”)
model.to(device)
接着就是将所有的张量变量放到 GPU 上:
mytensor = my_tensor.to(device)
注意,这里 my_tensor.to(device) 是返回一个 my_tensor 的新的拷贝对象,而不是直接修改 my_tensor 变量,因此你需要将其赋值给一个新的张量,然后使用这个张量。
Pytorch 默认只会采用一个 GPU,因此需要使用多个 GPU,需要采用 DataParallel ,代码如下所示:
model = nn.DataParallel(model)
这代码也就是本节教程的关键。
3.1.导入和参数
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader# Parameters and DataLoaders
input_size = 5
output_size = 2batch_size = 30
data_size = 100device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
定义网络输入大小和输出大小,batch 以及图片的大小,并定义了一个 device 对象。
3.2.构造一个虚拟数据集
接着就是构建一个假的(随机)数据集。实现代码如下:
class RandomDataset(Dataset):def __init__(self, size, length):self.len = lengthself.data = torch.randn(length, size)def __getitem__(self, index):return self.data[index]def __len__(self):return self.lendataset=RandomDataset(input_size, data_size)
print(dataset[0:5])
rand_loader = DataLoader(dataset,batch_size=batch_size,shuffle=True)
3.3.简单的网络
接下来构建一个简单的网络模型,仅仅包含一层全连接层的神经网络,加入 print() 函数用于监控网络输入和输出 tensors 的大小:
class Model(nn.Module):# Our modeldef __init__(self, input_size, output_size):super(Model, self).__init__()self.fc = nn.Linear(input_size, output_size)def forward(self, input):output = self.fc(input)print("\tIn Model: input size", input.size(),"output size", output.size())return output
3.4.创建数据并行
⭐⭐⭐⭐⭐定义一个模型实例,并且检查是否拥有多个 GPUs,如果是就可以将模型包裹在 nn.DataParallel ,并调用 model.to(device) 。代码如下:
model = Model(input_size, output_size)
if torch.cuda.device_count() >0:print("Let's use", torch.cuda.device_count(), "GPUs!")# dim = 0 [30, xxx] -> [10, ...], [10, ...], [10, ...] on 3 GPUsmodel = nn.DataParallel(model)model.to(device)
3.5.运行模型
接着就可以运行模型,看看打印的信息:
for data in rand_loader:input = data.to(device)output = model(input)print("Outside: input size", input.size(),"output_size", output.size())
如果仅仅只有 1 个或者没有 GPU ,那么 batch=30 的时候,模型会得到输入输出的大小都是 30。但如果有多个 GPUs,那么结果如下:
2 GPUs
# on 2 GPUs
Let’s use 2 GPUs!
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])
In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])
Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])3 GPUs
Let’s use 3 GPUs!
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])8 GPUs
Let’s use 8 GPUs!
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2]
DataParallel 会自动分割数据集并发送任务给多个 GPUs 上的多个模型。然后等待每个模型都完成各自的工作后,它又会收集并融合结果,然后返回。
相关文章:
【深度学习:理论篇】--Pytorch进阶教程
目录 1.神经网络 1.1.torch.nn 核心模块 1.2.定义神经网络 1.3.损失函数 1.4.反向传播 1.5.梯度更新 2.图片分类器 2.1.数据加载 2.2.卷积神经网络 2.3.优化器和损失 2.4.训练网络 2.5.测试网络 2.6.GPU上训练 3.数据并行训练--多块GPU 3.1.导入和参数 3.2.构造…...
卷积神经网络(CNN)基础
目录 一、应用场景 二、卷积神经网络的结构 1. 输入层(Input Layer) 2. 卷积层(Convolutional Layer) 3. 池化层(Pooling Layer) 最大池化(max_pooling)或平均池化(…...
第 28 场 蓝桥入门赛 JAVA 完整题解
前言 本文总结了六个编程题目的解题思路与核心考点,涵盖基础语法、逻辑分析、贪心算法、数学推导等知识点。每个题目均从问题本质出发,通过巧妙的算法设计或数学优化降低复杂度,展现了不同场景下的编程思维与解题技巧。以下为各题的详细考点解…...
Python 网络请求利器:requests 包详解与实战
诸神缄默不语-个人技术博文与视频目录 文章目录 一、前言二、安装方式三、基本使用1. 发起 GET 请求2. 发起 POST 请求 四、requests请求调用常用参数1. URL2. 数据data3. 请求头 headers4. 参数 params5. 超时时间 timeout6. 文件上传 file:上传纯文本文件流7. jso…...
聊透多线程编程-线程基础-1.进程、线程基础概念
目录 一、进程 二、线程 三、进程与线程的关系 四、进程与线程的比较 注:本文多张图片来源于网络,如有侵权,请联系删除 一、进程 1. 进程的定义 进程是指在系统中正在运行的一个应用程序的实例,是操作系统进行资源分配和调…...
Android:Android Studio右侧Gradle没有assembleRelease等选项
旧版as是“Do not build Gradle task list during Gradle sync” 操作这个选项。 参考这篇文章:Android Studio Gradle中没有Task任务,没有Assemble任务,不能方便导出aar包_gradle 没有task-CSDN博客 在as2024版本中,打开Setting…...
LeetcodeBST2JAVA
235.二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大&…...
如何创建单独的城市活码?活码能永久使用吗?
如何创建单独的城市活码 创建单独的城市活码通常需要借助专业的第三方工具,以下是具体步骤: 1.选择合适的工具 推荐使用专业的活码生成工具。 2.注册并登录 访问官网,完成注册并登录。 3.创建活码 在首页点击“创建活码”按钮。输入活码…...
用户画像(https://github.com/memodb-io/memobase)应用
1.下载项目的源代码,我们要先启动后端,用docker启动 cd src/server cp .env.example .env cp ./api/config.yaml.example ./api/config.yaml 这里我的配置内容如下config.yaml(因为我是调用的符合openai格式的大模型,所以我没改,如果要是别的大模型的话,需要自己再做兼容…...
基于形状补全和形态测量描述符的腓骨游离皮瓣下颌骨重建自动规划|文献速递-深度学习医疗AI最新文献
Title 题目 Automated planning of mandible reconstruction with fibula free flap basedon shape completion and morphometric descriptors 基于形状补全和形态测量描述符的腓骨游离皮瓣下颌骨重建自动规划 01 文献速递介绍 因创伤、骨髓炎和肿瘤而接受下颌骨节段切除术…...
Python3笔记之号称替代pip的uv包管理器
uv是什么? uv,这是一个由 Astral 团队开发的极快速的Python包和项目管理工具,用Rust语言编写。它集成了多种功能,旨在替代pip、pip-tools、pipx、poetry、pyenv、twine、virtualenv等多个工具,提供更高效、更全面的Py…...
面试如何应用大模型
在面试中,如果被问及如何应用大模型,尤其是面向政务、国有企业或大型传统企业的数字化转型场景,你可以从以下几个角度进行思考和回答: 1. 确定应用大模型的目标与痛点 首先,明确应用大模型的业务目标,并结合企业的实际需求分析可能面临的痛点。这些企业通常会关注如何提…...
贪心算法:部分背包问题深度解析
简介: 该Java代码基于贪心算法实现了分数背包问题的求解,核心通过单位价值降序排序和分阶段装入策略实现最优解。首先对Product数组执行双重循环冒泡排序,按wm(价值/重量比)从高到低重新排列物品;随后分两阶段装入:循环…...
Java程序的基本规则
java程序的基本规则 1.1 java程序的组成形式 Java程序是一种纯粹的面向对象的程序设计语言,因此Java程序 必须以类(class)的形式存在,类(class)是Java程序的最小程序 单位。Java程序不允许可执行性语句…...
机器学习-线性回归模型
机器学习-线性回归模型 线性模型笔记1、向量化2、线性回归模型公式3、损失函数(代价函数)4、梯度下降法5、Python 实现示例 6、使用 sklearn 实现线性回归模型✅ 基本步骤如下:📦 示例代码: 7、numpy中的切片X[n,:]是取…...
Linux 入门指令(1)
(1)ls指令 ls -l可以缩写成 ll 同时一个ls可以加多个后缀 比如 ll -at (2)pwd指令 (3)cd指令 cd .是当前目录 (4)touch指令 (5)mkdir指令 (6)rmdir和rm…...
密码学基础——AES算法
目录 一、算法背景 AES算法与Rijndael算法 二、算法特点 1.安全性高 2.效率高 3.灵活性好 三、算法说明 3.1状态、种子密钥和轮数的概念 (1)状态(State) 定义 结构:通常状态是一个 4N 字节的矩阵࿰…...
淘宝API与小程序深度联动:商品详情页“一键转卖”功能开发
要实现淘宝 API 与小程序深度联动,开发商品详情页 “一键转卖” 功能,可按以下步骤进行: 1. 前期准备 淘宝开放平台接入:在淘宝开放平台注册开发者账号,创建应用,获取 App Key 和 App Secret,…...
深入解析 C++ 设计模式:原理、实现与应用
一、引言 在 C 编程的广袤领域中,设计模式犹如闪耀的灯塔,为开发者指引着构建高效、可维护软件系统的方向。设计模式并非神秘莫测的代码魔法,实际上,我们在日常编程中或许早已与之打过交道。简单来说,设计模式常常借助…...
配置与管理代理服务器
安装squid Squid软件包在标准yum存储库中可用,因此,我们正在使用yum命令安装Squid代理。 [rootserver ~]# dnf install -y squid //安装 [rootserver ~]#systemctl enable --now squid.service [rootserver ~]#systemctl status squid.serv…...
RuntimeError: CUDA error: invalid device function
CUDA内核编译时的架构设置与当前GPU不兼容导致 -- The CUDA compiler identification is NVIDIA 11.5.119 (实际为 12.6) 解决方案: 1. 查看显卡计算能力 2. CMakeLists.txt 修改 set_target_properties(my_library PROPERTIESCUDA_AR…...
vulnhub:sunset decoy
靶机下载地址https://www.vulnhub.com/entry/sunset-decoy,505/ 渗透过程 简单信息收集 nmap 192.168.56.0/24 -Pn # 确定靶机ip:192.168.56.121 nmap 192.168.56.121 -A -T4 # 得到开放端口22,80 在80端口得到save.zip,需要密码解压。 john破解压缩…...
MySQL日期时间类型详解:DATE、TIME和DATETIME的用法与区别
在数据库设计中,正确处理日期和时间数据是至关重要的。MySQL提供了多种数据类型来存储时间信息,其中最常用的三种是DATE、TIME和DATETIME。本文将详细介绍这三种类型的特性、区别以及实际应用场景。 一、基本数据类型介绍 1. DATE类型 用途࿱…...
js异步机制
1、什么是异步机制?为什么js需要异步机制? 异步机制和同步机制是相对应的,异步是指:当代码按照顺序执行到一些比较耗时的操作,不会立刻执行,而是将这些操作推到一个队列中等待合适的时机从队列中取出任务执…...
Pycharm常用快捷键总结
主要是为了记录windows下的PyCharm的快捷键,里面的操作都试过了功能描述会增加备注。 文件操作 快捷键功能描述Ctrl N新建文件Ctrl Shift N根据名称查找文件Ctrl O打开文件Ctrl S保存当前文件Ctrl Shift S另存为Alt F12打开终端(Terminal&…...
巧记英语四级单词 Unit2-下【晓艳老师版】
mit传递(send 送)、 superiority n.优势,优越性 超越别人的东西就是自己的优势govern v.统治 government政府 统治的机构administer v.管理,治理 minister 大臣 部长,mini-小人,一再的做大臣 部长…...
走进底层 - JVM工作原理入门指南
走进底层 - JVM工作原理入门指南 Java 之所以能够实现“一次编写,到处运行”(Write Once, Run Anywhere, WORA),核心在于 Java 虚拟机(JVM, Java Virtual Machine)。JVM 是 Java 程序的运行环境,…...
windows 10频繁通知A字“出现了问题,无法安装功能。”
一、故障突现 windows 10频繁通知A字“出现了问题,无法安装功能。” 编辑文档时发现黑体、楷体gb_2312等常用字体,在字体列表中失踪,原来设置好的字体也显示失效。 二、起因分析 回想了一下,是3月27日安装了 2025-适用于Windows…...
基础环境配置
1.GitGerritjenkins Linux 远程登录 | 菜鸟教程 https://zhuanlan.zhihu.com/p/22766058062 2.Samba 配置 3.软件安装 (1)MobaXterm (2)Vscode (3)Xmind (4) Audacity Aud…...
ROS2——foxy apt打包离线安装deb包
需要从A设备复制ROS2环境到B设备,且B设备有可能没网络,所以选择制作离线资源包 1. 本机安装指令 本机环境ubuntu20.04,安装ros2-foxy版本,直接输入以下指令,基本不会遇到问题 这里安装的是ros-base版本,不…...
大数据学习(104)-clickhouse与hdfs
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一…...
大数据 - 1. 概述
早期的计算机(上世纪70年代前) 是相互独立的,各自处理各自的数据上世纪70年代后,出现了基于TCP/IP协议的小规模的计算机互联互通。上世纪90年代后,全球互联的互联网出现。当全球互联网逐步建成(2000年左右&…...
CD25.【C++ Dev】类和对象(16) static成员(上)
目录 1.static成员变量 问题:实现一个类,计算程序中创建出了多少个类对象 设计思路 代码示例 版本1 版本2 static成员 特点1.static成员为静态成员,为所有类对象所共享(在某种程度上可以理解为全局的,用类去封装"全局变量"),存放在静态区,则不属于某个具体的…...
C语言今天开始了学习
好多年没有弄了,还是捡起来弄下吧 用的vscode 建议大家参考这个配置 c语言vscode配置 c语言这个语言简单,但是今天听到了一个消息说python 不知道怎么debug。人才真多啊...
Mockito如何对静态方法进行测试
在 Mockito 中,直接对静态方法进行模拟是困难的,因为 Mockito 的设计理念是优先通过依赖注入(DI)管理对象,而静态方法破坏了这种设计(难以解耦)。不过,从 Mockito 3.4.0 版本开始,通过 mockStatic 方法支持了对静态方法的模拟(需配合 mockito-inline 依赖)。 从 Mo…...
Three.js 入门实战:安装、基础概念与第一个场景⭐
学习本章节你不必要追求细节,你只需要了解基本的3D场景需要哪些元素组成,如何通过组成3D场景的元素属性调整来控制3D物体或者场景即可。 在上一篇文章中我们初识了 Three.js,今天我们正式进入实战环节 🎯 前置准备: …...
【QT】QT的消息盒子和对话框(自定义对话框)
QT的消息盒子和对话框(自定义对话框) 一、消息盒子QMessageBox1、弹出警告盒子示例代码:现象: 2、致命错误盒子示例代码:现象: 3、帮助盒子示例代码:现象: 4、示例代码: …...
QT面试题:内存管理与对象生命周期
题目: 在Qt中,当一个父对象被销毁时,其子对象是否会被自动释放?请结合Qt的内存管理机制说明原因,并解释在什么情况下可能导致内存泄漏。如何避免这类问题? 参考答案 父子对象的内存管理机制 …...
linux查询inode使用率
在 Linux 中,inode 用于存储文件和目录的元数据(如权限、所有者、时间戳等)。当文件系统的 inode 被耗尽时,即使磁盘空间充足,系统也会提示 No space left on device。以下是查询 inode 使用率的详细方法: …...
算法基础—二分算法
目录 一、⼆分查找例题 1 牛可乐和魔法封印 2 A-B 数对 3 烦恼的高考志愿 二、 ⼆分答案 1 木材加⼯ 2 砍树 3 跳石头 ⼆分算法的原理以及模板其实是很简单的,主要的难点在于问题中的各种各样的细节问题。因此,⼤多数情况下,只是背会…...
2024年第十五届蓝桥杯CC++大学A组--成绩统计
2024年第十五届蓝桥杯C&C大学A组--成绩统计 题目: 动态规划, 对于该题,考虑动态规划解法,先取前k个人的成绩计算其方差,并将成绩记录在数组中,记录当前均值,设小蓝已检查前i-1个人的成绩&…...
家居实用品:生活中的艺术,家的温馨源泉
在快节奏的现代生活中,家居实用品不仅是日常所需的工具,更是营造温馨家居氛围、提升生活品质的关键元素。它们以其独特的魅力,默默地融入我们的日常生活,成为连接物质世界与精神世界的桥梁。 走进家门,首先映入眼帘的或…...
TCP重传率高与传输延迟问题
目录标题 排查步骤:TCP重传率高与传输延迟问题v1.0通过 rate(node_netstat_Tcp_RetransSegs[3m]) 排查 TCP 重传问题的步骤1. **指标含义与初步分析**2. **关联指标排查**3. **定位具体问题源**4. **解决方案**5. **验证与监控** v2.0一、基础检查二、网络层分析三、…...
超越简单检索:探索知识图谱与大型语言模型的协同进化之路
摘要: 大型语言模型(LLM)在自然语言处理领域取得了革命性进展,但其在事实准确性、复杂推理和可解释性方面仍面临挑战,“幻觉”现象是其固有局限性的体现。知识图谱(KG)作为结构化人类知识的载体,…...
汽车的四大工艺
文章目录 冲压工艺核心流程关键技术 焊接工艺核心流程 涂装工艺核心流程 总装工艺核心流程终检与测试静态检查动态检查四轮定位制动转鼓测试淋雨测试总结 简单总结下汽车的四大工艺(从网上找了一张图,感觉挺全面的)。 冲压工艺 将金属板材通过…...
研发效能实践:技术评审会生存指南
文章目录 🚨开篇暴击:为什么你的评审会像「菜鸡互啄」?⚙️第一章:Google Design Sprint——5天把争议变成共识📅 Day 1-5 实操手册Map the Problem(画地图)Sketch Solutions…...
js 拷贝
在 JavaScript 中,拷贝对象和数组时需要特别注意,因为对象和数组是引用类型,直接赋值只会复制引用,而不是实际的数据。以下是几种常见的拷贝方法及其应用场景: 1. 浅拷贝(Shallow Copy) 浅拷贝…...
AI比人脑更强,因为被植入思维模型【51】效率思维模型
giszz的理解:效率实际没有用,过分的追求效率,也是当下社会的弊病。但是效率思维,让我们能够用一个最简单的模型,去平衡投入和产出的最佳比例。过高的效率,会导致过大的压力,合适是最好的。 一、…...
Spark RDD相关概念
Spark运行架构与核心组件 1.Spark运行梁构 spark运行架构包括master和slave两个主要部分。master负责管理整个集群的作业任务调度,而slave则负责实际执行任务。 dirver是Spark驱动器节点,负责执行Spark任务中的main方法,将用户程序转换成作业…...
每日一题(小白)数组娱乐篇21
由于题意可知我们是要将对应的数字转换为英文,我们要考虑两点一个是进制的转换,也就是类似于我们的十进制一到9就多一位,这里的进制就是Z进制也就是27进制一旦到26下一位则进位;另一方面要考虑数字的转换也就是1~26对应A~Z。解决上…...