PyTorch深度学习——张量及其运算

深度学习框架的张量

张量的运算是深度学习的核心,如一张图片可以看作是四维的张量,一个迷你批次的文本可以看作是二维张量,基本上所有的深度学习模型都可以表示为张量的操作,梯度、反向传播算法也可以表示为张量和张量的运算

张量在内存中的排列方式是连续的,而且是从最后一个维度开始排列

张量的性质

  1. 在深度学习中,张量应该能够支持得到每一个维度的长度,也就是保存张量的形状
  2. 张量需要支持和其他相同类型的张量的加减乘除运算
  3. 张量还应该支持变形,也就是说,张量可以变换为总元素的数目相同,但是维度不同的另一个张量——可以将一个张量的某个维度分割为两个维度,或者将最后几个维度合并为一个维度。由于变形之前的两个张量的分量在内存中的排列形状一定是相同的,所以,这两个张量一般会在内存的底层哦女相同一个内存区域
  4. 张量应当支持线性变换(如在卷积层和全连接层中进行的运算)和对每个元素的激活函数进行操作,实现线性变换和激活函数的操作是为了能够方便地进行神经网络的前向运算

Pytorch的张量一共支持9种数据类型,每种数据类型都对应CPU和GPU的两种子类型——如果要获取一个张量的具体类型,可以直接访问张量的dtype属性,如果想要进一步获取张量的存储位置和数据类型,可以通过调用张量的type方法来同时获取存储位置和数据类型的值

现阶段Pytorch并不支持负数类型,如果有要用到的场合,需要使用张量的两个分量来分别模拟负数的实部和虚部,不同的类型之间,可以通过调用to方法进行转换,该方法传入的参数是转换目标类型

张量的创建方式

在Pytorch中创建张量的方式主要有四种方式:

torch.Tensor()、torch.tensor()、torch.as_tensor()、torch.from_numpy()

Pytorch创建张量的四种函数方法及其区别_python_脚本之家

pytorch中8种特殊张量创建方法_pytorch创建-CSDN博客

PyTorch : 了解Tensor(张量)依据数值和概率的创建方法 - 知乎

张量的存储设备

pytorch的张量可以在两种设备上创建:CPU和GPU

通过访问张量的device属性可以获取张量所在的设备,在没有指定设备的时候,pytorch会默认存储张量到CPU上面,如果要想转移到GPU上面,则需要指定张量转移到GPU设备:首先可以使用cpu方法把张量转移到CPU上,其次可以使用cuda方法把张量转移到GPU上,其中需要传入具体的GPU的设备编号;也可以使用to方法把张量从一个设备转移到另一个设备上面,该方法的参数是目标设备的名称(可以使字符串名称,也可以是torch.device实例)

PyTorch 将 PyTorch 代码从 CPU 移植到 GPU|极客笔记

需要注意的是——两个或多个张量之间的运算只有在相同的设备上才能运行(都在CPU或GPU上面),否则就会报错

和张量维度相关的方法

在深度学习中常会用到一些方法获取张量的维度数目,以及某一维度的具体大小,或者对张量的某些维度进行操作

tensor / numpy维度变换操作总结_np维度调换-CSDN博客

张量的运算

涉及单个张量的函数运算

深度学习中,常会用到对张量作四则运算、线性变换和激活等,这些方法可以由张量自带的方法实现,也可以由torch包中的一些函数实现

1、张量的四则运算

import torch  
  
# 创建两个张量  
tensor1 = torch.tensor([1.0, 2.0, 3.0])  
tensor2 = torch.tensor([4.0, 5.0, 6.0])  
  
# 加法  
addition = tensor1 + tensor2  
print("加法:", addition)  
  
# 减法  
subtraction = tensor1 - tensor2  
print("减法:", subtraction)  
  
# 乘法  
multiplication = tensor1 * tensor2  
print("乘法:", multiplication)  
  
# 除法  
division = tensor1 / tensor2  
print("除法:", division)

2、线性变换

线性变换通常通过矩阵乘法实现。在PyTorch中,可以使用mm(针对二维张量)或matmul(针对任意维度的张量)进行矩阵乘法

# 创建一个二维张量(矩阵)  
matrix = torch.tensor([[1.0, 2.0], [3.0, 4.0]])  
  
# 创建一个向量  
vector = torch.tensor([5.0, 6.0])  
  
