Einstein Summation 爱因斯坦求和 torch.einsum

Einstein Summation 爱因斯坦求和 torch.einsum

flyfish

理解爱因斯坦求和的基本概念和语法,这对初学者来说可能有一定难度。对于不熟悉该表示法的用户来说,可能不如直接的矩阵乘法表达式易于理解。

整个思路是

向量的点积 -》矩阵乘法-》einsum

向量之间的点积在几何上表示两个向量的投影和夹角,在代数上用于衡量向量的相似性,并且在物理学中用于计算力做的功。
矩阵乘法是由多个向量点积组成的,可以看作是多个向量点积的组合
einsum 操作可以用其他内置的矩阵运算函数来实现

使用 einsum 进行矩阵乘法

import torch# 定义两个矩阵
A = torch.randn(2, 3)
B = torch.randn(3, 4)# 使用 einsum 表示矩阵乘法
C = torch.einsum('ik,kj->ij', A, B)
print(C)
使用 matmul 进行矩阵乘法
import torch# 定义两个矩阵
A = torch.randn(2, 3)
B = torch.randn(3, 4)# 使用 matmul 表示矩阵乘法
C = torch.matmul(A, B)
print(C)

开始解释

向量之间的点积(也称为内积或标量积)在数学、物理学和计算中有着重要的意义。点积是两个向量乘积的一种特殊形式,其结果是一个标量。点积在许多领域中都有广泛的应用,包括向量的投影、计算角度、物理学中的功、机器学习中的相似性度量等。

点积的定义

给定两个n维向量 a \mathbf{a} a b \mathbf{b} b,它们的点积定义如下:
a ⋅ b = ∑ i = 1 n a i b i \mathbf{a} \cdot \mathbf{b} = \sum_{i=1}^{n} a_i b_i ab=i=1naibi

点积的几何意义

  1. 计算向量间的夹角
    点积可以用来计算两个向量之间的夹角 θ \theta θ。根据点积的定义,可以得到:
    a ⋅ b = ∥ a ∥ ∥ b ∥ cos ⁡ ( θ ) \mathbf{a} \cdot \mathbf{b} = \|\mathbf{a}\| \|\mathbf{b}\| \cos(\theta) ab=a∥∥bcos(θ)
    其中 ∥ a ∥ \|\mathbf{a}\| a ∥ b ∥ \|\mathbf{b}\| b 分别是向量 a \mathbf{a} a b \mathbf{b} b 的模(或长度)。因此,可以通过点积计算两个向量之间的夹角:
    cos ⁡ ( θ ) = a ⋅ b ∥ a ∥ ∥ b ∥ \cos(\theta) = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{a}\| \|\mathbf{b}\|} cos(θ)=a∥∥bab
  2. 投影
    点积可以用来计算一个向量在另一个向量方向上的投影。例如,向量 a \mathbf{a} a 在向量 b \mathbf{b} b 方向上的投影长度为:
    proj b a = a ⋅ b ∥ b ∥ \text{proj}_{\mathbf{b}} \mathbf{a} = \frac{\mathbf{a} \cdot \mathbf{b}}{\|\mathbf{b}\|} projba=bab

点积的代数意义

  1. 向量相似性
    在机器学习和数据分析中,点积可以用来衡量两个向量之间的相似性。如果两个向量的方向相同,它们的点积为正;如果两个向量的方向相反,它们的点积为负;如果两个向量正交,它们的点积为零。
  2. 功的计算
    在物理学中,点积用于计算力和位移的乘积,即功。例如,如果一个物体在力 F \mathbf{F} F 的作用下移动了位移 d \mathbf{d} d,则做的功为:
    W = F ⋅ d W = \mathbf{F} \cdot \mathbf{d} W=Fd

例子

计算两个二维向量的点积

