动手学深度学习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, 而卷积核只与图像中每个大小完全适合的位置进行互相关运算。 所以,输出大小等于输入大小 n_h \times n_w 减去卷积核大小 k_h \times k_w ,即:

(n_h-k_h+1) \times (n_w-k_w+1).

这是因为我们需要足够的空间在图像上“移动”卷积核。稍后,我们将看到如何通过在图像边界周围填充零来保证有足够的空间移动卷积核,从而保持输出大小不变。 接下来,我们在corr2d函数中实现如上过程,该函数接受输入张量X和卷积核张量K,并返回输出张量Y

二维卷积层

  • 输入 \mathbf{X}: n_h \times n_w
  • 核 \mathbf{W}: k_h \times k_w
  • 偏差 b \in \mathbf{R}
  • 输出 c\mathbf{Y}: (n_h - k_h + 1) \times (n_w - k_w + 1)
  • \mathbf{Y} = \mathbf{X} * \mathbf{W} + b
  • \mathbf{W} 和 b 是可学习的参数
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__构造函数中,将weightbias声明为两个模型参数。前向传播函数调用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

高度和宽度分别为 h 和 w 的卷积核可以被称为 h \times w 卷积或 h \times w 卷积核。 我们也将带有 h \times w 卷积核的卷积层称为 h \times w 卷积层。

图像中目标的边缘检测

如下是[卷积层的一个简单应用:]通过找到像素变化的位置,来(检测图像中不同颜色的边缘)。 首先,我们构造一个 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) ** 2
    conv2d.zero_grad()
    l.sum().backward()
    # 迭代卷积核
    conv2d.weight.data[:] -= lr * conv2d.weight.grad
    if (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)中定义的严格卷积运算,而不是互相关运算。 幸运的是,它们差别不大,我们只需水平和垂直翻转二维卷积核张量,然后对输入张量执行互相关运算。

值得注意的是,由于卷积核是从数据中学习到的,因此无论这些层执行严格的卷积运算还是互相关运算,卷积层的输出都不会受到影响。 为了说明这一点,假设卷积层执行互相关运算并学习 上图 中的卷积核,该卷积核在这里由矩阵 \mathbf{K} 表示。 假设其他条件不变,当这个层执行严格的卷积时,学习的卷积核 \mathbf{K}' 在水平和垂直翻转之后将与 \mathbf{K} 相同。 也就是说,当卷积层对 上图 中的输入和 \mathbf{K}' 执行严格卷积运算时,将得到与互相关运算 上图中相同的输出。

为了与深度学习文献中的标准术语保持一致,我们将继续把“互相关运算”称为卷积运算,尽管严格地说,它们略有不同。 此外,对于卷积核张量上的权重,我们称其为元素

补充:

  • 二维互相关

y_{i,j} = \sum_{a = 1}^{h} \sum_{b = 1}^{w}w_{a,b}x_{i+a,i+b}

  • 二维卷积

y_{i,j} = \sum_{a = 1}^{h} \sum_{b = 1}^{w}w_{-a,-b}x_{i+a,i+b}

  • 由于对称性,在实际使用中没有区别

一维和三维互相关

  • 一维:文本、语言、时序序列(音频)

y_i = \sum_{a=1}^h w_a x_{i+a}

  • 三维:视频、医学图像、气象地图

y_{i,j,k} = \sum_{a=1}^h \sum_{b=1}^w \sum_{c=1}^d w_{a,b,c} x_{i+a,j+b,k+c}

特征映射和感受野

如在 6.1.4.1节 中所述, 上图 中输出的卷积层有时被称为特征映射(feature map),因为它可以被视为一个输入映射到下一层的空间维度的转换器。 在卷积神经网络中,对于某一层的任意元素 x ,其感受野(receptive field)是指在前向传播期间可能影响 x 计算的所有元素(来自所有先前层)。

请注意,感受野可能大于输入的实际大小。让我们用 上图 为例来解释感受野: 给定 2×2 卷积核,阴影输出元素值19的感受野是输入阴影部分的四个元素。 假设之前输出为 \mathbf{Y} ,其大小为 2×2,现在我们在其后附加一个卷积层,该卷积层以 \mathbf{Y} 为输入,输出单个元素 z 。 在这种情况下,\mathbf{Y} 上的 z 的感受野包括 \mathbf{Y} 的所有四个元素,而输入的感受野包括最初所有九个输入元素。 因此,当一个特征图中的任意元素需要检测更广区域的输入特征时,我们可以构建一个更深的网络。

