空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)

这篇具有很好参考价值的文章主要介绍了空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 空洞卷积的介绍

空洞卷积(Atrous Convolution)又名膨胀卷积(Dilated Convolution)。

dilated 英[daɪˈleɪtɪd][daɪˈleɪtɪd]
v. 扩大; (使)膨胀,扩张;
[词典] dilate的过去分词和过去式;

atrous
adj. 深黑的; 暗灰色的; 纯黑色的;

1.1 空洞卷积和普通卷积的对比

下面是普通的卷积:
空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)

kernel_size=3, stride=1, padding=0

下面是空洞卷积:
空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)

kernel_size = 3, dilated_ratio = 2, stride = 1, padding = 0

二者的卷积核大小都是一样的(滑窗的实际大小是一样的),但空洞卷积的滑窗(kernel)元素之间是存在一些间隙的,这些间隙在空洞卷积中成为膨胀因子(dilated ratio)。

如果 dilated ratio=1 时,空洞卷积就是普通卷积。

1.2 膨胀卷积的作用

  1. 增大感受野
  2. 保持原输入特征图的高度和宽度

上面的膨胀卷积示意图中,因为没有设置padding,所以特征图变小了。而在实际使用中,一般都会对padding进行设置(将padding设置为1),这样就能保证输入特征图的高度和宽度不变

1.3 为什么要使用膨胀卷积

在语义分割中,通常会使用分类网络作为backbone通过backbone之后会对特征图进行一系列的下采样,之后再进行一系列的上采样还原原图的大小。流程如下图所示:

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)

在分类网络中,一般都会对图片的高度和宽度下采样 32 倍。由于后续需要通过上采样还原到原来的尺寸,所以如果下采样的倍率很大时,使用上采样还原回原来的尺寸,这个过程就是导致比较严重的信息丢失。


以 VGG16 为例,该网络通过 MaxPooling 层对特征图进行下采样:

  • 通过 MaxPooling 会降低特征图的 shape
  • MaxPooling 会丢失特征图的一些细节信息(毕竟是用最大值代替局部值,丢失信息是肯定的)
  • 丢失的信息和目标是无法通过上采样进行还原的

这就导致在语义分割任务的效果不理想。


思考
Q1:既然MaxPooling会损失信息,那么直接不用MaxPooling不就行了?
A1:如果我们简单粗暴地将MaxPooling去掉的话,会引入新的问题:

  • 特征图对应原图的感受野变小了
  • 为后面的卷积层带来影响(感受野不变,卷积层就无法获取深层的信息)

此时,膨胀卷积就可以解决上面的问题,因为膨胀卷积:

  • 增大特征图的感受野
  • 保证输入输出特征图的shape不变

Q2:既然膨胀卷积有这样的好处,那我们是否可以简单粗暴地堆叠膨胀卷积层呢?
A2:很明显,不行!

2. gridding effect问题

在膨胀卷积使用的过程中经常会遇到一个名叫 gridding effect 的问题。

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)

2. 1 什么是gridding effect —— 连续使用几个膨胀系数相同的膨胀卷积

如下图所示,连续使用3个膨胀卷积层(卷积核大小都为3×3,膨胀系数均为2
空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)


我们先看一下 Layer2 上,每一个pixel利用到了 Layer1 上的哪些pixels。

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
我们可以看到,膨胀系数是2表示卷积核每两个数据之间都间隔一行或一列0

所以Layer2 上一个pixels会使用Layer1的9个pixels。


我们再看一下Layer3
空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
当我们连续使用2个膨胀系数为2的膨胀卷积时,Layer3上一个pixel利用到了Layer1上25个pixels的信息。

每个pixel上的数字表示:通过累加得到Layer3上一个pixel利用到Layer1上该像素的次数


看一下Layer4

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
当我们连续使用3个膨胀系数为2的膨胀卷积时,Layer4上一个pixel利用到了Layer1上的数据并不是连续的!在每个非零元素之间都存在一定的间隔 —— 这就是gridding effect现象。