# 矩阵乘法  
linear_transformation = torch.matmul(matrix, vector.view(-1, 1))  
print("线性变换:", linear_transformation)

3、激活函数

激活函数是神经网络中非常重要的组成部分,它们为模型引入了非线性。PyTorch提供了许多内置的激活函数

# 创建一个张量  
input_tensor = torch.tensor([-2.0, 0.0, 2.0])  
  
# 使用ReLU激活函数  
relu_output = torch.relu(input_tensor)  
print("ReLU激活:", relu_output)  
  
# 使用Sigmoid激活函数  
sigmoid_output = torch.sigmoid(input_tensor)  
print("Sigmoid激活:", sigmoid_output)

在实际的深度学习模型中,这些操作会组合在一起,形成复杂的神经网络结构

涉及多个张量的函数方法

在深度学习中,经常需要对两个形状相同的张量进行逐个元素的四则运算。这些操作都是逐元素的,意味着张量中对应位置的元素会分别进行加法、减法、乘法或除法运算。在PyTorch中,这些操作可以通过简单的运算符重载实现

import torch  
  
# 创建两个形状相同的张量  
tensor1 = torch.tensor([[1.0, 2.0], [3.0, 4.0]])  
tensor2 = torch.tensor([[5.0, 6.0], [7.0, 8.0]])  
  
# 逐个元素的加法  
addition = tensor1 + tensor2  
print("加法:", addition)  
  
# 逐个元素的减法  
subtraction = tensor1 - tensor2  
print("减法:", subtraction)  
  
# 逐个元素的乘法  
multiplication = tensor1 * tensor2  
print("乘法:", multiplication)  
  
# 逐个元素的除法  
# 注意:除法运算需要确保分母不为0,否则会导致错误或无穷大的结果  
division = tensor1 / tensor2  
print("除法:", division)  
  
# 对于除法,如果担心分母为0,可以使用clamp函数确保分母不会太小  
tensor2_clamped = tensor2.clamp(min=1e-6)  # 设置一个小的正数作为分母的最小值  
safe_division = tensor1 / tensor2_clamped  
print("安全的除法:", safe_division)

还可以通过add、sub、mul、div方法来实现,同样也可以通过内置方法的原地操作版本实现

import torch  
  
# 创建两个形状相同的张量  
tensor1 = torch.tensor([[1.0, 2.0], [3.0, 4.0]])  
tensor2 = torch.tensor([[5.0, 6.0], [7.0, 8.0]])  
  
# 使用add方法实现加法  
addition = tensor1.add(tensor2)  
print("加法:", addition)  
  
# 使用sub方法实现减法  
subtraction = tensor1.sub(tensor2)  
print("减法:", subtraction)  
  
# 使用mul方法实现乘法  
multiplication = tensor1.mul(tensor2)  
print("乘法:", multiplication)  
  
# 使用div方法实现除法  
# 注意:同样需要确保分母不为0  
division = tensor1.div(tensor2)  
print("除法:", division)  
  
# 原地操作版本,直接在原张量上修改  
# 注意:原地操作不会返回新的张量,而是修改原张量  
result = tensor1.clone()  # 复制tensor1以便进行原地操作  
result.add_(tensor2)     # 原地加法  
print("原地加法结果:", result)  
  
result = tensor1.clone()  # 再次复制tensor1  
result.sub_(tensor2)     # 原地减法  
print("原地减法结果:", result)  
  
result = tensor1.clone()  
result.mul_(tensor2)     # 原地乘法  
print("原地乘法结果:", result)  
  
result = tensor1.clone()  
result.div_(tensor2)     # 原地除法  
print("原地除法结果:", result)
张量的极值和排序

深度学习中,我们常需要获取张量的最大值和最小值,以及这些值所在的位置,如果只需要最大值和最小值,可以使用argmax和argmin,通过传入具体要沿着那个维度求最大值和最小值的位置,返回沿着该维度最大和最小值对应的序号是多少,如果既要求获取最大值和最小值,又要求获得具体的值,就需要使用max和min,通过传入具体的维度,同时返回沿着该维度最大和最小值的位置,以及对应的最大值和最小值组成的元组

