本教程译文的第一部分,请见我的上一篇博文:

Stanford CS224N: PyTorch Tutorial (Winter ‘21) —— 斯坦福CS224N PyTorch教程 (第一部分)_放肆荒原的博客-CSDN博客

运算(Operations)

PyTorch 运算与 NumPy 的运算非常相似。 我们可以使用标量和其他张量。

In [40]:

# Create an example tensor
# 创建一个示例张量
x = torch.ones((3,2,2))
x

Out [40]:

tensor([[[1., 1.],[1., 1.]],[[1., 1.],[1., 1.]],[[1., 1.],[1., 1.]]])

In [41]:

# Perform elementwise addition
# Use - for subtraction
# 执行元素级加法
# 使用 - 进行减法
x + 2

Out [41]:

tensor([[[3., 3.],[3., 3.]],[[3., 3.],[3., 3.]],[[3., 3.],[3., 3.]]])

In [42]:

# Perform elementwise multiplication
# Use / for division
# 执行元素乘法
# 用 / 进行除法
x * 2

Out [42]:

tensor([[[2., 2.],[2., 2.]],[[2., 2.],[2., 2.]],[[2., 2.],[2., 2.]]])

我们可以在大小兼容的不同张量之间应用相同的运算。

In [43]:

# Create a 4x3 tensor of 6s
# 创建一个全6的4x3张量
a = torch.ones((4,3)) * 6
a

Out [43]:

tensor([[6., 6., 6.],[6., 6., 6.],[6., 6., 6.],[6., 6., 6.]])

In [44]:

# Create a 1D tensor of 2s
# 创建一个全2的1D张量
b = torch.ones(3) * 2
b

Out [44]:

tensor([2., 2., 2.])

In [45]:

# Divide a by b
# 把a除以b
a / b

Out [45]:

tensor([[3., 3., 3.],[3., 3., 3.],[3., 3., 3.],[3., 3., 3.]])

我们可以使用 tensor.matmul(other_tensor) 进行矩阵乘法,使用 tensor.T 进行转置。 矩阵乘法也可以用@ 来执行。

In [46]:

# Alternative to a.matmul(b)
# a @ b.T returns the same result since b is 1D tensor and the 2nd dimension
# is inferred
# 可替代 a.matmul(b)
# a @ b.T 返回相同的结果,因为b是1D张量,第二维是推断的。
a @ b 

Out [46]:

tensor([36., 36., 36., 36.])

In [47]:

pp.pprint(a.shape)
pp.pprint(a.T.shape)

Out [47]:

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

我们可以使用 mean(dim) 和 std(dim) 方法沿某个维度获取均值和标准差。 也就是说,如果我们想得到一个 4x3x2 矩阵中的平均 3x2 矩阵,我们将设置 dim 为 0。我们可以不带参数调用这些方法来获取整个张量的均值和标准差。 要使用 mean 和 std 我们的张量应该是浮点类型。

In [48]:

# Create an example tensor
# 创建一个示例张量
m = torch.tensor([[1., 1.],[2., 2.],[3., 3.],[4., 4.]]
)pp.pprint("Mean: {}".format(m.mean()))
pp.pprint("Mean in the 0th dimension: {}".format(m.mean(0)))
pp.pprint("Mean in the 1st dimension: {}".format(m.mean(1)))

Out [48]:

'Mean: 2.5'
'Mean in the 0th dimension: tensor([2.5000, 2.5000])'
'Mean in the 1st dimension: tensor([1., 2., 3., 4.])'

我们可以使用 torch.cat 连接张量。

In [49]:

# Concatenate in dimension 0 and 1
# 在维度 0 和 1 中连接
a_cat0 = torch.cat([a, a, a], dim=0)
a_cat1 = torch.cat([a, a, a], dim=1)print("Initial shape: {}".format(a.shape))
print("Shape after concatenation in dimension 0: {}".format(a_cat0.shape))
print("Shape after concatenation in dimension 1: {}".format(a_cat1.shape))

Out [49]:

Initial shape: torch.Size([4, 3])
Shape after concatenation in dimension 0: torch.Size([12, 3])
Shape after concatenation in dimension 1: torch.Size([4, 9])

PyTorch 中的大部分操作都没有就地操作。 但是,PyTorch 通过在方法名称的末尾添加下划线 (_) 来提供可用的就地操作版本。

In [50]:

# Print our tensor
a

Out [50]:

tensor([[6., 6., 6.],[6., 6., 6.],[6., 6., 6.],[6., 6., 6.]])

In [51]:

# add() is not in place
# add() 不能就地操作
a.add(a)
a

Out [51]:

tensor([[6., 6., 6.],[6., 6., 6.],[6., 6., 6.],[6., 6., 6.]])

In [52]:

# add_() is in place
# add_() 是就地操作的
a.add_(a)
a

Out [52]:

tensor([[12., 12., 12.],[12., 12., 12.],[12., 12., 12.],[12., 12., 12.]])

Autograd(自动梯度计算)

PyTorch 和其他机器学习库以其自动微分功能而闻名。 也就是说,鉴于我们已经定义了需要执行的一组操作,框架本身可以弄清楚如何计算梯度。 我们可以调用backward() 方法让PyTorch 计算梯度,然后将其存储在grad 属性中。

In [53]:

# Create an example tensor
# requires_grad parameter tells PyTorch to store gradients
# 创建一个示例张量
# requires_grad参数告诉 PyTorch 存储梯度
x = torch.tensor([2.], requires_grad=True)# Print the gradient if it is calculated
# Currently None since x is a scalar
# 如果梯度计算出来就打印
# 目前没有,因为 x 是一个标量
pp.pprint(x.grad)
None

In [54]:

# Calculating the gradient of y with respect to x
# 计算 y 相对于 x 的梯度
y = x * x * 3 # 3x^2
y.backward()
pp.pprint(x.grad) # d(y)/d(x) = d(3x^2)/d(x) = 6x = 12
tensor([12.])

让我们再次从不同的张量运行反向传播,看看会发生什么。

In [55]:

z = x * x * 3 # 3x^2
z.backward()
pp.pprint(x.grad)
tensor([24.])

我们可以看到 x.grad 被更新为到目前为止计算的梯度的总和。 当我们在神经网络中运行反向传播时,我们会在进行更新之前汇总特定神经元的所有梯度。 这正是这里发生的事情! 这也是我们需要在每次训练迭代中运行 zero_grad() 的原因(稍后会详细介绍)。 否则我们的梯度会从一个训练迭代到另一个训练迭代不断增加,这将导致我们的更新错误。

神经网络模块(Neural Network Module)

到目前为止,我们已经研究了张量,它们的性质和对张量的基本运算。如果我们从头开始构建网络的各个层,那么熟悉这些功能尤其有用。我们将在作业3中使用这些模块,但接下来,我们将在PyTorch的torch.nn模块中使用预定义的模块。然后,我们将把这些块放在一起,创建复杂的网络。让我们先用一个别名导入这个模块,这样我们就不必在每次使用它时都键入torch。

In [56]:

import torch.nn as nn

线性层(Linear Layer)

我们可以使用 nn.Linear(H_in, H_out) 创建一个线性层。 这将采用 (N, *, H_in) 维矩阵并输出 (N, *, H_out) 矩阵。 * 表示两者之间可以有任意数量的维度。 线性层执行操作 Ax+b,其中 A 和 b 随机初始化。 如果我们不想让线性层学习偏置参数,我们可以用bias=False 来初始化我们的层。

In [57]:

# Create the inputs
# 创建输入
input = torch.ones(2,3,4)# Make a linear layers transforming N,*,H_in dimensinal inputs to N,*,H_out
# 创建一个线性层,将 N,*,H_in 维度输入转换为 N,*,H_out
# dimensional outputs
linear = nn.Linear(4, 2)
linear_output = linear(input)
linear_output

Out [57]:

tensor([[[0.1796, 0.1423],[0.1796, 0.1423],[0.1796, 0.1423]],[[0.1796, 0.1423],[0.1796, 0.1423],[0.1796, 0.1423]]], grad_fn=<AddBackward0>)

其他模块层(Other Module Layers)

nn 模块中还有其他几个预配置层。 一些常用的例子是 nn.Conv2d、nn.ConvTranspose2d、nn.BatchNorm1d、nn.BatchNorm2d、nn.Upsample 和 nn.MaxPool2d 等等。 随着课程的进展,我们将更多地了解这些。 目前,唯一要记住的重要事情是我们可以将这些层中的每一个都视为即插即用的组件:我们将提供所需的维度,PyTorch 将负责设置它们。

激活函数层(Activation Function Layer)

