神经网络-pytorch版本

news2024/11/19 21:28:58

pytorch神经网络基础

torch简介

torch和numpy

import torch
import numpy as np
np_data=np.arange(6).reshape((2,3))
torch_data=torch.from_numpy(np_data)
tensor2array=torch_data.numpy()
print(np_data,"\n",torch_data,"\n",tensor2array)

在这里插入图片描述

torch的数学运算

data=[-1,-2,1,2]
tensor=torch.FloatTensor(data)
# 绝对值abs
print(np.abs(data),"\n",torch.abs(tensor))
#三角函数sin
print(np.sin(data),"\n",torch.sin(tensor))
#mean均值
print(np.mean(data),"\n",torch.mean(tensor))

# np.dot (x,y)是用于计算两个数组的点积,即对应元素相乘再相加,
# 而np.matmul (x,y)则是用于计算两个数组的矩阵乘积
data=[[1,2],[3,4]]
tensor=torch.FloatTensor(data)
print(np.matmul(data,data),"\n",torch.mm(tensor,tensor))

在这里插入图片描述

变量(variable)

在PyTorch中,Variable在早期版本中用于自动求导(autograd)的功能,但从PyTorch 0.4.0版本开始,Variable已经被弃用,取而代之的是Tensor的功能。因此,如果你使用的是PyTorch 0.4.0或更新版本,你不再需要使用Variable

以下是Variable和普通的变量(如Tensor)之间的一些区别,以及在新版本中的情况:

  1. 自动求导(Autograd):

    • Variable在早期版本中主要用于自动求导。你可以使用Variable包装一个Tensor,并在其上进行操作,PyTorch会跟踪这些操作以计算梯度。但在新版本中,Tensor自身具有自动求导功能,无需Variable
  2. In-Place操作:

    • 在早期版本中,Variable支持in-place操作(如var.data += 1),但这不是推荐的做法。在新版本中,in-place操作被明确禁止,以避免梯度计算中的错误。你应该使用.data属性来访问Tensor的数据,并避免in-place操作。
  3. 性能:

    • Variable的引入会增加一些额外的开销,因为它需要跟踪操作以进行自动求导。在新版本中,Tensor的性能更高,因为它不再需要这些额外的开销。

所以,总的来说,在PyTorch的新版本中,你应该使用Tensor而不是Variable来处理数据,因为Tensor包括了Variable的所有功能,而且性能更好。如果你在早期版本中使用Variable,你可能需要考虑升级你的代码以适应新的PyTorch版本。

什么是激励函数(activation function)

其实就是另外一个非线性函数. 比如说relu, sigmoid, tanh. 使得输出结果 y 也有了非线性的特征.

激励函数(activation)

一句话概括 Activation: 就是让神经网络可以描述非线性问题的步骤, 是神经网络变得更强大.

import torch
import torch.nn.functional as F  # 激励函数都在这里

# 做一些假数据来观看图像
x=torch.linspace(-5,5,100)  # x data (tensor), shape=(100, 1)
print(x)
x_np=x.numpy()  # 换成 numpy array, 出图时用

# 几种常用的激励函数
y_relu=F.relu(x).numpy()
y_sigmoid=torch.sigmoid(x).numpy()
y_sigmoid=F.sigmoid(x).numpy()
y_tanh=torch.tanh(x).numpy()
y_softplus=F.softplus(x).numpy()

# 画图部分还没看matplotlib,后续再补充
import matplotlib.pyplot as plt  # python 的可视化模块, 我有教程 (https://mofanpy.com/tutorials/data-manipulation/plt/)

plt.figure(1, figsize=(8, 6))
plt.subplot(221)
plt.plot(x_np, y_relu, c='red', label='relu')
plt.ylim((-1, 5))
plt.legend(loc='best')

plt.subplot(222)
plt.plot(x_np, y_sigmoid, c='red', label='sigmoid')
plt.ylim((-0.2, 1.2))
plt.legend(loc='best')

plt.subplot(223)
plt.plot(x_np, y_tanh, c='red', label='tanh')
plt.ylim((-1.2, 1.2))
plt.legend(loc='best')

