【动手学深度学习】--10.卷积神经网络

news2024/11/28 2:43:57

文章目录

  • 卷积神经网络
    • 1.从全连接层到卷积
      • 1.1全连接层
      • 1.2平移不变性
      • 1.3局部性
      • 1.4卷积
    • 2.卷积层
      • 2.1互相关计算
      • 2.2卷积层
      • 2.3图像中目标的边缘检测
      • 2.4学习卷积核
    • 3.填充和步幅
      • 3.1填充
      • 3.2步幅
    • 4.多输入多输出通道
      • 4.1多输入通道
      • 4.2多输出通道
      • 4.3 1×1卷积层
    • 5.池化层
      • 5.1池化层
      • 5.2填充和步幅
      • 5.3多个通道

卷积神经网络

1.从全连接层到卷积

官方笔记:从全连接层到卷积

学习视频:卷积层【动手学深度学习v2】

卷积神经网络正是将空间不变性(spatial invariance)的这一概念系统化,从而基于这个模型使用较少的参数来学习有用的表示。

有以下两个原则:

  1. 平移不变性(translation invariance):不管检测对象出现在图像中的哪个位置,神经网络的前面几层应该对相同的图像区域具有相似的反应,即为“平移不变性”。
  2. 局部性(locality):神经网络的前面几层应该只探索输入图像中的局部区域,而不过度在意图像中相隔较远区域的关系,这就是“局部性”原则。最终,可以聚合这些局部特征,以在整个图像级别进行预测

1.1全连接层

image-20230717153730934

image-20230717151757900

1.2平移不变性

image-20230717153925356

image-20230717151833908

1.3局部性

image-20230717154010550

image-20230717152012343

总结:

image-20230717152110315

1.4卷积

image-20230717154206294

image-20230717154222382

2.卷积层

官方笔记:图像卷积

2.1互相关计算

严格来说,卷积层是个错误的叫法,因为它所表达的运算其实是互相关运算(cross-correlation),而不是卷积运算,在卷积层中,输入张量和核张量通过互相关运算产生输出张量。

image-20230717154619726

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

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 = 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.]])
'''

2.2卷积层

交叉相关vs卷积

image-20230717152527989

一维和三维交叉相关

image-20230717152617418

总结:

  • 卷积层将输入和核矩阵进行交叉相关,加上偏移后得到输出
  • 核矩阵和偏移是可学习的参数
  • 核矩阵的大小是超参数

卷积层对输入和卷积核权重进行互相关运算,并在添加标量偏置之后产生输出。 所以,卷积层中的两个被训练的参数是卷积核权重和标量偏置。 就像我们之前随机初始化全连接层一样,在训练基于卷积层的模型时,我们也随机初始化卷积核权重。

基于上面定义的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×w卷积或h×w卷积核,我们也将带有h×w卷积核的卷积层成为h×w卷积层

2.3图像中目标的边缘检测

如下是卷积层的一个简单应用:通过找到像素变化的位置,来检测图像中不同颜色的边缘。 首先,我们构造一个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.]])
'''

2.4学习卷积核

