动手学深度学习6.2 图像卷积-笔记练习(PyTorch)
以下内容为结合李沐老师的课程和教材补充的学习笔记,以及对课后练习的一些思考,自留回顾,也供同学之人交流参考。
本节课程地址:卷积层_哔哩哔哩_bilibili 代码_哔哩哔哩_bilibili
本节教材地址:6.2. 图像卷积 — 动手学深度学习 2.0.0 documentation (d2l.ai)
本节开源代码:...>d2l-zh>pytorch>chapter_multilayer-perceptrons>conv-layer.ipynb
图像卷积
上节我们解析了卷积层的原理,现在我们看看它的实际应用。由于卷积神经网络的设计是用于探索图像数据,本节我们将以图像为例。
互相关运算
严格来说,卷积层是个错误的叫法,因为它所表达的运算其实是互相关运算(cross-correlation),而不是卷积运算。 根据 6.1节 中的描述,在卷积层中,输入张量和核张量通过(互相关运算)产生输出张量。
首先,我们暂时忽略通道(第三维)这一情况,看看如何处理二维图像数据和隐藏表示。在 下图 中,输入是高度为3、宽度为3的二维张量(即形状为3 × 3)。卷积核的高度和宽度都是2,而卷积核窗口(或卷积窗口)的形状由内核的高度和宽度决定(即2 × 2)。
在二维互相关运算中,卷积窗口从输入张量的左上角开始,从左到右、从上到下滑动。 当卷积窗口滑动到新一个位置时,包含在该窗口中的部分张量与卷积核张量进行按元素相乘,得到的张量再求和得到一个单一的标量值,由此我们得出了这一位置的输出张量值。 在如上例子中,输出张量的四个元素由二维互相关运算得到,这个输出高度为2、宽度为2,如下所示:
0×0+1×1+3×2+4×3=19,1×0+2×1+4×2+5×3=25,3×0+4×1+6×2+7×3=37,4×0+5×1+7×2+8×3=43.
注意,输出大小略小于输入大小。这是因为卷积核的宽度和高度大于1, 而卷积核只与图像中每个大小完全适合的位置进行互相关运算。 所以,输出大小等于输入大小 减去卷积核大小
,即:
这是因为我们需要足够的空间在图像上“移动”卷积核。稍后,我们将看到如何通过在图像边界周围填充零来保证有足够的空间移动卷积核,从而保持输出大小不变。 接下来,我们在corr2d
函数中实现如上过程,该函数接受输入张量X
和卷积核张量K
,并返回输出张量Y
。
二维卷积层:
- 输入
- 核
- 偏差
- 输出 c
和
是可学习的参数
import torch
from torch import nn
from d2l import torch as d2l
def corr2d(X, K): #@save"""计算二维互相关运算"""h, w = K.shape #获取卷积核的长&宽Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))for i in range(Y.shape[0]):for j in range(Y.shape[1]):Y[i, j] = (X[i:i + h, j:j + w] * K).sum()return Y
通过 上图 的输入张量X
和卷积核张量K
,我们来[验证上述二维互相关运算的输出]。
X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
corr2d(X, K)
输出结果:
tensor([[19., 25.],
[37., 43.]])
卷积层
卷积层对输入和卷积核权重进行互相关运算,并在添加标量偏置之后产生输出。 所以,卷积层中的两个被训练的参数是卷积核权重和标量偏置。 就像我们之前随机初始化全连接层一样,在训练基于卷积层的模型时,我们也随机初始化卷积核权重。
基于上面定义的corr2d
函数[实现二维卷积层]。在__init__
构造函数中,将weight
和bias
声明为两个模型参数。前向传播函数调用corr2d
函数并添加偏置。
class Conv2D(nn.Module):def __init__(self, kernel_size):super().__init__()self.weight = nn.Parameter(torch.rand(kernel_size))self.bias = nn.Parameter(torch.zeros(1))def forward(self, x):return corr2d(x, self.weight) + self.bias
高度和宽度分别为 和
的卷积核可以被称为
卷积或
卷积核。 我们也将带有
卷积核的卷积层称为
卷积层。
图像中目标的边缘检测
如下是[卷积层的一个简单应用:]通过找到像素变化的位置,来(检测图像中不同颜色的边缘)。 首先,我们构造一个 6 × 8像素的黑白图像。中间四列为黑色(0),其余像素为白色(1)。
X = torch.ones((6, 8))
X[:, 2:6] = 0
X
输出结果:
tensor([[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.],
[1., 1., 0., 0., 0., 0., 1., 1.]])
接下来,我们构造一个高度为1、宽度为2的卷积核K
。当进行互相关运算时,如果水平相邻的两元素相同,则输出为零,否则输出为非零。
K = torch.tensor([[1.0, -1.0]])
现在,我们对参数X
(输入)和K
(卷积核)执行互相关运算。 如下所示,[输出Y
中的1代表从白色到黑色的边缘,-1代表从黑色到白色的边缘],其他情况的输出为0。
Y = corr2d(X, K)
Y
输出结果:
tensor([[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.],
[ 0., 1., 0., 0., 0., -1., 0.]])
现在我们将输入的二维图像转置,再进行如上的互相关运算。 其输出如下,之前检测到的垂直边缘消失了。 不出所料,这个[卷积核K
只可以检测垂直边缘],无法检测水平边缘。
corr2d(X.t(), K)
输出结果:
tensor([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
补充:
学习卷积核
如果我们只需寻找黑白边缘,那么以上[1, -1]
的边缘检测器足以。然而,当有了更复杂数值的卷积核,或者连续的卷积层时,我们不可能手动设计滤波器。那么我们是否可以[学习由X
生成Y
的卷积核]呢?
现在让我们看看是否可以通过仅查看“输入-输出”对来学习由X
生成Y
的卷积核。 我们先构造一个卷积层,并将其卷积核初始化为随机张量。接下来,在每次迭代中,我们比较Y
与卷积层输出的平方误差,然后计算梯度来更新卷积核。为了简单起见,我们在此使用内置的二维卷积层,并忽略偏置。
# 构造一个二维卷积层,它具有1个输出通道和形状为(1,2)的卷积核
conv2d = nn.Conv2d(1,1, kernel_size=(1, 2), bias=False)# 这个二维卷积层使用四维输入和输出格式(批量大小、通道、高度、宽度),
# 其中批量大小和通道数都为1
X = X.reshape((1, 1, 6, 8))
Y = Y.reshape((1, 1, 6, 7))
lr = 3e-2 # 学习率for i in range(10):Y_hat = conv2d(X)l = (Y_hat - Y) ** 2conv2d.zero_grad()l.sum().backward()# 迭代卷积核conv2d.weight.data[:] -= lr * conv2d.weight.gradif (i + 1) % 2 == 0:print(f'epoch {i+1}, loss {l.sum():.3f}')
输出结果:
epoch 2, loss 4.114
epoch 4, loss 0.798
epoch 6, loss 0.178
epoch 8, loss 0.048
epoch 10, loss 0.016
在10 次迭代之后,误差已经降到足够低。现在我们来看看我们[所学的卷积核的权重张量]。
conv2d.weight.data.reshape((1, 2))
输出结果:
tensor([[ 1.0016, -0.9785]])
细心的读者一定会发现,我们学习到的卷积核权重非常接近我们之前定义的卷积核K
。
互相关和卷积
回想一下我们在 6.1节 中观察到的互相关和卷积运算之间的对应关系。 为了得到正式的卷积运算输出,我们需要执行 (6.1.6)中定义的严格卷积运算,而不是互相关运算。 幸运的是,它们差别不大,我们只需水平和垂直翻转二维卷积核张量,然后对输入张量执行互相关运算。
值得注意的是,由于卷积核是从数据中学习到的,因此无论这些层执行严格的卷积运算还是互相关运算,卷积层的输出都不会受到影响。 为了说明这一点,假设卷积层执行互相关运算并学习 上图 中的卷积核,该卷积核在这里由矩阵 表示。 假设其他条件不变,当这个层执行严格的卷积时,学习的卷积核
在水平和垂直翻转之后将与
相同。 也就是说,当卷积层对 上图 中的输入和
执行严格卷积运算时,将得到与互相关运算 上图中相同的输出。
为了与深度学习文献中的标准术语保持一致,我们将继续把“互相关运算”称为卷积运算,尽管严格地说,它们略有不同。 此外,对于卷积核张量上的权重,我们称其为元素。
补充:
- 二维互相关
- 二维卷积
- 由于对称性,在实际使用中没有区别
一维和三维互相关:
- 一维:文本、语言、时序序列(音频)
- 三维:视频、医学图像、气象地图
特征映射和感受野
如在 6.1.4.1节 中所述, 上图 中输出的卷积层有时被称为特征映射(feature map),因为它可以被视为一个输入映射到下一层的空间维度的转换器。 在卷积神经网络中,对于某一层的任意元素 ,其感受野(receptive field)是指在前向传播期间可能影响
计算的所有元素(来自所有先前层)。
请注意,感受野可能大于输入的实际大小。让我们用 上图 为例来解释感受野: 给定 2×2 卷积核,阴影输出元素值19的感受野是输入阴影部分的四个元素。 假设之前输出为 ,其大小为 2×2,现在我们在其后附加一个卷积层,该卷积层以
为输入,输出单个元素
。 在这种情况下,
上的
的感受野包括
的所有四个元素,而输入的感受野包括最初所有九个输入元素。 因此,当一个特征图中的任意元素需要检测更广区域的输入特征时,我们可以构建一个更深的网络。
小结
- 二维卷积层的核心计算是二维互相关运算。最简单的形式是,对二维输入数据和卷积核执行互相关操作,然后添加一个偏置。
- 我们可以设计一个卷积核来检测图像的边缘。
- 我们可以从数据中学习卷积核的参数。
- 学习卷积核时,无论用严格卷积运算或互相关运算,卷积层的输出不会受太大影响。
- 当需要检测输入特征中更广区域时,我们可以构建一个更深的卷积网络。
练习
1. 构建一个具有对角线边缘的图像X
。
1)如果将本节中举例的卷积核K
应用于X
,会发生什么情况?
2)如果转置X
会发生什么?
3)如果转置K
会发生什么?
解:
代码如下:
X = torch.ones((5, 5))
for i in range(X.shape[0]):for j in range(X.shape[1]):if i == j:X[i,j] = 0
X
输出结果:
tensor([[0., 1., 1., 1., 1.],
[1., 0., 1., 1., 1.],
[1., 1., 0., 1., 1.],
[1., 1., 1., 0., 1.],
[1., 1., 1., 1., 0.]])
K = torch.tensor([[1.0, -1.0]])
corr2d(X, K)
# 输出形状为(5,4),检测对角线边缘,对角线上为-1,下为1
输出结果:
tensor([[-1., 0., 0., 0.],
[ 1., -1., 0., 0.],
[ 0., 1., -1., 0.],
[ 0., 0., 1., -1.],
[ 0., 0., 0., 1.]])
corr2d(X.t(), K)
# X转置后结果不变
输出结果:
tensor([[-1., 0., 0., 0.],
[ 1., -1., 0., 0.],
[ 0., 1., -1., 0.],
[ 0., 0., 1., -1.],
[ 0., 0., 0., 1.]])
corr2d(X, K.t())
# 输出形状变成(4,5),检测对角线边缘,对角线上为1,下为-1
输出结果:
tensor([[-1., 1., 0., 0., 0.],
[ 0., -1., 1., 0., 0.],
[ 0., 0., -1., 1., 0.],
[ 0., 0., 0., -1., 1.]])
2. 在我们创建的Conv2D
自动求导时,有什么错误消息?
解:
报错:维度不匹配。因为输入和输出格式是四维的,包括批量大小、通道、高和宽,但自定义的Conv2D仅包含二维信息,即高和宽。
将输入和输出的批量大小和通道去掉,或者创建卷积层时增加批量大小和通道,均可解决该问题。
conv2d = Conv2D((1,2))
Y_hat = conv2d(X)
l = (Y_hat - Y) ** 2
conv2d.zero_grad()
l.sum().backward()
conv2d.weight.data[:] -= lr * conv2d.weight.grad
输出结果:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
Cell In[24], line 3
1 conv2d = Conv2D((1,2))
2 Y_hat = conv2d(X)
----> 3 l = (Y_hat - Y) ** 2
4 conv2d.zero_grad()
5 l.sum().backward()
RuntimeError: The size of tensor a (4) must match the size of tensor b (7) at non-singleton dimension 3
3. 如何通过改变输入张量和卷积核张量,将互相关运算表示为矩阵乘法?
解:
核心思想是,将输入张量中每个与卷积核做互相关运算的元素展成一行,
比如将本节举例的X转变为: [0134124534674578]
再与reshape成列向量的卷积核K做矩阵乘法: [0134124534674578][0123]=[19253743]
再将结果reshape成输出Y的尺寸即可。
def corr2d_matmul(X, K): h, w = K.shape# 将输入X中每次与卷积核做互相关运算的元素展平成一行# X_reshaped的每一行元素均为与卷积核做互相关的元素X_reshaped = torch.zeros((X.shape[0] - h + 1)*(X.shape[1] - w + 1), h*w)k = 0for i in range(X.shape[0] - h + 1):for j in range(X.shape[1] - w + 1):X_reshaped[k,:] = X[i:i + h, j:j + w].reshape(1,-1)k += 1# 将卷积核K转为列向量,并与X_reshaped做矩阵乘法,再reshape成输出尺寸即可Y = X_reshaped@K.view(-1)return Y.reshape(X.shape[0] - h + 1, X.shape[1] - w + 1)
X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
Y = corr2d_matmul(X, K)
Y
输出结果:
tensor([[19., 25.],
[37., 43.]])
4.手工设计一些卷积核。
1)二阶导数的核的形式是什么?
2)积分的核的形式是什么?
3)得到 𝑑 次导数的最小核的大小是多少?
解:
1)
- 对于一阶导数:
对应的一阶导数卷积核为
扩展至二维,对应的一阶导数水平卷积核为 或者
对应的一阶导数垂直卷积核为 或者
- 进一步地,对于二阶导数:
对应的二阶导数卷积核为
扩展至二维,
对应的二阶导数水平卷积核为 或者
二阶导数垂直卷积核为 或者
二阶导数叠加卷积核为
2)
- 一维积分核--平均滤波器:
其中,
是
中的元素数量。
- 二维积分核: 积分核可以是平均滤波器,也称为均值滤波器,其形式如下:
二维平均滤波器 (也称为盒式滤波器或均质滤波器):
其中,
和
分别是
的高度和宽度。
高斯积分核: 在空间域具有高斯形状,用于实现平滑效果,如下:
其中, 是高斯分布的标准差,
是滤波器中每个元素的坐标。
双边滤波器核:结合了空间域的高斯权重和强度域的高斯权重,用于在保持边缘的同时实现平滑,如下:
其中, 是归一化因子,确保核的总权重为 1,
是空间域的标准差,
是强度域的标准差, 𝐼(𝑥,𝑦) 是图像在点
的强度,
是中心像素的强度。
3)结合第一小问的解答,
- 对于一阶导数,最小核的大小是3(一个3点中心差分近似)。
- 对于二阶导数,在一维情况下,最小核的大小是3(一个3点中心差分近似)。在二维情况下,一个简单的近似可能是一个3×3的核。
- 对于更高阶的导数,核的大小至少应与导数的阶数d相匹配,但这通常不足以提供良好的近似。实际使用的核会更大,以确保足够的平滑性和减少误差。
相关文章:
动手学深度学习6.2 图像卷积-笔记练习(PyTorch)
以下内容为结合李沐老师的课程和教材补充的学习笔记,以及对课后练习的一些思考,自留回顾,也供同学之人交流参考。 本节课程地址:卷积层_哔哩哔哩_bilibili 代码_哔哩哔哩_bilibili 本节教材地址:6.2. 图像卷积 — 动…...