plt.subplot(224)
plt.plot(x_np, y_softplus, c='red', label='softplus')
plt.ylim((-0.2, 6))
plt.legend(loc='best')

plt.show()

在这里插入图片描述
在这里插入图片描述

torch.sigmoid(x)F.sigmoid(x) 都是计算输入张量 x 上的 sigmoid 函数,它们的输出结果是一样的。在最新版本的PyTorch中,通常建议使用 torch.sigmoid(x),而不再需要导入torch.nn.functional中的F.sigmoid(x),因为PyTorch的最新版本中已经将这些激活函数作为张量的方法进行了实现。

所以,以下两行代码是等价的:

y_sigmoid = torch.sigmoid(x).numpy()
y_sigmoid = F.sigmoid(x).numpy()  # 在最新版本的PyTorch中也是有效的,但不推荐

通常情况下,建议使用 torch.sigmoid(x),因为它更符合PyTorch的现代风格。

建造第一个神经网络

关系拟合(回归)

要点

看神经网络是如何通过简单的形式将一群数据用一条线条来表示。

或者说, 是如何在数据当中找到他们的关系, 然后用神经网络模型来建立一个可以代表他们关系的线条。
在这里插入图片描述

建立数据集

import torch
import matplotlib.pyplot as plt

x=torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
y=x.pow(2)+0.2*torch.rand_like(x)

plt.scatter(x.numpy(),y.numpy())
plt.show()

在这里插入图片描述

x=torch.unsqueeze(torch.linspace(-1,1,100),dim=1)

这行代码使用了PyTorch库来创建一个包含100个元素的张量(tensor),该张量的值是从-1到1均匀分布的。

让我们一步一步来解释这行代码:

  1. torch.linspace(-1, 1, 100):这部分代码使用torch.linspace函数创建一个从-1到1的等间距数列,其中包含100个数值。torch.linspace函数的第一个参数是起始值(-1),第二个参数是结束值(1),第三个参数是要生成的数值的数量(100)。这将生成一个张量,其中包含了从-1到1之间的100个均匀分布的数值。

  2. torch.unsqueeze(..., dim=1):接下来,torch.unsqueeze函数被用来在张量中添加一个维度(dimension)。dim=1参数指定了要在哪个位置添加维度。在这里,我们将在第1维(即列维度)上添加一个维度。这将把原始的一维张量(形状为(100,))变成一个二维张量(形状为(100, 1)),其中有100行和1列。

最终的结果是一个形状为(100, 1)的二维张量,其中包含了从-1到1均匀分布的100个数值,每个数值都位于独立的行中。这种形式的张量通常在机器学习和深度学习中用于输入数据的处理,特别是当处理单个特征的数据时,常常需要将其转换为二维张量。

y=x.pow(2)+0.2*torch.rand_like(x)

这一行首先计算了 x 的平方,然后加上了一些噪声。让我们逐步解释:

  • x.pow(2):这部分代码计算了 x 中每个元素的平方。因为 x 是一个 PyTorch 张量,所以这个操作会对 x 中的每个元素都进行平方操作,生成一个新的张量,形状与 x 相同,但每个元素都是原来的元素的平方。

  • 0.2*torch.rand_like(x):这部分代码生成了一个与 x 具有相同形状的张量,但其中的每个元素都是从均匀分布 [0, 1) 中随机采样的数值,并且每个数值都乘以0.2。这个操作引入了一些噪声,将其与平方项相加,以创建一个新的张量 y

最终,y 包含了与 x 对应的平方项加上一些随机噪声,因此它是一个形状相同的二维张量,其中包含了与 x 相关的数值。这种操作常见于机器学习中的回归任务,其中 x 可能表示输入特征,而 y 表示对应的目标值(或标签),噪声用于模拟现实世界中的不确定性和随机性。这种情况下,模型的任务是拟合从 xy 的映射关系。

建立神经网络