最后一个和大小有关的函数是排序函数sort(默认是从小到大,如果需要从大到小排序,则需要设置参数 descending=True),同样是传入具体需要进行排序的维度,返回的是排序完的张量,记忆对应排序后的元素在原始张量上的位置,如果要知道原始张量还是那的元素沿着某个维度排第几位,只需要对应排序后的元素在原始张量上的位置进行再次排序,得到新位置的值即为原始张量沿着搞方向进行大小排序后的序号,和前面一样,关于排序和极值的函数,既可以是Pytorch的函数,也可以是张量的内置方法,两种方法的调用方法等价

import torch  
  
# 创建一个张量  
tensor = torch.tensor([[4.0, 2.0, 9.0], [6.0, 5.0, 3.0], [8.0, 1.0, 7.0]])  
  
# 使用argmax获取最大值的位置  
max_indices = tensor.argmax(dim=1)  # 沿着维度1(列)查找最大值的位置  
print("最大值的位置:", max_indices)  
  
# 使用argmin获取最小值的位置  
min_indices = tensor.argmin(dim=1)  # 沿着维度1(列)查找最小值的位置  
print("最小值的位置:", min_indices)  
  
# 使用max获取最大值及其位置  
max_values, max_positions = tensor.max(dim=1)  # 沿着维度1(列)查找最大值及其位置  
print("最大值和它们的位置:", max_values, max_positions)  
  
# 使用min获取最小值及其位置  
min_values, min_positions = tensor.min(dim=1)  # 沿着维度1(列)查找最小值及其位置  
print("最小值和它们的位置:", min_values, min_positions)  
  
# 使用sort对张量进行排序  
sorted_tensor, sorted_indices = tensor.sort(dim=1, descending=False)  # 从小到大排序,并获取原始位置的索引  
print("排序后的张量:", sorted_tensor)  
print("排序后的元素在原始张量上的位置:", sorted_indices)  
  
# 如果要知道原始张量中的元素沿着某个维度排第几位,需要对排序后的索引进行排序  
original_indices = torch.arange(sorted_indices.size(0)).to(sorted_indices.device)  # 创建原始索引  
sorted_original_indices = sorted_indices.argsort(dim=1)  # 对排序后的索引进行排序  
print("原始张量元素排序后的序号:", sorted_original_indices)
矩阵的乘法和张量的缩并

除上述的运算之外,由两个张量作为参数的操作还有矩阵乘法(线性变换),可以使用torch.mm函数或者张量内置的mm方法进行矩阵乘法,还可以使用@运算符实现

需要注意的是,如果你的张量不是二维的(例如,它们包含额外的维度,如批次维度),你可能需要使用torch.matmul函数或matmul方法,或者使用@运算符(在PyTorch中,@运算符在内部实际上是调用torch.matmul)。torch.matmul可以处理任意维度的张量,只要它们的维度是兼容的以进行矩阵乘法

import torch  
  
# 创建两个二维张量(矩阵)  
matrix1 = torch.tensor([[1.0, 2.0], [3.0, 4.0]])  
matrix2 = torch.tensor([[5.0, 6.0], [7.0, 8.0]])  
  
# 使用torch.mm函数进行矩阵乘法  
result_mm = torch.mm(matrix1, matrix2)  
print("使用torch.mm的结果:", result_mm)  
  
# 使用张量内置的mm方法进行矩阵乘法  
result_method = matrix1.mm(matrix2)  
print("使用张量mm方法的结果:", result_method)  
  
# 使用@运算符进行矩阵乘法  
result_at = matrix1 @ matrix2  
print("使用@运算符的结果:", result_at)

另一个特殊的矩阵乘法的函数是bmm函数,在深度学习中,实际经常用到的数据是迷你批次的数据,一般来说,第一个维度是迷你批次的大小,因此,数据的矩阵实际上是一个迷你批次的矩阵,即一个三维的张量(可以看作是一个迷你批次数量和矩阵叠加在一起)

此时如果两个张量做矩阵乘法,一般情况下是沿着迷你批次的方向分别对每个矩阵对做乘法,最后把结果整合在一起,如果是一个 b×m×k 的张量和 b×k×n 的张量相乘,那么结果应该是 b×m×n 的张量,torch.einsum 函数的使用如下

torch.einsum 是一个极其强大的函数,它用于在 PyTorch 中执行爱因斯坦求和约定(Einstein summation convention)。爱因斯坦求和约定提供了一种紧凑的方式来表示多维数组(如张量)之间的复杂操作,包括但不限于点积、外积、转置、矩阵乘法、批量矩阵乘法等。

