内容提要:GCN背景简介+torch_geometric库安装+GCN处理Cora数据集

1.图神经网络

1.1 概念

原有的卷积神经网络主要用来解决欧式空间中的数据(数据规整,形状固定),例如图像数据。

无法应对非欧式空间中的数据,例如图数据。

但是神经网络是规整的计算方式,所以图神经网络的目标就是,如何去用规整的神经网络去处理不规整的图数据。

1.2 应用场景

非欧数据的场景很多,如:社交网络,计算机网络,病毒传播路径,交通运输网络(地铁网络),食物链,粒子网络(物理学家描述基本粒子生存的关系,有点类似家谱),说到家谱,家谱也是,(生物)神经网络(神经网络本来就是生物学术语,现在人工神经网络ANN太多,鸠占鹊巢了),基因控制网络,分子结构,知识图谱,推荐系统,论文引用网络等等。这些场景的非欧数据用(Graph)来表达是最合适的,但是,经典的深度学习网络(ANN,CNN,RNN)却难以处理这些非欧数据,于是,图神经网络(GNN)应运而生,GNN以图作为输入,输出各种下游任务的预测结果。

下游任务包括但不限于:

  • 节点分类:预测某一节点的类型
  • 边预测:预测两个节点之间是否存在边
  • 社区预测:识别密集连接的节点所形成的簇
  • 网络相似性: 两个(子)网络是否相似

2.GCN

2.1 图神经网络中层的概念

传统神经网络中是存在层的概念的,而在图神经网络中,层就代表从当前节点,是采用n跳的结果进行更新,这里的n就是层的数目,1跳就是用该节点临近的节点进行更新。

2.2 每一层的运算

每一层的计算其实可以看成一个矩阵相乘的运算,当前节点在当前层的嵌入等于它的邻居节点以及它本身的加权和,这个权值可以使用矩阵的形式表示(邻接矩阵),而节点的嵌入也可以使用矩阵的形式表示,所以最终可以把该运算转换成了一个矩阵相乘运算。

2.3 举例

问题标号

A:邻接矩阵(当有边存在,则为1,无边存在,则为0)

X:节点特征

D:度矩阵(度矩阵是对角矩阵,对角线表示了每个节点存在几个邻居,其余位置均为0)

结果向量中的6表示节点0的三个相邻节点的值和和,2表示节点1的两个相邻节点的和,以此类推。

你可能发现,节点0存在3个邻居,而节点3只有1个邻居,上面的矩阵乘法会导致邻居多的节点,在消息交换后的值倾向于比较大,这样不太合理,以均值代替求和更合适,这就是Aggregation Function = Mean的情况,一种实现这种均值消息交换的方法是使用度矩阵(Degree Matrix)。

A去除以D

注意到每行的和都等于1,第1行表示节点0有3条边,与节点2,3,4相连,故都是1/3;第4行表示节点3只有1条边与节点0相连,故为1。

但是这种安排,只考虑了邻居,而忽略了节点自己(A的对角线均为0),假设每个节点都有一条自指的边,则原来的邻接矩阵就变成了:

另外在实际应用中,对于度矩阵的应用,常常采用对称归一化,即:

最终的GCN公式为:

2.4 bonus

上面我们假设边的权重为1,权重也可以是不为1的的其他静态值,或者动态权重,那就是基于注意力的GAT了。

3.torch_geometric库安装

3.1 简介

torch_geometric(Pytorch Geometric)库是Pytorch中的图神经网络库,具体的使用方式和pytorch的平常使用没有区别,下面介绍它的安装方式

3.2 安装步骤

安装顺序:cuda->pytorch->torch_geometric

第一步:安装cuda(有gpu)+pytorch

第二步:安装torch_geometric

推荐在官网上安装torch-geometric

torch-geometric官网

注:这里不推荐在已有的python环境中安装,会出现奇怪的bug,这里推荐新建一个虚拟环境进行安装。

4.GCN处理Cora数据集

4.1 Cora数据集介绍

Cora数据集由2708篇机器学习领域的论文构成,每个样本点都是一篇论文,这些论文被分成7个类别。

4.2 数据集读取

# %%
# 数据加载
dataset = Planetoid(root="data/Cora", name="Cora")
print(dataset.num_classes)

4.3 数据探索