# 建立神经网络
import torch
import torch.nn as nn
class Net(nn.Module):
    # 搭建我们的层数时要用到的信息
    def __init__(self,n_feature,n_hidden,n_output):
        super(Net,self).__init__()   #可以暂时理解为初始化,这块要弄清楚是有难度的
        self.hidden=nn.Linear(n_feature,n_hidden)#隐藏层,关心有多少个输入,有多少个神经元个数
        self.predict=nn.Linear(n_hidden,n_output)#输出层,关心有多少个输入(从隐藏层而来的神经元),有多少个输出
    # 神经网络前向传递的过程,真正开始搭建神经网络
    def forward(self,x):
        x=torch.relu(self.hidden(x))#我们的x过了一个hidden层,输出了n_hidden个神经元的个数
        x=self.predict(x) #输出层接受x并输出结果
        # 为什么我们的预测不用激励函数呢。因为在大多数的情况下回归问题的取值可以从负无穷到正无穷,
        #而用了激励函数,会把取值范围截断一部分
        return x
net=Net(n_feature=1,n_hidden=10,n_output=1)
print(net)

在这里插入图片描述

在这段代码中,self.hiddenself.predict 是神经网络模型 Net 类的成员变量(或属性),它们分别用来表示神经网络的隐藏层和输出层。这些成员变量的值来自于PyTorch中的 nn.Linear 类,它是PyTorch中用于创建线性层的类。

让我更详细地解释这些成员变量的来源:

  1. self.hidden = nn.Linear(n_feature, n_hidden)

    • 这一行代码创建了一个名为 hidden 的成员变量,并将其初始化为一个 nn.Linear 对象。
    • nn.Linear 类表示一个线性层,通常用于神经网络的前向传播。这个线性层将具有 n_feature 个输入特征和 n_hidden 个神经元。
    • 在神经网络的前向传播过程中,输入数据将通过 self.hidden 这个线性层,并且在传递时会经过线性变换,然后传递给激活函数(在你的代码中是ReLU),最终产生隐藏层的输出。
  2. self.predict = nn.Linear(n_hidden, n_output)

    • 类似地,这一行代码创建了一个名为 predict 的成员变量,并将其初始化为另一个 nn.Linear 对象。
    • 这个 nn.Linear 对象表示输出层,它接受来自隐藏层的输出(n_hidden 个输入特征)并生成模型的最终输出,通常在回归任务中,输出层只有一个神经元。

这些 nn.Linear 层是PyTorch中提供的模块,它们封装了神经网络中的线性变换操作,可以自动进行权重初始化以及在模型的反向传播中计算梯度。这简化了神经网络的构建和训练过程,因为你只需要定义网络的结构,而不必手动管理权重和梯度。这些操作都由PyTorch的自动微分系统自动处理。

训练网络

# 训练网路
import torch
import torch.nn as nn
import torch.optim as optim
# 创建优化器和损失函数
optimizer=optim.SGD(net.parameters(),lr=0.2)
loss_func=nn.MSELoss()
for t in range(100):
    prediction=net(x)               # 喂给net训练数据x,输出预测值
    loss=loss_func(prediction,y)    # 计算两者的误差
    optimizer.zero_grad()           # 清空上一步的残余更新参数值
    loss.backward()                 # 误差反向传播,计算参数更新值
    optimizer.step()                # 将参数更新值施加到net的parameters上
    print(loss)

在这里插入图片描述

可视化训练过程


后面学了matplotlib再放

区分类型(分类)

要点

我们来看看神经网络是怎么进行事物的分类
在这里插入图片描述

建立数据集

import torch
import matplotlib.pyplot as plt

# 生成随机数据
n_data = torch.ones(100, 2)
print(n_data[:5])
x0 = torch.normal(2 * n_data, 1)
print(x0[:5])
y0 = torch.zeros(100, dtype=torch.long)
print(y0[:5])
x1 = torch.normal(-2 * n_data, 1)
print(x1[:5])
y1 = torch.ones(100, dtype=torch.long)
print(y1[:5])

# 合并数据
x = torch.cat((x0, x1), 0)
print(x[:5])
y = torch.cat((y0, y1))
print(y)
# 绘制散点图
plt.scatter(x[:, 0], x[:, 1], c=y, s=100, lw=0, cmap='RdYlGn')
plt.show()