torch.einsum 的基本语法是:

torch.einsum(equation, *operands)

其中 equation 是一个描述操作的字符串,而 *operands 是参与操作的张量列表。

Einstein Summation Convention 的基本思想

爱因斯坦求和约定使用特定的标记来表示张量的维度,并通过省略号来指定对这些维度进行求和。

  • 字母(如 i, j, k, ...)表示张量的维度。
  • 每个字母在每个张量中最多出现两次:一次在输入位置,一次在输出位置。
  • 如果一个字母在输出位置没有出现,则意味着对该维度进行求和。
  • 省略号 ... 用于表示多个维度。

示例

1. 向量点积

import torch 

a = torch.tensor([1.0, 2.0, 3.0]) 
b = torch.tensor([4.0, 5.0, 6.0]) 

result = torch.einsum('i,i->', a, b) # 点积:1*4 + 2*5 + 3*6 
print(result) # 输出:32.0

2. 矩阵乘法

A = torch.tensor([[1.0, 2.0], [3.0, 4.0]]) 
B = torch.tensor([[5.0, 6.0], [7.0, 8.0]]) 

result = torch.einsum('ij,jk->ik', A, B) # 矩阵乘法 
print(result)

3. 批量矩阵乘法

A = torch.randn(3, 2, 5) # 3个2x5矩阵 
B = torch.randn(3, 5, 4) # 3个5x4矩阵 

result = torch.einsum('bij,bjk->bik', A, B) # 批量矩阵乘法,输出为3个2x4矩阵 
print(result.shape) # 输出:torch.Size([3, 2, 4])

4. 转置

M = torch.randn(2, 3) 

# 转置矩阵,从 'ij' 变为 'ji' 
transposed = torch.einsum('ij->ji', M) 
print(transposed)

5. 外积

a = torch.tensor([1.0, 2.0]) 
b = torch.tensor([3.0, 4.0]) 

# 外积,输出是一个2x2的矩阵 
outer_product = torch.einsum('i,j->ij', a, b) 
print(outer_product)

torch.einsum 的强大之处在于它可以以非常简洁的方式表达复杂的张量操作,而不需要编写冗长的循环或显式的维度操作代码。这使得它在处理高维数据和复杂的神经网络结构时特别有用

张量的拼接和分割

在PyTorch中,你可以使用torch.cat来拼接张量,使用torch.chunk、torch.split或torch.narrow等函数来分割张量。下面是一些代码示例:

张量的拼接

假设我们有两个形状相同的张量,我们想要将它们沿某个维度拼接起来

import torch 


# 创建两个形状相同的张量 
tensor1 = torch.tensor([[1, 2], [3, 4]]) 
tensor2 = torch.tensor([[5, 6], [7, 8]]) 


# 沿着第一个维度(行)拼接 
concatenated_row = torch.cat((tensor1, tensor2), dim=0) 
print("沿着行拼接:") 
print(concatenated_row) 


# 沿着第二个维度(列)拼接 
concatenated_col = torch.cat((tensor1, tensor2), dim=1) 
print("沿着列拼接:") 
print(concatenated_col)

张量的分割

分割张量通常涉及到将一个大张量分成若干个小张量。

使用torch.chunk分割张量

torch.chunk函数将张量分割成指定数量的块

# 创建一个张量 
tensor = torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) 


# 沿着第一个维度(行)分割成2块 
chunks_row = torch.chunk(tensor, chunks=2, dim=0) 
for chunk in chunks_row: 
print(chunk) 


# 沿着第二个维度(列)分割成2块 
chunks_col = torch.chunk(tensor, chunks=2, dim=1) 
for chunk in chunks_col: 
print(chunk)

使用torch.split分割张量

torch.split函数允许你按照更灵活的规则分割张量,可以指定每个块的大小

# 创建一个张量 
tensor = torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) 


# 沿着第二个维度(列)分割,指定每个块的大小 
split_col = torch.split(tensor, split_size_or_sections=[2, 1, 1], dim=1) 
for part in split_col: 
print(part)

使用torch.narrow选择张量的狭窄切片

torch.narrow不是用来分割张量的,但它可以用来选择张量沿着某一维度的一个狭窄切片

# 创建一个张量 
tensor = torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) 