也就是说Layer4上的一个像素并没有利用到范围内的所有像素值,而是一部分。

因为没有利用到所有的像素值,所以一定会丢失一部分细节信息 —— 和MaxPooling一样(但是比MaxPooling要轻微)

所以在使用膨胀卷积时要尽可能避免 gridding effect 问题(不要连续使用多个膨胀系数相同的膨胀卷积)

2.2 连续使用几个膨胀系数不同的膨胀卷积

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
膨胀系数设置为1就是普通的卷积


看一下Layer2:

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
因为是普通卷积,所以利用到了卷积核大小窗口内所有Layer1的像素。


看一下Layer3:

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
Layer3上的一个像素对应Layer1上7×7的区域,而且该区域中每一个像素的利用次数不同(但都利用到了


看一下Layer4:

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
Layer4上的一个像素对应Layer1上13×13的区域,而且该区域中每一个像素的利用次数不同(但都利用到了

2.3 两种使用方法的对比

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)

  • 两种方法的参数数量是一样的
  • 仅仅是膨胀系数不同而已

对于 r=[2, 2, 2] 这样连续相同的膨胀卷积来说,Layer4的感受野是13×13,但在这个视野下有很多像素值是没有利用到的。我们更加倾向于使用 r=[1, 2, 3] 这样不相同连续的膨胀系数 —— 感受野下使用的区域是连续的。

2.4 如果全部使用普通的卷积

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
我们发现:

  • 直接使用普通卷积Layer4的感受野和前面的两种膨胀卷积不同
    • 膨胀卷积的感受野为 13×13
    • 普通卷积的感受野为 7×7
  • 这说明使用膨胀卷积可以大幅度增加感受野

3. 膨胀卷积使用方法 —— Hybird Dilated Convolution (HDC,混合膨胀卷积)

上面我们讲到,如果我们连续使用多个膨胀系数相同的膨胀卷积时,就会遇到 gridding effect 问题,所以我们建议连续使用多个膨胀系数不同的膨胀卷积。但这样的说法并没有给我一个明确的设计原则,所以接下来讲一下,如果我们想要连续使用多个膨胀卷积时,应该如何设计它们的膨胀系数。

3.1 论文中第一个建议: M 2 ≤ K M_2 \le K M2​≤K

通过 2.2 和 2.3 的实验可以得出:使用 r=[1, 2, 3] 的膨胀系数和使用 r=[2, 2, 2] 膨胀系数的感受野是相同的,但前者对于输入信息的利用率高 —— 理论效果更好。

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)

假设我们连续堆叠 N N N个膨胀卷积(它的 kernel_size 都是等于 K × K K \times K K×K 的),每个膨胀卷积的膨胀系数分别对应 [ r 1 , r 2 , . . . , r n ] [r_1, r_2, ..., r_n] [r1,r2,...,rn]。那 HDC 的目标是通过一系列膨胀卷积之后可以完全覆盖底层特征层的方形区域,并且该方形区域中间是没有任何孔洞或缺失的边缘(withou any holes or missing edges)。作者定义了一个叫做"maximum distance between two nonzero values"的公式,即两个非零元素之间最大的距离

需要注意的是,在计算距离的时候需要+1。举个例子,A→B假设有两行的0元素,那么它们直接的距离就是3,而非2)

公式定义如下

M i = max ⁡ [ M i + 1 − 2 r i , M i + 1 − 2 ( M i + 1 − r i ) , r i ] = max ⁡ [ M i + 1 − 2 r i , 2 r i − M i + 1 , r i ] = max ⁡ [ 正 , 负 , r i ] \begin{aligned} M_i & = \max [M_{i+1} - 2r_i, M_{i+1} - 2(M_{i+1} - r_i), r_i] \\ & = \max[M_{i+1} - 2r_i, 2r_i - M_{i+1}, r_i] \\ & = \max[正, 负, r_i] \end{aligned} Mi=max[Mi+12ri,Mi+12(Mi+1ri),ri]=max[Mi+12ri,2riMi+1,ri]=max[,,ri]

