4. Pytorch入门教程——创建一个基类来构建一个基本的神经网络

2024-05-14 00:08

本文主要是介绍4. Pytorch入门教程——创建一个基类来构建一个基本的神经网络,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

现在我们已经准备好了Dataloaders,之后要定义神经网络并训练它。为了定义一个神经网络,最好的方法是定义类来分离和抽象所有类型网络的通用功能,如训练循环,验证,评估,预测,设置不同的超参数等。

我们还需要定义实现特定类型网络的类,例如专门用于迁移学习的类,或为全连接操作的类等等。我们将创建三个主要类:

  • 从Pytorch的核心类nn.Module派生的神经网络的基类,它是Pytorch中任何神经网络的基础;
  • 派生自我们创建的基类的一个类,实现迁移学习的功能;
  • 派生自我们创建的基类的一个类,实现全连接网络的功能。

让我们一步步来创建名叫Network的基类

'''
从创建神经网络的Pytorch核心类nn.Module继承我们的类
'''
class Network(nn.Module):def __init__(self,device=None):'''我们调用父类的构造函数'''super().__init__()'''如果过用gpu,我们就设置设备属性为‘cuda’,否则设置为‘cpu'这将帮助我们避免在代码中到处检查是否有CUDA可用'''if device is not None:self.device = deviceelse:self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")'''我们创建一个虚构的forward方法。forward方法是Pytorch中的核心方法,它执行网络图并通过网络传递输入,将输入转换后在另一端获得输出在Pytorch中,我们编写自己的forward方法,该方法在运行时执行在__init__方法中定义的模块因为我们将在派生类中编写forward方法,所以在基类中它是空的'''def forward(self,x):pass

注意forward方法通过nn.Module的“call”方法调用,因此,我们的类对象可以成为一个“可调用的”对象,当它被调用时,forward方法将被自动调用。

一、训练方法

1. 接下来,我们添加了train方法。对于任何神经网络的训练,在训练循环的每次迭代中都需要执行一些常见的任务。这部分代码遍历每个批处理。这里定义了一个single epoch(单遍历整个数据集):

  • 获取数据的下一个批;
  • 将该批Tensors移到设备中(GPU或者CPU);
  • 将所有权重归零;
  • 调用forward函数,通过网络输入;
  • 将得到的输出传递给criterion(损失函数),与标签(目标)进行比较,并计算损失(loss);
  • 计算梯度;
  • 根据梯度和学习率更新所有权重;
  • 更新该epoch中的所有损失。

如果你熟悉神经网络的基础知识,那么你肯定知道这些步骤,因为它们对于所有框架和神经网络类型都是通用的。train_方法中的以下代码执行这些步骤。代码是非常好解释的,下面是Pytorch特定函数的简要介绍:

class Network(nn.Module):...'''print_every代表我们要打印多少批之后的损失信息'''def train_(self,trainloader,criterion,optimizer,print_every):'''下面的train方法(self.train())是基类(nn.Module)中的一个内置Pytorch方法,它在模型对象上设置一个标志,代表正在训练此标志在几个Pytorch模块使用,这些模块在训练和验证/测试期间表现不同,例如Dropout、batch normalization等'''self.train()t0 = time.time()batches = 0running_loss = 0'''inputs和labels分别来自trainloader的一批图像及其对应的标签'''for inputs, labels in trainloader:batches += 1#t1 = time.time()inputs, labels = inputs.to(self.device), labels.to(self.device)optimizer.zero_grad()outputs = self.forward(inputs)'''Criterion是基本的损失函数,计算网络输出和实际标签的差异'''loss = criterion(outputs, labels)'''loss.backward()实现反向传播,计算根据连通张量的完全图计算网络中的梯度'''loss.backward()'''损失函数执行完后,Optimizer.step实现优化算法的一步,产生新的梯度'''optimizer.step()'''item()给出一个标量值,它用于返回单个值的张量(在本例中,loss是一个浮点数值)'''loss = loss.item()#print('training this batch took {:.3f} seconds'.format(time.time() - t1))'''计算一个epoch完整的loss'''running_loss += loss'''输出loss信息,如果批的数量已经达到print_every'''if batches % print_every == 0:print(f"{time.asctime()}.."f"Time Elapsed = {time.time()-t0:.3f}.."f"Batch {batches+1}/{len(trainloader)}.. "f"Average Training loss: {running_loss/(batches):.3f}.. "f"Batch Training loss: {loss:.3f}.. ")t0 = time.time()'''最后我们返回该epoch的平均loss'''return running_loss/len(trainloader) 