# 选择第二行 
narrow_tensor = tensor.narrow(0, 1, 1) 
print(narrow_tensor) 


# 选择第一列到第三列 
narrow_tensor_col = tensor.narrow(1, 0, 3) 
print(narrow_tensor_col)

注意:上述代码中torch.cat函数的括号使用有误,正确的应该是去掉内层的括号。修正后的代码应该如下所示:

# 沿着第一个维度(行)拼接 
concatenated_row = torch.cat((tensor1, tensor2), dim=0) # 错误用法 
concatenated_row = torch.cat((tensor1, tensor2), dim=0) # 正确用法,但内层括号是多余的 
concatenated_row = torch.cat([tensor1, tensor2], dim=0) # 更常见的正确用法 


# 沿着第二个维度(列)拼接 
concatenated_col = torch.cat((tensor1, tensor2), dim=1) # 错误用法 
concatenated_col = torch.cat([tensor1, tensor2], dim=1) # 正确用法

在实际使用中,通常更推荐使用列表[]来传递要拼接的张量,而不是元组(),尽管在某些情况下元组也是可行的

张量维度的扩增和压缩

在PyTorch中,张量维度的扩增(也称为扩展或广播)和压缩是常见的操作。这通常通过torch.unsqueeze和torch.squeeze函数实现。此外,torch.shape、torch.view和torch.flatten等函数也常用于改变张量的形状

张量维度的扩增(Unsqueeze)

torch.unsqueeze函数用于在张量的指定位置增加一个新的维度,大小为1

import torch 


# 创建一个形状为 [2, 3] 的张量 
tensor = torch.tensor([[1, 2, 3], [4, 5, 6]]) 
print("原始张量:") 
print(tensor) 
print("形状:", tensor.shape) 


# 在第一个维度前增加一个新维度 
tensor_unsqueezed_dim0 = torch.unsqueeze(tensor, dim=0) 
print("在第一个维度前增加维度后的张量:") 
print(tensor_unsqueezed_dim0) 
print("形状:", tensor_unsqueezed_dim0.shape) 


# 在第二个维度后增加一个新维度 
tensor_unsqueezed_dim1 = torch.unsqueeze(tensor, dim=1) 
print("在第二个维度后增加维度后的张量:") 
print(tensor_unsqueezed_dim1) 
print("形状:", tensor_unsqueezed_dim1.shape)

张量维度的压缩(Squeeze)

torch.squeeze函数用于移除张量中所有大小为1的维度

# 使用上面的 tensor_unsqueezed_dim1 张量,它有一个大小为1的维度在第二个位置 
print("带有一个大小为1的维度的张量:") 
print(tensor_unsqueezed_dim1) 
print("形状:", tensor_unsqueezed_dim1.shape) 


# 压缩大小为1的维度 
tensor_squeezed = torch.squeeze(tensor_unsqueezed_dim1) 
print("压缩维度后的张量:") 
print(tensor_squeezed) 
print("形状:", tensor_squeezed.shape)

重塑张量形状(Reshape/View)

torch.resape和torch.view函数用于改变张量的形状,但不改变数据

# 使用原始的 [2, 3] 张量 
print("原始张量:") 
print(tensor) 
print("形状:", tensor.shape) 


# 使用reshape改变形状为 [3, 2] 
tensor_reshaped = tensor.reshape(3, 2) 
print("重塑后的张量:") 
print(tensor_reshaped) 
print("形状:", tensor_reshaped.shape) 


# 使用view改变形状为 [6] 
tensor_view = tensor.view(6) 
print("view后的张量:") 
print(tensor_view) 
print("形状:", tensor_view.shape)

请注意,reshape和view要求新形状与原始张量的元素总数相同。如果尝试将张量重塑为不兼容的形状,将会引发错误

张量展平(Flatten)

展平张量意味着将其所有维度合并成一个维度,通常用于将多维张量转换为一维张量

# 使用原始的 [2, 3] 张量 
print("原始张量:") 
print(tensor) 
print("形状:", tensor.shape) 


# 使用flatten展平张量 
tensor_flattened = tensor.flatten() 
print("展平后的张量:") 
print(tensor_flattened) 
print("形状:", tensor_flattened.shape)

torch.flatten函数还允许你指定从哪一维度开始展平以及是否保持批处理维度。这对于处理具有批处理维度的张量(如在神经网络中)特别有用

