2016年,DeepMind的围棋机器人AlphaGo在与李世石的第二局对决中第37手落子的瞬间,整个围棋界都震惊了。评棋人Michael Redmond,一位有着近千场顶级比赛经验的职业棋手,在直播中目瞪口呆,他甚至把这颗棋子从棋盘上拿下来观察周边的情况,仿佛要确认AlphaGo是否下错了棋。第二天,Redmond告诉美国围棋E杂志:“我到现在还不明白这步棋背后的道理。”李世石这位统治了世界棋坛十年的大师,花了 12 分钟来研究这一棋局,之后才做出回应。图 13-1展示了这手传说中的落子。

图13-1 AlphaGo在对阵李世石的第二局中做出的传奇落子动作。这手落子震惊了许多职业棋手

这手落子完全违背了传统的围棋理论。对角落子,或者叫尖冲,会引诱白子沿着边界继续长出,并做出一道实墙。人们通常认为这是一个五五开的交换:白方获得边界的空点,而黑方则获得对棋盘中央区域的影响力。但是白棋落在离边界4格的地方,一旦让黑方做出实墙,黑方会得到过多的地盘。(我们需要对正在阅读的围棋高手表示歉意,这里的描述做了过多的简化。)第5行的尖冲看起来有些业余——至少在“AlphaGo教授”最终五局四胜战胜这位传奇棋手之前看来确实如此。在这一步尖冲之后,AlphaGo还做出了许多出人意料的落子动作。一年之后,上到顶级职业棋手,下至业余俱乐部棋手,所有人都在尝试模仿AlphaGo所采用的动作。

本章我们将学习组成AlphaGo的所有结构,并了解它的工作机制。AlphaGo是基于职业棋谱的监督深度学习(即我们在第5章至第8章中所学的)与基于自我对弈数据的深度强化学习(即第9章至第12章所介绍的)的一种巧妙结合,然后再创造性地用这两种深度学习网络来改进树搜索。读者可能会感觉惊奇,原来我们已经对AlphaGo的所有组件都有所了解了。更精确地说,我们将要详细介绍AlphaGo系统的如下流程工作。

  • 首先开始训练两个深度卷积神经网络(即策略网络),用于动作预测。在这两个网络架构中,其中一个深度更深,能够产生更准确的结果,而另一个则更浅,可以更快地进行评估。我们将它们分别称为强策略网络和快策略网络。
  • 强策略网络和快策略网络采用了更加复杂的棋盘编码器,包含48个特征平面。它们的网络架构深度也比我们在第6章和第7章中所见的网络更深。不过除此之外,它们看起来还是让人觉得很熟悉的。13.1节会介绍AlphaGo的策略网络架构。
  • 在13.2节中,在完成了策略网络的第一个训练步骤之后,我们将会用强策略网络作为初始点来进行自我对弈。如果用大量的算力来执行这一步,将会让机器人得到巨大的改进。
  • 在13.3节中,我们将使用这个强自我对弈网络来生成一个价值网络。这样就完成了网络训练阶段,之后就不用再做任何深度学习了。
  • 要进行一局围棋对弈,可以把树搜索作为下棋策略的基础。但与第4章的简单蒙特卡洛推演法不同的是,我们需要使用快策略网络来指导接下来的步骤。另外,还需要参考价值函数的输出,来平衡这个树搜索算法的输出。我们会在13.4节中介绍这种创新技术。
  • 从训练策略网络到自我对弈,再到使用超越人类棋手的搜索树来下棋的整个过程,都需要巨大的计算资源和计算时间。13.5节会给出几点思考,解释AlphaGo如何达到它所具有的强度,以及在进行自己的实验时合理的预期程度。

图13-2归纳了我们刚刚列出的整个流程。在本章中,我们会深入讨论图中的各个部分,并在各节中提供更多的细节。

图13-2 如何训练AlphaGo AI背后的3个神经网络。

首先,从人类棋谱集合开始,训练两个神经网络来预测下一步动作:一个网络更小更迅速,而另一个更大更准确。接着,我们可以继续通过自我对弈来改进较大网络的性能。自我对弈同时也为训练一个价值网络提供了数据。最后,AlphaGo会在一个树搜索算法中同时采用这3个网络,得到极强的对弈表现

为AlphaGo训练深度神经网络