其中:

  • M i M_i Mi 是第 i i i 层两个非零元素之间的最大距离;
  • r i r_i ri 为第 i i i 层的膨胀系数;
  • 对于最后一层,它的最大距离为 M n = r n M_n = r_n Mn=rn,即最大距离为该层的膨胀率

这么设计的目的是让 M 2 ≤ K M_2 \le K M2K,即 第二层的两个非零元素之间的最大距离 ≤ 该层卷积核的大小

需要注意的是:

  • 紧密挨着的距离为 1
  • r=[2, 2, 2] 中那样,两个非零元素之间的距离为2 —— 意味着二者之间间隔了一行或者一列。

3.2 针对第一个建议给出的两个例子

3.2.1 例子1

kernel_size=3,即 K = 3 K=3 K=3 时,对于膨胀系数 r = [ 1 , 2 , 5 ] r=[1, 2, 5] r=[1,2,5] 来说:

M 2 = max ⁡ [ M i + 1 − 2 r i , M i + 1 − 2 ( M i + 1 − r i ) , r i ] = max ⁡ [ M 3 − 2 r 2 , M 3 − 2 ( M 3 − r 2 ) , r 2 ] = max ⁡ [ 5 − 4 , 4 − 5 , 2 ] = max ⁡ [ 1 , − 1 , 2 ] = 2 ≤ K ( 3 ) \begin{aligned} M_2 & = \max [M_{i+1} - 2r_i, M_{i+1} - 2(M_{i+1} - r_i), r_i]\\ & = \max [M_3 - 2r_2, M_3 - 2(M_3 - r_2), r_2]\\ & = \max [5-4, 4-5, 2]\\ & = \max [1, -1, 2]\\ & =2 \le K(3) \end{aligned} M2=max[Mi+12ri,Mi+12(Mi+1ri),ri]=max[M32r2,M32(M3r2),r2]=max[54,45,2]=max[1,1,2]=2K(3)

因为 M 2 ≤ K M_2 \le K M2K,所以当 kernel_size=3时,选择 r=[1, 2, 5] 是满足设计要求的。

3.2.2 例子2

kernel_size=3,即 K = 3 K=3 K=3,对于膨胀系数 r = [ 1 , 2 , 9 ] r=[1, 2, 9] r=[1,2,9] 来说:

M 2 = max ⁡ [ M i + 1 − 2 r i , M i + 1 − 2 ( M i + 1 − r i ) , r i ] = max ⁡ [ M 3 − 2 r 2 , M 3 − 2 ( M 3 − r 2 ) , r 2 ] = max ⁡ [ 9 − 4 , 4 − 9 , 2 ] = max ⁡ [ 5 , − 5 , 2 ] = 5 ≥ K ( 3 ) \begin{aligned} M_2 & = \max [M_{i+1} - 2r_i, M_{i+1} - 2(M_{i+1} - r_i), r_i]\\ & = \max [M_3 - 2r_2, M_3 - 2(M_3 - r_2), r_2]\\ & = \max [9 - 4, 4-9, 2]\\ & = \max [5, -5, 2]\\ & = 5 \ge K(3) \end{aligned} M2=max[Mi+12ri,Mi+12(Mi+1ri),ri]=max[M32r2,M32(M3r2),r2]=max[94,49,2]=max[5,5,2]=5K(3)

因为 M 2 > K M_2 > K M2>K,所以不满足设计要求,所以这组参数是不合适的。

3.2.3 ⭐️使用代码直观展示元素间的最大距离

代码如下:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap


def dilated_conv_one_pixel(center: (int, int),
                           feature_map: np.ndarray,
                           k: int = 3,
                           r: int = 1,
                           v: int = 1):
    """
    膨胀卷积核中心在指定坐标center处时,统计哪些像素被利用到,
    并在利用到的像素位置处加上增量v
    Args:
        center: 膨胀卷积核中心的坐标
        feature_map: 记录每个像素使用次数的特征图
        k: 膨胀卷积核的kernel大小
        r: 膨胀卷积的dilation rate
        v: 使用次数增量
    """
    assert divmod(3, 2)[1] == 1

    # left-top: (x, y)
    left_top = (center[0] - ((k - 1) // 2) * r, center[1] - ((k - 1) // 2) * r)
    for i in range(k):
        for j in range(k):
            feature_map[left_top[1] + i * r][left_top[0] + j * r] += v


def dilated_conv_all_map(dilated_map: np.ndarray,
                         k: int = 3,
                         r: int = 1):
    """
    根据输出特征矩阵中哪些像素被使用以及使用次数,
    配合膨胀卷积k和r计算输入特征矩阵哪些像素被使用以及使用次数
    Args:
        dilated_map: 记录输出特征矩阵中每个像素被使用次数的特征图
        k: 膨胀卷积核的kernel大小
        r: 膨胀卷积的dilation rate
    """
    new_map = np.zeros_like(dilated_map)
    for i in range(dilated_map.shape[0]):
        for j in range(dilated_map.shape[1]):
            if dilated_map[i][j] > 0:
                dilated_conv_one_pixel((j, i), new_map, k=k, r=r, v=dilated_map[i][j])

    return new_map


def plot_map(matrix: np.ndarray):
    plt.figure()

    c_list = ['white', 'blue', 'red']
    new_cmp = LinearSegmentedColormap.from_list('chaos', c_list)
    plt.imshow(matrix, cmap=new_cmp)

    ax = plt.gca()
    ax.set_xticks(np.arange(-0.5, matrix.shape[1], 1), minor=True)
    ax.set_yticks(np.arange(-0.5, matrix.shape[0], 1), minor=True)

    # 显示color bar
    plt.colorbar()

    # 在图中标注数量
    thresh = 5
    for x in range(matrix.shape[1]):
        for y in range(matrix.shape[0]):
            # 注意这里的matrix[y, x]不是matrix[x, y]
            info = int(matrix[y, x])
            ax.text(x, y, info,
                    verticalalignment='center',
                    horizontalalignment='center',
                    color="white" if info > thresh else "black")
    ax.grid(which='minor', color='black', linestyle='-', linewidth=1.5)
    plt.show()
    plt.close()


def main():
    # bottom to top
    dilated_rates = [1, 2, 5]
    # init feature map
    size = 31
    m = np.zeros(shape=(size, size), dtype=np.int32)
    center = size // 2
    m[center][center] = 1
    # print(m)
    # plot_map(m)

    for index, dilated_r in enumerate(dilated_rates[::-1]):
        new_map = dilated_conv_all_map(m, r=dilated_r)
        m = new_map
    print(m)
    plot_map(m)


if __name__ == '__main__':
    main()
3.2.3.1 r = [1, 2, 5] 的效果图

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
很明显,这组参数最后一层的感受野包含了所有像素,输入的每一个像素都利用到了,不存在gridding effect问题。

3.2.3.2 r = [1, 2, 9] 的效果图

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
这里并不是有9个感受野,实际上这9个小块合起来才是真正的感受野。很明显,两个小块之间非零元素的最大距离为3,这与我们的期望1不符,所以该组参数是不合适的。

3.3 为什么例子中的 r r r 都是从 1 开始的?

我们希望在高层特征图的每个像素可以利用到底层特征图的感受野内的所有像素,那么 M 1 M_1 M1应该等于1。因为 M 1 = 1 M_1 = 1 M1=1意味着非零元素之间是相邻的(没有间隙的),而 M 1 M_1 M1的计算公式如下:

M 1 = max ⁡ [ M 2 − 2 r 1 , M 2 − 2 ( M 2 − r 1 ) , r 1 ] = max ⁡ [ M 2 − 2 r 1 , 2 r 1 − M 2 , r 1 ] = max ⁡ [ 正 , 负 , r 1 ] \begin{aligned} M_1 & = \max [M_{2} - 2r_1, M_{2} - 2(M_{2} - r_1), r_1] \\ & = \max[M_{2} - 2r_1, 2r_1 - M_{2}, r_1] \\ & = \max[正, 负, r_1] \end{aligned} M1=max[M22r1,M22(M2r1),r1]=max[M22r1,2r1M2,r1]=max[,,r1]

既然我们希望 M 1 = 1 M_1 = 1 M1=1,那么 M 1 M_1 M1 应该 ≥ r 1 \ge r_1 r1,即 1 ≥ r 1 1 \ge r_1 1r1,所以 r 1 r_1 r1被迫等于1。因此在设计连续膨胀卷积时,第一个膨胀率一般都是从1开始的

3.4 论文中第二个建议:将膨胀系数设置为锯齿形状

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
第二个建议为:将膨胀系数设置为锯齿形状。如:r=[1, 2, 3, 1, 2, 3]

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)

3.4 论文中第三个建议: r r r 的公约数 ≤ 1

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)
论文中的第三个建议:公约数不能大于1。如:

  • r = [ 1 , 2 , 3 ] r = [1, 2, 3] r=[1,2,3]:它们的公约数为 1 1 1,符合①②③建议 → 设计合理
  • r = [ 2 , 4 , 8 ] r=[2, 4, 8] r=[2,4,8]:它们的公约数为 2 2 2,不符合③的建议 → 设计不合理

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)

