【PyTorch】图像多分类项目

【PyTorch】图像二分类项目

【PyTorch】图像二分类项目-部署

【PyTorch】图像多分类项目

【PyTorch】图像多分类项目部署

多类图像分类的目标是为一组固定类别中的图像分配标签。

目录

加载和处理数据

搭建模型

定义损失函数

定义优化器

训练和迁移学习

用随机权重进行训练

用预训练权重进行训练


加载和处理数据

将使用 PyTorch torchvision 包中提供的 STL-10 数据集,数据集中有 10 个类:飞机、鸟、车、猫、鹿、狗、马、猴、船、卡车。图像为96*96像素的RGB图像。数据集包含 5,000 张训练图像和 8,000 张测试图像。在训练数据集和测试数据集中,每个类分别有 500 和 800 张图像。

from torchvision import datasets
import torchvision.transforms as transforms
import ospath2data="./data"
# 如果数据路径不存在,则创建
if not os.path.exists(path2data):os.mkdir(path2data)# 定义数据转换
data_transformer = transforms.Compose([transforms.ToTensor()])# 从datasets库中导入STL10数据集,并指定数据集的路径、分割方式、是否下载以及数据转换器
train_ds=datasets.STL10(path2data, split='train',download=True,transform=data_transformer)# 打印数据形状
print(train_ds.data.shape)

 若数据集导入较慢可直接下载:http://ai.stanford.edu/~acoates/stl10/stl10_binary.tar.gz

import collections# 获取标签
y_train=[y for _,y in train_ds]# 统计标签
counter_train=collections.Counter(y_train)
print(counter_train)

# 加载数据
test0_ds=datasets.STL10(path2data, split='test', download=True,transform=data_transformer)
# 打印数据形状
print(test0_ds.data.shape)

# 导入StratifiedShuffleSplit模块
from sklearn.model_selection import StratifiedShuffleSplit# 创建StratifiedShuffleSplit对象,设置分割次数为1,测试集大小为0.2,随机种子为0
sss = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=0)# 获取test0_ds的索引
indices=list(range(len(test0_ds)))# 获取test0_ds的标签
y_test0=[y for _,y in test0_ds]# 对索引和标签进行分割
for test_index, val_index in sss.split(indices, y_test0):# 打印测试集和验证集的索引print("test:", test_index, "val:", val_index)# 打印测试集和验证集的大小print(len(val_index),len(test_index))

# 从torch.utils.data中导入Subset类
from torch.utils.data import Subset# 从test0_ds中选取val_index索引的子集,赋值给val_ds
val_ds=Subset(test0_ds,val_index)
# 从test0_ds中选取test_index索引的子集,赋值给test_ds
test_ds=Subset(test0_ds,test_index)import collections
import numpy as np# 获取标签
y_test=[y for _,y in test_ds]
y_val=[y for _,y in val_ds]# 统计测试集和验证集的标签数量
counter_test=collections.Counter(y_test)
counter_val=collections.Counter(y_val)# 打印测试集和验证集的标签数量
print(counter_test)
print(counter_val)

from torchvision import utils
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline# 设置随机种子为0
np.random.seed(0)# 定义一个函数,用于显示图像
def show(img,y=None,color=True):# 将图像转换为numpy数组npimg = img.numpy()# 将图像的维度从(C,H,W)转换为(H,W,C)npimg_tr=np.transpose(npimg, (1,2,0))# 显示图像plt.imshow(npimg_tr)# 如果有标签,则显示标签if y is not None:plt.title("label: "+str(y))# 定义网格大小
grid_size=4
# 随机生成4个索引
rnd_inds=np.random.randint(0,len(train_ds),grid_size)
print("image indices:",rnd_inds)# 从训练集中获取这4个索引对应的图像和标签
x_grid=[train_ds[i][0] for i in rnd_inds]
y_grid=[train_ds[i][1] for i in rnd_inds]# 将这4个图像拼接成一个网格
x_grid=utils.make_grid(x_grid, nrow=4, padding=2)
print(x_grid.shape)# 调用helper函数显示网格
plt.figure(figsize=(10,10))
show(x_grid,y_grid)

 