在前面的介绍中我们已经了解到,AlphaGo使用了3个神经网络:2个策略网络和1个价值网络。虽然看起来有点多,但在本节中我们将会看到,这几个网络以及它们的输入特征在概念上是很接近的。而关于AlphaGo所用的深度学习技术,最令人惊奇的地方反而是我们对它们的熟悉程度,本书在第5章至第12章已经对它们做了大量的介绍。在深入介绍这几个神经网络的构建和训练的细节之前,让我们先讨论一下它们在AlphaGo系统中所扮演的角色。

  • 快策略网络——这个围棋动作预测网络与第7章和第8章中训练的网络有相似的规模。它的目的并不是成为最准确的动作预测器,而是在保证足够好的预测准确率的同时能够非常迅速地做出动作预测。13.4节介绍的树搜索推演过程会使用这个网络——而我们已经在第4章中了解到,在树搜索中要做到基本可用的程度,推演时必须能够迅速创建大量的网络。我们不会对这个网络做太深入的讨论,而会将更多的精力放在下面两个网络上。
  • 强策略网络——这个动作预测网络的优化目标是准确率,而不是速度。它是一个卷积网络,其架构比快策略网络的要深很多,而且动作预测的效果比快策略网络好两倍。和快策略网络一样,这个网络也是用人工棋谱数据训练得出的,这一点与第7章介绍的相同。训练好这个网络之后,就可以把它作为起始点来进行自我对弈,并采用第9章和第10章中介绍的强化学习技术进行改良。这个过程能够让强策略网络变得更加强大。
  • 价值网络——强策略网络进行的自我对弈产生了一个新的数据集,可以用来训练一个价值网络。具体来说,我们将采用这些棋局的输出,以及第11章和第12章中介绍的技术,来学习一个价值函数。它会在13.4节中扮演关键角色。

13.1.1 AlphaGo的网络架构

现在我们已经基本了解了这3个深度神经网络在AlphaGo中的作用,下一步接着展示如何在Python的Keras库构建它们。在深入讨论代码之前,我们先概述这几个网络的架构,如下所示。如果读者需要温习卷积网络的术语,请再次阅读第7章。

  • 强策略网络是一个13层卷积网络。这13层都产出19×19的过滤器,也就是说,在整个网络中,我们都保留了初始的棋盘尺寸。与第7章一样,我们需要把这个网络的输入进行对齐pad)操作。第一个卷积层的核心尺寸是5,而后面的所有层的核心尺寸都是3。最后一层采用softmax激活函数,并且有一个输出过滤器。前12层都采用ReLU激活函数,且各有192个输出过滤器。
  • 价值网络是一个16层卷积网络。它的前12层与强策略网络完全一致。第13层是一个额外的卷积层,与第2~12层结构一致。第14层是一个核心尺寸为1、有一个输出过滤器的卷积层。网络最后以两个稠密层结束,一个有256个输出,采用ReLU激活函数;另一个只有单个输出,并采用tanh激活函数。

可以看到,在AlphaGo中策略网络和价值网络采用的正是第6章所介绍的深度卷积神经网络。这两个网络非常相似,我们甚至可以直接用一个Python函数来定义它们。在此之前,我们先看看Keras的一种特殊用法,它可以显著地缩短网络的定义。第7章中讲过,我们可以使用Keras的ZeroPadding2D实用工具层来对齐输入图像。这样做完全没问题,但如果把它的功能移入Conv2D层中,就能在模型定义时节省许多笔墨。在价值网络和策略网络中,可以对齐每个卷积层的输入,使它们的输出过滤器的尺寸与输入相同(19×19)。例如,按照我们以往的做法,第1层有19×19输入,第2层核心尺寸为5,输出是19×19过滤器,需要将第1层对齐成23×23的图像。而现在我们可以直接让卷积层维持输入尺寸,只需在定义卷积层时提供参数padding='same',它就能够自己处理对齐操作了。有了这种快捷定义,接下来我们就可以方便地定义AlphaGo的策略网络与价值网络所共有的11个层,如代码清单13-1所示。读者可以在GitHub代码库中的dlgo.networks模块中的alphago.py文件中找到这个定义。

代码清单13-1 为AlphaGo的策略网络和价值网络初始化神经网络