小结

  • 二维卷积层的核心计算是二维互相关运算。最简单的形式是,对二维输入数据和卷积核执行互相关操作,然后添加一个偏置。
  • 我们可以设计一个卷积核来检测图像的边缘。
  • 我们可以从数据中学习卷积核的参数。
  • 学习卷积核时,无论用严格卷积运算或互相关运算,卷积层的输出不会受太大影响。
  • 当需要检测输入特征中更广区域时,我们可以构建一个更深的卷积网络。

练习

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 = 0
    for 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)

  • 对于一阶导数:
    f^\prime(x) \approx \lim_{h \rightarrow 0}\frac{f(x+h)-f(x-h)}{2h}= \frac{f(x+1)-f(x-1)}{2}

对应的一阶导数卷积核为 \left[\begin{matrix} -1 & 0 & 1 \end{matrix}\right]

扩展至二维,对应的一阶导数水平卷积核为 \left[\begin{matrix} 0 & 0 & 0 \\ -1 & 0 & 1 \\ 0 & 0 & 0 \end{matrix}\right] 或者 \left[\begin{matrix} -1 & 0 & 1 \\ -1 & 0 & 1 \\ -1 & 0 & 1 \end{matrix}\right]

对应的一阶导数垂直卷积核为\left[\begin{matrix} 0 & -1 & 0 \\ 0 & 0 & 0 \\ 0 & 1 & 0 \end{matrix}\right] 或者 \left[\begin{matrix} -1 & -1 & -1 \\ 0 & 0 & 0 \\ 1 & 1 & 1 \end{matrix}\right]

  • 进一步地,对于二阶导数: f^{\prime\prime}(x) \approx \lim_{h \rightarrow 0}\frac{f(x+h)-2f(x)+f(x-h)}{h^2} = f(x+1)-2f(x)+f(x-1)

对应的二阶导数卷积核为 \left[\begin{matrix} 1 & -2 & 1 \end{matrix}\right]

扩展至二维, \frac{\partial^2 f}{\partial^2 x}(x,y) \approx f(x+1,y)-2f(x,y)+f(x-1,y)\frac{\partial^2 f}{\partial^2 y}(x,y) \approx f(x,y+1)-2f(x,y)+f(x,y-1)

对应的二阶导数水平卷积核为 \left[\begin{matrix} 0 & 0 & 0 \\ 1 & -2 & 1 \\ 0 & 0 & 0 \end{matrix}\right] 或者 \left[\begin{matrix} 1 & -2 & 1 \\ 1 & -2 & 1 \\ 1 & -2 & 1 \end{matrix}\right]

二阶导数垂直卷积核为 \left[\begin{matrix} 0 & 1 & 0 \\ 0 & -2 & 0 \\ 0 & 1 & 0 \end{matrix}\right] 或者 \left[\begin{matrix} 1 & 1 & 1 \\ -2 & -2 & -2 \\ 1 & 1 & 1 \end{matrix}\right]

二阶导数叠加卷积核为 \left[\begin{matrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{matrix}\right]

2)

  • 一维积分核--平均滤波器: K = \frac{1}{N} \left[ \begin{matrix} 1 & 1 & \ldots & 1 \end{matrix} \right] 其中, N 是 K 中的元素数量。
  • 二维积分核: 积分核可以是平均滤波器,也称为均值滤波器,其形式如下:
    二维平均滤波器 (也称为盒式滤波器或均质滤波器):

K = \frac{1}{M \times N} \begin{bmatrix} 1 & 1 & \ldots & 1 \\ 1 & 1 & \ldots & 1 \\ \vdots & \vdots & \ddots & \vdots \\ 1 & 1 & \ldots & 1 \end{bmatrix} 其中, M 和 N 分别是 N 的高度和宽度。

高斯积分核: 在空间域具有高斯形状,用于实现平滑效果,如下:

K = \frac{1}{\sigma \sqrt{2\pi}} \begin{bmatrix} e^{-\frac{x_1^2 + y_1^2}{2\sigma^2}} & \ldots & e^{-\frac{x_1^2 + y_N^2}{2\sigma^2}} \\ \vdots & \ddots & \vdots \\ e^{-\frac{x_M^2 + y_1^2}{2\sigma^2}} & \ldots & e^{-\frac{x_M^2 + y_N^2}{2\sigma^2}} \end{bmatrix}