4. 遵循HDC原则前后效果对比

空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)

  • 没有按照HDC设计准则的模型(第二行),它分割的效果不是很好
  • 符合HDC设计准则的模型(第三行)相比第二行来说,效果要层好不少。

5. 膨胀卷积输出特征图计算公式

5.1 普通卷积

O i c o n v / p o o l = O i i n + 2 p i − k i s i + 1 O_i^{\mathrm{conv/pool}} = \frac{O_i^{\mathrm{in}} + 2p_i - k_i}{s_i} + 1 Oiconv/pool=siOiin+2piki+1

5.2 膨胀卷积

O i d i l a t e d   c o n v = O i i n + 2 p i − d i × ( k i − 1 ) s i + 1 O_i^{\mathrm{dilated \ conv}} = \frac{O_i^{\mathrm{in}} + 2p_i - d_i \times (k_i-1)}{s_i} + 1 Oidilated conv=siOiin+2pidi×(ki1)+1

5.3 转置卷积

5.3.1 不带膨胀卷积

O i t r a n s   c o n v = ( O i i n − 1 ) × s i − 2 × p i + k i O_i^{\mathrm{trans \ conv}} = (O_i^{\mathrm{in}} - 1) \times s_i - 2 \times p_i + k_i Oitrans conv=(Oiin1)×si2×pi+ki

5.3.2 带有膨胀卷积

O i t r a n s   c o n v = ( O i i n − 1 ) × s i − 2 × p i + d i × ( k i − 1 ) + output_padding i + 1 O_i^{\mathrm{trans \ conv}} = (O_i^{\mathrm{in}} - 1) \times s_i - 2 \times p_i + d_i \times (k_i - 1) + \text{output\_padding}_i + 1 Oitrans conv=(Oiin1)×si2×pi+di×(ki1)+output_paddingi+1

6. 总结

6.1 设计准则

  1. 第二层的两个非零元素之间的最大距离小于等于该层卷积核的大小,即 M 2 ≤ K M_2 \le K M2K
    其中 M i = max ⁡ [ M i + 1 − 2 r i , 负 , r i ] M_i = \max [M_{i+1} - 2r_i, 负, r_i] Mi=max[Mi+12ri,,ri]
  2. 将膨胀系数设置为锯齿形状。如:r=[1, 2, 3, 1, 2, 3]
  3. 膨胀系数的公约数 ≤ 1,如:采用 r=[1, 2, 3] 而不是 r=[2, 4, 6]

6.2 实际使用

在连续使用膨胀卷积时,我们应该参考 HDC 的设计准则以保证高层可以有效利用低层的信息。文章来源地址https://www.toymoban.com/news/detail-445504.html

