神经网络-pytorch版本

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 pltx=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))# 将保存的参数复制到net3net3.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.rhkb.cn/news/132800.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

竞赛 基于机器视觉的火车票识别系统

文章目录 0 前言1 课题意义课题难点: 2 实现方法2.1 图像预处理2.2 字符分割2.3 字符识别部分实现代码 3 实现效果最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 基于机器视觉的火车票识别系统 该项目较为新颖,适合作为竞赛…

【Linux学习笔记】 - 常用指令学习及其验证(上)

前言:本文主要记录对Linux常用指令的使用验证。环境为阿里云服务器CentOS 7.9。关于环境如何搭建等问题,大家可到同平台等各大资源网进行搜索学习,本文不再赘述。 由于本人对Linux学习程度尚且较浅,本文仅介绍验证常用指令的常用…

27、Flink 的SQL之SELECT (SQL Hints 和 Joins)介绍及详细示例(2-1)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

7-15 求矩阵的局部极大值

输入格式: 输入在第一行中给出矩阵A的行数M和列数N(3≤M,N≤20);最后M行,每行给出A在该行的N个元素的值。数字间以空格分隔。 输出格式: 每行按照“元素值 行号 列号”的格式输出一个局部极大值&#xff0…

事件监听-@TransactionalEventListener与@EventListener的介绍、区别和使用

文章目录 前言事件监听-TransactionalEventListener与EventListener的介绍、区别和使用1. EventListener 是什么?2. TransactionalEventListener 是什么?3. TransactionalEventListener与EventListener的缺点3.1. TransactionalEventListener 的缺点:3.2. EventLi…

2.9 PE结构:重建导入表结构

脱壳修复是指在进行加壳保护后的二进制程序脱壳操作后,由于加壳操作的不同,有些程序的导入表可能会受到影响,导致脱壳后程序无法正常运行。因此,需要进行修复操作,将脱壳前的导入表覆盖到脱壳后的程序中,以…

openGauss学习笔记-69 openGauss 数据库管理-创建和管理普通表-更新表中数据

文章目录 openGauss学习笔记-69 openGauss 数据库管理-创建和管理普通表-更新表中数据 openGauss学习笔记-69 openGauss 数据库管理-创建和管理普通表-更新表中数据 修改已经存储在数据库中数据的行为叫做更新。用户可以更新单独一行、所有行或者指定的部分行。还可以独立更新…

【linux基础(六)】Linux中的开发工具(中)--gcc/g++

💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:Linux从入门到开通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学更多操作系统知识   🔝🔝 Linux中的开发工具 1. 前言2.…

为什么建议将常量用const关键字来修饰

嵌入式软件中,内存资源是非常宝贵的,即sram资源。因此我们在编码过程中需要规划好并且使用好sram资源,这点非常重要! 在此之前需要预备一点基础知识,在IAR中,一般会用ICF配置文件给工程配置存储区域&#…

MongoDB差异数据对比的快速指南

MongoDB是一种非关系型数据库,它以灵活的 JSON-like 文档的形式存储数据,这种特性使其在处理大量数据和实现快速开发时更具有优势。而由于其灵活的数据模型和强大的性能,MongoDB 被广泛应用在各种业务场景中。随着业务的发展和数据的增长&…

vue中v-for循环数组使用方法中splice删除数组元素(错误:每次都删掉点击的下面的一项)

总结:平常使用v-for的key都是使用index,这里vue官方文档也不推荐,这个时候就出问题了,我们需要key为唯一标识,这里我使用了时间戳(new Date().getTime())处理比较复杂的情况, 本文章…

解决虚拟机重启后ifconfig看不到IP的问题

目录 背景 解决方案 背景 虚拟机,桥接模式,启动后一切正常,但重启后发现终端连不上虚机了,也ping不到,最后检查发现,IP消失了,虚机没有IP了。 解决方案 不论是否重启,只要是看不…

【css | loading】各种简单的loading特效

先看一下简单的效果图 线上预览 https://code.juejin.cn/pen/7278511766991339579 代码 HTML <!-- / 1 --><section><div class"sk-rotating-plane"></div></section><!-- / 2 --><section><div class"sk-doub…

【CSS3】

文章目录 1.简介2.边框3.圆角4.背景5.渐变CSS3 径向渐变6.文本效果7.字体8.2D转换9.3D转换10.过渡11.动画12.多列13.用户界面14.按钮 ​ 1.简介 模块 CSS3 被拆分为"模块"。旧规范已拆分成小块&#xff0c;还增加了新的。 一些最重要 CSS3 模块如下&#xff1a; 选…

内网隧道代理技术(二十六)之 搭建ICMP隧道上线CS

搭建ICMP隧道上线CS ICMP隧道原理 ICMP隧道简单实用,是一个比较特殊的协议。在一般的通信协议里,如果两台设备要进行通信,肯定需要开放端口,而在ICMP协议下就不需要。最常见的ping命令就是利用的ICMP协议,攻击者可以利用命令行得到比回复更多的ICMP请求。在通常情况下,…

input 的 placeholder 样式

::placeholder 伪元素 这个伪元素可以改变 input、textarea 占位文本的样式。 input::placeholder {color: green; }完整的兼容性写法&#xff1a; input {&::-webkit-input-placeholder, /* WebKit browsers*/ &:-moz-input-placeholder, /* Mozilla Firefox 4 to …

67、数据源配置 及 配置多个数据源--C3P0 数据源 和 Hikari 数据源

★ Spring Boot如何选择DataSource数据源 优先级从高到低&#xff1a; HikariCP > Tomcat pooling DataSource > Commons DBCP2 如果要使用Tomcat pooling DataSource这种池化数据源&#xff0c; 那么可以用</exclusions>这个把HikariCP 排除掉&#xff0c;然后sp…

16. Docker容器监控CAdvisor+InfluxDB+Granfana

目录 1、前言 2、原始命令 3、CAdvisorInfluxDBGranfana 3.1、什么是CAdvisor 3.2、什么是Influxdb 3.3、什么是Granfana 4、安装使用 4.1、安装influxdb 4.2、安装CAdvisor 4.3、安装Granfana 4.4、访问Influxdb 4.5、创建CAdvisor数据库 4.6、访问CAdvisor 4.7…

评价模型:层次分析法

1. 模型建立 1.1 建立层次结构模型 在深入分析实际问题的基础上&#xff0c;将有关的各个因素按照不同属性自上而下地分解成若干层次&#xff0c;同一层的诸因素从属于上一层的因素或对上层因素有影响&#xff0c;同时又支配下一层的因素或受到下层因素的作用。最上层为目标层…

python集合

集合set set_python1.集合的创建2.集合的相关操作3.集合间的关系4.集合的数学操作5.集合生成式 set_python 集合(set)是一个可变的数据类型&#xff0c;它用于存储一组唯一的元素。集合中的元素是无序的&#xff0c;并且不能重复。可以使用大括号{}或者set()函数来创建一个集合…