在这里插入图片描述
在这里插入图片描述
在PyTorch中,数据类型(dtype)是一个非常重要的概念,它指定了张量中元素的数据类型。在代码中,y0 = torch.zeros(100, dtype=torch.long) 将创建一个包含100个零的张量,并将其数据类型设置为 torch.long

加入 dtype=torch.long 的原因是,通常在深度学习中,torch.long 数据类型被用来表示整数类型的标签或类别。在分类任务中,标签通常是整数,每个整数代表一个不同的类别。例如,如果你正在处理一个图像分类任务,每个图像的类别标签可以是从0到(类别总数-1)的整数,这些整数用来表示不同的类别。

设置数据类型为 torch.long 有两个主要作用:

  1. 确保整数类型的存储torch.long 数据类型确保了张量中的元素都是整数。这是因为默认情况下,PyTorch 创建的张量可能具有 torch.float32(32位浮点数)数据类型,但类别标签应该是整数,因此需要显式设置数据类型为 torch.long 以确保它们被解释为整数。

  2. 与损失函数兼容:许多损失函数(例如交叉熵损失)要求标签是整数类型,因此将标签的数据类型设置为 torch.long 可以确保它们与损失函数兼容,而不会引发数据类型不匹配的错误。

总之,dtype=torch.long 的设置是为了明确指定标签张量的数据类型为整数类型,以确保与深度学习任务中的标签和损失函数兼容。如果标签是整数,通常都应该使用这种设置。

torch.cat() 是PyTorch中的一个张量拼接函数,用于将多个张量沿指定的维度进行拼接(连接)操作。这个函数的目的是将多个张量合并成一个更大的张量。让我们详细解释一下 torch.cat() 函数的用法和参数:

torch.cat(tensors, dim=0, out=None) -> Tensor

参数说明:

  • tensors:一个包含要拼接的张量(可以是一个张量列表或元组)。
  • dim:指定拼接的维度。默认是0,表示在第一个维度上进行拼接,即按行拼接。
  • out:可选参数,用于指定输出张量,如果不提供将会创建一个新的张量来保存拼接后的结果。

示例:

import torch

# 创建两个张量
x = torch.tensor([[1, 2], [3, 4]])
y = torch.tensor([[5, 6]])

# 在第一个维度上拼接(按行拼接)
result = torch.cat((x, y), dim=0)
print(result)

在这个示例中,我们创建了两个张量 xy,然后使用 torch.cat() 函数将它们在第一个维度(按行)上进行拼接。结果是一个新的张量 result,其中包含了两个原始张量的内容:

tensor([[1, 2],
        [3, 4],
        [5, 6]])

torch.cat() 可以用于在任何维度上进行拼接操作,你可以根据需要选择合适的维度。这在深度学习中经常用于连接不同批次的数据、连接不同特征的数据等各种情况。

plt.scatter(x[:, 0], x[:, 1], c=y, s=100, lw=0, cmap='RdYlGn')

这行代码使用了Matplotlib库的 scatter 函数来创建一个散点图,以可视化数据点。让我们逐个参数来解释这行代码:

  1. x[:, 0]x[:, 1]:这部分代码使用索引操作从 x 中选择特定的列。假设 x 是一个二维张量,这里 x[:, 0] 表示选择所有行的第一个特征,而 x[:, 1] 表示选择所有行的第二个特征。这将分别用作散点图的 x 和 y 坐标。

  2. c=y:这是 c 参数,用于设置散点的颜色。通常,c 接受一个数组,表示每个数据点的颜色。在这里,y 可能是一个数组,其中包含与 x 对应的类别或标签。这将根据标签值决定每个数据点的颜色,以区分不同的数据类别。

  3. s=100:这是 s 参数,用于设置散点的大小。在这里,所有的散点都设置为相同的大小,大小为100。

  4. lw=0:这是 lw 参数,用于设置散点的边界线宽度(linewidth)。在这里,将边界线的宽度设置为0,表示没有边界线。

  5. cmap='RdYlGn':这是 cmap 参数,用于设置颜色映射。它指定了用于将不同的标签值映射到不同颜色的颜色映射表。在这里,使用了名为 ‘RdYlGn’ 的颜色映射,它代表了一种从红色到黄色再到绿色的颜色渐变。