假设 a = [ a 1 , a 2 ] \mathbf{a} = [a_1, a_2] a=[a1,a2] b = [ b 1 , b 2 ] \mathbf{b} = [b_1, b_2] b=[b1,b2],它们的点积为:
a ⋅ b = a 1 b 1 + a 2 b 2 \mathbf{a} \cdot \mathbf{b} = a_1 b_1 + a_2 b_2 ab=a1b1+a2b2

import numpy as np# 定义两个向量
a = np.array([1, 2])
b = np.array([3, 4])# 计算点积
dot_product = np.dot(a, b)
print(dot_product)  # 输出: 11
计算两个三维向量的夹角

假设 a = [ a 1 , a 2 , a 3 ] \mathbf{a} = [a_1, a_2, a_3] a=[a1,a2,a3] b = [ b 1 , b 2 , b 3 ] \mathbf{b} = [b_1, b_2, b_3] b=[b1,b2,b3],它们的点积和夹角计算如下:

import numpy as np# 定义两个向量
a = np.array([1, 0, 0])
b = np.array([0, 1, 0])# 计算点积
dot_product = np.dot(a, b)# 计算向量的模
norm_a = np.linalg.norm(a)
norm_b = np.linalg.norm(b)# 计算夹角的余弦值
cos_theta = dot_product / (norm_a * norm_b)
theta = np.arccos(cos_theta)print(f"夹角: {np.degrees(theta)} 度")  # 输出: 90.0 度

矩阵乘法

矩阵乘法是两个矩阵 A A A B B B 的乘积 C C C,其中:

  • 矩阵 A A A 的形状为 m × n m \times n m×n
  • 矩阵 B B B 的形状为 n × p n \times p n×p
  • 矩阵 C C C 的形状为 m × p m \times p m×p
    矩阵乘法的定义是:
    C i j = ∑ k = 1 n A i k B k j C_{ij} = \sum_{k=1}^{n} A_{ik} B_{kj} Cij=k=1nAikBkj

换句话说,矩阵 C C C 的元素 C i j C_{ij} Cij 是矩阵 A A A 的第 i i i 行和矩阵 B B B 的第 j j j 列的点积。

从矩阵乘法到向量点积

考虑两个矩阵 A A A B B B,我们可以将矩阵乘法分解为一系列的向量点积:

  1. 提取行向量和列向量
  • 矩阵 A A A 的第 i i i 行可以表示为向量 a i \mathbf{a_i} ai
  • 矩阵 B B B 的第 j j j 列可以表示为向量 b j \mathbf{b_j} bj
  1. 计算点积
  • C i j C_{ij} Cij 是向量 a i \mathbf{a_i} ai 和向量 b j \mathbf{b_j} bj 的点积,即:
    C i j = a i ⋅ b j C_{ij} = \mathbf{a_i} \cdot \mathbf{b_j} Cij=aibj
    例如,考虑矩阵 A A A B B B
    A = ( 1 2 3 4 ) A =\begin{pmatrix}1 & 2 \\ 3 & 4 \\ \end{pmatrix} A=(1324)
    B = ( 5 6 7 8 ) B = \begin{pmatrix} 5 & 6 \\ 7 & 8 \\ \end{pmatrix} B=(5768)
    它们的乘积 C = A B C = AB C=AB 为:
    C = ( 1 ⋅ 5 + 2 ⋅ 7 1 ⋅ 6 + 2 ⋅ 8 3 ⋅ 5 + 4 ⋅ 7 3 ⋅ 6 + 4 ⋅ 8 ) = ( 19 22 43 50 ) C = \begin{pmatrix} 1 \cdot 5 + 2 \cdot 7 & 1 \cdot 6 + 2 \cdot 8 \\ 3 \cdot 5 + 4 \cdot 7 & 3 \cdot 6 + 4 \cdot 8 \\ \end{pmatrix} = \begin{pmatrix} 19 & 22 \\ 43 & 50 \\ \end{pmatrix} C=(15+2735+4716+2836+48)=(19432250)
    在这里:
    C 11 = 1 ⋅ 5 + 2 ⋅ 7 = 19 C 12 = 1 ⋅ 6 + 2 ⋅ 8 = 22 C 21 = 3 ⋅ 5 + 4 ⋅ 7 = 43 C 22 = 3 ⋅ 6 + 4 ⋅ 8 = 50 C_{11} = 1 \cdot 5 + 2 \cdot 7 = 19 \\ C_{12} = 1 \cdot 6 + 2 \cdot 8 = 22 \\ C_{21} = 3 \cdot 5 + 4 \cdot 7 = 43 \\ C_{22} = 3 \cdot 6 + 4 \cdot 8 = 50 C11=15+27=19C12=16+28=22C21=35+47=43C22=36+48=50