2. 损失函数
注意,Pytorch附带了许多内置的损失函数,用于分类和回归等常见情况。这里我们将损失函数作为参数传递给train_。在分类中使用的一些常见的损失函数有交叉损失、Negative Likehood Log损失(NLLLoss)和二进制交叉损失。在本教程稍后讨论全连接类时,我们将更多地讨论损失函数。
3. 优化器模块
优化器模块应用梯度下降或其变体,执行梯度和学习率的更新。优化器有几种不同的算法,可以在torch.optim模块中找到。例子包括随机梯度下降(SGD),Adam,AdaDelta等。

二、验证方法

验证是将模型应用到验证集进行评估。目的是定期评估我们在训练方面的性能。如果你熟悉机器学习的概念,你很可能知道bias(拟合不足)和variance(过拟合)。如果我们在验证集上的损失显著且始终的高于在训练集上的损失,就是过拟合。这基本上意味着我们的模型在任何其他数据集上都不能泛化得足够好,因为模型与训练集的联系太紧密了。

  • 在每隔几个epochs之后在验证集上评估模型(默认是在每个epoch之后),测量损失并将其输出,以查看是否过拟合;
  • 验证方法与训练方法的区别在于,在验证过程中我们不需要进行反向传播、计算梯度、应用梯度下降和更新权重。我们所需要做的就是通过我们的模型分批传递验证数据集,并使用损失函数评估loss;
  • 当模型在几个epochs后性能变得更好后,验证loss就会下降;
  • 在验证中我们还想做的另一件事是计算分类的准确性,就是在预测中有多少次是正确的百分比:100x(准确预测类的数量/数据集大小);
  • 计算每个类的准确性,也就是说,对于每个单独的类,我们计算有多少是正确的;
  • 因此,我们还编写了一个实用函数来计算每个类(classwise)的准确性,如下所示。当我们对测试集或任何其他图像集进行预测时,这可能会很方便。
from collections import defaultdictdef update_classwise_accuracies(preds,labels,class_correct,class_totals):correct = np.squeeze(preds.eq(labels.data.view_as(preds)))'''我们只需遍历batch(shape[0]是batch大小)并更新classwise正确的数量和总的数量'''for i in range(labels.shape[0]):label = labels.data[i].item()class_correct[label] += correct[i].item()class_totals[label] += 1class Network(nn.Module):...def validate_(self,validloader):running_loss = 0.accuracy = 0'''创建两个默认字典来存储每个类classwise正确的预测和总的图片数'''class_correct = defaultdict(int)class_totals = defaultdict(int)'''self.eval()是一个将模型放入验证模式的Pytorch方法。它告诉Pytorch,我们只想在网络中执行正向传递,而不需要反向传播。它与我们在训练循环中使用的训练方法相反'''self.eval()'''无论我们在torch.no_grad()块中放入什么,都会告诉Pytorch不要计算梯度。我们要确保在计算循环中梯度永远不会被计算。'''with torch.no_grad():for inputs, labels in validloader:inputs, labels = inputs.to(self.device), labels.to(self.device)outputs = self.forward(inputs)loss = self.criterion(outputs, labels)running_loss += loss.item()_, preds = torch.max(torch.exp(outputs), 1) # you can safely remove the call to #torch.exp(as described below)update_classwise_accuracies(preds,labels,class_correct,class_totals)'''用前面讨论过的简单公式来计算精度。'''accuracy = (100*np.sum(list(class_correct.values()))/np.sum(list(class_totals.values())))'''把模型放回训练模式'''self.train()'''Running loss是所有批的loss,用它除以trainloader的长度(批次的数量)就得到了整个验证集的平均损失'''return (running_loss/len(validloader),accuracy)
  • np.squeeze(preds.eq(labels.data.view_as(preds)))
  • 这似乎是一个相当模糊的语句,所以让我们来分析一下:实际的标签包含在dataloader的数据属性中。预测是网络的输出,view_as方法根据参数传递的张量的维数来重新组织一个张量。在我们的例子中,这个语句会将批处理中的标签与预测张量(即batch_size x 10)对齐,因为我们的网络有10个类,而我们最终的全连接层会为每个批输出这么多outputs。eq(equal)方法比较张量的每一行,如果这些行相等则为1(True),否则为0。最终的结果将是一个50x1张量,我们通过挤压额外的批维度使其变平,成为一个50维的向量(1维张量),其中包含1s(预测等于标签,否则为0s)。np.squeeze从数组的形状中删除单维度条目,即把shape中为1的维度去掉,labels.data.view_as(preds))让预测的维度和labels的维度一样。
  • _, preds = torch.max(torch.exp(outputs), 1)
  • 我们在全连接模型中使用带有负对数似然损失(NLLLoss)的Softmax log(稍后将详细介绍)。因此,我们的输出应该是概率值的对数(也称为Logits)。我们不需要对logit取幂因为logit的最大值仍然会给我们相同的类下标。在这里这样做只是为了让我们的预测看起来像概率,这有时有助于调试。torch.max返回一个包含最大值和张量最大值索引的元组。