# 设置随机种子为0 
np.random.seed(0)# 设置网格大小
grid_size=4
# 从验证数据集中随机选择grid_size个索引
rnd_inds=np.random.randint(0,len(val_ds),grid_size)
print("image indices:",rnd_inds)# 从验证数据集中选择对应的图像
x_grid=[val_ds[i][0] for i in rnd_inds]
# 从验证数据集中选择对应的标签
y_grid=[val_ds[i][1] for i in rnd_inds]# 将图像排列成网格
x_grid=utils.make_grid(x_grid, nrow=4, padding=2)
print(x_grid.shape)# 调用辅助函数
plt.figure(figsize=(10,10))
# 显示网格图像和标签
show(x_grid,y_grid)

 

 

import numpy as np# 计算训练集中每个样本的RGB均值
meanRGB=[np.mean(x.numpy(),axis=(1,2)) for x,_ in train_ds]  
# 计算训练集中每个样本的RGB标准差
stdRGB=[np.std(x.numpy(),axis=(1,2)) for x,_ in train_ds]  meanR=np.mean([m[0] for m in meanRGB])  # 计算所有样本的R通道均值的平均值
meanG=np.mean([m[1] for m in meanRGB])  
meanB=np.mean([m[2] for m in meanRGB])  stdR=np.mean([s[0] for s in stdRGB])  # 计算所有样本的R通道标准差的平均值
stdG=np.mean([s[1] for s in stdRGB])  
stdB=np.mean([s[2] for s in stdRGB])  print(meanR,meanG,meanB)  # 打印R、G、B通道的均值
print(stdR,stdG,stdB)  # 打印R、G、B通道的标准差