张量的广播

在PyTorch中,广播(broadcasting)是一种强大的机制,它允许PyTorch在元素级操作中对不同形状的张量进行自动扩展。这允许你在不显式重塑张量的情况下执行诸如加法、乘法等操作。广播规则基于NumPy的广播规则

import torch  
  
# 创建两个形状不同的张量  
tensor1 = torch.tensor([[1, 2, 3]])  # 形状: [1, 3]  
tensor2 = torch.tensor([[4], [5], [6]])  # 形状: [3, 1]  
  
# 由于广播规则,我们可以直接对这两个张量进行加法操作  
# tensor1 会沿着第0维(行)复制以匹配tensor2的形状  
# tensor2 会沿着第1维(列)复制以匹配tensor1的形状  
# 结果形状为 [3, 3]  
result = tensor1 + tensor2  
  
print("tensor1:")  
print(tensor1)  
print("形状:", tensor1.shape)  
  
print("tensor2:")  
print(tensor2)  
print("形状:", tensor2.shape)  
  
print("广播后的结果:")  
print(result)  
print("形状:", result.shape)

在上面的例子中,tensor1 的形状是 [1, 3],而 tensor2 的形状是 [3, 1]。当我们将这两个张量相加时,PyTorch会根据广播规则自动扩展它们以匹配对方的形状。具体来说,tensor1 会在第0维(行)上复制以匹配 tensor2 的3行,而 tensor2 会在第1维(列)上复制以匹配 tensor1 的3列。因此,结果张量的形状是 [3, 3]

广播规则要求,从右到左比较每个维度的大小:

  1. 如果两个维度的大小相等,或者其中一个维度的大小为1,则它们兼容,因此可以进行广播。
  2. 如果两个维度的大小都不为1且不相等,则它们不兼容,无法广播。

在上述例子中,tensor1 的第1维(列)大小为3,而 tensor2 的第0维(行)大小为3,因此它们是兼容的。同时,tensor1 的第0维(行)大小为1,而 tensor2 的第1维(列)大小为1,因此它们也是兼容的。因此,这两个张量可以广播

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

opencv图像处理技术(阈值处理与图像平滑)

进行图像处理时,常常需要对图像进行预处理以提取所需的信息或改善图像质量。阈值处理和图像平滑是两种常见的预处理技术。 阈值处理 阈值处理是一种图像分割技术,其基本思想是将图像中的像素值与一个或多个预先设定的阈值进行比较,根据比较…

Git入门实战教程之创建版本库

一、Git简介 Git是一个分布式版本控制系,分层结构如下: Git分为四层: 1、工作目录 当前正在工作的项目的实际文件目录,我们执行命令git init时所在的地方,也就是我们执行一切文件操作的地方。 2、暂存区 暂存区是…

软件测试常考面试题-软件测试面试宝典(一篇足矣)

🔥 交流讨论:欢迎加入我们一起学习! 🔥 资源分享:耗时200小时精选的「软件测试」资料包 🔥 教程推荐:火遍全网的《软件测试》教程 📢欢迎点赞 👍 收藏 ⭐留言 &#x1…

数据库表设计18条黄金规则

前言 对于后端开发同学来说,访问数据库,是代码中必不可少的一个环节。 系统中收集到用户的核心数据,为了安全性,我们一般会存储到数据库,比如:mysql,oracle等。 后端开发的日常工作&#xff…

C语言初阶—9函数

函数的声明 (main函数前)----告诉有一个函数 格式: 类型 函数名(参数); 函数的声明 放到头文件add.c 函数的定义 ----创建函数----放到add.c 格式:类型 函数名(参数) { 语句项; } 在文…

leetcode.707. 设计链表

题目 题意: 在链表类中实现这些功能: get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。 addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的…

Dubbo 序列化

Dubbo 序列化 1、什么是序列化和反序列化 序列化(serialization)在计算机科学的资料处理中,是指将数据结构或对象状态转换成可取用格式(例如存成文件,存于缓冲,或经由网络中发送),…

MySQL数据库基础--事务

事务 是一组操作的集合,他是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。 默认MySQL的事务是自动提交的,也就是说,当执行…

《C语言深度解剖》(2):详解C语言分支语句和循环