# %%
# 数据转换
CoraNet = to_networkx(dataset.data)
CoraNet = CoraNet.to_undirected()
Node_class = dataset.data.y.data.numpy()
print(Node_class)# %%
# 查看每个节点度的情况
Node_degree = pd.DataFrame(data=CoraNet.degree, columns=["Node", "Degree"])
Node_degree = Node_degree.sort_values(by=["Degree"], ascending=False)
Node_degree = Node_degree.reset_index(drop=True)
Node_degree.iloc[0:30, :].plot(x="Node", y="Degree", kind="bar", figsize=(10, 7))
plt.xlabel("Node", size=12)
plt.ylabel("Degree", size=12)
plt.show()

在可视化数据连接时,使用张量数据格式并不方便,我们这里使用torch_geometric库中的to_networkx函数,可以将Data格式转换成networks库中有向图的图数据,随后再进行可视化。

然后将节点的度信息转化为pandas的格式,进行绘图的结果如下:

# %%
# 绘制分布图
pos = nx.spring_layout(CoraNet)  # 网络图中节点的布局方式
nodecolor = ['red', 'blue', 'green', 'yellow', 'peru', 'violet', 'cyan']  # 颜色
nodelabel = np.array(list(CoraNet.nodes))  # 节点
plt.figure(figsize=(16, 12))# %%
for ii in np.arange(len(np.unique(Node_class))):nodelist = nodelabel[Node_class == ii]  # 对应类别的节点print(nodelist, ii)nx.draw_networkx_nodes(CoraNet, pos, nodelist=list(nodelist),node_size=50, node_color=nodecolor[ii],alpha=0.8)
nx.draw_networkx_edges(CoraNet, pos, width=1, edge_color="black")
plt.show()

在这里,主要是对于数据的分布进行查看,其中Node_class为每个节点对应的类别,这里不好理解的主要是np.arange(len(np.unique(Node_class)),这句主要是为了根据类别数获得对应的类别向量(例如,原来的类别数为7,则可获得[0,1,2,3,4,5,6]这样的类别向量)

最终绘图的结果如下图所示,这里是先绘制点,再绘制边:

我们这里的处理方法主要是使用半监督学习,这里只使用前140个样本对应的类别标签,而其他的节点虽然参与图卷积的计算,但是不会使用其类别标签进行监督。

下面对这140个样本进行可视化

# %%
#  可视化训练集节点分布
nodecolor = ['red', 'blue', 'green', 'yellow', 'peru', 'violet', 'cyan']  # 颜色
nodelabel = np.arange(0,140)
Node_class = dataset.data.y.data.numpy()[0:140]for ii in np.arange(len(np.unique(Node_class))):nodelist = nodelabel[Node_class == ii]nx.draw_networkx_nodes(CoraNet, pos, nodelist=list(nodelist),node_size=50, node_color=nodecolor[ii],alpha=0.8)plt.show()

4.4 网络构建和训练

# %%
# 构建一个网络模型类
class GCNnet(torch.nn.Module):def __init__(self, input_feature, num_classes):super(GCNnet, self).__init__()self.input_feature = input_feature  # 输入数据中,每个节点的特征数量self.num_classes = num_classesself.conv1 = GCNConv(input_feature, 32)self.conv2 = GCNConv(32, num_classes)def forward(self, data):x, edge_index = data.x, data.edge_indexx = self.conv1(x, edge_index)x = F.relu(x)x = self.conv2(x, edge_index)return F.softmax(x, dim=1)

使用torch_geometric.nn模块中的GCNConv类,可以完成图卷积的操作,十分简单,而且输入只需要指定,节点的输入特征数和最终目标特征数即可,在这里需要注意的是,在forward函数中,需要传入边的信息,也就是edge_index

# %%
input_feature = dataset.num_node_features  # 节点对应的特征数
num_classes = dataset.num_classes  # 类别数目
mygcn = GCNnet(input_feature, num_classes)
print(mygcn)

上面为网络初始化部分。

# %%
device = torch.device("cpu")
model = mygcn.to(device)
data = dataset[0].to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)
train_loss_all = []
val_loss_all = []
model.train()
for epoch in range(200):optimizer.zero_grad()out = model(data)loss = F.cross_entropy(out[data.train_mask], data.y[data.train_mask])loss.backward()optimizer.step()train_loss_all.append(loss.data.numpy())loss = F.cross_entropy(out[data.val_mask], data.y[data.val_mask])val_loss_all.append(loss)if epoch % 20 ==0:print("epoch",epoch,train_loss_all[-1],val_loss_all[-1])

训练部分中,只有前140个样本是训练集,也就是我们在做半监督学习,我们把整个数据集作为一个完整的batch进行训练。在优化的时候,只使用训练集中的数据,最终训练的结果如下:

绘制loss曲线

# %%
# 可视化损失函数
plt.figure(figsize=(10,6))
plt.plot(train_loss_all, "ro-", label="Train loss")
plt.plot(val_loss_all, "bs-", label="Val loss")
plt.legend()
plt.grid()
plt.xlabel("epoch", size=13)
plt.ylabel("Loss", size=13)
plt.show()

# %%
# 计算测试集上的准确率
model.eval()
_, pred = model(data).max(dim=1)
correct = float(pred[data.test_mask].eq(data.y[data.test_mask]).sum().item())
acc = correct / data.test_mask.sum().item()
print(acc)

最终的准确率为0.81

4.5 隐藏层特征可视化

# %%
# 进行TSNE姜维
from sklearn.manifold import TSNE
x_tsne = TSNE(n_components=2).fit_transform(dataset.data.x.data.numpy())
plt.figure()
ax1 = plt.subplot(1, 1, 1)
X = x_tsne[:, 0]
Y = x_tsne[:, 1]
ax1.set_xlim([min(X), max(X)])
ax1.set_ylim([min(Y), max(Y)])
for ii in range(x_tsne.shape[0]):text = dataset.data.y.data.numpy()[ii]ax1.text(X[ii], Y[ii], str(text), fontsize=5,bbox=dict(boxstyle="round", facecolor=plt.cm.Set1(text), alpha=0.7))
ax1.set_xlabel("TSNE Feature 1", size=13)
ax1.set_ylabel("TSNE Feature 2", size=13)
plt.show()

对原来的1433维的向量采用TSNE进行降维,并绘制对应的曲线。

​​​​​​​

# %%
# 使用钩子函数,查看网络中间的输出特征
activation = {}  # 保存不同层的输出def get_activation(name):def hook(model, input, output):  # 使用闭包activation[name] = output.detach()return hookmodel.conv1.register_forward_hook(get_activation("conv1"))
_ = model(data)
conv1 = activation["conv1"].data.numpy()
print(conv1.shape)

为了可视化图神经网络的中间特征,我们这里需要使用钩子函数,钩子函数是一种闭包函数。

# %%
# 使用钩子函数,查看网络中间的输出特征
activation = {}  # 保存不同层的输出def get_activation(name):def hook(model, input, output):  # 使用闭包activation[name] = output.detach()return hookmodel.conv1.register_forward_hook(get_activation("conv1"))
_ = model(data)
conv1 = activation["conv1"].data.numpy()
print(conv1.shape)# %%
conv1_tsne = TSNE(n_components=2).fit_transform(conv1)
plt.figure(figsize=(12, 8))
ax1 = plt.subplot(1, 1, 1)
X = conv1_tsne[:, 0]
Y = conv1_tsne[:, 1]
ax1.set_xlim([min(X), max(X)])
ax1.set_ylim([min(Y), max(Y)])
for ii in range(conv1_tsne.shape[0]):text = dataset.data.y.data.numpy()[ii]ax1.text(X[ii], Y[ii], str(text), fontsize=5,bbox=dict(boxstyle="round", facecolor=plt.cm.Set1(text), alpha=0.7))
ax1.set_xlabel("TSNE Feature 1", size=13)
ax1.set_ylabel("TSNE Feature 2", size=13)
plt.show()

由此图可见,数据分类已初见雏形。

4.6 与SVM,LP分类结果对比

# %%
from sklearn.metrics import accuracy_score
from sklearn.svm import SVC
from sklearn.semi_supervised import _label_propagation
X = dataset.data.x.data.numpy()
Y = dataset.data.y.data.numpy()
train_mask = dataset.data.train_mask.data.numpy()
test_mask = dataset.data.test_mask.data.numpy()
train_x = X[0:140, :]
train_y = Y[train_mask]
test_x = X[1708:2708, :]
test_y = Y[test_mask]svmmodel = SVC()
svmmodel.fit(train_x,train_y)
prelab = svmmodel.predict(test_x)
print(accuracy_score(test_y,prelab))

SVM方法,最终在测试集上的准确率为0.56,由于没有考虑节点之间的关系,所以准确率不如图神经网络的准确率.