from keras.models import Sequential
from keras.layers.core import Dense, Flatten
from keras.layers.convolutional import Conv2Ddef alphago_model(input_shape, is_policy_net=False,    ⇽---  这个布尔值选项用来在初始化时指定是策略网络还是价值网络num_filters=192,    ⇽---  除最后一个卷积层之外,所有层的过滤器数量都相同first_kernel_size=5,other_kernel_size=3):    ⇽---  第1层的核心尺寸为5,其他层都是3model = Sequential()model.add(Conv2D(num_filters, first_kernel_size, input_shape=input_shape,padding='same',data_format='channels_first', activation='relu'))for i in range(2, 12):    ⇽---  AlphaGo的策略网络和价值网络的前12层完全一致model.add(Conv2D(num_filters, other_kernel_size, padding='same',data_format='channels_first', activation='relu'))

注意,我们还没有指定第1层的输入形状。这是因为这个形状在策略网络和价值网络中略有不同。我们可以在13.1.2节介绍AlphaGo的棋盘编码器的代码中看到这个区别。继续model的定义,我们还差一个最终卷积层就能完成强策略网络的定义,如代码清单13-2所示。

代码清单13-2 在Keras中创建AlphaGo的强策略网络

    if is_policy_net:model.add(Conv2D(filters=1, kernel_size=1, padding='same',data_format='channels_first', activation='softmax'))model.add(Flatten())return model

可以看到,最后需要添加一个Flatten层来展平前面的预测输出,并确保与第5章至第8章中定义的模型的一致性。

如果想要返回的是AlphaGo的价值网络,可以再添加两个Conv2D层、一个Flatten层和两个Dense层,然后将它们连接起来,如代码清单13-3所示。

代码清单13-3 在Keras中构建AlphaGo的价值网络

    else:model.add(Conv2D(num_filters, other_kernel_size, padding='same',data_format='channels_first', activation='relu'))model.add(Conv2D(filters=1, kernel_size=1, padding='same',data_format='channels_first', activation='relu'))model.add(Flatten())model.add(Dense(256, activation='relu'))model.add(Dense(1, activation='tanh'))return model

这里我们不具体讨论快策略网络的架构。快策略网络的输入特征定义与网络架构有更多技术细节,但并不能帮助我们加深对AlphaGo系统的理解。所以如果读者想要进行自己的试验,完全可以直接采用我们在dlog.networks模块中已经定义好的网络,例如small、medium或large。快策略网络的主要目的是构建一个比强策略网络更小的网络,能够进行快速评估。接下来我们会深入了解训练过程的细节。

13.1.2 AlphaGo棋盘编码器

现在我们已经了解了AlphaGo使用的所有网络,下面讨论一下AlphaGo如何对棋盘数据进行编码。在第6章和第7章中我们已经实现了不少棋盘编码器,包括oneplane、sevenplane和simple,这些编码器都存放在dlgo.encoders模块中。AlphaGo所使用的特征平面会比它们更复杂一些,但也是这些已知编码器的自然延续。

AlphaGo策略网络所用的棋盘编码器有48个特征平面,而它的价值网络还需要再添加一个平面。这48个平面包含11种概念,其中一部分是我们已经见过的,其他则是新的,我们会逐一详细讨论。总的来说,与以往的编码器相比,AlphaGo更多地利用了围棋专有的定式。最典型的例子就是在特征集合中引入了征子和引征概念(参见图13-3)。

图13-3 AlphaGo将很多围棋策略概念直接编码到特征平面中,包括征子概念。在第一个例子中,白子只剩一口气了,这意味着黑方可以在下一回合吃掉它。白方可以长出来增加一口气,但是黑方也可以接着落子将白子的气减少为一口。这样一直持续下去,直到碰到棋盘边线,白子还是会被全部吃掉。而在另一种情况下,如果在征子的路线上已经有一颗白子,白方就有可能逃离被吃子的命运。AlphaGo中有一个特征平面专门用来表示征子是否能成功

我们之前所有的围棋棋盘编码器都采用了一个技巧,即二元特征binary feature),这个技巧在AlphaGo中也被采用。例如,在捕获气的概念(棋盘上相邻的空白点)时,我们并不只用一个特征平面来表示棋盘上每颗棋子的气数,而是用3个二元表达的平面来表示一颗棋子是有1口气、2口气还是3口气。在AlphaGo中也可以看到相同的做法,但是它采用了8个特征平面来记录二元计数。在气的例子中,这意味着8个平面分别代表每颗棋子是否有1口、2口、3口、4口、5口、6口、7口和至少8口气。