三、评估方法

评估方法的目的是在完成训练后在测试集上评估模型的性能。假设我们为要传递给这个方法的数据集提供了可用的标签。

代码几乎与validate相同。唯一的区别是我们不需要计算这种情况下的损失,因为我们已经完成了训练。

因为这个方法返回总体精度和类级精度,所以我们需要另一个实用函数get_accuracies。我们还需要class_names来获得类的实际名称。在创建迁移学习模型时(本教程稍后),我们将把类名存储为字典映射ids(numbers)到类名字符串。

from collections import defaultdictdef update_classwise_accuracies(preds,labels,class_correct,class_totals):correct = np.squeeze(preds.eq(labels.data.view_as(preds)))for i in range(labels.shape[0]):label = labels.data[i].item()class_correct[label] += correct[i].item()class_totals[label] += 1def get_accuracies(class_names,class_correct,class_totals):accuracy = (100*np.sum(list(class_correct.values()))/np.sum(list(class_totals.values())))'''我们获得这个类的名称,并通过用这个类的正确预测除以在测试数据集中拥有的这个类的图像的总数来得到这个类的准确性我们添加了一个额外的条件,即我们至少有一个类的图片,以避免除以0'''class_accuracies = [(class_names[i],100.0*(class_correct[i]/class_totals[i])) for i in class_names.keys() if class_totals[i] > 0]return accuracy,class_accuraciesclass Network(nn.Module):...def evaluate(self,testloader):self.eval()self.model.to(self.device)class_correct = defaultdict(int)class_totals = defaultdict(int)with torch.no_grad():for inputs, labels in testloader:inputs, labels = inputs.to(self.device), labels.to(self.device)outputs = self.forward(inputs)ps = torch.exp(outputs)_, preds = torch.max(ps, 1)update_classwise_accuracies(preds,labels,class_correct,class_totals)self.train()    return get_accuracies(self.class_names,class_correct,class_totals)

五、预测方法

预测方法用于从训练模型中预测或得出推断,以确定我们没有标签的图像的类别。这是在实际部署模型时将调用的方法。

  • 除了没有标签之外,它与evaluate非常相似;
  • 另一个不同之处在于,我们还对预测类的概率感兴趣;
  • 我们可能还想知道一个以上类别的预测概率,比如前三个最有可能的类别以及它们的指数。
class Network(nn.Module):...'''因为我们需要概率和(可能的)多个类的排序,我们传递topk参数,它告诉我们的函数有多少排序类和它们的概率'''def predict(self,inputs,topk=1):self.eval()self.model.to(self.device)with torch.no_grad():inputs = inputs.to(self.device)outputs = self.forward(inputs)ps = torch.exp(outputs)p,top = ps.topk(topk, dim=1)return p,top

Pytorch中张量的topk方法返回k个指标和它们在一个维度上的值(dim=1表示行,也就是水平方向上的值)。因为张量是50倍的类数,这将返回topk类和它们每一行的概率)。

六、拟合方法

这是我们类在启动训练时调用的主要方法。它实现了epoch循环的主训练循环。