# %%
# LP
X = dataset.data.x.data.numpy()
Y = dataset.data.y.data.numpy()
train_mask = dataset.data.train_mask.data.numpy()
test_mask = dataset.data.test_mask.data.numpy()
train_y = Y.copy()
train_y[test_mask == True] = -1
test_y = Y[test_mask]
lp_model = _label_propagation.LabelPropagation(kernel="knn", n_neighbors=3)
lp_model.fit(X, train_y)
prelab = lp_model.transduction_
print(accuracy_score(Y[test_mask], prelab[test_mask]))

LP方法,是一种半监督方法,最终的准确率为0.45.

4.7 代码汇总版

import torch
import torch.nn.functional as F
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from torch_geometric.nn import GCNConv
from torch_geometric.datasets import Planetoid
from torch_geometric.utils import to_networkx
import networkx as nx# %%
# 数据加载
dataset = Planetoid(root="data/Cora", name="Cora")
print(dataset.num_classes)# %%
# 数据探索
CoraNet = to_networkx(dataset.data)
CoraNet = CoraNet.to_undirected()
Node_class = dataset.data.y.data.numpy()
print(Node_class)# %%
# 查看每个节点度的情况
Node_degree = pd.DataFrame(data=CoraNet.degree, columns=["Node", "Degree"])
Node_degree = Node_degree.sort_values(by=["Degree"], ascending=False)
Node_degree = Node_degree.reset_index(drop=True)
Node_degree.iloc[0:30, :].plot(x="Node", y="Degree", kind="bar", figsize=(10, 7))
plt.xlabel("Node", size=12)
plt.ylabel("Degree", size=12)
plt.show()# %%
# 绘制分布图
pos = nx.spring_layout(CoraNet)  # 网络图中节点的布局方式
nodecolor = ['red', 'blue', 'green', 'yellow', 'peru', 'violet', 'cyan']  # 颜色
nodelabel = np.array(list(CoraNet.nodes))  # 节点
plt.figure(figsize=(16, 12))# %%
for ii in np.arange(len(np.unique(Node_class))):nodelist = nodelabel[Node_class == ii]  # 对应类别的节点print(nodelist, ii)nx.draw_networkx_nodes(CoraNet, pos, nodelist=list(nodelist),node_size=50, node_color=nodecolor[ii],alpha=0.8)
nx.draw_networkx_edges(CoraNet, pos, width=1, edge_color="black")
plt.show()# %%
#  可视化训练集节点分布
nodecolor = ['red', 'blue', 'green', 'yellow', 'peru', 'violet', 'cyan']  # 颜色
nodelabel = np.arange(0, 140)
Node_class = dataset.data.y.data.numpy()[0:140]for ii in np.arange(len(np.unique(Node_class))):nodelist = nodelabel[Node_class == ii]nx.draw_networkx_nodes(CoraNet, pos, nodelist=list(nodelist),node_size=50, node_color=nodecolor[ii],alpha=0.8)plt.show()# %%
# 构建一个网络模型类
class GCNnet(torch.nn.Module):def __init__(self, input_feature, num_classes):super(GCNnet, self).__init__()self.input_feature = input_feature  # 输入数据中,每个节点的特征数量self.num_classes = num_classesself.conv1 = GCNConv(input_feature, 32)self.conv2 = GCNConv(32, num_classes)def forward(self, data):x, edge_index = data.x, data.edge_indexx = self.conv1(x, edge_index)x = F.relu(x)x = self.conv2(x, edge_index)return F.softmax(x, dim=1)# %%
input_feature = dataset.num_node_features  # 节点对应的特征数
num_classes = dataset.num_classes  # 类别数目
mygcn = GCNnet(input_feature, num_classes)
print(mygcn)# %%
data = dataset[0].train_mask
print(data)
data = data[data == True]
print(len(data))# %%
device = torch.device("cpu")
model = mygcn.to(device)
data = dataset[0].to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)
train_loss_all = []
val_loss_all = []
model.train()
for epoch in range(200):optimizer.zero_grad()out = model(data)loss = F.cross_entropy(out[data.train_mask], data.y[data.train_mask])loss.backward()optimizer.step()train_loss_all.append(loss.data.numpy())loss = F.cross_entropy(out[data.val_mask], data.y[data.val_mask])val_loss_all.append(loss.data.numpy())if epoch % 20 == 0:print("epoch", epoch, train_loss_all[-1], val_loss_all[-1])# %%
# 可视化损失函数
plt.figure(figsize=(10, 6))
plt.plot(train_loss_all, "ro-", label="Train loss")
plt.plot(val_loss_all, "bs-", label="Val loss")
plt.legend()
plt.grid()
plt.xlabel("epoch", size=13)
plt.ylabel("Loss", size=13)
plt.show()# %%
# 计算测试集上的准确率
model.eval()
_, pred = model(data).max(dim=1)
correct = float(pred[data.test_mask].eq(data.y[data.test_mask]).sum().item())
acc = correct / data.test_mask.sum().item()
print(acc)# %%
# 进行TSNE姜维
from sklearn.manifold import TSNEx_tsne = TSNE(n_components=2).fit_transform(dataset.data.x.data.numpy())
plt.figure(figsize=(12, 8))
ax1 = plt.subplot(1, 1, 1)
X = x_tsne[:, 0]
Y = x_tsne[:, 1]
ax1.set_xlim([min(X), max(X)])
ax1.set_ylim([min(Y), max(Y)])
for ii in range(x_tsne.shape[0]):text = dataset.data.y.data.numpy()[ii]ax1.text(X[ii], Y[ii], str(text), fontsize=5,bbox=dict(boxstyle="round", facecolor=plt.cm.Set1(text), alpha=0.7))
ax1.set_xlabel("TSNE Feature 1", size=13)
ax1.set_ylabel("TSNE Feature 2", size=13)
plt.show()# %%
# 使用钩子函数,查看网络中间的输出特征
activation = {}  # 保存不同层的输出def get_activation(name):def hook(model, input, output):  # 使用闭包activation[name] = output.detach()return hookmodel.conv1.register_forward_hook(get_activation("conv1"))
_ = model(data)
conv1 = activation["conv1"].data.numpy()
print(conv1.shape)# %%
conv1_tsne = TSNE(n_components=2).fit_transform(conv1)
plt.figure(figsize=(12, 8))
ax1 = plt.subplot(1, 1, 1)
X = conv1_tsne[:, 0]
Y = conv1_tsne[:, 1]
ax1.set_xlim([min(X), max(X)])
ax1.set_ylim([min(Y), max(Y)])
for ii in range(conv1_tsne.shape[0]):text = dataset.data.y.data.numpy()[ii]ax1.text(X[ii], Y[ii], str(text), fontsize=5,bbox=dict(boxstyle="round", facecolor=plt.cm.Set1(text), alpha=0.7))
ax1.set_xlabel("TSNE Feature 1", size=13)
ax1.set_ylabel("TSNE Feature 2", size=13)
plt.show()# %%
# SVM
from sklearn.metrics import accuracy_score
from sklearn.svm import SVC
from sklearn.semi_supervised import _label_propagation
X = dataset.data.x.data.numpy()
Y = dataset.data.y.data.numpy()
train_mask = dataset.data.train_mask.data.numpy()
test_mask = dataset.data.test_mask.data.numpy()
train_x = X[0:140, :]
train_y = Y[train_mask]
test_x = X[1708:2708, :]
test_y = Y[test_mask]svmmodel = SVC()
svmmodel.fit(train_x,train_y)
prelab = svmmodel.predict(test_x)
print(accuracy_score(test_y,prelab))# %%
# LP
X = dataset.data.x.data.numpy()
Y = dataset.data.y.data.numpy()
train_mask = dataset.data.train_mask.data.numpy()
test_mask = dataset.data.test_mask.data.numpy()
train_y = Y.copy()
train_y[test_mask == True] = -1
test_y = Y[test_mask]
lp_model = _label_propagation.LabelPropagation(kernel="knn", n_neighbors=3)
lp_model.fit(X, train_y)
prelab = lp_model.transduction_
print(accuracy_score(Y[test_mask], prelab[test_mask]))