展开说说:Android服务之bindService解析
前面两篇文章我们分别总结了Android四种Service的基本使用以及源码层面总结一下startService的执行过程,本篇继续从源码层面总结bindService的执行过程。 本文依然按着是什么?有什么?怎么用?啥原理?的步骤来分析。 b…...

node-sass 老版本4.14.0 安装失败解决办法
旧项目 npm install 发现 node-sass 安装 失败 切换淘宝镜像之后 不能完全解决问题。因为需要编译,本地没有Python环境不能实现 安装node-sass时,在install阶段会从Github上下载一个叫binding.node的文件,而「GitHub Releases」里的文件…...

最近很火的字幕截图生成器
网址 https://disksing.com/fake-screenshot/ 最近很火的字幕截图生成器,对于自媒体来说真的太实用了 另外透露一下,你仔细研究就会发现,这是个纯前端的项目...

使用RabbitMQ实现可靠的消息传递机制
使用RabbitMQ实现可靠的消息传递机制 大家好,我是微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 1. RabbitMQ简介 RabbitMQ是一个开源的消息代理软件,实现了高级消息队列协议(AMQP&…...

Function Call ReACT,Agent应用落地的加速器_qwen的function calling和react有什么不同
探索智能体Agent的未来之路:Function Call与ReACT框架的较量,谁能引领未来? 引言 各大平台出现智能体应用创建,智能体逐渐落地,背后的使用哪种框架? 随着各大平台,例如百度千帆APPbuilder、阿…...

Java的JSONPath(fastjson)使用总结
背景 最近使用json实现复杂业务配置, 因为功能需要解析读取json的中节点数据。如果使用循环或者stream处理,可以实现,但是都过于麻烦。在想能否使用更简单json读取方式,正好发现fastjson支持该功能,本文做一个记录 案例说明 示…...

【大模型】大语言模型:光鲜背后的阴影——事实准确性和推理能力的挑战
大语言模型:光鲜背后的阴影——事实准确性和推理能力的挑战 引言一、概念界定二、事实准确性的局限2.1 训练数据的偏差2.2 知识的时效性问题2.3 复杂概念的理解与表述 三、推理能力的局限3.1 表层理解与深层逻辑的脱节3.2 缺乏常识推理3.3 无法进行长期记忆和连续推…...

Java面向对象练习(1.手机类)(2024.7.4)
手机类 package Phone;public class Phone {private String brand;private int price;private String color;public Phone(){}public Phone(String brand, int price, String color){this.brand brand;this.price price;this.color color;}public void setBrand(String bra…...

智慧生活新篇章,Vatee万腾平台领航前行
在21世纪的科技浪潮中,智慧生活已不再是一个遥远的梦想,而是正逐步成为我们日常生活的现实。从智能家居的温馨便捷,到智慧城市的高效运转,科技的每一次进步都在为我们的生活增添新的色彩。而在这场智慧生活的变革中,Va…...

Spring Cloud Gateway报sun.misc.Unsafe.park(Native Method)
项目引入spring cloud gateway的jar报,启动的时候报: [2024-07-05 10:10:16.162][main][ERROR][org.springframework.boot.web.embedded.tomcat.TomcatStarter][61]:Error starting Tomcat context. Exception: org.springframework.beans.factory.Bean…...

select single , select endselect
select single , select endselect single 根据条件找到一条数据,就出来了。 select endselect是在里面循环,每次找一条,依次放到into table中,或者放到into work area中,下面append table 。 实际开发中不建议这么操…...

后端学习(一)
添加数据库包: 数据库连接时 发生错误: 解决方式: SqlConnection conn new SqlConnection("serverlocalhost;databaseMyBBSDb;uidsa;pwd123456;Encryptfalse;") ;conn.Open();SqlCommand cmd new SqlCommand("SELECT * FROM…...

【活动行】参与上海两场线下活动,教育生态行业赛总决赛活动和WAIC人工智能大会活动 - 上海活动总结
目录 背景决赛最后一公里领域范围 决赛作品AI智教相机辅导老师Copilot辅导老师Copilot雅思写作竞技场 优秀作品总结 背景 决赛 百度发起的千帆杯教育生态行业赛于2024年7月4日进行线下决赛,博主虽然没能进入决赛,但也非常荣幸能够以嘉宾身份到现场给进…...

conda 安装设置
安装anaconda 推荐官网下载和安装,最新版本是anaconda3+python3.11,个人选择。有可能找不到 Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror Tips:小白一定要全部勾选,特别第二项“add anaconda3 to my path environment variable…...

用PlantUML和语雀画UML类图
概述 首先阐述一下几个简单概念: UML:是统一建模语言(Unified Modeling Language)的缩写,它是一种用于软件工程的标准化建模语言,旨在提供一种通用的方式来可视化软件系统的结构、行为和交互。UML由Grady…...

uniapp微信小程序电子签名
先上效果图,不满意可以直接关闭这页签 新建成单独的组件,然后具体功能引入,具体功能点击签名按钮,把当前功能页面用样式隐藏掉,v-show和v-if也行,然后再把这个组件显示出来。 【签名-撤销】原理是之前绘画时…...

MetaPoint_速读
Meta-Point Learning and Refining for Category-Agnostic Pose Estimation https://arxiv.org/abs/2404.14808https://github.com/chenbys/metapointabstract 这篇文章介绍了一种名为Meta-Point Learning and Refining的框架,用于实现类别不可知的姿势估计。该框…...

数据库逆向工程工具reverse_sql
reverse_sql 是一个用于解析和转换 MySQL 二进制日志(binlog)的工具。它可以将二进制日志文件中记录的数据库更改操作(如插入、更新、删除)转换为反向的 SQL 语句,以便对系统或人为产生的误操作进行数据回滚和恢复。 *…...

四大内网穿透利器对比
本文精选四款市场上的佼佼者——巴比达、花生壳、Frp及NatApp,详细剖析它们的特点与优势,助力企业和个人用户精准选择,其中特别强调了巴比达在企业级安全访问方面的突出贡献。 1. 巴比达 特点 深度安全防护:巴比达提供全方位安…...

【LeetCode】每日一题:跳跃游戏 II
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - 1] 的最小…...

SpringBoot拦截器
目录 一、拦截器快速入门 (1)什么是拦截器 (2)拦截器的使用步骤 1、定义拦截器 🍀preHandle() 方法 🍀postHandle() 方法 🍀afterCompletion() 方法 2、注册配置拦截器 二、拦截器详解…...

uniapp中实现跳转链接到游览器(安卓-h5)
uniapp中实现跳转链接到游览器(安卓-h5) 项目中需要做到跳转到外部链接,网上找了很多都不是很符合自己的要求,需要编译成app后是跳转到游览器打开链接,编译成web是在新窗口打开链接。实现的代码如下: 效果&…...

WPF UI 界面布局 魔术棒 文字笔记识别 技能提升 布局功能扩展与自定义 继承Panel的对象,测量与排列 系列七
应用开发第一步 功能分类:页面上的功能区域划分。。。。需求分析 业务逻辑 数据流 功能模块 UI/UX 编码 测试 发布 功能开发与布局 不用显式的方式设定元素的尺寸 不使用屏幕坐标来指定位置 Grid 功能最强大,布局最灵活的容器…...

文件格式是.pb应该怎么查看?
文件格式为.pb的文件,通常是Google Protocol Buffers(简称PB)序列化后的二进制文件。要查看.pb文件的内容,可以采用以下方法: 1. **直接打开(不推荐)**: - 直接打开.pb文件通常会显示…...

android2024 gradle8 Processor和ksp两种编译时注解实现
android编译时注解,老生常谈,外面的例子都是bindView,脑壳看疼了,自己学习和编写下。 而且现在已经进化到kotlin2.0,google也逐渐放弃kapt,进入维护状态。所以要好好看看本贴。 参考我的工程: h…...

elementui的table的@selection-change阻止事件改变
说明: 最近有个不想说的(xxx)业务,在表格勾选每一行的时候要触发一系列查询功能,查询失败还要把那个勾勾回退。真实蛋疼!表格勾选的默认selection-change是change事件,一般change事件是在完成之…...

空间数据采集与管理:为什么选择ArcGISPro和Python?
你还在为找不到合适的数据而苦恼吗?你还在面对大量数据束手无策,不知如何处理吗?对于从事生产和科研的人员来说,空间数据的采集与管理是地理信息系统(GIS)和空间分析领域的关键环节。通过准确高效地采集和管…...

案例精选 | 聚铭综合日志分析系统为江苏省电子口岸构建高效安全的贸易生态
江苏省电子口岸有限公司,成立于2009年,由江苏省贸促会携手南京海关、江苏检验检疫局及江苏海事局等部门共同出资组建。公司承载着推动江苏乃至长三角地区国际贸易便利化的重大使命,致力于打造一个集先进性、创新性、高效性于一体的电子口岸综…...

TCP粘包
目录 TCP粘包产生的原因 TCP粘包的现象 TCP粘包的解决方案 TCP粘包是指在TCP通信中,发送方发送的多个数据包在接收方被错误地合并成一个数据包的现象。tcp粘包在发送端和接收端都有可能发生。发送端粘包:发送端需要等缓冲区满才发送出去,造成粘包。接收方粘包:接收方不及…...