使用 PyTorch 进行矩阵乘法和点积

以下是如何在 PyTorch 中实现矩阵乘法和向量点积:

import torch
# 定义两个矩阵
A = torch.tensor([[1, 2], [3, 4]])
B = torch.tensor([[5, 6], [7, 8]])
# 使用 torch.matmul 进行矩阵乘法
C = torch.matmul(A, B)
print(C)
# 输出:
# tensor([[19, 22],
# [43, 50]])
# 提取行向量和列向量
a1 = A[0, :] # A 的第一行
b1 = B[:, 0] # B 的第一列
# 计算点积
dot_product = torch.dot(a1, b1)
print(dot_product)
# 输出: tensor(19)

爱因斯坦求和

爱因斯坦求和约定(Einstein Summation Convention)是一种在物理学和数学中简化张量运算表示的方法。它由阿尔伯特·爱因斯坦在他的广义相对论论文中引入。这个约定的核心思想是通过省略求和符号(∑),简化公式的书写,增强表达的简洁性和可读性。

背景与起源

在物理学中,尤其是在处理广义相对论和量子力学中的张量时,常常需要进行大量的求和运算。为了简化这些计算的书写,爱因斯坦提出了一种简便的表示法:对于任何重复出现的指标,默认对其进行求和。

具体规则

  1. 求和隐含性:在一个表达式中,如果一个指标(下标或上标)在一个单项式中出现两次,则认为对该指标求和。例如: a i b i = ∑ i a i b i a_i b_i = \sum_{i} a_i b_i aibi=iaibi在这种表示法中,i 被称为“哑指标”或“虚指标”。
  2. 自由指标:如果一个指标在表达式中仅出现一次,则称其为自由指标,这个指标代表一个范围的所有可能值。例如: c i = a i j b j c_i = a_{ij} b_j ci=aijbj这里的 i 是自由指标,而 j 是哑指标。
  3. 多重求和:可以在一个表达式中使用多个哑指标进行多重求和。例如: d = a i j b j k c k d = a_{ij} b_{jk} c_k d=aijbjkck在这个例子中,j 和 k 都是哑指标,意味着: d = ∑ j ∑ k a i j b j k c k d = \sum_{j} \sum_{k} a_{ij} b_{jk} c_k d=jkaijbjkck

在使用 torch.einsum 时,我们可以利用爱因斯坦求和约定来简洁地表示矩阵乘法、张量收缩等操作:

import torch# 矩阵乘法
A = torch.randn(3, 4)
B = torch.randn(4, 5)
C = torch.einsum('ik,kj->ij', A, B)

在上面的例子中,‘ik,kj->ij’ 表示矩阵乘法,其中 k k k 是求和下标,最终结果的维度由 i i i j j j 确定。

‘ik,kj->ij’ 是爱因斯坦求和约定在 torch.einsum 中的一个具体应用,表示矩阵乘法。让我们详细解析一下这个表示:

表达式解析

  1. 输入张量
  • 假设我们有两个矩阵 A 和 B。
  • A 的形状为 (i, k),即 A 有 i 行和 k 列。
  • B 的形状为 (k, j),即 B 有 k 行和 j 列。
  1. 爱因斯坦求和约定
  • ‘ik,kj->ij’ 中的 ik 和 kj 分别对应输入张量 A 和 B 的维度标签。
  • 中间的 , 用于分隔多个输入张量的维度标签。
  • 箭头 -> 左侧表示输入张量的维度标签,右侧表示输出张量的维度标签。
  • ‘ik,kj’ 表示对两个输入张量 A 和 B 进行操作,其中 k 是求和下标。
  1. 求和与输出
  • 在 ‘ik,kj’ 中,k 是求和下标,表示我们要对 k 维度进行求和。
  • i 和 j 出现在箭头 -> 右侧,表示输出张量的维度标签。