5.总结

由于自己目前在做的项目与图神经网络有一定关系,所以就抽了一些时间以GCN这一种方法为例进行了学习。本文中很多基础知识都来自于知乎的gwave大佬(gwave - 知乎),然后本文的GCN项目是来自余本国老师的《Pytorch深度学习入门与实战》(Pytorch 深度学习入门与实战)

图神经网络学习(一)-GCN及其应用相关推荐

  1. 【GNN报告】考虑拓扑信息的图神经网络学习

    1.简介 打算之后在本博客里存放BAAI里面邀请的所有演讲者有关GNN的报告学习(本人筛选的都是自己感兴趣的或者感觉还不错的) 2.报告 腾讯林衍凯:图神经网络,考虑「拓扑信息」会怎样? [专栏:前沿 ...

  2. 图神经网络学习笔记-01基础

    图神经网络-01基础-图与图学习 文章目录 图神经网络-01基础-图与图学习 图是什么 图的定义 图的基本表示方法 e.g 图的存储 图的类型和性质 图算法 1. 寻路和图搜索算法 1). 搜索算法 ...

  3. 【笔记整理】图神经网络学习

    [笔记整理]图神经网络学习 文章目录 [笔记整理]图神经网络学习 一.GNN简介 1.图结构 & 图基础算法 1)引言("非欧几何, 处理图数据的NN") 2)图基本概念 ...

  4. 【论文解读】Graph Normalization (GN):为图神经网络学习一个有效的图归一化

    作者|平安产险视觉计算组 编辑丨极市平台 本文为极市开发者投稿,转载请获授权. 极市专栏 论文推荐:在图神经网络里面,应该如何选择更好的归一化技术?本文将介绍一种为图神经网络学习有效的图归一化的方式. ...

  5. 2023.2.9,周四【图神经网络 学习记录23】动态图算法 之 SGNN(DGNN):更新组件(update component),传播组件(propagation component)

    路虽远,行则将至. 声明:仅学习使用. 前情提要: 2023.2.9,周四[图神经网络 学习记录22]动态图算法 之 EvolveGCN:离散型动态GNN网络,将GNN和RNN结合到同一层,结合时间和 ...

  6. 2023.2.3,周五【图神经网络 学习记录17】二部图——BiNE算法:显式关系,隐式关系;新的随机游走方式 特点:随机游走次数 是跟节点中心性相关的,在随机游走的过程中 添加一个停止随机游走的概率

    声明:仅学习使用~ 前情提要: 2023.2.2,周四[图神经网络 学习记录16]异构图Graph Embedding算法--GATNE(异构图多属性 多边 类型算法),不建议普通PC跑-PyChar ...

  7. 【图神经网络】简化 GCN(SGC)

    本文为图神经网络学习笔记,讲解 SGC.欢迎在评论区与我交流

  8. PGL图学习之图神经网络GNN模型GCN、GAT

    在4922份提交内容中,主要涉及13个研究方向,具体有: 1.AI应用应用,例如:语音处理.计算机视觉.自然语言处理等 2.深度学习和表示学习 3.通用机器学习 4.生成模型 5.基础设施,例如:数据 ...

  9. 逆势而上的技术:图神经网络学习来了!

    要问这几年一直在逆势而上的技术有哪些?你一定不会忽略它--图神经网络. 相比传统神经网络,图神经网络的优势非常明显: 1.非顺序排序的特征学习:GNN的输出不以节点的输入顺序为转移的. 2.两个节点之 ...