AlphaGo与第6章至第8章中介绍的唯一不同点在于,它将棋子的颜色独立出来,显式地编码到另一个单独的特征平面中。回顾一下第7章的sevenplane编码器,我们的眼平面同时包含黑子平面和白子平面,而AlphaGo只用一个特征集合用来记录气的数量,并且所有的特征都是针对下一回合的执子方。例如,在特征集“吃子数”(用来记录一个动作能吃掉的棋子数目)中,只记录当前执子方能够吃掉的棋子数量,不论它是黑方还是白方。

表13-1总结了AlphaGo所使用的全部特征平面。前48个平面用于策略网络,最后一个只用于价值网络。

表13-1 AlphaGo所使用的特征平面

特征名称

平面数量

说明

执子颜色

3

3个特征平面分别代表当前执子方、对手方,以及棋盘上的空点的棋子颜色

1

一个全部填入值1的特征平面

1

一个全部填入值0的特征平面

明智度

1

一个动作如果合法,且不会填补当前棋手的眼,则会在平面上填入1,否则填入0

动作回合数

8

这个集合有8个二元平面,代表一个动作落子离现在有多少个回合

气数

8

当前动作所在的棋链的气数,也分为8个二元平面

动作后气数

8

如果这个动作执行了之后,还会剩多少口气

吃子数

8

这个动作会吃掉多少颗对方棋子

自劫争数

8

如果这个动作执行之后,有多少己方的棋子会陷入劫争,可能在下一回合被对方提走

征子提子

1

这颗棋子是否会被通过征子吃掉

引征

1

这颗棋子是否能够逃出一个可能的征子局面

当前执子方

1

如果当前执子方是黑子,整个平面填入1;如果是白子,则填入0

这些特征的实现可以在本书的GitHub代码库中的dlgo.encoder模块中找到,文件是alphago.py。虽然每一个特征集的实现都不困难,但和我们将要介绍的AlphaGo其他部分相比,它们并不显得很有趣。实现“征子提子”平面难度较高,而且要对一个动作从执行时到现在的回合数进行编码,需要修改围棋棋盘的定义。因此如果读者对这些实现有兴趣的话,可以参看GitHub上的实现代码。

让我们看看AlphaGoEncoder如何初始化,然后把它应用到深度神经网络的训练中。它需要一个围棋棋盘尺寸参数,以及一个布尔值参数use_player_plane(代表是否包含第49个平面)。代码清单13-4展示了它的签名以及初始化过程。

代码清单13-4 AlphaGo棋盘编码器的签名以及初始化

class AlphaGoEncoder(Encoder):def __init__(self, board_size, use_player_plane=False):self.board_width, self.board_height = board_sizeself.use_player_plane = use_player_planeself.num_planes = 48 + use_player_plane

13.1.3 训练AlphaGo风格的策略网络

网络架构和输入特征都准备好之后,我们开始为AlphaGo训练策略网络。第一步与第7章的流程完全一致:指定一个棋盘编码器和一个代理,加载棋谱数据,并使用这些数据来训练代理。图13-4展示了这个流程。虽然我们使用了更加复杂的特征和网络,但流程还是完全一样的。

图13-4 AlphaGo的策略网络监督训练过程与第6章和第7章中介绍的完全一致。我们对人工棋谱进行复盘,并重新产生一系列游戏状态。每个游戏状态编码为一个张量(这个图展示了一个只有两个平面的张量,而AlphaGo实际使用了48个平面)。训练目标是一个与棋盘尺寸相同的向量,并在实际落子点填入1

要初始化并训练AlphaGo的强策略网络,需要先初始化一个AlphaGoEncoder,然后创建两个围棋数据生成器,分别用于训练和测试,如代码清单13-5所示。这个步骤与第7章一样。这一步的代码可以在GitHub上的
examples/alphago/alphago_policy_sl.py文件中找到。

代码清单13-5 为AlphaGo的策略网络的第一步训练加载数据

from dlgo.data.parallel_processor import GoDataProcessor
from dlgo.encoders.alphago import AlphaGoEncoder
from dlgo.agent.predict import DeepLearningAgent
from dlgo.networks.alphago import alphago_modelfrom keras.callbacks import ModelCheckpoint
import h5pyrows, cols = 19, 19
num_classes = rows * cols
num_games = 10000encoder = AlphaGoEncoder()
processor = GoDataProcessor(encoder=encoder.name())
generator = processor.load_go_data('train', num_games, use_generator=True)
test_generator = processor.load_go_data('test', num_games, use_generator=True)