举例说明

假设我们有两个矩阵:

A = ( a 11 a 12 a 21 a 22 a 31 a 32 ) , B = ( b 11 b 12 b 13 b 21 b 22 b 23 ) A = \begin{pmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \\ a_{31} & a_{32} \end{pmatrix}, \quad B = \begin{pmatrix} b_{11} & b_{12} & b_{13} \\ b_{21} & b_{22} & b_{23} \end{pmatrix} A= a11a21a31a12a22a32 ,B=(b11b21b12b22b13b23)

其中:

  • A A A 是一个 3 × 2 3 \times 2 3×2 的矩阵,对应维度标签 ‘ik’(即 i = 3 i = 3 i=3, k = 2 k = 2 k=2)。
  • B B B 是一个 2 × 3 2 \times 3 2×3 的矩阵,对应维度标签 ‘kj’(即 k = 2 k = 2 k=2, j = 3 j = 3 j=3)。
    使用 torch.einsum 表示矩阵乘法:
import torchA = torch.tensor([[a11, a12],[a21, a22],[a31, a32]])B = torch.tensor([[b11, b12, b13],[b21, b22, b23]])C = torch.einsum('ik,kj->ij', A, B)

矩阵乘法过程

‘ik,kj->ij’ 表示通过对 k 维度进行求和,得到输出矩阵 C:

C = A ⋅ B C = A \cdot B C=AB

其中:

C i j = ∑ k A i k B k j C_{ij} = \sum_{k} A_{ik} B_{kj} Cij=kAikBkj

即:

C i j = A i 1 B 1 j + A i 2 B 2 j C_{ij} = A_{i1}B_{1j} + A_{i2}B_{2j} Cij=Ai1B1j+Ai2B2j

结果

根据上面的定义,最终的结果 C 是一个 3 × 3 3 \times 3 3×3 的矩阵:

C = ( c 11 c 12 c 13 c 21 c 22 c 23 c 31 c 32 c 33 ) C = \begin{pmatrix} c_{11} & c_{12} & c_{13} \\ c_{21} & c_{22} & c_{23} \\ c_{31} & c_{32} & c_{33} \end{pmatrix} C= c11c21c31c12c22c32c13c23c33

每个元素 c i j c_{ij} cij 由对应的矩阵乘法和求和计算得到。

注意力机制

在编写注意力的时候有这样的代码
scores = torch.einsum(“blhe,bshe->bhls”, queries, keys)

从向量内积的角度解释

假设 queries 和 keys 的形状分别为 ( B , L , H , E ) (B, L, H, E) (B,L,H,E) ( B , S , H , E ) (B, S, H, E) (B,S,H,E),其中:

  • B B B 是批次大小 (Batch Size)
  • L L L 是查询序列的长度 (Length of queries)
  • S S S 是键序列的长度 (Length of keys)
  • H H H 是注意力头的数量 (Number of heads)
  • E E E 是嵌入维度 (Embedding Dimension)
    我们计算 queries 和 keys 在嵌入维度 E E E 上的内积,即通过 torch.einsum(“blhe,bshe->bhls”, queries, keys) 来计算注意力得分。

示例

假设我们有以下输入:

import torchqueries = torch.tensor([[[[0.5, 1.2], [0.3, 0.7]],  # 第一个 query 序列,两个头,每个头两个维度[[1.5, 2.2], [1.3, 1.7]],  # 第二个 query 序列,两个头,每个头两个维度]
])  # 形状 (1, 2, 2, 2)keys = torch.tensor([[[[0.8, 1.5], [0.4, 0.9]],  # 第一个 key 序列,两个头,每个头两个维度[[1.1, 2.3], [1.0, 1.5]],  # 第二个 key 序列,两个头,每个头两个维度]
])  # 形状 (1, 2, 2, 2)