参考

  1. https://www.bilibili.com/video/BV1Bf4y1g7j8?spm_id_from=333.999.0.0
  2. https://github.com/vdumoulin/conv_arithmetic

到了这里,关于空洞卷积(膨胀卷积)的相关知识以及使用建议(HDC原则)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • YOLOV7改进-空洞卷积+共享权重的Scale-Aware RFE

    代码 1、先把文件复制到common.py中 2、yolo.py添加类名 3、下半部分进行添加修改 4、cfg-training:新建配置文件 加了一行,后面对于序号+1 5、这里选择12层替代

    2024年02月09日
    浏览(43)
  • 目标检测算法——YOLOv5/YOLOv7改进之结合​ASPP(空洞空间卷积池化金字塔)

    首先要介绍 Atrous Convolution(空洞卷积) ,它是一种增加感受野的方法。 空洞卷积 和普通的卷积操作不同的地方在于卷积核中按照一定的规律插入了一些(rate-1)为零的值,使得感受野增加,而无需通过减小图像大小来增加感受野。 空洞空间卷积池化金字塔(Atrous Spatial Pyram

    2023年04月15日
    浏览(48)
  • Ribbon基础知识以及相关配置

    1、什么是Ribbon Ribbon 是 Netflix 发布的一个负载均衡器,有助于控制HTTP和TCP客户端行为在 SpringCloud 中,Nacos一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从Nacos中读取到的服务信息,在调用服务节点提供的服务时,会合理的进行负载。 在SpringCloud中可以

    2024年02月10日
    浏览(49)
  • linux相关知识以及有关指令3

    在linux中文件大致分为以下几类: -:普通文件,源代码,可执行程序,库等等。 d:目录文件 c:字符设备文件,键盘,显示器 b:块设备文件 l:链接文件 p:管道文件 上面的字母是各类文件的表示他们位于这个位置: 我们可以看到在linux中文件的前面有很多属性而位于最前

    2024年02月07日
    浏览(37)
  • MinIO与MySQL对比以及存储的相关知识

    看了一些文章,也没有特别清晰的理解面向对象存储。我发现中文网站上并没有人去对比的写MinIO和MySQL的不同,可能大家觉得这俩根本没必要对比吧。这篇文章会对比MinIO与MySQL,能更直观的理解面向对象存储。(以下内能很多都是按自己的理解,可能有错误,如有错误,请

    2024年02月02日
    浏览(43)
  • git如何忽略指定文件以及gitignore相关知识

    文章概要 :本文主要介绍了git中如何忽略指定文件,包括已经commit了的文件。解释了gitignore文件的写法以及提供了常见的gitignore模版。 本文内容来自:谷流仓AI - ai.guliucang.com 在平常写代码使用git的过程中,我们项目有些文件是不适合提交到仓库的,因此需要让git忽略这些文

    2024年04月25日
    浏览(43)
  • Docker的相关知识介绍以及mac环境的安装

    大型项目组件较多,运行环境也较为复杂,部署时会碰到一些问题: 依赖关系复杂,容易出现兼容性问题 开发、测试、生产环境有差异 Docker就是来解决这些问题的。Docker是一个快速交付应用、运行应用的技术:可以将程序及其依赖、运行环境一起打包为一个镜像,可以迁移

    2024年02月05日
    浏览(39)
  • 深入理解前端字节二进制知识以及相关API

    当前,前端对二进制数据有许多的API可以使用,这丰富了前端对文件数据的处理能力,有了这些能力,就能够对图片等文件的数据进行各种处理。 本文将着重介绍一些前端二进制数据处理相关的API知识,如Blob、File、FileReader、ArrayBuffer、TypeArray、DataView等等。 在介绍各种API之

    2024年02月03日
    浏览(44)
  • 推荐系统[一]:超详细知识介绍,一份完整的入门指南,解答推荐系统相关算法流程、衡量指标和应用,以及如何使用jieba分词库进行相似推荐,业界广告推荐技术最新进展

    搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目

    2024年02月13日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包