# 定义训练数据的转换器
train_transformer = transforms.Compose([# 随机水平翻转,翻转概率为0.5transforms.RandomHorizontalFlip(p=0.5),  # 随机垂直翻转,翻转概率为0.5transforms.RandomVerticalFlip(p=0.5),  # 将图像转换为张量transforms.ToTensor(),# 对图像进行归一化,均值和标准差分别为meanR, meanG, meanB和stdR, stdG, stdBtransforms.Normalize([meanR, meanG, meanB], [stdR, stdG, stdB])])# 定义测试数据的转换器
test0_transformer = transforms.Compose([# 将图像转换为张量transforms.ToTensor(),# 对图像进行归一化,均值和标准差分别为meanR, meanG, meanB和stdR, stdG, stdBtransforms.Normalize([meanR, meanG, meanB], [stdR, stdG, stdB]),])   # 将训练数据集的转换器赋值给训练数据集的transform属性
train_ds.transform=train_transformer
# 将测试数据集的转换器赋值给测试数据集的transform属性
test0_ds.transform=test0_transformerimport torch
import numpy as np
import matplotlib.pyplot as plt# 设置随机种子
np.random.seed(0)
torch.manual_seed(0)# 定义网格大小
grid_size=4# 从训练数据集中随机选择grid_size个样本的索引
rnd_inds=np.random.randint(0,len(train_ds),grid_size)
print("image indices:",rnd_inds)# 根据索引从训练数据集中获取对应的样本
x_grid=[train_ds[i][0] for i in rnd_inds]
y_grid=[train_ds[i][1] for i in rnd_inds]# 将样本转换为网格形式
x_grid=utils.make_grid(x_grid, nrow=4, padding=2)
print(x_grid.shape)# 创建一个10x10的图像
plt.figure(figsize=(10,10))
# 显示网格和对应的标签
show(x_grid,y_grid)

from torch.utils.data import DataLoader# 创建训练数据集的DataLoader,batch_size为32,shuffle为True,表示每次迭代时都会打乱数据集
train_dl = DataLoader(train_ds, batch_size=32, shuffle=True)
# 创建验证数据集的DataLoader,batch_size为64,shuffle为False,表示每次迭代时不会打乱数据集
val_dl = DataLoader(val_ds, batch_size=64, shuffle=False)  # 遍历训练数据集
for x, y in train_dl:# 打印x的形状print(x.shape)# 打印y的形状print(y.shape)# 跳出循环break

# 遍历val_dl中的每个元素,x和y分别表示输入和标签
for x, y in val_dl:# 打印输入的形状print(x.shape)# 打印标签的形状print(y.shape)# 退出循环break

# 从datasets库中导入FashionMNIST数据集,并将其设置为训练集
fashion_train=datasets.FashionMNIST(path2data, train=True, download=True)

搭建模型

使用torchvision为多分类任务构建一个模型。torchvision软件包提供了用于图像分类的多个最先进的深度学习模型的实现,包括 AlexNet、VGG、ResNet、SqueezeNet、DenseNet、Inception、GoogleNet、ShuffleNet。这些模型在 ImageNet 数据集上进行了训练,其中包含来自 1,000 个班级的 1400 多万张图像。可以分别使用具有随机初始化权重的架构、预训练权重进行尝试。

from torchvision import models
import torch# 创建一个resnet18模型,pretrained参数设置为False,表示不使用预训练的权重
model_resnet18 = models.resnet18(pretrained=False)
# 打印模型ResNet18
print(model_resnet18)

from torch import nn
# 定义类别数量
num_classes=10
# 获取模型ResNet18的全连接层输入特征数量
num_ftrs = model_resnet18.fc.in_features 
# 将全连接层替换为新的全连接层,输出特征数量为类别数量
model_resnet18.fc = nn.Linear(num_ftrs, num_classes)# 定义设备为GPU
device = torch.device("cuda:0")
# 将模型移动到GPU上
model_resnet18.to(device)

from torchsummary import summary# 打印模型结构,输入大小为(3, 224, 224),即3个通道,224x224大小的图像
summary(model_resnet18, input_size=(3, 224, 224))

# 遍历模型ResNet18的参数
for w in model_resnet18.parameters():# 将参数转换为CPU数据w=w.data.cpu()# 打印参数的形状print(w.shape)break# 计算参数的最小值
min_w=torch.min(w)
# 计算w1,其中w1 = (-1/(2*min_w))*w + 0.5 
w1 = (-1/(2*min_w))*w + 0.5 
# 打印w1的最小值和最大值
print(torch.min(w1).item(),torch.max(w1).item())# 计算网格大小
grid_size=len(w1)
# 生成网格
x_grid=[w1[i] for i in range(grid_size)]
x_grid=utils.make_grid(x_grid, nrow=8, padding=1)
print(x_grid.shape)# 创建一个5x5的图像
plt.figure(figsize=(5,5))
show(x_grid)

采用预训练权重

from torchvision import models
import torch# 加载预训练的resnet18模型
resnet18_pretrained = models.resnet18(pretrained=True)# 定义分类的类别数
num_classes=10
# 获取resnet18模型的最后一层全连接层的输入特征数
num_ftrs = resnet18_pretrained.fc.in_features
# 将最后一层全连接层替换为新的全连接层,新的全连接层的输出特征数为num_classes
resnet18_pretrained.fc = nn.Linear(num_ftrs, num_classes)# 定义设备为cuda:0
device = torch.device("cuda:0")
# 将模型移动到cuda:0设备上
resnet18_pretrained.to(device) 

# 遍历resnet18_pretrained的参数
for w in resnet18_pretrained.parameters():# 将参数转换为cpu格式w=w.data.cpu()print(w.shape)break# 计算w的最小值
min_w=torch.min(w)
# 计算w1,其中w1=(-1/(2*min_w))*w + 0.5
w1 = (-1/(2*min_w))*w + 0.5 
# 打印w1的最小值和最大值
print(torch.min(w1).item(),torch.max(w1).item())# 计算w1的网格大小
grid_size=len(w1)
# 将w1转换为网格形式
x_grid=[w1[i] for i in range(grid_size)]
x_grid=utils.make_grid(x_grid, nrow=8, padding=1)
print(x_grid.shape)# 创建一个5x5的图像
plt.figure(figsize=(5,5))
show(x_grid)

 

定义损失函数

定义损失函数的目的是将模型优化为预定义的指标。分类任务的标准损失函数是交叉熵损失或对数损失。在定义损失函数时,需要考虑模型输出的数量及其激活函数。对于多类分类任务,输出数设置为类数,输出激活函数确确定损失函数。

输出激活输出数量损失函数
None num_classes nn.CrossEntropyLoss
log_Softmax num_classes nn.NLLLoss
torch.manual_seed(0)# 定义输入数据的维度
n,c=4,5
# 生成随机输入数据,并设置requires_grad=True,表示需要计算梯度
y = torch.randn(n, c, requires_grad=True)
# 打印输入数据的形状
print(y.shape)# 定义交叉熵损失函数,reduction参数设置为"sum",表示将所有样本的损失相加
loss_func = nn.CrossEntropyLoss(reduction="sum")
# 生成随机目标数据,表示每个样本的类别
target = torch.randint(c,size=(n,))
# 打印目标数据的形状
print(target.shape)# 计算损失
loss = loss_func(y, target)
# 打印损失值
print(loss.item())

# 反向传播,计算梯度
loss.backward()
# 打印输出y的值
print (y.data)

定义优化器

torch.optim 包提供了通用优化器的实现。优化器将保持当前状态,并根据计算出的梯度更新参数。对于分类任务,随机梯度下降 (SGD) 和 Adam 优化器非常常用。Adam 优化器在速度和准确性方面通常优于 SGD,因此这里选择 Adam 优化器。

from torch import optim
# 定义优化器,使用Adam优化算法,优化model_resnet18的参数,学习率为1e-4
opt = optim.Adam(model_resnet18.parameters(), lr=1e-4)
# 定义一个函数,用于获取优化器的学习率
def get_lr(opt):# 遍历优化器的参数组for param_group in opt.param_groups:# 返回学习率return param_group['lr']# 调用函数,获取当前学习率
current_lr=get_lr(opt)
# 打印当前学习率
print('current lr={}'.format(current_lr))

 

from torch.optim.lr_scheduler import CosineAnnealingLR# 创建学习率调度器,T_max表示周期长度,eta_min表示最小学习率
lr_scheduler = CosineAnnealingLR(opt,T_max=2,eta_min=1e-5)
# 定义一个空列表lrs
lrs=[]
# 循环10次
for i in range(10):# 调用lr_scheduler.step()方法lr_scheduler.step()# 调用get_lr()方法获取当前学习率lr=get_lr(opt)# 打印当前epoch和对应的学习率print("epoch %s, lr: %.1e" %(i,lr))# 将当前学习率添加到列表lrs中lrs.append(lr)
# 绘制lrs列表中的数据
plt.plot(lrs)

 

 

训练和迁移学习

到目前为止,已经创建了数据集并定义了模型、损失函数和优化器,接下来将进行训练和验证。首先使用随机初始化的权重训练模型。然后使用预先训练的权重训练模型,这也称为迁移学习。迁移学习将从一个问题中学到的知识(权重)用于其他类似问题。训练和验证脚本可能很长且重复。为了提高代码可读性并避免代码重复,将先构建一些辅助函数。

# 定义一个函数metrics_batch,用于计算预测结果和目标之间的正确率
def metrics_batch(output, target):# 将输出结果的最大值所在的索引作为预测结果pred = output.argmax(dim=1, keepdim=True)# 计算预测结果和目标之间的正确率corrects=pred.eq(target.view_as(pred)).sum().item()# 返回正确率return corrects
def loss_batch(loss_func, output, target, opt=None):# 计算batch的损失loss = loss_func(output, target)# 计算batch的评估指标metric_b = metrics_batch(output,target)# 如果有优化器,则进行反向传播和参数更新if opt is not None:opt.zero_grad()loss.backward()opt.step()# 返回损失和评估指标return loss.item(), metric_bdevice = torch.device("cuda")# 定义一个函数loss_epoch,用于计算模型在数据集上的损失
def loss_epoch(model,loss_func,dataset_dl,sanity_check=False,opt=None):# 初始化运行损失和运行指标running_loss=0.0running_metric=0.0# 获取数据集的长度len_data=len(dataset_dl.dataset)# 遍历数据集for xb, yb in dataset_dl:# 将数据移动到GPU上xb=xb.to(device)yb=yb.to(device)# 获取模型输出output=model(xb)# 计算当前批次的损失和指标loss_b,metric_b=loss_batch(loss_func, output, yb, opt)# 累加损失和指标running_loss+=loss_bif metric_b is not None:running_metric+=metric_b# 如果是sanity_check模式,则只计算一个批次if sanity_check is True:break# 计算平均损失和指标loss=running_loss/float(len_data)metric=running_metric/float(len_data)# 返回平均损失和指标return loss, metricdef train_val(model, params):# 获取参数num_epochs=params["num_epochs"]loss_func=params["loss_func"]opt=params["optimizer"]train_dl=params["train_dl"]val_dl=params["val_dl"]sanity_check=params["sanity_check"]lr_scheduler=params["lr_scheduler"]path2weights=params["path2weights"]# 初始化损失和指标历史记录loss_history={"train": [],"val": [],}metric_history={"train": [],"val": [],}# 复制模型参数best_model_wts = copy.deepcopy(model.state_dict())# 初始化最佳损失best_loss=float('inf')# 遍历每个epochfor epoch in range(num_epochs):# 获取当前学习率current_lr=get_lr(opt)print('Epoch {}/{}, current lr={}'.format(epoch, num_epochs - 1, current_lr))# 训练模型model.train()train_loss, train_metric=loss_epoch(model,loss_func,train_dl,sanity_check,opt)# 记录训练损失和指标loss_history["train"].append(train_loss)metric_history["train"].append(train_metric)# 评估模型model.eval()with torch.no_grad():val_loss, val_metric=loss_epoch(model,loss_func,val_dl,sanity_check)# 如果验证损失小于最佳损失,则更新最佳损失和最佳模型参数if val_loss < best_loss:best_loss = val_lossbest_model_wts = copy.deepcopy(model.state_dict())# 将最佳模型参数保存到本地文件torch.save(model.state_dict(), path2weights)print("Copied best model weights!")# 记录验证损失和指标loss_history["val"].append(val_loss)metric_history["val"].append(val_metric)# 更新学习率lr_scheduler.step()# 打印训练损失、验证损失和准确率print("train loss: %.6f, dev loss: %.6f, accuracy: %.2f" %(train_loss,val_loss,100*val_metric))print("-"*10) # 加载最佳模型参数model.load_state_dict(best_model_wts)# 返回模型、损失历史和指标历史return model, loss_history, metric_history

用随机权重进行训练

import copy# 定义交叉熵损失函数,reduction参数设置为"sum",表示将所有样本的损失相加
loss_func = nn.CrossEntropyLoss(reduction="sum")
# 定义Adam优化器,优化模型参数,学习率为1e-4
opt = optim.Adam(model_resnet18.parameters(), lr=1e-4)
# 定义余弦退火学习率调度器,T_max参数设置为5,eta_min参数设置为1e-6
lr_scheduler = CosineAnnealingLR(opt,T_max=5,eta_min=1e-6)# 定义训练参数字典
params_train={"num_epochs": 3,  # 训练轮数"optimizer": opt,  # 优化器"loss_func": loss_func,  # 损失函数"train_dl": train_dl,  # 训练数据集"val_dl": val_dl,  # 验证数据集"sanity_check": False,  # 是否进行sanity check"lr_scheduler": lr_scheduler,  # 学习率调度器"path2weights": "./models/resnet18.pt",  # 模型权重保存路径
}# 训练和验证模型
model_resnet18,loss_hist,metric_hist=train_val(model_resnet18,params_train)

# 获取训练参数中的训练轮数
num_epochs=params_train["num_epochs"]# 绘制训练和验证损失曲线
plt.title("Train-Val Loss")
plt.plot(range(1,num_epochs+1),loss_hist["train"],label="train")
plt.plot(range(1,num_epochs+1),loss_hist["val"],label="val")
plt.ylabel("Loss")
plt.xlabel("Training Epochs")
plt.legend()
plt.show()# 绘制训练和验证准确率曲线
plt.title("Train-Val Accuracy")
plt.plot(range(1,num_epochs+1),metric_hist["train"],label="train")
plt.plot(range(1,num_epochs+1),metric_hist["val"],label="val")
plt.ylabel("Accuracy")
plt.xlabel("Training Epochs")
plt.legend()
plt.show()

用预训练权重进行训练

import copy# 定义损失函数,使用交叉熵损失,并设置reduction为sum
loss_func = nn.CrossEntropyLoss(reduction="sum")
# 定义优化器,使用Adam优化器,并设置学习率为1e-4
opt = optim.Adam(resnet18_pretrained.parameters(), lr=1e-4)
# 定义学习率调度器,使用余弦退火调度器,设置最大周期为5,最小学习率为1e-6
lr_scheduler = CosineAnnealingLR(opt,T_max=5,eta_min=1e-6)# 定义训练参数
params_train={"num_epochs": 3,  # 设置训练周期为3"optimizer": opt,  # 设置优化器"loss_func": loss_func,  # 设置损失函数"train_dl": train_dl,  # 设置训练数据集"val_dl": val_dl,  # 设置验证数据集"sanity_check": False,  # 设置是否进行sanity check"lr_scheduler": lr_scheduler,  # 设置学习率调度器"path2weights": "./models/resnet18_pretrained.pt",  # 设置权重保存路径
}# 调用train_val函数进行训练和验证,并返回训练后的模型、损失历史和指标历史
resnet18_pretrained,loss_hist,metric_hist=train_val(resnet18_pretrained,params_train)

# 获取训练参数中的训练轮数
num_epochs=params_train["num_epochs"]# 绘制训练和验证损失曲线
plt.title("Train-Val Loss")
plt.plot(range(1,num_epochs+1),loss_hist["train"],label="train")
plt.plot(range(1,num_epochs+1),loss_hist["val"],label="val")
plt.ylabel("Loss")
plt.xlabel("Training Epochs")
plt.legend()
plt.show()# 绘制训练和验证准确率曲线
plt.title("Train-Val Accuracy")
plt.plot(range(1,num_epochs+1),metric_hist["train"],label="train")
plt.plot(range(1,num_epochs+1),metric_hist["val"],label="val")
plt.ylabel("Accuracy")
plt.xlabel("Training Epochs")
plt.legend()
plt.show()

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

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

相关文章

【HTML — 构建网络】HTML 入门

在本文中,我们将介绍 HTML 的绝对基础知识。为了帮助您入门,本文定义了元素、属性以及您可能听说过的所有其他重要术语。它还解释了这些在 HTML 中的位置。您将学习 HTML 元素的结构、典型的 HTML 页面的结构以及其他重要的基本语言功能。在此过程中,也将有机会玩转 HTML! …

SpringBoot 项目配置文件注释乱码的问题解决方案

一、问题描述 在项目的配置文件中&#xff0c;我们写了一些注释&#xff0c;如下所示&#xff1a; 但是再次打开注释会变成乱码&#xff0c;如下所示&#xff1a; 那么如何解决呢&#xff1f; 二、解决方案 1. 点击” File→Setting" 2. 搜索“File Encodings”, 将框…

Mac安装Hoomebrew与升级Python版本

参考 mac 安装HomeBrew(100%成功)_mac安装homebrew-CSDN博客 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 安装了Python 3.x版本&#xff0c;你可以使用以下命令来设置默认的Python版本&#xff1a; # 首先找到新安…

图片格式转换工具哪个好?一键转换图片格式就用这4个

在贵州的街头&#xff0c;福建的游神活动吸引了众多目光&#xff0c;人们纷纷拿出手机记录下这难得一见的盛况。然而&#xff0c;在分享这些精彩瞬间时&#xff0c;我们往往会遇到格式不兼容的问题。 想象一下&#xff0c;如果你能一键将手机拍摄的HEIC格式转换为更通用的JPG或…

2024 微信小程序 学习笔记 第二天

1. WXML 模板语法 数据绑定 事件绑定 条件渲染 列表渲染 2. WXSS 模板样式 rpx 样式导入 全局和局部样式 3. 全局配置 window tabBar 配置tabBar案例 4. 网络数据请求 Get请求 Post 请求 加载时请求 5. 案例 -本地生活&#xff08;首页&#xff09; 导航栏 轮播图 九宫格效果…

leetcode10 -- 正则表达式匹配

题目描述&#xff1a; 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符* 匹配零个或多个前面的那一个元素 所谓匹配&#xff0c;是要涵盖 整个 字符串 s的&#xff0c;而不是部分字符串。 示例 1&#xff1…

配置sublime的中的C++编译器(.sublime-build),实现C++20

GCC 4.8: 支持 C11 (部分) GCC 4.9: 支持 C11 和 C14 (部分) GCC 5: 完全支持 C14 GCC 6: 支持 C14 和 C17 (部分) GCC 7: 支持 C17 (大部分) GCC 8: 完全支持 C17&#xff0c;部分支持 C20 GCC 9: 支持更多的 C20 特性 GCC 10: 支持大部分 C20 特性 GCC 11: 更全面地支持 C20 …

原生PHP/JS自主开发的交友内核框架婚恋交友系统V10

本文来自&#xff1a;婚恋交友系统V10 - 源码1688 应用介绍 原生PHP/JS自主开发的交友内核框架&#xff0c;极高性能、无捆绑、自主权、无流水扣点、独立全开源 01脱单盲盒&#xff1a;脱单盲盒类似于漂流瓶&#xff0c;先将自己《投放》到盲盒中&#xff0c;另一伴有缘将您取…

解决显存不足问题:深度学习中的 Batch Size 调整【模型训练】

解决显存不足问题&#xff1a;深度学习中的 Batch Size 调整 在深度学习训练中&#xff0c;显存不足是一个常见的问题&#xff0c;特别是在笔记本等显存有限的设备上。本文将解释什么是 Batch Size&#xff0c;为什么调整 Batch Size 可以缓解显存不足的问题&#xff0c;以及调…

【Git多人协作开发】同一分支下的多人协作开发模式

目录 0.前言场景 1.开发者1☞完成准备工作&协作开发 1.1创建dev分支开发 1.2拉取远程dev分支至本地 1.3查看分支情况和分支联系情况 1.4创建本地dev分支且与远程dev分支建立联系 1.5在本地dev分支上开发file.txt 1.6推送push至远程仓库 2.开发者2☞完成准备工作&…

【学习笔记】Elasticsearch学习汇总(包含SpringData、Spark、Flink操作)

文章目录 前言数据类型种类ES解决什么问题ELK StackES是什么数据格式正排(正向)索引倒排索引创建索引索引查询索引删除创建文档(添加数据)自定义ID 简单查询类似于主键查询查询所有数据 修改数据全量修改局部修改 删除数据条件查询请求路径(不推荐)请求体全查询分页查询指定查询…

普元EOS学习笔记-EOS的ide开发工具的介绍

前言 普元EOS开发包括低开和高开。 EOS低开&#xff0c;直接在浏览器操作即可&#xff0c;不需要编码。 EOS高开&#xff0c;需要使用EOS的ide工具&#xff0c;进行编码开发。 EOS的ide工具是普元在Eclipse基础上进行的扩展&#xff0c;添加了若干插件&#xff0c;专门用于…

如何使用Proxy实现JavaScript中的观察者模式

在软件开发中&#xff0c;尤其是JavaScript中&#xff0c;观察者模式是一种行为设计模式&#xff0c;它定义了一种一对多的关系。它允许多个观察者对象监听一个主题对象&#xff0c;并在主题状态发生变化时自动得到通知。这种模式常用于事件系统、数据绑定等场景。 在JavaScrip…

【React】箭头函数:现代 JavaScript 的高效编程方式

文章目录 一、箭头函数的基本语法二、箭头函数的特性三、在 React 中的常见用法四、最佳实践 在现代 JavaScript 中&#xff0c;箭头函数&#xff08;Arrow Functions&#xff09;是一种简洁的函数表达方式&#xff0c;并且在 React 开发中非常常见。箭头函数不仅简化了函数的语…

HighConcurrencyCommFramework c++通讯服务器框架 :目录,修改标题,配置,日志打印

目录规划 nginx 根目录下的三个文件 makefile :编译项目的入口&#xff0c;编译项目从这里开始 config.mk&#xff1a;也是个配置脚本用来增加变动的东西&#xff0c;应付可变 common.mk&#xff1a;最核心的编译脚本&#xff0c;每个子目录都要被编译.cpp程序 配置文件 配…

构建未来客户服务的智能平台架构

随着科技的飞速发展&#xff0c;客户服务不再仅仅是响应投诉和提供支持&#xff0c;而是成为企业与客户之间重要的互动和沟通桥梁。在这个信息化和智能化的时代&#xff0c;构建一个优秀的客户服务平台架构至关重要&#xff0c;它不仅能提升服务效率&#xff0c;还能增强客户满…

《0基础》学习Python——第二十一讲__网络爬虫/<4>爬取豆瓣电影电影信息

爬取网页数据&#xff08;获取网页信息全过程&#xff09; 1、爬取豆瓣电影的电影名称、导演、主演、年份、国家、评价 2、首先我们先爬取页面然后再获取信息 1、爬取网页源码 import requests from lxml import etree if __name__ __main__:#UA伪装head{User-Agent:Mozilla/…

Bootstrap实现dialog上一步下一步多个弹窗交互

Bootstrap实现dialog上一步下一步多个弹窗交互 版本介绍&#xff1a; Bootstrap v3.3.7jQuery v3.5.1 一、功能介绍 重新设置bootstrap主题色内容区以card形式展示&#xff0c;纯js实现分页功能共两步骤&#xff0c;第一步选择模板&#xff0c;第二步进行其他操作步骤一内的按…

隧道洞外亮度检测器的工作原理

TH-SDG2隧道洞外亮度检测器是一种专门用于监测隧道洞外光照强度的设备&#xff0c;它通过感光器件和计算机技术&#xff0c;实时测量隧道出口处的光照强度&#xff0c;并根据测量结果控制隧道内的照明系统&#xff0c;以确保车辆在隧道内外切换时的行驶安全性。 隧道洞外亮度检…

谷粒商城实战笔记-54-商品服务-API-三级分类-拖拽效果

文章目录 一&#xff0c;54-商品服务-API-三级分类-修改-拖拽效果1&#xff0c;el-tree控件加上允许拖拽的属性2&#xff0c;是否允许拖拽3&#xff0c;完整代码 一&#xff0c;54-商品服务-API-三级分类-修改-拖拽效果 本节的主要内容是给三级分类树形结构加上拖拽功能&#…