这里 queries 和 keys 的形状都是 (1, 2, 2, 2),表示 1 个批次,2 个序列,2 个头,每个头 2 个维度。

我们希望计算注意力得分矩阵 scores,其形状为 (1, 2, 2, 2)。

计算步骤

使用 torch.einsum 计算 scores:

scores = torch.einsum("blhe,bshe->bhls", queries, keys)
print(scores)

手动计算

头 1:
  • 第一个 query 序列和第一个 key 序列的内积:
    0.5 × 0.8 + 1.2 × 1.5 = 0.4 + 1.8 = 2.2 0.5 \times 0.8 + 1.2 \times 1.5 = 0.4 + 1.8 = 2.2 0.5×0.8+1.2×1.5=0.4+1.8=2.2
  • 第一个 query 序列和第二个 key 序列的内积:
    0.5 × 1.1 + 1.2 × 2.3 = 0.55 + 2.76 = 3.31 0.5 \times 1.1 + 1.2 \times 2.3 = 0.55 + 2.76 = 3.31 0.5×1.1+1.2×2.3=0.55+2.76=3.31
  • 第二个 query 序列和第一个 key 序列的内积:
    1.5 × 0.8 + 2.2 × 1.5 = 1.2 + 3.3 = 4.5 1.5 \times 0.8 + 2.2 \times 1.5 = 1.2 + 3.3 = 4.5 1.5×0.8+2.2×1.5=1.2+3.3=4.5
  • 第二个 query 序列和第二个 key 序列的内积:
    1.5 × 1.1 + 2.2 × 2.3 = 1.65 + 5.06 = 6.71 1.5 \times 1.1 + 2.2 \times 2.3 = 1.65 + 5.06 = 6.71 1.5×1.1+2.2×2.3=1.65+5.06=6.71
头 2:
  • 第一个 query 序列和第一个 key 序列的内积:
    0.3 × 0.4 + 0.7 × 0.9 = 0.12 + 0.63 = 0.75 0.3 \times 0.4 + 0.7 \times 0.9 = 0.12 + 0.63 = 0.75 0.3×0.4+0.7×0.9=0.12+0.63=0.75
  • 第一个 query 序列和第二个 key 序列的内积:
    0.3 × 1.0 + 0.7 × 1.5 = 0.3 + 1.05 = 1.35 0.3 \times 1.0 + 0.7 \times 1.5 = 0.3 + 1.05 = 1.35 0.3×1.0+0.7×1.5=0.3+1.05=1.35
  • 第二个 query 序列和第一个 key 序列的内积:
    1.3 × 0.4 + 1.7 × 0.9 = 0.52 + 1.53 = 2.05 1.3 \times 0.4 + 1.7 \times 0.9 = 0.52 + 1.53 = 2.05 1.3×0.4+1.7×0.9=0.52+1.53=2.05
  • 第二个 query 序列和第二个 key 序列的内积:
    1.3 × 1.0 + 1.7 × 1.5 = 1.3 + 2.55 = 3.85 1.3 \times 1.0 + 1.7 \times 1.5 = 1.3 + 2.55 = 3.85 1.3×1.0+1.7×1.5=1.3+2.55=3.85

最终结果

根据上述计算,我们可以得到:

scores = torch.tensor([[[[2.2, 3.31], [4.5, 6.71]],  # 第一个头的得分[[0.75, 1.35], [2.05, 3.85]]  # 第二个头的得分]
])

使用 PyTorch 计算

运行以下代码验证手动计算结果:

import torchqueries = torch.tensor([[[[0.5, 1.2], [0.3, 0.7]],  [[1.5, 2.2], [1.3, 1.7]],  ]
]) keys = torch.tensor([[[[0.8, 1.5], [0.4, 0.9]],  [[1.1, 2.3], [1.0, 1.5]],  ]
])scores = torch.einsum("blhe,bshe->bhls", queries, keys)
print(scores)

输出:

tensor([[[[2.2000, 3.3100],[4.5000, 6.7100]],[[0.7500, 1.3500],[2.0500, 3.8500]]]])

从矩阵乘法的角度解释

使用矩阵乘法计算

为了将 queries 和 keys 的计算表示成矩阵乘法,我们可以按以下步骤操作:

  1. 调整形状
  • 将 queries 和 keys 调整形状,使每个头的查询和键序列变成矩阵。
  1. 矩阵乘法
  • 对每个头分别进行矩阵乘法。

调整形状并进行矩阵乘法

我们将 queries 和 keys 形状从 (B, L, H, E) 和 (B, S, H, E) 调整为 (B, H, L, E) 和 (B, H, E, S),以便进行矩阵乘法。

queries_reshaped = queries.permute(0, 2, 1, 3)  # (B, H, L, E)
keys_reshaped = keys.permute(0, 2, 3, 1)       # (B, H, E, S)# 使用矩阵乘法
scores_matmul = torch.matmul(queries_reshaped, keys_reshaped)  # (B, H, L, S)
print(scores_matmul)

输出:

tensor([[[[2.2000, 3.3100],[4.5000, 6.7100]],[[0.7500, 1.3500],[2.0500, 3.8500]]]])

这里的矩阵乘法使用 torch.matmul ,没有使用 torch.mm
torch.matmul 和 torch.mm 是 PyTorch 中用于矩阵乘法的两个函数,但它们在适用的张量维度上有一些不同。具体来说:

torch.mm

  • 用途:专门用于两个二维矩阵(矩阵)之间的乘法。
  • 输入:必须是两个二维张量,形状分别为 (m, n) 和 (n, p)。
  • 输出:结果是一个二维张量,形状为 (m, p)。
    示例:
import torch# 定义两个二维矩阵
A = torch.randn(2, 3)
B = torch.randn(3, 4)# 使用 torch.mm 进行矩阵乘法
C = torch.mm(A, B)
print(C.shape)  # 输出: torch.Size([2, 4])

torch.matmul

  • 用途:更通用的矩阵乘法函数,可以处理二维及以上的张量。
  • 输入:可以是二维矩阵,也可以是具有更多维度的张量。
  • 输出:根据输入张量的维度,输出可能是一个矩阵或更高维度的张量。
  • 广播:torch.matmul 可以处理广播(broadcasting),即输入张量的形状可以不完全匹配,但需要满足广播规则。
    示例:
import torch# 定义两个二维矩阵
A = torch.randn(2, 3)
B = torch.randn(3, 4)# 使用 torch.matmul 进行矩阵乘法
C = torch.matmul(A, B)
print(C.shape)  # 输出: torch.Size([2, 4])# 定义两个三维张量
A_3d = torch.randn(5, 2, 3)
B_3d = torch.randn(5, 3, 4)# 使用 torch.matmul 进行三维张量的矩阵乘法
C_3d = torch.matmul(A_3d, B_3d)
print(C_3d.shape)  # 输出: torch.Size([5, 2, 4])# 广播示例
A_broadcast = torch.randn(2, 3)
B_broadcast = torch.randn(5, 3, 4)# A_broadcast 的形状将广播成 (5, 2, 3)
C_broadcast = torch.matmul(A_broadcast, B_broadcast)
print(C_broadcast.shape)  # 输出: torch.Size([5, 2, 4])

主要区别

  • 适用维度:torch.mm 只适用于二维矩阵;torch.matmul 则适用于二维及以上维度的张量。
  • 广播:torch.matmul 支持广播,而 torch.mm 不支持。

permute

在 PyTorch 中,permute 是一个张量(tensor)的方法,用于改变张量的维度顺序。这个操作不会改变张量的数据,只是重新排列它的维度。这对于需要改变数据的形状以适应不同操作的需求非常有用。

举例来说,如果你有一个形状为 (batch_size, height, width, channels) 的图像张量,而你的模型需要输入形状为 (batch_size, channels, height, width) 的张量,你可以使用 permute 方法来重新排列维度。

以下是一个简单的例子:

import torch# 创建一个形状为 (2, 3, 4, 5) 的随机张量
x = torch.randn(2, 3, 4, 5)# 使用 permute 方法改变维度顺序
x_permuted = x.permute(0, 3, 1, 2)# 打印新张量的形状
print(x_permuted.shape)  # 输出: torch.Size([2, 5, 3, 4])

在这个例子中:

  • 原始张量 x 的形状为 (2, 3, 4, 5)。
  • 调用 x.permute(0, 3, 1, 2) 后,新张量 x_permuted 的形状变为 (2, 5, 3, 4)。
    permute 方法的参数是新维度顺序的索引。例如,x.permute(0, 3, 1, 2) 意味着将第 0 维保持不变,将原第 3 维移到第 1 位置,将原第 1 维移到第 2 位置,将原第 2 维移到第 3 位置。

https://pytorch.org/docs/stable/generated/torch.transpose.html
https://pytorch.org/docs/stable/generated/torch.einsum.html

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

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

相关文章

揭秘抖音矩阵号低成本高效运作批量账号的秘诀!

在当今互联网时代,抖音矩阵号搭建已经成为了许多企业和个人追求高效率媒介管理的重要方式,但是高效、低成本地运作这些账号却是一个相当具有挑战性的任务。 在这篇文章中,我将从抖音矩阵账号准备,如何低成本制作视频以及在进行内容制作时,如何高效运作批量账号等大家比较…

翻译软件就用DT浏览器

翻译软件就用DT浏览器

GUI GUIDER、LVGL、LCD驱动关系

理解GUI Guider、LVGL和LCD驱动之间的关系对于开发嵌入式图形用户界面(GUI)非常重要。以下是它们之间关系的详细说明: 1. LVGL(Light and Versatile Graphics Library) 简介:LVGL 是一个轻量级、灵活的嵌…

LeetCode 7- 整数反转

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [-231, 231 - 1] ,就返回 0。 假设环境不允许存储 64 位整数(有符号或无符号)。 示例 1: 输入&…

最长递增子序列 - LeetCode 热题 87

大家好!我是曾续缘💖 今天是《LeetCode 热题 100》系列 发车第 87 天 动态规划第 7 题 ❤️点赞 👍 收藏 ⭐再看,养成习惯 最长递增子序列 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列 是由数组…

diffusers 使用脚本导入自定义数据集

在训练扩散模型时,如果附加额外的条件图片数据,则需要我们准备相应的数据集。此时我们可以使用官网提供的脚本模板来控制导入我们需要的数据。 您可以参考官方的教程来实现具体的功能需求,为了更加简洁,我将简单描述一下整个流程…

CentOS 7基础操作13_Linux下添加、修改、删除用户账号

1、添加、修改、删除用户账号 1)useradd命令——添加用户账号。 useradd [选项] 用户名 最简单的用法是,不添加任何选项.只使用用户名作为useradd命令的参数,按系统默认配置建立指定的用户账号。在CentOS系统中&#xff0…

