图神经网络实战——基于DeepWalk创建节点表示

图神经网络实战——基于DeepWalk创建节点表示

    • 0. 前言
    • 1. Word2Vec
      • 1.1 CBOW 与 skip-gram
      • 1.2 构建 skip-gram 模型
      • 1.3 skip-gram 模型
      • 1.4 实现 Word2Vec 模型
    • 2. DeepWalk 和随机行走
    • 3. 实现 DeepWalk
    • 小结
    • 系列链接

0. 前言

DeepWalk 是机器学习 (machine learning, ML) 技术在图数据中的成功应用之一,其引入了嵌入等重要概念,这些概念是图神经网络 (Graph Neural Network, GNN) 的核心。与传统的神经网络不同,这种架构的目标是产生表示 (representations),然后将其传递给其他模型执行下游任务(例如节点分类)时使用。
在本节中,我们将了解 DeepWalk 架构及其两个主要组件: Word2Vec 和随机游走 (random walks)。首先介绍 Word2Vec 架构的工作原理,并重点介绍 skip-gram 模型,并在自然语言处理 (natural language processing, NLP) 任务中使用 gensim 库实现 skip-gram 模型,以了解其使用方法。然后,我们将重点研究 DeepWalk 算法,学习如何使用分层 softmax (hierarchical softmax, H-Softmax) 提高性能。然后在图上实现随机游走,最后使用 “Zachary’s Karate Club” 数据集实现一个端到端的监督节点分类模型。

1. Word2Vec

理解 DeepWalk 算法的第一步是了解其主要组成部分: Word2VecWord2VecNLP 领域最具影响力的深度学习技术之一,该技术由 Tomas Mikolov 等人于 2013 年提出,是一种利用大规模文本数据集将单词转化为向量( vectors,也称为嵌入,embeddings )表示的技术,这种单词表示可用于情感分类等下游任务。
使用 Word2Vec 将单词转化为向量的示例如下:
v e c ( k i n g ) = [ − 2.0 , 4.2 , 0.5 ] v e c ( q u e e n ) = [ − 1.8 , 2.7 , 1.4 ] v e c ( m a n ) = [ 2.9 , − 1.0 , − 1.9 ] v e c ( w o m a n ) = [ 2.8 , − 2.6 , − 1.0 ] vec(king) = [−2.0, 4.2, 0.5]\\ vec(queen) = [−1.8, 2.7, 1.4]\\ vec(man) = [2.9,−1.0, −1.9]\\ vec(woman) = [2.8,−2.6,−1.0]\\ vec(king)=[2.0,4.2,0.5]vec(queen)=[1.8,2.7,1.4]vec(man)=[2.9,1.0,1.9]vec(woman)=[2.8,2.6,1.0]

在以上例子中,就欧氏距离而言,kingqueen 的词向量比 kingwoman 的词向量更接近。在实践中,我们通常会使用其他更精确的度量方法来衡量这些词的相似度,例如常用的余弦相似度 (cosine similarity)。余弦相似度关注的是向量之间的角度,而不考虑它们的大小(长度):
c o s i n e s i m i l a r i t y ( A ⃗ , B ⃗ ) = c o s ( θ ) = A ⃗ ⋅ B ⃗ ∣ ∣ A ⃗ ∣ ∣ ⋅ ∣ ∣ B ⃗ ∣ ∣ cosine\ similarity(\vec A,\vec B)=cos(\theta)=\frac {\vec A \cdot \vec B} {||\vec A||\cdot ||\vec B||} cosine similarity(A ,B )=cos(θ)=∣∣A ∣∣∣∣B ∣∣A B
Word2Vec 能够解决类比问题,最著名的例子是,它可以回答 "man is to woman, what king is to ___?"的问题。计算方法如下:
v e c ( k i n g ) − v e c ( m a n ) + v e c ( w o m a n ) ≈ v e c ( q u e e n ) vec(king)-vec(man)+vec(woman)≈vec(queen) vec(king)vec(man)+vec(woman)vec(queen)
当然这种性质并不适用于所有类比问题,但这一特性可以为嵌入算术运算带来有趣的应用。

1.1 CBOW 与 skip-gram