接下来,我们可以使用本节之前定义的alphago_model函数来加载AlphaGo的策略网络,并采用分类交叉熵损失函数和随机梯度下降法来对这个 Keras 模型进行编译,如代码清单 13-6所示。我们把这个模型称为alphago_sl_policy,以表示它是一个采用监督学习(sl是supervised learning的简写)的策略网络。

代码清单13-6 用Keras创建一个AlphaGo策略网络

input_shape = (encoder.num_planes, rows, cols)
alphago_sl_policy = alphago_model(input_shape, is_policy_net=True)alphago_sl_policy.compile('sgd', 'categorical_crossentropy', metrics=['accuracy'])

现在第一阶段的训练只剩下最后一步了。和第7章一样,使用训练生成器和测试生成器对这个策略网络调用fit_generator。除网络更大、编码器更复杂之外,其他地方都和第6章至第8章完全一样。

训练结束后,我们可以从model和encoder创建一个DeepLearningAgent,并把它存储起来(如代码清单13-7所示),以备后面讨论的两个训练阶段使用。

代码清单13-7 训练一个策略网络并持久化存储

epochs = 200
batch_size = 128
alphago_sl_policy.fit_generator(generator=generator.generate(batch_size, num_classes),epochs=epochs,steps_per_epoch=generator.get_num_samples() / batch_size,validation_data=test_generator.generate(batch_size, num_classes),validation_steps=test_generator.get_num_samples() / batch_size,callbacks=[ModelCheckpoint('alphago_sl_policy_{epoch}.h5')]
)alphago_sl_agent = DeepLearningAgent(alphago_sl_policy, encoder)with h5py.File('alphago_sl_policy.h5', 'w') as sl_agent_out:alphago_sl_agent.serialize(sl_agent_out)

为简洁起见,在本章中我们并不需要像AlphaGo论文所说的那样分别训练强策略网络和快策略网络。我们不另外单独训练一个更小更快的策略网络,而是直接使用alphago_sl_agent作为快策略网络。下一节会介绍如何以这个代理为起点进行强化学习,生成一个更强的策略网络。

本文摘自《深度学习与围棋》

  • AlphaGo技术原理详解,深度学习实践性入门教程
  • 采用Keras框架,提供配套Python源代码
  • Google旗下Deepmind研究科学家作序推荐

这是一本深入浅出且极富趣味的深度学习入门书。本书选取深度学**年来最重大的突破之一 AlphaGo,将其背后的技术和原理娓娓道来,并配合一套基于 BetaGo 的开源代码,带领读者从零开始一步步实现自己的“AlphaGo”。本书侧重实践,深入浅出,庖丁解牛般地将深度学习和AlphaGo这样深奥的话题变得平易近人、触手可及,内容非常精彩。

全书共分为3个部分:第一部分介绍机器学习和围棋的基础知识,并构建一个最简围棋机器人,作为后面章节内容的基础;第二部分分层次深入介绍AlphaGo背后的机器学习和深度学习技术,包括树搜索、神经网络、深度学习机器人和强化学习,以及强化学习的几个高级技巧,包括策略梯度、价值评估方法、演员-评价方法 3 类技术;第三部分将前面两部分准备好的知识集成到一起,并最终引导读者实现自己的AlphaGo,以及改进版AlphaGo Zero。读完本书之后,读者会对深度学习这个学科以及AlphaGo的技术细节有非常全面的了解,为进一步深入钻研AI理论、拓展AI应用打下良好基础。

本书不要求读者对AI或围棋有任何了解,只需要了解基本的Python语法以及基础的线性代数和微积分知识。