融云:应用出海新增长引擎,GPT-4o 后的 AI 创新与用户运营

近日,融云与 TikTok、维卓联合在京举办了“十年出海,遇上 AI”私享会。 会上,融云解决方案架构师于洪达带来了《应用出海新增长引擎,AI 创新与用户精细化运营》主题分享,探讨在 AI 技术大潮下应用出海通过创新运营方式…

从0开发一个Chrome插件:背景脚本实战——开发一个显示当前时间的小功能

前言 这是《从0开发一个Chrome插件》系列的第八篇文章,本系列教你如何从0去开发一个Chrome插件,每篇文章都会好好打磨,写清楚我在开发过程遇到的问题,还有开发经验和技巧。 专栏: 从0开发一个Chrome插件:什么是Chrome插件?从0开发一个Chrome插件:开发Chrome插件的必要…

等级保护2.0新变化

等级保护2.0:新时代网络安全的新篇章 引言 随着信息技术的飞速发展,网络安全已成为国家安全的重要组成部分。等级保护2.0作为我国网络安全等级保护制度的最新标准,标志着我国网络安全等级保护工作迈入了新时代。本文将探讨等级保护2.0的新变…

金融科技:跨境支付的新引擎,开启全球化支付新时代

一、引言 在全球经济一体化的今天,跨境支付作为连接各国经贸往来的重要桥梁,其便捷性、安全性和效率性成为了各国企业和消费者关注的焦点。金融科技,作为现代金融与传统科技深度融合的产物,正以其独特的创新力和推动力,成为跨境支付领域的新引擎,引领着全球化支付新时代…