综合起来,这行代码创建了一个散点图,其中每个数据点的 x 和 y 坐标由 x 的两个特征决定,颜色由 y 的值决定,散点的大小相同,没有边界线,并且使用 ‘RdYlGn’ 的颜色映射表来表示不同的标签值。这种可视化方式有助于可视化数据的分布和类别信息,特别是在二维空间中。

建立神经网络

# 建立神经网络
import torch
import torch.nn as nn
class Net(nn.Module):
    def __init__(self,n_feature,n_hidden,n_output):
        super(Net,self).__init__()
        self.hidden=nn.Linear(n_feature,n_hidden)
        self.out=nn.Linear(n_hidden,n_output)
    def forward(self,x):
        x=torch.relu(self.hidden(x))
        x=self.out(x)
        return x
net=Net(n_feature=2,n_hidden=10,n_output=2)
print(net)

在这里插入图片描述

训练网络

# 训练网络

import torch.optim as optim

# 创建优化器和损失函数
optimizer=optim.SGD(net.parameters(),lr=0.02)
loss_func=nn.CrossEntropyLoss()

for t in range(100):
    out=net(x)#喂给net训练数据x,输出分析值
    loss=loss_func(out,y)#计算两者的误差
    optimizer.zero_grad()#清空上一步的残余更新参数值
    loss.backward()#误差反向传播,计算参数更新值
    optimizer.step()#将参数更新值施加到net的parameters上
    print(loss)

在这里插入图片描述

可视化训练过程


后续再补充

快速搭建法

要点

Torch 中提供了很多方便的途径, 同样是神经网络, 能快则快, 我们看看如何用更简单的方式搭建同样的回归神经网络.

快速搭建

我们之前是这样子搭建神经网络

import torch
import torch.nn as nn
class Net(nn.Module):
    # 搭建我们的层数时要用到的信息
    def __init__(self,n_feature,n_hidden,n_output):
        super(Net,self).__init__()   #可以暂时理解为初始化,这块要弄清楚是有难度的
        self.hidden=nn.Linear(n_feature,n_hidden)#隐藏层,关心有多少个输入,有多少个神经元个数
        self.predict=nn.Linear(n_hidden,n_output)#输出层,关心有多少个输入(从隐藏层而来的神经元),有多少个输出
    # 神经网络前向传递的过程,真正开始搭建神经网络
    def forward(self,x):
        x=torch.relu(self.hidden(x))#我们的x过了一个hidden层,输出了n_hidden个神经元的个数
        x=self.predict(x) #输出层接受x并输出结果
        # 为什么我们的预测不用激励函数呢。因为在大多数的情况下回归问题的取值可以从负无穷到正无穷,
        #而用了激励函数,会把取值范围截断一部分
        return x
net=Net(n_feature=1,n_hidden=10,n_output=1)
print(net)

在这里插入图片描述
上面我们用 class 继承了一个 torch 中的神经网络结构, 然后对其进行了修改, 不过还有更快的方法

import torch.nn as nn
net=nn.Sequential(
    nn.Linear(1,10),
    nn.ReLU(),
    nn.Linear(10,1)
)
print(net)

在这里插入图片描述
两种方法都可以用于构建神经网络,每种方法有其优点和适用场景。让我解释一下它们的优缺点以及何时使用哪种方法:

1. 自定义类方法(第一个示例):

  • 优点:

    • 更灵活:你可以定义自己的前向传播逻辑,可以实现非常复杂的模型结构。
    • 易于理解和调试:因为你可以明确地看到每个层的定义和前向传播的计算过程,更容易理解和调试。
  • 缺点:

    • 代码量较多:相对来说,需要编写更多的代码来定义每个层和前向传播的逻辑。
    • 可读性较差:对于简单的模型,可能会感到冗长,不够紧凑。

2. Sequential 方法(第二个示例):

  • 优点:

    • 简洁:使用 nn.Sequential 可以更紧凑地定义模型结构,特别适合简单的线性模型。
    • 减少代码量:避免了手动定义每个层的繁琐过程。
  • 缺点:

    • 有限灵活性:nn.Sequential 适用于线性堆叠的模型结构,对于复杂的模型结构和非线性连接不够灵活。
    • 难以定制:如果需要在不同层之间添加自定义操作或者非线性激活函数,使用 nn.Sequential 可能会不方便。