其中, \sigma 是高斯分布的标准差, (x_i, y_j) 是滤波器中每个元素的坐标。

双边滤波器核:结合了空间域的高斯权重和强度域的高斯权重,用于在保持边缘的同时实现平滑,如下: K(i, j) = \frac{1}{W} \frac{1}{2\pi \sigma_s \sigma_r^2} e^{-\frac{(i - x)^2}{2\sigma_s^2}} e^{-\frac{(r - I(x,y))^2}{2\sigma_r^2}}

其中, W 是归一化因子,确保核的总权重为 1, \sigma_s 是空间域的标准差, \sigma_r 是强度域的标准差, 𝐼(𝑥,𝑦) 是图像在点 (x, y) 的强度, r 是中心像素的强度。

3)结合第一小问的解答,

  • 对于一阶导数,最小核的大小是3(一个3点中心差分近似)。
  • 对于二阶导数,在一维情况下,最小核的大小是3(一个3点中心差分近似)。在二维情况下,一个简单的近似可能是一个3×3的核。
  • 对于更高阶的导数,核的大小至少应与导数的阶数d相匹配,但这通常不足以提供良好的近似。实际使用的核会更大,以确保足够的平滑性和减少误差。

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

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

相关文章

进程,进程的调度,进程的调度算法(详解)ฅ( ̳• · • ̳ฅ)

目录 😇进程的概念: 😚进程的组成: 🥰进程的调度: 一.进程调度的概念: 二.进程调度的方式: 三.进程调度的时机: 🤪进程的调度算法: 一.先…

leetcode--二叉树中的最大路径和

leetcode地址:二叉树中的最大路径和 二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。 路径和 是路径中各节点值的总…

UE5 本地化多语言方案

导入插件: https://www.unrealengine.com/marketplace/zh-CN/product/07e1d9bd9ced444c9b2a7e232161f74d​www.unrealengine.com/marketplace/zh-CN/product/07e1d9bd9ced444c9b2a7e232161f74d 打开测试关卡 打开插件下图目录,csv文件可以添加多个&…

SVN小乌龟没有绿勾解决方法

SVN小乌龟没有绿勾解决方法 1、步骤一2、步骤二3、步骤三(修改注册表)4、参考文章 1、步骤一 在链接文件夹中右击鼠标 2、步骤二 3、步骤三(修改注册表) ①在Tortoise1Normal前面放空格,保证Tortoise1Normal前面的空格…

系统吃swap问题排查

目录 背景 问题 分析并解决 1.控制线程数 2.更换IO组件 3.Linux进程信息文件分析 总结加餐 参考文档 背景 隔壁业务组系统是简单的主从结构,写索引的服务(主)叫primary, 读索引并提供搜索功能的服务(从)叫replica。业务线同步数据并不是平滑的&…

【转载】目标检测mAP的含义

转载自三叔家的猫 https://blog.csdn.net/qq_39056987 https://blog.csdn.net/qq_39056987/article/details/104348493 <div id"content_views" class"markdown_views prism-atom-one-light"><svg xmlns"http://www.w3.org/2000/svg" s…

rocketmq实现限流

目录 问题背景 技术方向 方案确认 消息队列&#xff08;√&#xff09; 分布式锁&#xff08;&#xff09; 方案实现 监控方向 业务方向 问题背景 公司邮件服务token有 分钟内超200封的熔断机制&#xff0c;当前token被熔断后&#xff0c;系统发邮件操作会被忽略&…

使用F1C200S从零制作掌机之构建debian文件系统

前情&#xff1a;使用buildrootfs构建的文件系统调试了很久NES模拟器&#xff0c;执行InfoNES模拟器的时候一直黑屏&#xff0c;无内容显示&#xff0c;调不通了&#xff0c;所以改用debian系统试试。 一、环境配置 首先下载两个工具&#xff1a;qemu-arm-static和debootstra…

如何在 Microsoft Edge 上使用开发人员工具