java应用性能优化思路(一)

1.动静分离,将静态资源交给nginx管理,动态请求交给我们开发的应用程序处理; 2.为数据库表常用查询字段添加索引; 3.如果查询的sql语句还打印在控制台,需将日志级别提高到info或error; logging:level:com.atguigu.gu…

Visual Studio的快捷按键

Visual Studio的快捷按键对于提高编程效率至关重要。以下是一些常用的Visual Studio快捷按键,并按照功能进行分类和归纳: 1. 文件操作 Ctrl O:打开文件Ctrl S:保存文件Ctrl Shift S:全部保存Ctrl N:…

群体优化算法---灰狼优化算法学习介绍以及在卷积神经网络训练上的应用

**长文预警**介绍 在自然界中,狼群的社会结构和捕猎策略展现了高度的智能和协调性,灰狼优化算法(Grey Wolf Optimizer, GWO)正是受此启发提出的一种群体智能优化算法。GWO主要模拟了灰狼的社会等级制度和捕猎行为,其核…

深度学习 - 激活函数

深度学习 - 激活函数 激活函数(Activation Function)是神经网络中的关键组件,用于引入非线性,使得网络能够学习和表示复杂的模式和关系。以下是几种常见的激活函数及其详细解释: 1. Sigmoid(S型激活函数&…

Playwright框架入门

自从2023年底playwright框架火起来之后,很多小伙伴咨询我们这个框架,甚至问我们什么时候出这个课程. 这步这个课程在我们千呼万唤中出来了.具体的课程大纲和试听可以联系下方二维码获取. 今天给大家分享一下playwright的安装和一些常用API,为后续的学习做好准备工作. Playwrig…

Unit9

Unit9 gene 基因,生产,类型 genetic genius ingenious generate generation degenerate genuine generous generosity gender genre homogeneous time 时间 time timely timer first-timer temporary temporarily tempo contemporary dra 戏剧…

欧智通恒玄BES2600W基于Openharmony v3.0的分布式软总线测试过程记录

恒玄BES2600W SoC 的欧智通的单板基于Openharmony v3.0的底座,其测试的样例代码是基于恒玄公司开发的轻量带屏显示产品样例代码,主要包括图形、软总线等特性产品的开发。 基础介绍: ​ L0的系统基于Liteos-m的m内核,网络使用lwi…

计算机网络--传输层

计算机网络--计算机网络概念 计算机网络--物理层 计算机网络--数据链路层 计算机网络--网络层 计算机网络--传输层 计算机网络--应用层 1. 概述 1.1 传输层的意义 网络层可以把数据从一个主机传送到另一个主机,但是没有和进程建立联系。 传输层就是讲进程和…

【中间件系列】浅析redis是否适合做消息队列

文章目录 一、简单的list消息队列1.命令示例2.伪代码示例3.方案优劣 二、Pub/Sub发布订阅1.消息丢失2.消息堆积 三、相对成熟的Stream1.redis命令介绍2.多消费者组测试3.Stream会持久化吗?4.消息堆积如何解决? 总结 用redis也是比较久了,并且…