我们还可以使用 nn 模块将激活函数应用于我们的张量。 激活函数用于为我们的网络添加非线性。 一些激活函数的例子是 nn.ReLU()、nn.Sigmoid() 和 nn.LeakyReLU()。 激活函数分别对每个元素进行操作,因此我们作为输出得到的张量的形状与我们传入的张量的形状相同。

In [58]:

linear_output

Out [58]:

tensor([[[0.1796, 0.1423],[0.1796, 0.1423],[0.1796, 0.1423]],[[0.1796, 0.1423],[0.1796, 0.1423],[0.1796, 0.1423]]], grad_fn=<AddBackward0>)

In [59]:

sigmoid = nn.Sigmoid()
output = sigmoid(linear_output)
output

Out [59]:

tensor([[[0.5448, 0.5355],[0.5448, 0.5355],[0.5448, 0.5355]],[[0.5448, 0.5355],[0.5448, 0.5355],[0.5448, 0.5355]]], grad_fn=<SigmoidBackward>)

把层放在一起(Putting the Layers Together)

到目前为止,我们已经看到,我们可以创建层,并将一个层的输出作为下一个层的输入传递。我们可以使用nn.Sequentual,而不是创建中间张量并传递它们,它正是这样做的。

In [60]:

block = nn.Sequential(nn.Linear(4, 2),nn.Sigmoid()
)input = torch.ones(2,3,4)
output = block(input)
output

Out [60]:

tensor([[[0.3630, 0.3951],[0.3630, 0.3951],[0.3630, 0.3951]],[[0.3630, 0.3951],[0.3630, 0.3951],[0.3630, 0.3951]]], grad_fn=<SigmoidBackward>)

自定义模块(Custom Modules)

除了使用预定义的模块,我们还可以通过扩展 nn.Module 类来构建我们自己的模块。 例如,我们可以使用前面介绍的张量自行构建一个 nn.Linear(它也扩展了 nn.Module)! 我们还可以构建新的、更复杂的模块,例如自定义神经网络。 您将在以后的作业中练习这些。

要创建自定义模块,我们要做的第一件事就是扩展 nn.Module。 然后我们可以在 __init__ 函数中初始化我们的参数,从调用超类的 __init__ 函数开始。 我们定义的所有 nn 模块对象的类属性都被视为参数,可以在训练期间学习。 张量不是参数,但如果将它们包装在 nn.Parameter 类中,则可以将它们变成参数。

所有扩展 nn.Module 的类也应该实现一个 forward(x) 函数,其中 x 是一个张量。 这是在将参数传递给我们的模块时调用的函数,例如在 model(x) 中。

In [61]:

class MultilayerPerceptron(nn.Module):def __init__(self, input_size, hidden_size):# Call to the __init__ function of the super class# 调用超类的 __init__ 函数super(MultilayerPerceptron, self).__init__()# Bookkeeping: Saving the initialization parameters# 簿记:保存初始化参数self.input_size = input_size self.hidden_size = hidden_size # Defining of our model# There isn't anything specific about the naming of `self.model`. It could# be something arbitrary.# 定义我们的模型# 关于`self.model`的命名没有什么特别的,它是任意的。self.model = nn.Sequential(nn.Linear(self.input_size, self.hidden_size),nn.ReLU(),nn.Linear(self.hidden_size, self.input_size),nn.Sigmoid())def forward(self, x):output = self.model(x)return output

这是定义相同类的另一种方法。 可以看到,我们可以通过在 __init__ 方法中定义各个层并在 forward 方法中连接它们来替换 nn.Sequential。

class MultilayerPerceptron(nn.Module):def __init__(self, input_size, hidden_size):# Call to the __init__ function of the super class# 调用超类的 __init__ 函数super(MultilayerPerceptron, self).__init__()# Bookkeeping: Saving the initialization parameters# 簿记:保存初始化参数self.input_size = input_size self.hidden_size = hidden_size # Defining of our layers# 定义我们的层self.linear = nn.Linear(self.input_size, self.hidden_size)self.relu = nn.ReLU()self.linear2 = nn.Linear(self.hidden_size, self.input_size)self.sigmoid = nn.Sigmoid()def forward(self, x):linear = self.linear(x)relu = self.relu(linear)linear2 = self.linear2(relu)output = self.sigmoid(linear2)return output

现在我们已经定义了我们的类,我们可以实例化它并看看它做了什么。

In [63]:

# Make a sample input
# 做一个样本输入
input = torch.randn(2, 5)# Create our model
# 创建我们的模型
model = MultilayerPerceptron(5, 3)# Pass our input through our model
# 传递我们的输入到我们的模型
model(input)

Out [63]:

tensor([[0.5887, 0.4685, 0.4995, 0.6062, 0.3894],[0.5292, 0.5144, 0.4310, 0.5821, 0.3681]], grad_fn=<SigmoidBackward>)

我们可以使用 named_parameters() 和 parameters() 方法检查模型的参数。

In [64]:

list(model.named_parameters())

Out [64]:

[('linear.weight', Parameter containing:tensor([[ 0.0517,  0.0466, -0.3616, -0.3459, -0.3524],[ 0.0680,  0.0945, -0.3261,  0.1835,  0.4344],[-0.3985,  0.1973, -0.1373, -0.2314, -0.1868]], requires_grad=True)),('linear.bias', Parameter containing:tensor([-0.0924,  0.1563, -0.3934], requires_grad=True)),('linear2.weight', Parameter containing:tensor([[-0.1111,  0.4216, -0.0263],[-0.5714, -0.3207, -0.5514],[ 0.1727,  0.4809, -0.4426],[ 0.3308,  0.1744, -0.2814],[ 0.2347,  0.1584,  0.0537]], requires_grad=True)),('linear2.bias', Parameter containing:tensor([ 0.1169,  0.0575, -0.2778,  0.3314, -0.5406], requires_grad=True))]

优化(Optimization)

我们已经展示了使用backward()函数是如何计算梯度的。对于我们的模型来说,拥有梯度是不够的。我们还需要知道如何更新模型的参数。这就是优化器的用武之地。torch.optim 模块包含几个我们可以使用的优化器。 一些流行的例子是 optim.SGD 和 optim.Adam。在初始化优化器时,我们传递我们的模型参数,这些参数可以通过 model.parameters() 访问,告诉优化器它将优化哪些值。 优化器还有一个学习率 (lr) 参数,它决定了每一步将进行多大的更新。 不同的优化器也有不同的超参数。

In [65]:

import torch.optim as optim

有了优化函数后,我们可以定义要优化的损失。 我们可以自己定义损失,也可以使用 PyTorch 中预定义的损失函数之一,例如 nn.BCELoss()。 现在让我们把所有东西放在一起! 我们将从创建一些虚拟数据开始。

In [66]:

# Create the y data
# 创建y数据
y = torch.ones(10, 5)# Add some noise to our goal y to generate our x
# We want out model to predict our original data, albeit the noise
# 给我们的目标 y 添加一些噪音来生成我们的 x
# 我们希望我们的模型预测我们的原始数据,尽管有噪音
x = y + torch.randn_like(y)
x

Out [66]:

tensor([[ 0.6017, -0.1942,  1.5013,  0.8077,  0.4822],[ 2.4198,  1.6348,  1.7984,  2.7030,  1.8514],[-0.2632,  1.1230,  0.4369,  1.1091, -0.7259],[ 1.5842,  1.6495, -0.6160,  1.4506,  0.5238],[-0.4652,  1.1538,  4.0669, -0.4767,  3.2751],[ 1.6152,  0.1758,  0.6275,  1.8919,  2.0594],[ 2.4223,  0.6465,  1.0125,  0.2578, -0.2029],[ 1.6735,  0.9132,  0.3643,  0.9575,  1.7279],[ 3.0019,  0.7942,  2.0360,  1.3991,  1.3139],[ 0.8813,  0.7213,  1.6067, -0.5509,  1.3748]])

现在,我们可以定义我们的模型、优化器和损失函数。

In [67]:

# Instantiate the model
# 实例化模型
model = MultilayerPerceptron(5, 3)# Define the optimizer
# 定义优化器
adam = optim.Adam(model.parameters(), lr=1e-1)# Define loss using a predefined loss function
# 使用预定义的损失函数定义损失
loss_function = nn.BCELoss()# Calculate how our model is doing now
# 计算看看我们的模型现在的表现
y_pred = model(x)
loss_function(y_pred, y).item()

Out [67]:

0.7392909526824951

让我们看看我们是否可以让我们的模型实现更小的损失。 现在我们拥有了所需的一切,我们可以设置训练循环。

In [68]:

# Set the number of epoch, which determines the number of training iterations
# 设置epoch数,决定训练迭代次数
n_epoch = 10 for epoch in range(n_epoch):# Set the gradients to 0# 设置梯度为0adam.zero_grad()# Get the model predictions# 获取模型预测y_pred = model(x)# Get the loss# 获取损失loss = loss_function(y_pred, y)# Print stats# 打印统计信息print(f"Epoch {epoch}: traing loss: {loss}")# Compute the gradients# 计算梯度loss.backward()# Take a step to optimize the weights# 走一个step优化权重adam.step()
Epoch 0: traing loss: 0.7392909526824951
Epoch 1: traing loss: 0.6668772101402283
Epoch 2: traing loss: 0.5994036793708801
Epoch 3: traing loss: 0.5073628425598145
Epoch 4: traing loss: 0.4047197103500366
Epoch 5: traing loss: 0.30285021662712097
Epoch 6: traing loss: 0.21625970304012299
Epoch 7: traing loss: 0.13478505611419678
Epoch 8: traing loss: 0.0776328295469284
Epoch 9: traing loss: 0.042155299335718155

你可以看到我们的损失在减少。 现在让我们检查一下我们模型的预测,看看它们是否接近我们原来的 y,它全是 1。

In [69]:

# See how our model performs on the training data
# 查看我们的模型在训练数据上的表现
y_pred = model(x)
y_pred

Out [69]:

tensor([[0.8869, 0.9687, 0.9948, 0.9771, 0.9804],[0.9883, 0.9996, 1.0000, 0.9999, 0.9999],[0.8704, 0.9590, 0.9919, 0.9672, 0.9716],[0.9508, 0.9937, 0.9996, 0.9973, 0.9979],[0.9012, 0.9760, 0.9967, 0.9839, 0.9864],[0.9526, 0.9941, 0.9997, 0.9975, 0.9981],[0.9466, 0.9926, 0.9995, 0.9967, 0.9973],[0.9450, 0.9922, 0.9995, 0.9964, 0.9971],[0.9812, 0.9989, 1.0000, 0.9997, 0.9998],[0.8866, 0.9685, 0.9948, 0.9769, 0.9803]], grad_fn=<SigmoidBackward>)

In [70]:

# Create test data and check how our model performs on it
# 创建测试数据并检查我们的模型在其上的表现
x2 = y + torch.randn_like(y)
y_pred = model(x2)
y_pred

Out [70]:

tensor([[0.9582, 0.9954, 0.9998, 0.9982, 0.9986],[0.9217, 0.9847, 0.9984, 0.9912, 0.9927],[0.9209, 0.9844, 0.9984, 0.9909, 0.9925],[0.9410, 0.9911, 0.9994, 0.9957, 0.9966],[0.9694, 0.9974, 0.9999, 0.9992, 0.9994],[0.9360, 0.9896, 0.9992, 0.9947, 0.9957],[0.9561, 0.9949, 0.9997, 0.9980, 0.9984],[0.9290, 0.9874, 0.9988, 0.9931, 0.9944],[0.9754, 0.9983, 1.0000, 0.9995, 0.9996],[0.8905, 0.9706, 0.9953, 0.9789, 0.9821]], grad_fn=<SigmoidBackward>)

太棒了! 看起来我们的模型几乎完美地学会了从我们传入的 x 中过滤掉噪声!

(第三部分 演示:词窗分类 一(Demo: Word Window Classification I)​​​​​​​)