为了生成这些向量,模型必须在一个前置任务上进行训练。任务本身并不需要有实际意义,其唯一目标就是生成高质量的嵌入向量。在实践中,这个任务通常与根据特定上下文预测单词相关。通常,可以使用两种具有类似任务的架构:

  • 连续词袋 (continuous bag-of-words, CBOW) 模型: 模型的训练目标是利用周围上下文(目标单词前后的单词)预测一个单词。上下文单词的顺序并不重要,因为它们的嵌入向量会在模型中求和。实践表明,使用预测单词前后的四个单词进行预测时,可以获得更好的结果
  • 连续 skip-gram (continuous skip-gram, skip-gram)模型: 模型的训练目标是根据一个输入单词预测其上下文单词。增加上下文单词的范围可以获得更好的嵌入向量,但也会增加训练时间

两种模型的输入和输出如下所示:

模型对比

通常,CBOW 模型的训练速度更快,但是由于 skip-gram 模型具有学习不常见单词的能力,因此更加准确。

1.2 构建 skip-gram 模型

由于 DeepWalk 采用的是 skip-gram 架构,因此我们现在将重点学习 skip-gram 模型。skip-gram 使用具有以下结构的单词对:(target word, context word),其中 target word 是输入词,context word 是要预测的词。同一目标词的 skip-gram 数量取决于参数上下文大小 (context size),如下图所示:

Skip-gram

这一单词对结构可以从单个句子扩展至整个文本语料库。为了节省内存,我们将同一目标词的所有上下文词存储在一个列表中。接下来,我们以整个段落为例构建单词对,为存储在 text 变量中的整个段落创建 skip-gram 单词对。将 CONTEXT_SIZE 变量设置为 2,即查看目标单词前后的两个单词。

(1) 导入所需库:

import numpy as np

(2)CONTEXT_SIZE 变量设置为 2,并导入要分析的文本 text

CONTEXT_SIZE = 2
text = """Tears came to my eyes as I realized what I had been a fool to judge Al as a failure. He had not left any material possessions behind. But he had been a kind loving father, and left behind his best love.""".split()

(3) 通过一个简单的 for 循环创建 skip-gram 单词对,以考虑 text 中的每个单词。使用列表推导式生成上下文单词,并存储在 skipgrams 列表中:

# Create skipgrams
skipgrams = []
for i in range(CONTEXT_SIZE, len(text) - CONTEXT_SIZE):array = [text[j] for j in np.arange(i - CONTEXT_SIZE, i + CONTEXT_SIZE + 1) if j != i]skipgrams.append((text[i], array))

(4) 使用 print() 函数查看生成的 skipgrams

print(skipgrams[0:2])

输出结果如下,观察这两个目标单词及其相应的上下文可以了解 Word2Vec 的输入-输出形式:

[('to', ['Tears', 'came', 'my', 'eyes']), ('my', ['came', 'to', 'eyes', 'as'])]

1.3 skip-gram 模型

Word2Vec 的目标是生成高质量的单词嵌入。为了学习这些嵌入,skip-gram 模型的训练目标是根据目标词预测正确的上下文单词。
假设,我们有一个由 N N N 个单词组成的序列 w 1 , w 2 , . . . , w N w_1, w_2 ,..., w_N w1,w2,...,wN。在给定单词 w 2 w_2 w2 的情况下,得到单词 w 2 w_2 w2 的概率为 p ( w 2 ∣ w 1 ) p(w_2|w_1) p(w2w1)。我们的目标是最大化整个文本中给定目标单词时得到每个上下文单词的概率之和:
1 N ∑ n = 1 N ∑ − c ≤ j ≤ c , j ≠ 0 log ⁡ p ( w n + j ∣ w n ) \frac 1 N\sum_{n=1}^N\sum_{-c≤j≤c,j≠0}\log p(w_{n+j}|w_n) N1n=1Ncjc,j=0logp(wn+jwn)
其中 c c c 是上下文向量的大小。那么,为什么我们要在以上等式中使用对数概率?将概率转换为对数概率是机器学习中的常用技术,主要有两个原因:

  • 乘法的计算成本比加法高,而使用对数可以将乘法转换为加法(除法转换为减法),因此计算对数概率更快:
    log ⁡ ( A × B ) = log ⁡ ( A ) + log ⁡ ( B ) \log (A\times B)=\log(A)+\log(B) log(A×B)=log(A)+log(B)
  • 计算机存储非常小的数字(如 3.14e-128 )的方式并不完全准确,当事件发生的可能性极小时,这些微小的误差就会累积起来,使最终结果产生偏差。而使用对数则不同,当结果同样为 3.14e-128 时,使用对数后结果为 -127.5 (log3.14e-128=-127.5)