何时使用哪种方法取决于你的需求:

  • 自定义类方法 更适合需要灵活性的情况,例如:

    • 当你需要定义复杂的非线性模型结构时。
    • 当你想要添加自定义操作或层之间的复杂连接时。
    • 当你需要更详细的控制权和可调试性。
  • Sequential 方法 更适合简单的线性模型或者需要紧凑表示的情况,例如:

    • 当你构建简单的线性堆叠模型时(例如,多层感知器)。
    • 当你只需要一系列简单的层按顺序连接,不需要复杂的结构。

通常,如果你的模型足够简单,可以使用 nn.Sequential 来简化代码。但如果你需要更高级的功能、更复杂的模型结构或者更多的控制权,那么自定义类方法会更有优势。在实践中,你可能会在不同的情况下使用这两种方法,根据任务的复杂性和要求来选择合适的方式。

保存提取

要点

训练好了一个模型, 我们当然想要保存它, 留到下次要用的时候直接提取直接用, 这就是这节的内容啦. 我们用回归的神经网络举例实现保存提取.

保存

我们先快速建造数据,搭建网络

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

# 设置随机种子以确保可重复性
torch.manual_seed(1)

#生成假数据
x=torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
y=x.pow(2)+0.2*torch.rand(x.size())

def save():
    # 建立网络
    net1=nn.Sequential(
        nn.Linear(1,10),
        nn.ReLU(),
        nn.Linear(10,1)
    )

    # 定义优化器和损失函数
    optimizer=optim.SGD(net1.parameters(),lr=0.5)
    loss_func=nn.MSELoss()

    # 训练
    for t in range(100):
        prediction=net1(x)
        loss=loss_func(prediction,y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    

代码解释:

  1. x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1)

    • torch.linspace(-1, 1, 100) 创建了一个包含100个均匀分布在-1到1之间的数值的张量。这些值将作为输入特征 x
    • torch.unsqueeze() 函数将这个一维张量转换为一个二维张量。具体来说,dim=1 参数表示在第1维上添加一个维度,从而将原始的一维张量转换为形状为 (100, 1) 的二维张量,这样可以作为神经网络的输入。
  2. y = x.pow(2) + 0.2 * torch.rand(x.size())

    • x.pow(2) 对输入特征 x 中的每个元素进行平方操作,从而得到一个张量,其中包含了100个元素,每个元素都是输入特征的平方。
    • torch.rand(x.size()) 创建一个与 x 相同大小的随机张量,其中的值是在0到1之间均匀分布的随机数。这个随机张量表示添加到目标 y 中的噪声。
    • 最后,通过将 x.pow(2) 和随机噪声相加,得到最终的目标张量 y。这个操作在原始函数 x^2 的基础上引入了一些随机变化,模拟了真实世界中的数据噪声。

总之,这段代码用于生成一个带有噪声的数据集,其中 x 是输入特征,表示在-1到1之间均匀分布的值,y 是与 x 之间的二次函数关系,并添加了一些随机噪声,以模拟实际数据集。这种数据集常用于回归任务的训练和测试。

接下来我们有两种途径来保存(下面的代码是写在save()里的)

# 保存整个网络:
torch.save(net1,'net1.pkl')
# 仅保存网络中的参数(推荐的方式,因为速度更快且占用内存更少):
torch.save(net1.state_dict(),'net1_params.pkl')

在这里插入图片描述

提取网络

# 读取模型
def restore_net():
    net2=torch.load('net1.pkl')
    print(net2)

只提取网络参数

def restore_params():
    # 新建net3,确保与之前的模型架构一致
    net3=torch.nn.Sequential(
        torch.nn.Linear(1,10),
        torch.nn.ReLU(),
        torch.nn.Linear(10,1)
    )
    # 将保存的参数复制到net3
    net3.load_state_dict(torch.load('net1_params.pkl'))
    print(net3)

显示结果

# 保存 net1 (1. 整个网络, 2. 只有参数)
save()