最新文章

  1. andriod studio中的显式跳转和隐式跳转
  2. 零基础学习大数据开发需要多久能工作?
  3. Android SharedPreferences存储map的方法
  4. 改善代码设计 —— 组织好你的数“.NET研究”据(Composing Data)
  5. 性能比拼!超详细的Tengine GEMM矩阵乘法汇编教程
  6. Android Instant Apps教程
  7. React Native组件(四)TextInput组件解析
  8. AWVS14.5最新版的安装与使用
  9. 关于Kubernetes集群中常见问题的排查方法的一些笔记
  10. AE表达式中英对照及解释
  11. UA OPTI570 量子力学 角动量 公式与结论总结
  12. #年轻人找工作应该把钱放第一位吗#
  13. LaTex学习-安装
  14. 如何运行PHP文件 /创建PHP项目【基于VScode、XAMPP】超级详细,亲测有效,这一篇就够了
  15. 通用计算机(PC)和手机是否属于嵌入式设备?(嵌入式的定义)-杂谈
  16. Camera开发常见专业术语名词解释
  17. php防止恶意注册,PHP怎样防止用户注册高仿其他人的用户名?
  18. 计算机游戏的作文,电脑游戏作文3000字初一_查字典作文网
  19. 14、ICMP协议的主要功能
  20. 2021春哈工大计算机系统大作业

热门文章

  1. [图像几何变换]——图像的仿射变换、透射变换及图像金字塔
  2. SQL经典语句大全及应用示例汇总
  3. java中IOException是什么异常
  4. helm模板开发-流程控制、作用域、循环、变量(三)
  5. 看看同一种字体是如何对应不同的字体文件的
  6. android应用程序耗电,Android的十大耗电量应用程序,在软件中排名第一
  7. C++ 简易的五子棋游戏 初学者
  8. 南阳ACM 题目722 数独
  9. 阿里云不同账号新旧服务器镜像迁移数据迁移同步
  10. 网页怎么算切屏_电脑怎么切屏