它调用train_方法,定期调用验证来监视性能和过拟合等,追踪到目前为止获得的最佳精度,保存最佳精度模型,将完整模型及其超参数和其他变量保存到磁盘作为checkpoint。如果由于某种原因断电或训练中断,可以恢复checkpoint并在以后继续训练。

让我们一步一步来构建这个方法:

class Network(nn.Module):...def fit(self,trainloader,validloader,epochs=2,print_every=10,validate_every=1):for epoch in range(epochs):'''将模型移到设备('gpu'或'cpu')'''self.model.to(self.device)print('epoch {:3d}/{}'.format(epoch+1,epochs))epoch_train_loss =  self.train_(trainloader,self.criterion,self.optimizer,print_every)'''检查是否需要在每个validate_every epochs之后调用validate,调用它并输出验证损失和准确性'''if  validate_every and (epoch % validate_every == 0):t2 = time.time()epoch_validation_loss,epoch_accuracy = self.validate_(validloader)time_elapsed = time.time() - t2print(f"{time.asctime()}--Validation time {time_elapsed:.3f} seconds.."f"Epoch {epoch+1}/{epochs}.. "f"Epoch Training loss: {epoch_train_loss:.3f}.. "f"Epoch validation loss: {epoch_validation_loss:.3f}.. "f"validation accuracy: {epoch_accuracy:.3f}")self.train()

七、保存最佳模型

拟合函数还应该监视到目前为止在所有epoch中获得的最佳精度,并在获得一个比以前更好的新模型时保存最佳精度模型。这确保了即使没有检查点,如果在训练期间验证损失开始下降,我们也应该能够检索出我们的最佳模型。

这是一个常见的场景,因为训练可能需要几个小时才能完成,我们可能不得不离开系统。这样我们可以确保我们总是重新加载最佳精度模型的权重,并使用它们进行推断。

from collections import defaultdict
import mathclass Network(nn.Module):def __init__(self,device=None):...'''初始化best_accuracy为0.'''self.best_accuracy = 0....def fit(self,trainloader,validloader,epochs=2,print_every=10,validate_every=1):for epoch in range(epochs):self.model.to(self.device)print('epoch {:3d}/{}'.format(epoch+1,epochs))epoch_train_loss =  self.train_(trainloader,self.criterion,self.optimizer,print_every)if  validate_every and (epoch % validate_every == 0):t2 = time.time()epoch_validation_loss,epoch_accuracy = self.validate_(validloader)time_elapsed = time.time() - t2print(f"{time.asctime()}--Validation time {time_elapsed:.3f} seconds.."f"Epoch {epoch+1}/{epochs}.. "f"Epoch Training loss: {epoch_train_loss:.3f}.. "f"Epoch validation loss: {epoch_validation_loss:.3f}.. "f"validation accuracy: {epoch_accuracy:.3f}")'''如果验证返回更好的精度,检查并保存最佳精度模型'''if self.best_accuracy == 0. or (epoch_accuracy > self.best_accuracy):print('updating best accuracy: previous best = {:.3f} new best = {:.3f}'.format(self.best_accuracy,epoch_accuracy))self.best_accuracy = epoch_accuracy'''Pytorch保存方法通过使用Python的Pickle模块序列化Pytorch张量数据结构来保存。在这里,我们存储由state_dict()方法返回的模型状态字典,该方法                     包含模型全图的所有权值(体系结构中的每个张量)'''torch.save(self.state_dict(),self.best_accuracy_file)self.train() # just in case we forgot to put the model back to train mode in validateprint('loading best accuracy model')'''当我们完成训练循环时,我们恢复最佳精度的模型。这确保我们使用最佳精度的模型。This ensures that any evaluation or inference we perform while the model remains in memory shall be done using the best accuracy model instead of the one obtained in the last iteration of the training loop.'''self.load_state_dict(torch.load(self.best_accuracy_file))

注意self.best_accuracy_file应该是在模型参数初始化期间设置的文件名(请参见下一节)

八、设置并获得不同的参数和超参数

我们需要设置模型中不同的参数和超参数。包括损失函数(criterion),优化器,dropout概率,学习率和其他参数。我们写四个方法:

  • set_criterion创建一个损失函数的实例并将其设置在模型上;
  • set_optimizer创建一个优化器的实例并将其设置在模型上;
  • set_model_params调用以上两个函数,设置另外的超参数;
  • get_model_params检索模型上当前设置的参数。当我们想要保存一个完整的模型检查点时,这将非常方便。