# 提取整个网络
restore_net()

# 提取网络参数, 复制到新网络
restore_params()

在这里插入图片描述

批训练

要点

Torch 中提供了一种帮你整理你的数据结构的东西,,叫做 DataLoader, 我们能用它来包装自己的数据,进行批训练。

DataLoader

DataLoader 是 torch 给你用来包装你的数据的工具. 所以你要讲自己的 (numpy array 或其他) 数据形式装换成 Tensor, 然后再放进这个包装器中. 使用 DataLoader 有什么好处呢? 就是他们帮你有效地迭代数据,


加速神经网络训练

优化器

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

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

相关文章

【循环冗余码检错示例】

接收方怎么看有错没有 余数为0就是无错!

竞赛选题 基于机器视觉的行人口罩佩戴检测

简介 2020新冠爆发以来,疫情牵动着全国人民的心,一线医护工作者在最前线抗击疫情的同时,我们也可以看到很多科技行业和人工智能领域的从业者,也在贡献着他们的力量。近些天来,旷视、商汤、海康、百度都多家科技公司研…

C++下标运算符详解

C++ 规定,下标运算符[ ]必须以成员函数的形式进行重载。该重载函数在类中的声明格式如下: 返回值类型 & operator[ ] (参数); const 返回值类型 & operator[ ] (参数) const; 使用第一种声明方式,[ ]不仅可以访问元素,还可以修改元素。使用第二种声明方式,[ ]只…

点灯科技实现 “ESP8266-01/01s + 继电器” 远程开关

教程视频 ESP-01S继电器插座怎么使用? 所需硬件 继电器 ESP-01S继电器插座 WIFI模块 esp8266-01s wifi模块 烧录器 软件准备 Arduino IDE需安装好esp8266扩展 点击下载 下载并安装blinker APP Android下载: 点击下载 或 在android应用商店…

构建健壮的Spring MVC应用:JSON响应与异常处理

目录 1. 引言 2. JSON 1. 轻量级和可读性 2. 易于编写和解析 3. 自描述性 4. 支持多种数据类型 5. 平台无关性 6. 易于集成 7. 社区支持和标准化 3. 高效处理异常 综合案例 异常处理方式一 异常处理方式二 异常处理方式三 1. 引言 探讨Spring MVC中关键的JSON数据…

day18-API(常见API,对象克隆)

课程目标 能够熟练使用Math类中的常见方法 能够熟练使用System类中的常见方法 能够理解Object类的常见方法作用 能够熟练使用Objects类的常见方法 能够熟练使用BigInteger类的常见方法 能够熟练使用BigDecimal类的常见方法 1 Math类 1.1 概述 tips:了解内容…

nbcio-boot移植到若依ruoyi-nbcio平台里一formdesigner部分(三)

因为这个版本的若依plus不支持本地文件上传&#xff0c;所以需要增加这些本地上传文件的后端代码 和前端代码修改。 1、后端部分 先配置跳过测试吧&#xff0c;平时编译也不需要这个 <!--添加配置跳过测试--><plugin><groupId>org.apache.maven.plugins<…

LVS负载均衡群集——LVS-NAT模式搭建和LVS-DR模式搭建

目录 lvs工作模式 1、NAT模式&#xff08;VS-NAT&#xff09; 2、直接路由模式&#xff08;VS-DR&#xff09; 3、IP隧道模式&#xff08;VS-TUN&#xff09; LVS调度算法 LVS群集类型 1&#xff09;负载均衡群集 LB 2&#xff09;高可用群集 HA 3&#xff09;高性能运…

分享篇:Canvas绘制简单图像

目录 Canvas绘制简单图形需要用到的基本知识&#xff1a; 1.moveTo() 2. lineTo() 3.stroke() 4.strokeStyle/lineWidth 5.beginPath() 6.closePath() 7.arc&#xff08;&#xff09; 8.createLinearGradient&#xff08;&#xff09; 9.createRadialGradient&#xf…

el-table 翻页记住上页选项,包含回显选中的数据