🤡博客主页:醉竺 🥰本文专栏:《C语言深度解剖》 😻欢迎关注:感谢大家的点赞评论关注,祝您学有所成! ✨✨💜💛想要学习更多数据结构与算法点击专栏链接查看&am…

Node操作mysql

配置 安装mysql模块 npm i mysql建立连接 const mysql require(mysql);const db mysql.createPool({host: 127.0.0.1,user: root,password: admin123,database: my_db_01 });测试 // select 1没有任何实质性作用 只是检查mysql模块是否正常 db.query(select 1, (err, results…

修电机所需要的基本工具

等距式 模具 同心式模具 电机划线刀 压脚 千分尺 -----测量线径 钳形电流表------- 测量 空载 满载下的电流值 摇表, 测量线圈是否碰到外壳 指针式万用表 胶锤 整理线圈 绝缘纸和青稞纸&#xf…

RuoYi-Vue若依框架-vue前端给对象添加字段

处理两个字段的时候有需求都要显示在下拉框的同一行,这里有两种解决方案,一是后端在实体类添加一个对象,加注解数据库忽略处理,在接口处拼接并传给前端,二是在前端获取的数据数组内为每个对象都添加一个字段&#xff0…

Ethernet 汇总

Ethernet系统 硬件最小系统 CPU:可以是复杂的芯片,也可以是小的单片机DMA:用于减轻CPU负担,搬运数据系统Memory<->FIFOMAC:可以集成在芯片里面,用于CPU和PHY之间的通信MII:接口用于MAC和PHY的通信,包括控制MDIO和数据DataPHY:模拟器件,最底层,数据收发源头软件…

Vue3【进阶】

简介 https://cn.vuejs.org/guide/introduction.html 创建vue3工程 【基于 vue-cli创建】 基本和vue-cli的过程类似&#xff0c;只是选择的时候用vue3创建 【基于vite创建】【推荐】 【官网】https://vitejs.cn/ 【可以先去学一下webpack】 步骤 【https://cn.vitejs.…

PostgreSQL入门到实战-第三弹

PostgreSQL入门到实战 PostgreSQL安装之linux官网地址PostgreSQL概述linux安装PostgreSQL更新计划 PostgreSQL安装之linux 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://www.postgresql.org/PostgreSQL概述 Postg…

【全套源码教程】基于SpringBoot+MyBatis+Vue的流浪动物救助网站的设计与实现

目录 前言 需求分析 可行性分析 技术实现 后端框架&#xff1a;Spring Boot 持久层框架&#xff1a;MyBatis 前端框架&#xff1a;Vue.js 数据库&#xff1a;MySQL 功能介绍 前台界面功能介绍 动物领养及捐赠 宠物论坛 公告信息 商品页面 寻宠服务 个人中心 购…

AI视觉入门:卷积和池化

从2012年以AlexNet为代表的模型问世以来&#xff0c;人工智能尤其是视觉cv部分飞速发展&#xff0c;在刚开始效果不如人类&#xff0c;到2015年在ImageNet1000数据集的表现就超过了人类。在Transformer模型出现之前&#xff0c;视觉模型的主要组成部分就是卷积和池化&#xff0…

在家也能赚钱!长期副业兼职,充分利用你的零碎时间!

2024年已然匆匆走过了三分之一&#xff0c;许多人或许都感受到了这一年大环境带来的压力。然而&#xff0c;对我而言&#xff0c;每个月的副业收入尚算可观&#xff0c;稳定在3000元以上&#xff0c;这让我深感庆幸&#xff0c;因为我找到了那份适合自己的副业。 打工的日子&a…

【40分钟速成智能风控1】互联网金融风险管理简介

目录 瓦联网金融的发展和现状 风险管理类型划分 欺诈风险 第一方和第三方 账户级和交易级 个人和团伙 互联网金融是传统金融业务与新兴互联网技术结合的一个交叉领域&#xff0c;例如互联网公司开展的金融业务&#xff0c;或者金融机构的线上化服务&#xff0c;都属于互联…

python 如何生成uuid

UUID&#xff08;Universally Unique Identifier&#xff09;是通用唯一识别码&#xff0c;在许多领域用作标识&#xff0c;比如我们常用的数据库也可以用它来作为主键&#xff0c;原理上它是可以对任何东西进行唯一的编码的。作为新手一看到类似varchar(40)这样的主键就觉得有…