总的来说,将概率转换为对数概率可以在不改变初始目标的情况下提高速度和准确性。

原始 skip-gram 模型使用 softmax 函数来计算给定目标单词嵌入 h t h_t ht 的情况下,上下文单词嵌入 h c h_c hc 的概率:
p ( w c ∣ w t ) = exp ⁡ ( h c h t T ) ∑ i = 1 ∣ V ∣ exp ⁡ ( h i h t T ) p(w_c|w_t)=\frac {\exp(h_ch_t^T)}{\sum_{i=1}^{|V|}\exp(h_ih_t^T)} p(wcwt)=i=1Vexp(hihtT)exp(hchtT)
其中, V V V 是大小为 ∣ V ∣ |V| V 的词汇表,词汇表 (vocabulary) 是指在一个文本语料库中出现的所有单词的集合。可以使用集合数据结构去除重复的单词,获得词汇表:

vocab = set(text)
VOCAB_SIZE = len(vocab)
print(f"Length of vocabulary = {VOCAB_SIZE}")
# Length of vocabulary = 33

得到词汇表大小后,还需要定义参数 N N N,用于表示单词向量的维度。通常情况下,这个值设置在 1001000 之间。在本节中,由于数据集的规模有限,将其设置为 10
skip-gram 模型仅由两层组成:

  • 权重为 W e m b e d W_{embed} Wembed 的投影层 (projection layer),将独热 (one-hot) 编码词向量作为输入,并返回相应的 N N N 维词嵌入。它就像一个简单的查找表,存储预定维度的嵌入
  • 权重为 W o u t p u t W_{output} Woutput 的全连接层 (fully connected layer),将词嵌入作为输入,并输出 ∣ V ∣ |V| Vlogits。对预测结果应用 softmax 函数,将 logits 转换为概率

skip-gram 中没有激活函数:Word2Vec 是一种线性分类器,可以模拟单词之间的线性关系。
将独热编码的单词向量称为输入 x x x,相应的单词嵌入可以通过简单的投影计算得出:
h = W e m b e d T ⋅ x h=W_{embed}^T\cdot x h=WembedTx
利用 skip-gram 模型,可以将以上概率改写如下:
p ( w c ∣ w t ) = exp ⁡ ( W o u t p u t T ⋅ x ) ∑ i = 1 ∣ V ∣ exp ⁡ ( W o u t p u t ( i ) ⋅ h ) p(w_c|w_t)=\frac {\exp(W_{output}^T\cdot x)} {\sum_{i=1}^{|V|}\exp(W_{output_{(i)}}\cdot h)} p(wcwt)=i=1Vexp(Woutput(i)h)exp(WoutputTx)
skip-gram 模型会输出一个 ∣ V ∣ |V| V 维向量,它是词汇表中每个单词的条件概率:
w o r d 2 v e c ( w t ) = [ p ( w 1 ∣ w t ) p ( w 2 ∣ w t ) ⋮ p ( w ∣ v ∣ ∣ w t ) ] word2vec(w_t)=\begin{bmatrix} p(w_1|w_t)\\ p(w_2|w_t)\\ \vdots \\ p(w_{|v|}|w_t) \end{bmatrix} word2vec(wt)= p(w1wt)p(w2wt)p(wvwt)
在训练过程中,这些概率会与正确的独热编码目标单词向量进行比较。这些值之间的差异(由损失函数计算,如交叉熵损失)通过网络反向传播,以更新权重并获得更好的预测结果。

1.4 实现 Word2Vec 模型

Word2Vec 的整体架构如下所示,包括两个权重矩阵(包括 W e m b e d W_{embed} Wembed 和 $W_{output} )和最后的 softmax 层:

Word2Vec 架构

接下来,使用 gensim 库实现 Word2Vec 模型,然后根据上一小节的文本构建词汇表并训练模型。gensim 库的安装和其他第三方库一样,可以在 shell 中执行以下命令进行安装:

pip install gensim

(1) 导入 Word2Vec 类:

from gensim.models.word2vec import Word2Vec

(2) 使用对象 Word2Vec 和参数 sg=1 (skip-gram = 1) 初始化 skip-gram 模型:

model = Word2Vec([text],sg=1,   # Skip-gramvector_size=10,min_count=0,window=2,workers=1)

(3) 检查权重矩阵 W_embed 的形状,其应该与词汇量大小和词嵌入维度相对应:

print(f'Shape of W_embed: {model.wv.vectors.shape}')
# Shape of W_embed: (33, 10)

(4) 对模型训练 10epoch

model.train([text], total_examples=model.corpus_count, epochs=10)

(5) 最后,打印一个单词嵌入,观察训练结果:

print('\nWord embedding =')
print(model.wv[0])

输出结果如下:

Word embedding =
[-0.00495417 -0.00025058  0.05408746  0.08913884 -0.09218638 -0.071533940.06835324  0.09274287 -0.05681597 -0.04169786]

虽然这种方法在处理小词汇量时效果很好,但在大多数情况下,对数百万个单词(词汇量)应用完整 softmax 函数的计算成本太高,这一直是开发精确语言模型的限制因素之一,但我们可以通过其他方法来解决这个问题。
Word2VecDeepWalk 通过实现 H-Softmax 技术解决此问题。与直接计算每个单词的概率的 softmax 不同,H-Softmax 技术采用二叉树结构,其中叶子节点是单词。此外,还可以使用哈夫曼树,将不常见的单词存储在比常见单词更深的层次上。在大多数情况下,这种方法可以将单词预测速度提高至少 50 倍。在 gensim 中,可以通过指定 hs=1 使用 H-Softmax

2. DeepWalk 和随机行走

DeepWalk2014 年由 Perozzi 等人提出,并很快在图学习中大受欢迎,它在多个数据集上的表现始终优于其他方法。虽然之后研究人员又提出了其他性能更高的架构,但 DeepWalk 作为一种简单可靠的基准方法,能够快速实现并解决大量问题。
DeepWalk 的目标是以无监督的方式生成高质量的节点特征表示。这一架构在很大程度上受到了 NLPWord2Vec 的启发。但 DeepWalk 所用的数据集由节点组成,而不是单词,因此我们想要使用随机游走来生成类似句子的有意义的节点序列。句子和图之间的联系如下所示:

句子和图

随机游走是通过在每一步随机选择一个相邻节点而生成的节点序列。因此,节点可以在同一序列中出现多次。
即使节点是随机选择的,但它们经常一起出现在一个序列中,就意味着它们彼此接近。根据网络同质性 ( network homophily) 假说,相互接近的节点是相似的。这在社交网络中尤为明显,因为在社交网络中,人们会倾向于与朋友和家人建立联系。
DeepWalk 算法的核心理念在于:当节点彼此接近时,我们希望相似度得分较高;相反,当节点之间距离较远时,我们希望相似度得分较低。接下来,我们使用 networkx 库实现随机游走函数。

(1) 导入所需的库:

import networkx as nx
import matplotlib.pyplot as plt
import random

(2) 利用 erdos_renyi_graph 函数生成一个随机图,图中节点数量固定 (10),节点之间建立边的概率为 0.3

G = nx.erdos_renyi_graph(10, 0.3, seed=1, directed=False)

(3) 绘制所生成的随机图:

nx.draw_networkx(G, pos=nx.spring_layout(G))
plt.axis('off')
plt.show()

随即图

(4) 实现随机游走函数,函数使用两个参数:起始节点 (start) 和游走长度 (length)。每走一步,我们都会使用 np.random.choice 随机选择一个相邻节点,直到游走完成:

def random_walk(start, length):walk = [str(start)]  # starting nodefor i in range(length):neighbors = [node for node in G.neighbors(start)]next_node = np.random.choice(neighbors, 1)[0]walk.append(str(next_node))start = next_nodereturn walk

(5) 打印函数执行结果,起始节点为 0,长度为 10

print(random_walk(0, 10))

输出结果如下:

['0', '9', '0', '4', '3', '4', '3', '6', '2', '5', '6']

可以看到某些节点,如 09 经常出现在一起。考虑到这是一个同构图,这意味着它们是相似的,这正是 DeepWalk 试图捕捉的关系类型。

3. 实现 DeepWalk

了解了 DeepWalk 架构中的每个组件后,实现 DeepWalk 解决一个实际的机器学习问题。我们使用 Zachary’s Karate Club 数据集,它简单地表示了 Wayne W. Zachary 研究的一个空手道俱乐部内部的关系。这是一种社交网络,其中的每个节点都是一个成员,而在俱乐部之外进行互动的成员则被连接在一起。
在本例中,俱乐部被分为两组:我们希望通过查看每个成员的连接,将每个成员分配到正确的组中(即节点分类,node classification)。

(1) 使用 nx.karate_club_graph() 导入数据集:

G = nx.karate_club_graph()

(2) 将字符串类标签转换成数值 (Mr. Hi = 0Officer = 1):

labels = []
for node in G.nodes:label = G.nodes[node]['club']labels.append(1 if label == 'Officer' else 0)

(3) 使用新标签绘制图:

plt.axis('off')
nx.draw_networkx(G, pos=nx.spring_layout(G, seed=0), node_color=labels)
plt.show()

标签图

(4) 接下来,生成随机游走数据集,为图中的每个节点创建 80 个长度为 10 的随机游走序列:

walks = []
for node in G.nodes:for _ in range(80):walks.append(random_walk(node, 10))

(5) 打印一个随机游走序列,验证其正确性:

print(walks[0])
# ['0', '1', '30', '1', '3', '12', '3', '7', '3', '0', '17']

(6) 实现 Word2Vec,使用 skip-gram 模型,可以调整其他参数,以提高嵌入质量:

model = Word2Vec(walks,hs=1,   # Hierarchical softmaxsg=1,   # Skip-gramvector_size=100,window=10,workers=1)

(7) 在生成的随机游走序列上对模型进行简单的训练:

# Build vocabulary
model.build_vocab(walks)
# Train model
model.train(walks, total_examples=model.corpus_count, epochs=30, report_delay=1)

(8) 模型训练完成后,可以将其应用在不同任务中。例如,查找与给定节点最相似的节点(根据余弦相似度):

print('Nodes that are the most similar to node 0:')
for similarity in model.wv.most_similar(positive=['0']):print(f'   {similarity}')

输出结果如下所示:

输出

另一个重要应用是计算两个节点之间的相似度得分:

print(f"\nSimilarity between node 0 and 4: {model.wv.similarity('0', '4')}")
# Similarity between node 0 and 4: 0.6553224921226501

可以使用 t-distributed stochastic neighbor embedding (t-SNE) 绘制嵌入结果,从而将这些高维向量可视化为二维图像:

(1)sklearn 中导入 TSNE 类:

from sklearn.manifold import TSNE

(2) 创建两个数组:一个用于存储单词嵌入,另一个用于存储标签:

nodes_wv = np.array([model.wv.get_vector(str(i)) for i in range(len(model.wv))])
labels = np.array(labels)

(3) 在嵌入上训练 2 维 (n_components=2) t-SNE 模型:

tsne = TSNE(n_components=2,learning_rate='auto',init='pca',random_state=0).fit_transform(nodes_wv)

(4) 将训练好的 t-SNE 模型生成的二维向量与相应的标签绘制成二维图像:

plt.figure(figsize=(6, 6))
plt.scatter(tsne[:, 0], tsne[:, 1], s=100, c=labels)
plt.show()

分类结果

可以看到使用一条简单的线就能够将两个类别区分开来。只要有足够的训练数据,简单的机器学习算法就能对这些节点进行分类。接下来,我们实现一个分类器,并对节点嵌入进行训练。

(1)sklearn 中导入随机森林 (Random Forest) 模型,使用准确率作为模型评估的指标:

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

(2) 将嵌入数据分成两组:训练数据和测试数据。一个简单的方法是创建如下掩码:

train_mask = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]
test_mask = [0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33]

(3) 在训练数据上训练随机森林分类器:

clf = RandomForestClassifier(random_state=0)
clf.fit(nodes_wv[train_mask], labels[train_mask])

(4) 在测试数据上根据准确率评估训练好的模型:

y_pred = clf.predict(nodes_wv[test_mask])
acc = accuracy_score(y_pred, labels[test_mask])
print(f'Accuracy = {acc*100:.2f}%')
# Accuracy = 95.45%

可以看到,模型准确率为 95.45%,虽然仍有改进的余地,但本例展示了 DeepWalk 的两个应用:

  • 使用嵌入和余弦相似性发现节点之间的相似性(无监督学习)
  • 将嵌入数据集用作节点分类等监督任务

学习节点表示可以为设计更深入、更复杂的架构提供了更大的灵活性。

小结

在本节中,我们了解了 DeepWalk 架构及其主要组件。然后,使用随机游走将图数据转化为序列,并应用了 Word2Vec 算法,使用图的拓扑信息创建节点嵌入,得到的嵌入结果可用于发现节点间的相似性,或作为其他算法的输入。最后,我们使用监督方法解决了节点分类问题。

系列链接

图神经网络实战——图神经网络(Graph Neural Networks, GNN)基础
图神经网络实战——图论基础

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

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

相关文章

matlab阶段学习小节1

数组排序 fliplr()实现数组倒序,但不对大小进行排序,只是元素位置掉头。 要想实现大小倒序排列,可以先sort()实现正序排列,再用fliplr倒一下 %数组运算 %矩阵 %xAb的解xb/A;(矩阵) %右除运算A/B,左矩阵为被除数&a…

SLAM ORB-SLAM2(21)基础矩阵的计算和评分

SLAM ORB-SLAM2(21)基础矩阵的计算和评分 1. 前言2. 基础矩阵2.1. 对级约束2.2. 推导2.3. 计算原理 3. ComputeF214. CheckFundamental 1. 前言 在 《SLAM ORB-SLAM2(20)查找基础矩阵》 中了解到 查找基础矩阵主要过程&#xff1…

基于springboot+vue的美食推荐商城

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

SLAM基础知识-卡尔曼滤波

前言: 在SLAM系统中,后端优化部分有两大流派。一派是基于马尔科夫性假设的滤波器方法,认为当前时刻的状态只与上一时刻的状态有关。另一派是非线性优化方法,认为当前时刻状态应该结合之前所有时刻的状态一起考虑。 卡尔曼滤波是…

【Transformer】笔记

主要参考 https://zhuanlan.zhihu.com/p/366592542 https://mp.weixin.qq.com/s/b-_M8GPK7FD7nbPlN703HQ 其他参考 原理 https://zhuanlan.zhihu.com/p/627448301 多头注意力机制 https://zhuanlan.zhihu.com/p/611684065 https://blog.csdn.net/shizheng_Li/article/details/1…

Launch学习

参考博客: (1) 史上最全的launch的解析来啦,木有之一欧 1 ROS工作空间简介 2 元功能包 src目录下可以包含多个功能包,假设需要使用机器人导航模块,但是这个模块中包含着地图、定位、路径规划等不同的功能包,它们的逻…

【二】【SQL】去重表数据及分组聚合查询

去重表数据 表的准备工作 去除表中重复的数据,重复的数据只留一份。 mysql> create table duplicate_table (-> id int,-> name varchar(20)-> ); Query OK, 0 rows affected (0.03 sec)mysql> insert into duplicate_table values-> (100,aaa)…

Doris——纵腾集团流批一体数仓架构

目录 前言 一、早期架构 二、架构选型 三、新数据架构 3.1 数据中台 3.2 数仓建模 3.3 数据导入 四、实践经验 4.1 准备阶段 4.2 验证阶段 4.3 压测阶段 4.4 上线阶段 4.5 宣导阶段 4.6 运行阶段 4.6.1 Tablet规范问题 4.6.2 集群读写优化 五、总结收益 六…

深度学习PyTorch 之 RNN-中文多分类

关于RNN的理论部分我们已经在前面介绍过,所以这里直接上代码 1、 数据部分 1.1 读取数据 # 加载数据 data_path ./data/news.csv data pd.read_csv(data_path)# 预览数据的前几行 data.head()数据是csv格式,只有两列,第一列是标签&#…

【解决方案】ArcGIS Engine二次开发时,运行后出现“正尝试在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain...”

我们在做ArcGIS Engine二次开发时,特别是新手,安装好了开发环境,满怀信心的准备将按照教程搭建好的框架在Visual Studio中进行运行。点击运行后,却出现了“正尝试在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化…

ABAP - SALV教程06 - 列的设置(隐藏、修改、优化列宽)

SAVL要想像Function ALV或OO ALV那样设置Fieldcat,也是有方法的。通过取得全体列的类引用 CL_SALV_COLUMNS来进行修改 METHOD set_columns.* 取得全部列的对象DATA(lo_cols) co_alv->get_columns( ).* 设置自动优化列宽度lo_cols->set_optimize( X ).T…

实例驱动计算机网络

文章目录 计算机网络的层次结构应用层DNSHTTP协议HTTP请求响应过程 运输层TCP协议TCP协议面向连接实现TCP的三次握手连接TCP的四次挥手断开连接 TCP协议可靠性实现TCP的流量控制TCP的拥塞控制TCP的重传机制 UDP协议 网际层IP协议(主机与主机)IP地址的分类…

计算机视觉基础知识(十六)--图像识别

图像识别 信息时代的一门重要技术;目的是让计算机代替人类处理大量的物理信息;随着计算机技术的发展,人类对图像识别技术的认识越来越深刻;图像识别技术利用计算机对图像进行处理\分析\理解,识别不同模式的目标和对象;过程分为信息的获取\预处理\特征抽取和选择\分类器设计\分…

在Golang中简化日志记录:提升性能和调试效率

最大化效率和有效故障排除:在Golang中简化日志记录 日志记录是软件开发的一个基本方面,有助于调试、监控和理解应用程序的流程。在Golang中,有效的日志记录实践可以显著提高性能并简化调试过程。本文探讨了优化Golang日志记录的技术&#xf…

[HackMyVM]靶场 VivifyTech

kali:192.168.56.104 主机发现 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 0a:00:27:00:00:05 (Unk…

基于Java的超市商品管理系统(Vue.js+SpringBoot)

目录 一、摘要1.1 简介1.2 项目录屏 二、研究内容2.1 数据中心模块2.2 超市区域模块2.3 超市货架模块2.4 商品类型模块2.5 商品档案模块 三、系统设计3.1 用例图3.2 时序图3.3 类图3.4 E-R图 四、系统实现4.1 登录4.2 注册4.3 主页4.4 超市区域管理4.5 超市货架管理4.6 商品类型…

浅谈 Linux fork 函数

文章目录 前言fork 基本概念代码演示示例1:体会 fork 函数返回值的作用示例2:创建多进程,加深对 fork 函数的理解 前言 本篇介绍 fork 函数。 fork 基本概念 pid_t fork(void) fork 的英文含义是"分叉",在这里就是 …

Java知识点整理(一)

反射 反射是在运行状态中,动态获取类信息,以及动态调用对象的方法的功能叫做反射机制。在JDBC,Servlet,SpringIOC中 优点:能够灵活的创建代码,动态执行方法访问属性。 缺点:破坏了封装性&…

Mysql学习之MVCC解决读写问题

多版本并发控制 什么是MVCC MVCC (Multiversion Concurrency Control)多版本并发控制。顾名思义,MVCC是通过数据行的多个版本管理来实现数据库的并发控制。这项技术使得在InnoDB的事务隔离级别下执行一致性读操作有了保证。换言之&#xff0…

从零自制docker-1-【环境配置 docker go介绍与安装】

文章目录 docker简介举例docker安装go语言go安装go 配置 docker简介 Docker可以看作是一种极其轻巧的“虚拟机”,它允许你将一个或多个程序及其运行环境打包在一起,形成一个标准化的单元,这个单元可以在任何支持Docker的系统上运行&#xff…