class Network(nn.Module):...def set_criterion(self,criterion_name):if criterion_name.lower() == 'nllloss':self.criterion_name = 'NLLLoss'self.criterion = nn.NLLLoss()elif criterion_name.lower() == 'crossentropyloss':self.criterion_name = 'CrossEntropyLoss'self.criterion = nn.CrossEntropyLoss()def set_optimizer(self,params,optimizer_name='adam',lr=0.003):from torch import optimif optimizer_name.lower() == 'adam':print('setting optim Adam')self.optimizer = optim.Adam(params,lr=lr)self.optimizer_name = optimizer_nameelif optimizer.lower() == 'sgd':print('setting optim SGD')self.optimizer = optim.SGD(params,lr=lr)elif optimizer.lower() == 'adadelta':print('setting optim Ada Delta')self.optimizer = optim.Adadelta(params)def set_model_params(self,criterion_name,optimizer_name,lr, # learning ratedropout_p,model_name,best_accuracy,best_accuracy_file,class_names):self.set_criterion(criterion_name)self.set_optimizer(self.parameters(),optimizer_name,lr=lr)self.lr = lrself.dropout_p = dropout_pself.model_name =  model_nameself.best_accuracy = best_accuracyself.best_accuracy_file = best_accuracy_fileself.class_names = class_namesdef get_model_params(self):params = {}params['device'] = self.deviceparams['model_name'] = self.model_nameparams['optimizer_name'] = self.optimizer_nameparams['criterion_name'] = self.criterion_nameparams['lr'] = self.lrparams['dropout_p'] = self.dropout_pparams['best_accuracy'] = self.best_accuracyparams['best_accuracy_file'] = self.best_accuracy_fileparams['class_names'] = self.class_namesreturn params
  • set_criterion支持两个损失函数:CrossEntropy和NLLLoss;
  • 它传递给损失函数的名称,并使用Pytorch API实例化一个对象;
  • set_optimizer通过使用Pytorch API对优化器进行实例化,从而启用优化器。它默认为“Adam”,而SGD和Adadelta也可以设置。同样,对其他优化器的支持可以很容易地添加;
  • set_model_params是一种更高级的方法,它调用set_criterion和set_optimizer以及其他参数,如model_name、当前最佳精度值、best_accuracy_file,我们在其中存储最佳精度、模型权重、学习率和dropout概率;
  • 为了简洁,我们省略了参数类型的完整性检查(例如model_name、optimizer_name应该是字符串、dropout_p、lr应该是浮点数等等);
  • set_model_param方法应该从主要的模型类中调用,例如迁移学习和全连接模型,我们接下来将从这个基础网络类中派生这些模型的类
  • get_model_param只返回当前参数作为字典。它将用于创建检查点(参见下一节);
  • class_names是一个字典,它包含类标识符(整数)到类名(字符串)的映射。

九、保存模型Checkpoint

  • 在训练深度学习模型时,保存模型的检查点是一项重要的任务;
  • 这样我们就可以轻松地执行长时间运行的训练循环;
  • 如果有任何中断,例如机器崩溃,电源故障,Jupyter Notebpook崩溃或任何其他不可预见的问题发生,我们的训练被中断,我们可以从上一个检查点恢复并继续训练。我们的训练时间不会浪费;
  • 现在我们将实现一个方法save_checkpoint;
  • 稍后在本教程中我们将实现一个实用函数load_checkpoint。
class Network(nn.Module):...'''增加chkpoint_file参数到set_params函数'''def set_model_params(self,criterion_name,optimizer_name,lr, # learning ratedropout_p,model_name,best_accuracy,best_accuracy_file,chkpoint_file):self.criterion_name = criterion_nameself.set_criterion(criterion_name)self.optimizer_name = optimizer_nameself.set_optimizer(self.parameters(),optimizer_name,lr=lr)self.lr = lrself.dropout_p = dropout_pself.model_name =  model_nameself.best_accuracy = best_accuracyprint('set_model_params: best accuracy = {:.3f}'.format(self.best_accuracy))  self.best_accuracy_file = best_accuracy_fileself.chkpoint_file = chkpoint_filedef get_model_params(self):params = {}params['device'] = self.deviceparams['model_name'] = self.model_nameparams['optimizer_name'] = self.optimizer_nameparams['criterion_name'] = self.criterion_nameparams['lr'] = self.lrparams['dropout_p'] = self.dropout_pparams['best_accuracy'] = self.best_accuracyprint('get_model_params: best accuracy = {:.3f}'.format(self.best_accuracy))  params['best_accuracy_file'] = self.best_accuracy_fileparams['chkpoint_file'] = self.chkpoint_fileprint('get_model_params: chkpoint file = {}'.format(self.chkpoint_file))  return paramsdef save_chkpoint(self):saved_model = {}'''通过get_model_params获取所有参数和类名,并将它们存储到chkpoint文件中'''saved_model['params'] = self.get_model_params()    torch.save(saved_model,self.chkpoint_file)print('checkpoint created successfully in {}'.format(self.chkpoint_file))

这篇关于4. Pytorch入门教程——创建一个基类来构建一个基本的神经网络的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/987198

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Python创建Excel的4种方式小结

《Python创建Excel的4种方式小结》这篇文章主要为大家详细介绍了Python中创建Excel的4种常见方式,文中的示例代码简洁易懂,具有一定的参考价值,感兴趣的小伙伴可以学习一下... 目录库的安装代码1——pandas代码2——openpyxl代码3——xlsxwriterwww.cppcns.c

MyBatis-Flex BaseMapper的接口基本用法小结

《MyBatis-FlexBaseMapper的接口基本用法小结》本文主要介绍了MyBatis-FlexBaseMapper的接口基本用法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具... 目录MyBATis-Flex简单介绍特性基础方法INSERT① insert② insertSelec

JAVA调用Deepseek的api完成基本对话简单代码示例

《JAVA调用Deepseek的api完成基本对话简单代码示例》:本文主要介绍JAVA调用Deepseek的api完成基本对话的相关资料,文中详细讲解了如何获取DeepSeekAPI密钥、添加H... 获取API密钥首先,从DeepSeek平台获取API密钥,用于身份验证。添加HTTP客户端依赖使用Jav

使用Python在Excel中创建和取消数据分组

《使用Python在Excel中创建和取消数据分组》Excel中的分组是一种通过添加层级结构将相邻行或列组织在一起的功能,当分组完成后,用户可以通过折叠或展开数据组来简化数据视图,这篇博客将介绍如何使... 目录引言使用工具python在Excel中创建行和列分组Python在Excel中创建嵌套分组Pyt

nginx-rtmp-module构建流媒体直播服务器实战指南

《nginx-rtmp-module构建流媒体直播服务器实战指南》本文主要介绍了nginx-rtmp-module构建流媒体直播服务器实战指南,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. RTMP协议介绍与应用RTMP协议的原理RTMP协议的应用RTMP与现代流媒体技术的关系2

解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题

《解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题》文章详细描述了在使用lombok的@Data注解标注实体类时遇到编译无误但运行时报错的问题,分析... 目录问题分析问题解决方案步骤一步骤二步骤三总结问题使用lombok注解@Data标注实体类,编译时

C++中使用vector存储并遍历数据的基本步骤

《C++中使用vector存储并遍历数据的基本步骤》C++标准模板库(STL)提供了多种容器类型,包括顺序容器、关联容器、无序关联容器和容器适配器,每种容器都有其特定的用途和特性,:本文主要介绍C... 目录(1)容器及简要描述‌php顺序容器‌‌关联容器‌‌无序关联容器‌(基于哈希表):‌容器适配器‌:(

MySQL分表自动化创建的实现方案

《MySQL分表自动化创建的实现方案》在数据库应用场景中,随着数据量的不断增长,单表存储数据可能会面临性能瓶颈,例如查询、插入、更新等操作的效率会逐渐降低,分表是一种有效的优化策略,它将数据分散存储在... 目录一、项目目的二、实现过程(一)mysql 事件调度器结合存储过程方式1. 开启事件调度器2. 创

mysql外键创建不成功/失效如何处理

《mysql外键创建不成功/失效如何处理》文章介绍了在MySQL5.5.40版本中,创建带有外键约束的`stu`和`grade`表时遇到的问题,发现`grade`表的`id`字段没有随着`studen... 当前mysql版本:SELECT VERSION();结果为:5.5.40。在复习mysql外键约