如果我们只需寻找黑白边缘,那么以上[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 15.223
epoch 4, loss 5.325
epoch 6, loss 2.029
epoch 8, loss 0.805
epoch 10, loss 0.326
'''

在10次迭代之后,误差已经降到足够低。现在我们来看看我们所学的卷积核的权重张量。

conv2d.weight.data.reshape((1, 2))

'''
tensor([[ 1.0486, -0.9313]])
'''

3.填充和步幅

学习视频:卷积层里的填充和步幅【动手学深度学习v2】

官方笔记:填充和步幅

有时,在应用了连续的卷积之后,我们最终得到的输出远小于输入大小。这是由于卷积核的宽度和高度通常大于1所导致的。比如,一个240×240像素的图像,经过10层5×5的卷积后,将减少到200×200像素。如此一来,原始图像的边界丢失了许多有用信息。而填充是解决此问题最有效的方法; 有时,我们可能希望大幅降低图像的宽度和高度。例如,如果我们发现原始的输入分辨率十分冗余。步幅则可以在这类情况下提供帮助

3.1填充

image-20230717162719703

image-20230717161540528

卷积神经网络中卷积核的高度和宽度通常为奇数,例如1、3、5或7。 选择奇数的好处是,保持空间维度的同时,我们可以在顶部和底部填充相同数量的行,在左侧和右侧填充相同数量的列。

此外,使用奇数的核大小和填充大小也提供了书写上的便利。对于任何二维张量X,当满足: 1. 卷积核的大小是奇数; 2. 所有边的填充行数和列数相同; 3. 输出与输入具有相同高度和宽度 则可以得出:输出Y[i, j]是通过以输入X[i, j]为中心,与卷积核进行互相关计算得到的。

比如,在下面的例子中,我们创建一个高度和宽度为3的二维卷积层,并在所有侧边填充1个像素。给定高度和宽度为8的输入,则输出的高度和宽度也是8

import torch
from torch import nn


# 为了方便起见,我们定义了一个计算卷积层的函数。
# 此函数初始化卷积层权重,并对输入和输出提高和缩减相应的维数
def comp_conv2d(conv2d, X):
    # 这里的(1,1)表示批量大小和通道数都是1
    X = X.reshape((1, 1) + X.shape)
    Y = conv2d(X)
    # 省略前两个维度:批量大小和通道
    return Y.reshape(Y.shape[2:])

# 请注意,这里每边都填充了1行或1列,因此总共添加了2行或2列
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)
X = torch.rand(size=(8, 8))
comp_conv2d(conv2d, X).shape

'''
torch.Size([8, 8])
'''

当卷积核的高度和宽度不同时,我们可以填充不同的高度和宽度,使输出和输入具有相同的高度和宽度。在如下示例中,我们使用高度为5,宽度为3的卷积核,高度和宽度两边的填充分别为2和1。

conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape

'''
torch.Size([8, 8])
'''

3.2步幅

将每次滑动元素的数量称为步幅(stride)

  • 填充减小的输出大小与层数线性相关
    • 给定输入大小224×224,在使用5×5卷积核的情况下,需要44层将输出降低到4×4
    • 需要大量计算才能得到较小输出

image-20230717163314702

下面,我们将高度和宽度的步幅设置为2,从而将输入的高度和宽度减半。

conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape

'''
torch.Size([4, 4])
'''

一个稍微复杂的例子:

conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))
comp_conv2d(conv2d, X).shape

'''
torch.Size([2, 2])
'''

image-20230717163525337

总结:

  • 填充和步幅是卷积层的超参数
  • 填充在输入周围添加额外的行/列,来控制输出形状的减少量
  • 步幅是每次滑动核窗口时的行/列的步长,可以成倍的减少输出形状

4.多输入多输出通道

学习视频:卷积层里的多输入多输出通道【动手学深度学习v2】

官方笔记:多输入多输出通道

4.1多输入通道

  • 彩色图片可能有RGB三个通道
  • 转换为灰度会丢失信息

当我们添加通道时,我们的输入和隐藏的表示都变成了三维张量。例如,每个RGB输入图像具有3×ℎ×w的形状。我们将这个大小为3的轴称为通道(channel)维度

image-20230717165309576

image-20230717165319874

import torch
from d2l import torch as d2l

def corr2d_multi_in(X, K):
    # 先遍历“X”和“K”的第0个维度(通道维度),再把它们加在一起
    return sum(d2l.corr2d(x, k) for x, k in zip(X, K))

可以构造输入张量X和核张量K

X = torch.tensor([[[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]],
               [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]])
K = torch.tensor([[[0.0, 1.0], [2.0, 3.0]], [[1.0, 2.0], [3.0, 4.0]]])

corr2d_multi_in(X, K)


'''
tensor([[ 56.,  72.],
        [104., 120.]])
'''

4.2多输出通道

image-20230717164227127

image-20230717165547936

实现一个计算多个通道的输出的互相关函数

def corr2d_multi_in_out(X, K):
    # 迭代“K”的第0个维度,每次都对输入“X”执行互相关运算。
    # 最后将所有结果都叠加在一起
    return torch.stack([corr2d_multi_in(X, k) for k in K], 0)

通过将核张量KK+1K中每个元素加1)和K+2连接起来,构造了一个具有3个输出通道的卷积核

K = torch.stack((K, K + 1, K + 2), 0)
K.shape

'''
torch.Size([3, 2, 2, 2])
'''

下面,我们对输入张量X与卷积核张量K执行互相关运算。现在的输出包含3个通道,第一个通道的结果与先前输入张量X和多输入单输出通道的结果一致。

corr2d_multi_in_out(X, K)

'''
tensor([[[ 56.,  72.],
         [104., 120.]],

        [[ 76., 100.],
         [148., 172.]],

        [[ 96., 128.],
         [192., 224.]]])
'''

4.3 1×1卷积层

image-20230717165820939

下面,我们使用全连接层实现1×1卷积。 请注意,我们需要对输入和输出的数据形状进行调整

def corr2d_multi_in_out_1x1(X, K):
    c_i, h, w = X.shape
    c_o = K.shape[0]
    X = X.reshape((c_i, h * w))
    K = K.reshape((c_o, c_i))
    # 全连接层中的矩阵乘法
    Y = torch.matmul(K, X)
    return Y.reshape((c_o, h, w))

**当执行1×1卷积运算时,上述函数相当于先前实现的互相关函数corr2d_multi_in_out。**让我们用一些样本数据来验证这一点。

X = torch.normal(0, 1, (3, 3, 3))
K = torch.normal(0, 1, (2, 3, 1, 1))

Y1 = corr2d_multi_in_out_1x1(X, K)
Y2 = corr2d_multi_in_out(X, K)
assert float(torch.abs(Y1 - Y2).sum()) < 1e-6

完整的二维卷积层

image-20230717164536700

总结:

  • 输出通道数是卷积层的超参数
  • 每个输入通道有独立的二维卷积核,所有通道结果相加得到一个输出通道结果
  • 每个输出通道有独立的三维卷积核

5.池化层

学习视频:池化层【动手学深度学习v2】

官方笔记:汇聚层

通常当我们处理图像时,我们希望逐渐降低隐藏表示的空间分辨率、聚集信息,这样随着我们在神经网络中层叠的上升,每个神经元对其敏感的感受野(输入)就越大。

而我们的机器学习任务通常会跟全局图像的问题有关(例如,“图像是否包含一只猫呢?”),所以我们最后一层的神经元应该对整个输入的全局敏感。通过逐渐聚合信息,生成越来越粗糙的映射,最终实现学习全局表示的目标,同时将卷积图层的所有优势保留在中间层。

此外,当检测较底层的特征时,我们通常希望这些特征保持某种程度上的平移不变性。例如,如果我们拍摄黑白之间轮廓清晰的图像X,并将整个图像向右移动一个像素,即Z[i, j] = X[i, j + 1],则新图像Z的输出可能大不相同。而在现实中,随着拍摄角度的移动,任何物体几乎不可能发生在同一像素上。即使用三脚架拍摄一个静止的物体,由于快门的移动而引起的相机振动,可能会使所有物体左右移动一个像素(除了高端相机配备了特殊功能来解决这个问题)。

本节将介绍汇聚(pooling)层,它具有双重目的:降低卷积层对位置的敏感性,同时降低对空间降采样表示的敏感性。

5.1池化层

与卷积层类似,汇聚层运算符由一个固定形状的窗口组成,该窗口根据其步幅大小在输入的所有区域上滑动,为固定形状窗口(有时称为汇聚窗口)遍历的每个位置计算一个输出。 然而,不同于卷积层中的输入与卷积核之间的互相关计算,汇聚层不包含参数。 相反,池运算是确定性的,我们通常计算汇聚窗口中所有元素的最大值或平均值。这些操作分别称为最大汇聚层(maximum pooling)和平均汇聚层(average pooling)。

image-20230717171602873

回到本节开头提到的对象边缘检测示例,现在我们将使用卷积层的输出作为2×2最大汇聚的输入。 设置卷积层输入为X,汇聚层输出为Y。 无论X[i, j]X[i, j + 1]的值相同与否,或X[i, j + 1]X[i, j + 2]的值相同与否,汇聚层始终输出Y[i, j] = 1。 也就是说,使用2×2最大汇聚层,即使在高度或宽度上移动一个元素,卷积层仍然可以识别到模式。

下面的代码中的pool2d函数,我们实现汇聚层的前向传播, 然而,这里我们没有卷积核,输出为输入中每个区域的最大值或平均值。

import torch
from torch import nn
from d2l import torch as d2l

def pool2d(X, pool_size, mode='max'):
    p_h, p_w = pool_size
    Y = torch.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))
    for i in range(Y.shape[0]):
        for j in range(Y.shape[1]):
            if mode == 'max':
                Y[i, j] = X[i: i + p_h, j: j + p_w].max()
            elif mode == 'avg':
                Y[i, j] = X[i: i + p_h, j: j + p_w].mean()
    return Y

构建输入张量X,验证二维最大汇聚层的输出。

X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
pool2d(X, (2, 2))

'''
tensor([[4., 5.],
        [7., 8.]])
'''

验证平均池化层

pool2d(X, (2, 2), 'avg')

'''
tensor([[2., 3.],
        [5., 6.]])
'''

image-20230717170811478

总结:

  • 池化层返回窗口中最大或平均值
  • 缓解卷积层会位置的敏感性
  • 同样有窗口大小、填充和步幅作为超参数

5.2填充和步幅

与卷积层一样,池化层也可以改变输出形状。和以前一样,我们可以通过填充和步幅以获得所需的输出形状。 下面,我们用深度学习框架中内置的二维最大池化层,来演示池化层中填充和步幅的使用。 我们首先构造了一个输入张量X,它有四个维度,其中样本数和通道数都是1。

X = torch.arange(16, dtype=torch.float32).reshape((1, 1, 4, 4))
X

'''
tensor([[[[ 0.,  1.,  2.,  3.],
          [ 4.,  5.,  6.,  7.],
          [ 8.,  9., 10., 11.],
          [12., 13., 14., 15.]]]])
'''

默认情况下,深度学习框架中的步幅与池化窗口的大小相同。 因此,如果我们使用形状为(3, 3)的池化窗口,那么默认情况下,我们得到的步幅形状为(3, 3)

pool2d = nn.MaxPool2d(3)
pool2d(X)

'''
tensor([[[[10.]]]])
'''

填充和步幅可以手动设定。

pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)

我们可以设定一个任意大小的矩形池化窗口,并分别设定填充和步幅的高度和宽度。

pool2d = nn.MaxPool2d((2, 3), stride=(2, 3), padding=(0, 1))
pool2d(X)

'''
tensor([[[[ 5.,  7.],
          [13., 15.]]]])
'''

5.3多个通道

在处理多通道输入数据时,池化层在每个输入通道上单独运算,而不是像卷积层一样在通道上对输入进行汇总。 这意味着池化层的输出通道数与输入通道数相同。 下面,我们将在通道维度上连结张量XX + 1,以构建具有2个通道的输入。

X = torch.cat((X, X + 1), 1)
X

'''
tensor([[[[ 0.,  1.,  2.,  3.],
          [ 4.,  5.,  6.,  7.],
          [ 8.,  9., 10., 11.],
          [12., 13., 14., 15.]],

         [[ 1.,  2.,  3.,  4.],
          [ 5.,  6.,  7.,  8.],
          [ 9., 10., 11., 12.],
          [13., 14., 15., 16.]]]])

'''

如下所示,池化后输出通道的数量仍然是2。

pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)

'''
tensor([[[[ 5.,  7.],
          [13., 15.]],

         [[ 6.,  8.],
          [14., 16.]]]])s
'''

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

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

相关文章

设计准则必备:学习UI设计规范的五大黄金法则

看到好看的设计&#xff0c;随手保存起来&#xff0c;这是设计师的基本习惯。但是如果只是好看&#xff0c;并不能驱使受众真正去了解产品。如果想要用户动心&#xff0c;还是需要了解一些设计心理学&#xff0c;从用户心理去引导用户行为。今天给大家分享一些常用的设计法则帮…

对话网易伏羲赵增:开源VS自研?哪条路是通向AIGC的捷径?|WAIC2023

点击关注 文 | 郝鑫、黄小艺 从去年底到现在&#xff0c;国内外肉眼可见地涌现出了一批文生图公司&#xff0c;这背后与基础架构开源有很大关系。 2022年8月&#xff0c;Stability.AI在GitHub上公开开源了Stable Diffusion模型的代码和训练数据集&#xff1b;当月底&#xf…

linux系统编程-文件系统

目录 1文件存储 1.1 inode 1.2 dentry 2.文件系统 2.1 stat函数 2.2 lstat函数 2.3特殊权限位、黏住位 2.4 access函数 2.5 chmod函数 2.6 truncate函数 2.7 link函数 2.8 unlink函数、 2.9 隐式回收 2.10 symlink函数 2.11 readlink函数 2.12 rename函数 2.1…

Java 常用的重构技巧指南 v1.0

前段时间&#xff0c;leader 在 review 代码的时候发现了代码中 存在的一部分的问题&#xff0c;导致 代码的复杂度太高了&#xff0c;包括大部分的sql 都是属于慢sql &#xff0c;还是在建立了索引的情况下 , 代码的流程过于臃肿&#xff0c;而且本人编码的习惯&#xff0c;习…

Mybatis-Plus(一)--Mybatis-Plus介绍与快速入门

阅读这篇文章之前确保你已经学过springboot和mybatis 一.Mybtis-Plus介绍 【1】Mybatis-Puls&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发&#xff0c;提高效率而生。 简单说就是其实很多sql语…

IntelliJ IDEA下载安装教程

目录 友情提醒第一章、IDEA软件下载1.1&#xff09;官网下载 第二章、IDEA软件安装2.1&#xff09;以"ideaIU-2018.3.3.exe"为例3.2&#xff09;启动IDEA软件 友情提醒 点击文章目录可以跳转 第一章、IDEA软件下载 IDEA 全称 IntelliJ IDEA。在智能代码助手、代码…

字节跳动春招研发部分编程题汇总

状压dp(不会) http://t.csdn.cn/W9Pi2 #include <iostream> #include<string.h> #include<math.h> using namespace std; char a[1005]; char c[1005]; int main() {int n;scanf("%d",&n);for(int i1;i<n;i){scanf("%s",a);int l…

Pytorch学习笔记(1)

目录 1. 张量&#xff08;Tensors&#xff09; 2. 自动求导&#xff08;Automatic Differentiation&#xff09; 3. 神经网络的构建和训练 送书活动 PyTorch是一个基于Python的开源机器学习库&#xff0c;广泛应用于深度学习和人工智能领域。它提供了丰富的工具和函数&…

什么是域服务(NETBASE第十一课)

域服务(NETBASE第十一课) web虚拟主机(一台服务器运行多个WEB站点) Web虚拟主机的实现方法&#xff1a; 1&#xff09;同IP不同端口&#xff08;基于端口的虚拟主机&#xff09; 2&#xff09;同端不同IP&#xff08;基于IP的虚拟主机&#xff09; 3&#xff09;同端口同I…

使用typora+PicGo+Gitee简单实现图片上传功能

本文通过配置PicGoGitee来实现typora图片上传功能&#xff0c;系统是window 注意下载的清单有&#xff1a;PicGo&#xff0c;node.js&#xff0c;配置有&#xff1a;PicGo&#xff0c;node.js&#xff0c;gitee&#xff0c;typora 看着复杂实际上并不难&#xff0c;只是繁琐&am…

OLLVM虚假控制流源码分析

文章目录 runOnFunction函数bogus函数目前源码&#xff1a;addBogusFlow函数1createAlteredBasicBlock函数原基本块&#xff1a;copy的基本块&#xff1a; addBogusFlow函数2 runOnFunction函数 if (ObfTimes < 0) {errs()<<"BogusControlFlow application numb…

缓存淘汰策略

LRU 与 LFU 缓存策略及其实现。 应用层缓存 鉴于磁盘和内存读写的差异性&#xff0c;DB 中低频写、高频读的数据适合放入内存中&#xff0c;直接供应用层读写。在项目中读取用户资料时就使用到了 LRU&#xff0c;而非放到 Redis 中。 缓存的 2 个基本实现 Set(key string, v…

RandLA-Net 复现

GPU3090 CUDA12 1、代码 [github地址] git clone --depth1 https://github.com/QingyongHu/RandLA-Net && cd RandLA-Net 2、虚拟环境中配置&#xff1a; 在跑代码的时候出现错误&#xff1a;open3d.so文件中函数报错。查看open3d版本发现不是要求的0.3版本&#xff…

基于PyQt5的UI界面开发——信号与槽

信号与槽的机制 PyQt5采用了一种被称为“信号与槽”机制的编程模式&#xff0c;用于处理对象间的通信和事件处理。在PyQt5中&#xff0c;信号&#xff08;signal&#xff09;是对象发出的特定事件&#xff0c;例如按钮被点击、文本被修改等。而槽&#xff08;slot&#xff09;…

攻不下dfs不参加比赛(十七)

标题 为什么练dfs题目为什么练dfs 相信学过数据结构的朋友都知道dfs(深度优先搜索)是里面相当重要的一种搜索算法,可能直接说大家感受不到有条件的大家可以去看看一些算法比赛。这些比赛中每一届或多或少都会牵扯到dfs,可能提到dfs大家都知道但是我们为了避免眼高手低有的东…

WooCommerce企业级电子商务需要了解的事情

建立成功的企业业务变得比以往任何时候都容易得多。借助各种可用的平台&#xff0c;将您的想法付诸实践是绝对可行的。 “WooCommerce 是最知名的 WordPress 网站电子商务平台之一。” 它于 2011 年推出&#xff0c;自此受到大型和小型企业的欢迎。它的流行主要归功于其各种免费…

【接口流程分析】唯品会WEB端

唯品会WEB端 来看看唯品会是怎么回事&#xff0c; 地址&#xff1a;aHR0cHM6Ly93d3cudmlwLmNvbS8 https://github.com/Guapisansan/gpss_learn_reverse 代码在这里&#xff0c;会持续更新逆向案例 免责声明&#xff1a; 此文档&#xff0c;以及脚本&#xff0c;仅用来对技术的…

七年老程序员的五六月总结:十一件有意义的事

你好&#xff0c;我是拭心&#xff0c;一名工作七年的安卓开发。 每两个月我会做一次总结&#xff0c;记下这段时间里有意义的事和值得反复看的内容&#xff0c;为的是留一些回忆、评估自己的行为、沉淀有价值的信息。 最近两周的我一直处于“战斗“状态&#xff0c;同时做好…

未来驾驶新标配;CarLuncher车载开发塑造智能娱乐导航系统

车载开发在新能源汽车的快速市场占有率增长背景下具有广阔的前景。随着环境保护意识的增强和政府对清洁能源的支持&#xff0c;新能源汽车&#xff08;如电动汽车&#xff09;在全球范围内呈现出快速增长的趋势。这种趋势为车载开发提供了许多机会和潜在市场。 新能源汽车的普…

一文搞定 Postman 接口自动化测试(全网最全版)

0 前言 本文适合已经掌握 Postman 基本用法的读者&#xff0c;即对接口相关概念有一定了解、已经会使用 Postman 进行模拟请求等基本操作。 工作环境与版本&#xff1a; Window 7&#xff08;64位&#xff09;Postman &#xff08;Chrome App v5.5.3&#xff09; P.S. 不同…