Microsoft Edge 提供了一套强大的开发人员工具&#xff0c;可帮助 Web 开发人员检查、调试和优化他们的网站或 Web 应用程序。 无论您是经验丰富的 Web 开发人员还是刚刚起步&#xff0c;了解如何有效地使用这些工具都可以对开发过程产生重大影响。 在本文中&#xff0c;我们…

vb.netcad二开自学笔记8:界面之任务窗格

使用net可以创建一个类似属性面板的自定义的任务窗格&#xff0c;从而实现应用程序更丰富的人机交互。 1、添加一个自定义控件 2、在前面创建的代码框架内增加一个命令函数ShowMyPalette Imports System.Windows.Media.Imaging Imports Autodesk.AutoCAD.ApplicationServices …

电机控制杂谈——位置环到底该用什么调节器?

1.为什么位置环用P调节器尽可以实现无静差调节&#xff1f; 当时在学《运动控制》这门课程时&#xff0c;用的是陈伯时老师的教材。在介绍调节器的时候&#xff0c;教材中说到&#xff0c;P&#xff08;比例&#xff09;调节器会存在稳态误差&#xff0c;所以在转速环和电流环…

html——VSCode的使用

快捷键 快速生成标签&#xff1a;标签名tab 保存文件&#xff1a;CtrlS 设置自动保存【文件】→【自动保存】 快速查看网页效果&#xff1a;右击→Open in Default Browser 快捷键&#xff1a;altb 注意&#xff1a;必须安装了open in brows…

显示渲染-OSG框架解析

1.背景介绍 1.1 OSG介绍 OSG的全称&#xff1a;OpenSceneGraph&#xff0c;它是一个开放源码&#xff0c;跨平台的图形开发包&#xff0c;它为诸如飞行器仿真&#xff0c;游戏&#xff0c;虚拟现实&#xff0c;科学计算可视化这样的高性能图形应用程序开发而设计。 它基于场…

生成图质量评价

1. RichHF-18K 论文地址 解决问题&#xff1a; 如何对生成图质量进行算法评价&#xff0c;以优化图片质量&#xff0c;提升模型生成能力 解决思路&#xff1a; 参考多模态模型&#xff0c;构建评价模型&#xff0c;从7个维度分三个分支对生成图进行测评&#xff1a; Tips&…

简单仿写MVC

代码地址&#xff08;需要自取&#xff09;&#xff1a;mvc_Imitation: 简单仿写实现MVC (gitee.com) 项目目录 先把架子搭好 Controller注解 Documented Retention(RetentionPolicy.RUNTIME) Target(ElementType.TYPE) public interface Controller { }RequestMapping Do…

java设计模式(十一)组合模式(Composite Pattern)

1、模式介绍&#xff1a; 组合模式是一种结构型设计模式&#xff0c;它允许你将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 2、应用场景&#xff1a; 表示树形结构&#xff1a;当你需要表示对象的部分-整体…

2024年06月CCF-GESP编程能力等级认证Python编程四级真题解析

本文收录于专栏《Python等级认证CCF-GESP真题解析》&#xff0c;专栏总目录&#xff1a;点这里&#xff0c;订阅后可阅读专栏内所有文章。 一、单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09; 第 1 题 小杨父母带他到某培训机构给他报名参加CCF组织的GESP认证…

前端视角下的Spring-Boot语法学习:打印 hello-world

今日话题 基于 Spring Boot 打印输出 hello world 作者&#xff1a;云层上的光 时间&#xff1a;2024年6月20日 14时25分14秒 主线任务 一、打印 hello world 1、点击 “新建项目”用来演示 打印输出 “hello world” 2、填写项目配置&#xff1a;&#xff08;详细版见&a…

Python基础知识——(002)

文章目录 P8——7. input函数的使用 基本的输入函数input P9——8. Python中的注释 P10——9. Python中的缩进与本章总结 本章总结 P11——10. 章节习题 P8——7. input函数的使用 基本的输入函数input 语法结构&#xff1a; x input(提示文字) 注意事项&#xff1a;无论输…

【matlab】【python】爬虫实战

目录 引言 具体步骤 1.设置请求选项 2.发送请求并获取响应 3.设置正则表达式 4.执行正则表达式匹配 matlab完整代码 python代码示例 引言 在当今这个信息爆炸的时代&#xff0c;数据已成为推动社会进步和企业发展的核心动力之一。随着互联网的普及和技术的飞速发展&am…