深度学习与围棋:为AlphaGo训练深度神经网络相关推荐

  1. 深度学习与围棋:神经网络入门

    本文主要内容 介绍人工神经网络的基础知识. 指导神经网络学习如何识别手写数字. 组合多个层来创建神经网络. 理解神经网络从数据中学习的原理. 从零开始实现一个简单的神经网络. 本章介绍人工神经网络(A ...

  2. 使用神经网络和深度学习构造围棋智能算法:实现棋盘落子编码

    在前面章节中,我们引入不少算法和数据结构用以支持围棋机器人实现.由于围棋的步骤组合太多,几乎没有确定性的算法能在合理的时间内给出好的走法.从本节开始,我们将像AlphGo那样引入深度学习技术,通过训练 ...

  3. 深度学习与围棋 名词笔记(一)

    对于对于1对于一门学科来说 对于一门学科来说,把书读薄,也就是记住与理解其相关名词是最重要的事情,记住与理解之后,这门学科也基本通透了.<深度学习与围棋>这本书中涉及到的深度学习相关知识众 ...

  4. 【深度学习】Tensorboard可视化模型训练过程和Colab使用

    [深度学习]Tensorboard可视化模型训练过程和Colab使用 文章目录 1 概述 2 手撸代码实现 3 Colab使用3.1 详细步骤3.2 Demo 4 总结 1 概述 在利用TensorF ...

  5. HALCON 20.11:深度学习笔记(6)---有监督训练

    HALCON 20.11:深度学习笔记(6)---有监督训练 HALCON 20.11.0.0中,实现了深度学习方法.不同的DL方法有不同的结果.相应地,它们也使用不同的测量方法来确定网络的" ...

  6. HALCON 20.11:深度学习笔记(4)--- 网络和训练过程

    HALCON 20.11:深度学习笔记(4)--- 网络和训练过程 HALCON 20.11.0.0中,实现了深度学习方法.关于网络和训练过程如下: 在深度学习中,任务是通过网络发送输入图像来执行的. ...

  7. 深度学习进入芯片领域,揭秘寒武纪神经网络处理器

    深度学习进入芯片领域,揭秘寒武纪神经网络处理器 2016-03-16 19:34 原创 铁流 10条评论 就在全世界媒体的焦点锁定于谷歌AlphaGo连续3盘战胜李世石的同时,中国科学院计算技术研究所 ...

  8. Python深度学习篇一《什么是深度学习》

    在过去的几年里,人工智能(AI)一直是媒体大肆炒作的热点话题.机器学习.深度学习 和人工智能都出现在不计其数的文章中,而这些文章通常都发表于非技术出版物.我们的未来被描绘成拥有智能聊天机器人.自动驾驶 ...

  9. 【深度学习】李宏毅2021/2022春深度学习课程笔记 - Convolutional Neural NetWork(CNN)

    文章目录 一.图片分类问题 二.观察图片分类问题的特性 2.1 观察1 2.2 简化1:卷积 2.3 观察2 2.4 简化2:共享参数 - 卷积核 2.5 观察3 2.6 简化3:池化 2.6.1 M ...

最新文章

  1. 爱上MVC3系列~分部视图中的POST
  2. KNN分类器、最近邻分类、KD树、KNN分类的最佳K值、基于半径的最近邻分类器、KNN多分类、KNN多标签分类、KNN多输出分类、KNN分类的优缺点
  3. org.springframework.expression.spel.SpelEvaluationException: EL1005E:(pos 0): Type cannot be found
  4. 让我们努力从“不可救药的乐观主义者”--华尔街知名投资人约翰。多尔那里学点东西(永远放弃尝试改变这个世界)...
  5. 15支持哪些数据库版本 tfs_我司虚拟主机支持脚本及数据库版本一览表
  6. python的难点_初学python的操作难点总结(新手必看篇)
  7. iOS imageio nsurlsession 渐进式图片下载
  8. SqlServer自定义聚合函数
  9. android10获取imei,Android 10 root用户获取imei
  10. android点赞刷新列表图片闪烁,RecyclerView使用——有效解决刷新数据错乱,图片闪烁,OOM问题...
  11. [Offer收割]编程练习赛12 题目1 : 歌德巴赫猜想
  12. 判断点在多边形内部的方法(Java版)
  13. python学习手册 第7章 字符串
  14. 测试计划和测试方案有什么区别?
  15. 如何成为一名机器学习算法工程师?
  16. Pentaho Report Designer
  17. 通过线程,HttpWebResponse,正则获取句子迷中的句子
  18. 微信重磅更新!上线4个实用功能,尝鲜体验有木有你想要的功能
  19. blender 51个必须熟练记住的基础操作
  20. ChemDraw使用不了怎么办

热门文章

  1. 解决 win10 RNDIS 导致 USB 网络 共享 蓝屏 问题
  2. Java利用switch实现简单买飞机票
  3. 模拟负荷不确定性——拉丁超立方抽样生成及缩减场景(Matlab全代码)
  4. 解决VIVO系列热点自动关闭
  5. (Tekla Structures二次开发)同一图纸中,不同视图中的局部坐标系也不一样
  6. 2020年中山大学数据科学与计算机学院夏令营面试
  7. Redhat Linux 2.6.18-308.el5修改系统时间
  8. List集合去重的几种方式
  9. 攻防世界 misc 签到题
  10. 内网安全之:Windows 密码抓取