需求为翻页记住上页选项,包含回显选中的数据,然后还能进行新增和取消勾选 首先element管网有提供及住翻页功能 所以可以根据官网提供的方法来改造 一定要做的操作就是清空一下选中的数据,否则不生效,this.$refs.selectTable.clearSelection(); 然后就是处理选中的数据,和原…

Qt Quick Layouts Overview

Qt快速布局概述 #【中秋征文】程序人生&#xff0c;中秋共享# Qt快速布局是用于在用户界面中排列项目的项目。由于Qt快速布局还可以调整其项目的大小&#xff0c;因此它们非常适合可调整大小的用户界面。 开始 可以使用文件中的以下导入语句将 QML 类型导入到应用程序中。.qml…

机器视觉康耐视visionpro-脚本常见的编辑编译错误和运行错误及警告性错误,调试解决办法

3.康耐视VisionPro高级脚本系列教程-3.脚本编辑错误和运行错误调试方法,break和Continue的差别_哔哩哔哩_bilibili 目录 第一:康耐视visionpro脚本-编辑编译错误第二:康耐视visionpro脚本-运行错误第三:康耐视visionpro脚本-警告性错误第一:康耐视visionpro脚本-编辑编译…

三分钟图解事务隔离级别

详细见&#xff1a; 三分钟图解事务隔离级别&#xff0c;看一遍就懂数据库中事务指的是什么 “锁" 是数据库系统区别于文件系统的一个关键特性&#xff0c;其对象是事务&#xff0c;用来锁定的是数据库中的对象&#xff0c;如表、页、行等。锁确实提高了并发性&#xff…

C++之修改结构体成员字节对齐(二百一十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

深度优先搜索和广度优先搜索(C++、MATLAB代码迷宫应用)

深度优先搜索算法与广度优先搜索算法及其C、MATLAB代码迷宫应用 1. 深度优先搜索算法&#xff08;DFS&#xff09;1.1 深度优先搜索伪代码&#xff1a;1.2 案例应用&#xff1a;迷宫最小步数1.2.1 DFS算法MATLAB代码1.2.1 DFS算法C代码 2. 广度优先搜索算法&#xff08;BFS&am…

Redis主从复制(Redis6.2.5版本)

1、Redis单击服务问题&#xff1f; Redis的单机服务在实际的应用中会有很多的问题&#xff0c;所以在实际的使用中如果使用了redis服务&#xff0c;往往都不是单机服务&#xff0c;都会配置主从复制或者哨兵机制及redis的集群服务等。 Redis的单机服务&#xff0c;当主机发生机…

nbcio-boot移植到若依ruoyi-nbcio平台里一formdesigner部分(四)

到目前为止&#xff0c;虽然基础的formdesigner部分已经完成&#xff0c;但流程用formdesigner提交与审批过程中的显示还有问题。 1、后端部分 其中FormConf修改如下&#xff1a; package com.ruoyi.flowable.core;import lombok.Data;import java.util.List; import java.uti…

慢查询SQL如何优化

一.什么是慢SQL? 慢SQL指的是Mysql中执行比较慢的SQL,排查慢SQL最常用的方法是通过慢查询日志来查找慢SQL。Mysql的慢查询日志是Mysql提供的一种日志记录&#xff0c;它用来记录Mysql中响应时间超过long_query_time值的sql,long_query_time的默认时间为10s. 二.查看慢SQL是否…

华为云云耀云服务器L实例评测|基于云耀云服务器在Docker上部署nginx服务

文章目录 1、服务介绍云耀云服务器Docker介绍Docker-Compse介绍 2、在云耀云服务器安装Docker3、通过Docker run命令运行nginx服务4、在云耀云服务器安装docker-compose5、通过docker-compose方式启动nginx服务 1、服务介绍 云耀云服务器 云耀云服务器&#xff08;Hyper Elas…

ArcGIS 10.3安装教程!

软件介绍&#xff1a;ArcGIS是一款专业的电子地图信息编辑和开发软件&#xff0c;提供一种快速并且使用简单的方式浏览地理信息&#xff0c;无论是2D还是3D的信息。软件内置多种编辑工具&#xff0c;可以轻松的完成地图生产全过程&#xff0c;为地图分析和处理提供了新的解决方…