Stanford CS224N: PyTorch Tutorial (Winter ‘21) —— 斯坦福CS224N PyTorch教程 (第二部分)相关推荐

  1. 第四期 | 带学斯坦福CS224n自然语言处理课+带打全球Kaggle比赛(文末重金招募老师!)...

    在未来五年,你认为人工智能领域最具有商业价值的方向是什么? 上个月我和一个算法工程师朋友聊了聊,询问算法岗的行业薪资,他说现在计算机视觉算法岗工程师年薪大约50万左右,正当我感叹如今计算机视觉的火爆时 ...

  2. 斯坦福CS224n追剧计划【大结局】:NLP和深度学习的未来

    一只小狐狸带你解锁炼丹术&NLP秘籍 简介 Stanford CS224n追剧计划是由夕小瑶的卖萌屋发起的开源开放NLP入门项目,借助github和微信群为大家提供同期小伙伴打卡讨论.内容沉淀 ...

  3. 斯坦福cs224n教程--- 学习笔记1

    一.前言 自然语言是人类智慧的结晶,自然语言处理是人工智能中最为困难的问题之一,而对自然语言处理的研究也是充满魅力和挑战的. 通过经典的斯坦福cs224n教程,让我们一起和自然语言处理共舞!也希望大家 ...

  4. 斯坦福 CS224n 中文笔记整理活动 | ApacheCN

    参与方式:https://github.com/apachecn/stanford-cs224n-notes-zh/blob/master/CONTRIBUTING.md 整体进度:https://g ...

  5. Show, Attend, and Tell | a PyTorch Tutorial to Image Captioning代码调试(跑通)

    Show, Attend, and Tell | a PyTorch Tutorial to Image Captioning代码调试(跑通) 文章目录 Show, Attend, and Tell ...

  6. PyTorch Tutorial

    目录 图像.视觉.CNN相关实现 对抗生成网络.生成模型.GAN相关实现 机器翻译.问答系统.NLP相关实现 先进视觉推理系统 深度强化学习相关实现 通用神经网络高级应用 图像.视觉.CNN相关实现 ...

  7. 【李宏毅2020 ML/DL】P16 PyTorch Tutorial | 最后提及了 apex.amp

    我已经有两年 ML 经历,这系列课主要用来查缺补漏,会记录一些细节的.自己不知道的东西. 已经有人记了笔记(很用心,强烈推荐): https://github.com/Sakura-gh/ML-not ...

  8. 全网顶尖,毫不夸张的说这份斯坦福大学机器学习教程中文笔记,能让你机器学习从入门到精通

    人工智能 人工智能,无疑是现在最火的概念,从AlphaGo打败李世石后,全世界掀起了一股人工智能的浪潮.我们在生活中的各个角落,都能感受到一个崭新的奇点时代即将来临 人工智能充气鞋垫 人工智能马桶 ( ...

  9. 基于pytorch使用实现CNN 如何使用pytorch构建CNN卷积神经网络

    基于pytorch使用实现CNN 如何使用pytorch构建CNN卷积神经网络 所用工具 文件结构: 数据: 代码: 结果: 改进思路 拓展 本文是一个基于pytorch使用CNN在生物信息学上进行位 ...

最新文章

  1. hdu 3622 Bomb Game【二分+2-SAT+tarjan】
  2. 键盘各键对应的ASCII码值
  3. Excel中的的经纬度坐标在地图上显示
  4. 3-4 第三天 Generator生成器
  5. c#endread怎么打印出来_C#编程直接发送打印机命令到打印机及ZPL常用的打印命令详解...
  6. 计算机编程输入与输出,计算机编程语言的发展与输入输出设备的使用
  7. 记一次成功部署kolla-ansible ocata版本过程
  8. 【新功能发布】事件监控升级-支持自动化处理云产品异常
  9. DIV布局美丽家乡网站设计——美丽家乡-含论文(4页) HTML+CSS+JavaScript web前端设计与开发期末作品_期末大作业
  10. c语言数学函数库根号程序,数学函数8.2.3次方与开根号C语言入门经典.ppt
  11. 2021-2027全球与中国兽医临床试验业务市场现状及未来发展趋势
  12. 用数字计算机公式表白,数学计算题表白公式
  13. 计算机桌面壁纸大小怎么设置,电脑桌面背景和大小比例怎么调试?教你调试电脑桌面背景和大小比例的方法...
  14. ms sqlserver sap ase 数据库server-client通讯协议 TDS
  15. ubuntu安装的微信不能发送图片
  16. 伍迷随想冷饭集 之 北国冬天之随想
  17. vue——评论的展开全文和收起
  18. 典型计算机控制的电子测试系统组成,LIV测试系统的结构组成和应用分析
  19. MySQL Workbench构建ER图(实体关系图)
  20. 计算机职称落户,人才引进落户等6类落户方式 新政策全部在这里

热门文章

  1. LeetCode刷题记录+数据结构总结
  2. z80 cpu 机电系统计算机控制,拆解PreComputer 1000计算机:基于可靠的Zilog Z80处理器电路设计方案...
  3. 【网络工程师必备路由篇】——OSPF-Nssa区域(华为模拟器)
  4. 烟花厂车辆监控管理系统解决方案
  5. Python 对图片进行颜色识别
  6. Mac Book pro(M1)使用总结
  7. 配置Nexus Tacacs管理
  8. 物联网设备与设备之间的通信,主要依靠的是什么?
  9. ARM硬件平台上基于UCOS移植Lwip网络协议栈
  10. Spring Boot+Eureka+Spring Cloud微服务快速上手项目实战