zoukankan      html  css  js  c++  java
  • 谷歌大规模机器学习:模型训练、特征工程和算法选择 (32PPT下载)

     

    本文转自:http://mp.weixin.qq.com/s/Xe3g2OSkE3BpIC2wdt5J-A

    谷歌大规模机器学习:模型训练、特征工程和算法选择 (32PPT下载)

    2017-01-26 新智元

    1新智元编译   

    来源:ThingsExpo、Medium

    作者:Natalia Ponomareva、Gokula Krishnan Santhanam

    整理&编译:刘小芹、李静怡、胡祥杰

    新智元日前宣布,获6家顶级机构总额达数千万元的PreA轮融资,蓝驰创投领投,红杉资本中国基金、高瓴智成、蓝湖资本 、蓝象资本、今日头条跟投。本轮融资将用于新智元团队规模扩充并增加新产品服务线,目标打造 To B 的人工智能全产业链服务平台。

    新智元启动新一轮大招聘:COO、执行总编、主编、高级编译、主笔、运营总监、客户经理、咨询总监、行政助理等 9 大岗位全面开放。 

    简历投递:jobs@aiera.com.cn

    HR 微信:13552313024

    新智元为COO和执行总编提供最高超百万的年薪激励;为骨干员工提供最完整的培训体系、高于业界平均水平的工资和奖金。

    加盟新智元,与人工智能业界领袖携手改变世界。

    【新智元导读】在 ThingsExpo 会议上,谷歌软件工程师 Natalia Ponomareva 作了有关如何在大规模机器学习中取得成功的讲座。Natalia 回顾了可用于对大量数据进行机器学习模型训练的框架,解释了特征工程和算法选择,并提供了有关如何避免错误的 tips。这是一份非常实用的机器学习指导手册。本文后半部分谈了如何选择深度学习框架的问题,以及Theano 贡献者、苏黎世联邦理工学院的深度学习研究者 Gokula Krishnan Santhanam 对常用深度学习框架基本构成的分析。

     

    【进入新智元微信公众号,在对话框输入“谷歌MLppt”,可下载32页ppt】

    谷歌机器学习:实际应用技巧

     

    什么是机器学习(ML)?

    从概念上讲:给定(训练)数据,发现一些潜在的模式并将这个模式应用于新数据。

    ML 的类型:监督学习;无监督学习;半监督学习;……

    监督学习:用于训练的输入数据有标记。

    • 分类(学习决策边界)。 示例:文本/图像/视频分类,垃圾邮件检测等

    • 回归(学习预测连续值)。 示例:预测房价,预测用户愿意支出的金额等

    无监督学习:输入数据没有标记,尝试在数据中查找“隐藏的”结构。

    • 聚类

    • 异常值/异常现象检测

    示例:对聚类流服务用户进行分组,对这些组以及某个视频在这些组中的受欢迎程度进行分析。

    ML如何帮助企业业务

    • 个性化服务(为每个用户提供量身定制的独特的体验),可以最大限度地提高参与度和收入

    • 自动化执行一些容易出错或需花费大量时间的任务(如转录,字形识别等)

    • 分析数据,提出更好的决策方案

    • ……

    • 从小处着手:数据取样;初始特征标记;建一个简单的模型,看看它性能如何

    • Scale:用完整的数据训练;改进特征(特征工程);尝试不同的算法(模型选择)

    特征工程(feature engineering)是什么?

    在概念上,特征工程是将原始数据(日志,产品购买的历史记录或上网行为等)转换成可以由学习算法在训练和预测中使用的矢量(vector)的过程。

    • 它是高度领域特定的。

    • 取决于你试图从数据中学习什么。

    • 劳动密集型

    特征工程:如何做?

    高级步骤:

    • 决定你想要获得的洞察力(例如,我们想训练一个模型,为用户听歌提供推荐)。

    • 决定如何建模(有许多方法!) .例如,建一个分类模型,给定用户和歌曲,模型将返回用户是否会对这首歌感兴趣的结果。或者我们有一个歌曲列表,把它给模型运行,模型将显示它认为用户可能会喜欢的歌曲。

    • 考虑你有什么数据(例如,用户收听歌曲的历史记录和用户配置文件信息)。

    • 考虑可能相关的要素:用户年龄(可能相关?); 用户名和电子邮件地址(完全无关); 用户位置(可能相关?);用户收听歌曲的历史记录(相关)。用户之前听过的歌曲的类型(乡村,摇滚,流行等)(非常相关)

    • 把相关信息用数字表示(找到特征): 描述用户的特征;描述歌曲的特征

    准备最终的训练数据

    • 给定用户u(u1,u2,u3 ... un)的特征

    • 歌曲的特征s1(s11,s12,s13,...,s1k),s2(s21,s22 ,... s2k)... 

    • 为用户创建训练实例,u(u,si)(1 - 收听)和(u,sj)(0 - 没有收听)

    特征标准化(Feature normalization )

    你的特征很有可能比例不同:

    • 用户年龄:0到100

    • 用户收入:从0到数百万

    有些机器学习模型可能无法很好地处理这样的范围各异的特征。

    • 正则化将对特征的惩罚不一致

    • 距离将受到范围最大的特征的控制

    • 一些优化算法可以更快地收敛(梯度下降)

    • ……

     

    解决方案: 标准化特征,使特征的范围大致相同

    怎样评估模型?

    你最关心的是什么?是“没有假正(false positives)”吗?还是整体的预测准确度?

    • 将你关心的问题表达为一个可计算的指标,确保该指标与你关心的内容直接相关。

    • 此指标可用于:选择模型;在部署之前测试模型;对模型或数据进行细化(例如添加更多特征)。

    模型选择:

    • 用简单的模型入手。 例如,尝试线性模型。

    • 这些模型通常有效:

        分类:逻辑回归,感知器算法,AdaBoost,SVM(线性内核为大量数据,RBF为小数据),随机森林

        回归:线性回归,随机森林

    • 尝试几个不同的模型

    • 基于模型在数据集上的性能选择模型

    • 确保在对不同数据集进行模型选择之后评估最终性能指标(例如,不要使用相同的数据集来选择模型)

    考虑深度学习

    •  如果你有大量的有标记数据

    • 如果你很难找到特征或特征之间的连接非常复杂(例如:对象检测)

    • 能够忍受更长的训练/细化时间

    • 如果你对深度学习有基本的了解:什么是架构选择?(多少层?完全连接还是不完全链接?等等); 如何防止过拟合?

    超参数调优(Hyperparameter tuning)

    ML模型具有超参数:这些是在训练开始之前就已经固定并且影响训练过程和复杂性的参数。

    例如:学习率,正则化常数等

    • 默认值只是让它们得到平均的性能;

    • 为了得到最好的ML模型,需要调优超参数

    过程:设置值,训练模型, 评估,(基于评估)细化值

    方法:Grid;算法辅助超参数调优(贝叶斯等)

    有监督 ML pipelines

    需要为以下内容设置 pipeline:

    • 训练:获取数据(可能还需要存储数据);特征提取和数据标记; 拟合模型; 测试模型/选择模型;存储模型

    • 预测:获取实时数据;从中提取特征;检索模型;在新数据上使用模型进行预测;根据预测执行

    选择工具/框架前需要考虑的事

    • 训练数据存储在哪里?数据库? 云?需要存储特征和标记吗?还是在训练时再提取特征和标记?

    • 怎样训练?在云上训练?还是离线?数据变化的频率如何?

    • 怎样使模型可用于预测?使用框架工具?还是从头开始编写pipeline?

    • 你希望框架具有监控功能吗?出现问题时能够 fallback 吗?

    初步的分析是有必要的,那么下一步该做什么?

    • 验证是否需要用大量数据训练(模型在增加训练规模时能表现得更好)

    • 如果是,请考虑用完整的数据进行训练

    • 考虑其他要求: 

          - 在有新数据时更新模型,还是根据情况进行再训练?

          - 训练数据是否都适合内存?

          - 是否有资源在云中设置一个完整的ML云 pipeline(DIY方法)?

          - 还是利用“ML即服务” (ML as a service)?

    ML生产工具:实践方法

    • 动手实践:选择存储工具(如 Google Cloud,Amazon 等);为存储数据、训练和预测编码;可以使用开源框架(liblinear,Weka,Tensorflow 等)或自己的实现模型;

    • 优点:可能成本更低(只需为聚类使用/数据存储付费);非常灵活;流行的框架有强大的社区支持

    • 缺点:人力投入多(需要一个开发者/数据科学家的团队)

    数据处理框架:

    • Map / Reduce + Hadoop——分布式存储和处理系统

    • M / R——处理大量数据的范式

    • Pig,Hive,Cascalog——在Map / Reduce 上的框架

    • Spark——数据处理和训练的全栈解决方案(full stack solution)

    • Google Cloud Dataflow

    ML 工具:ML 即服务

    ML即服务(ML as a service):预构建全栈解决方案(使用堆栈轻松训练和部署模型)

    • 特点:较少参与;不同组件无缝工作(存储,聚类,训练和预测等);可能不是很灵活

    • 其他选择:Amazon ML;Microsoft Azure;IBM Watson;Google Cloud ML

    Google 云服务:

    • 云存储(Cloud Storage)

    • BigQuery

    • Cloud DataLab

    • Cloud DataFlow

    • TensorFlow

    • Google Cloud Machine Learning (alpha)

    • 预训练模型(图像识别、语言检测和翻译、语音识别)

     

    TensorFlow

    • 开源计算引擎,专为神经网络设计,同时也可兼容其他非神经网络训练

    • 将你需要做的计算表示为数据流图(包括节点、边和张量)

    • 非常灵活:使用预定义的、构建神经网络常用的组件;可以根据特定的计算需求写你自己所需的图

    • 在 CPU 和GPU上都能运行,在桌面端、服务器和移动端平台都能运行

    • 使用 Python 和 C++,还有交互的iPython 使用教程

    • 开发者社区非常活跃

     

    谷歌云机器学习(alpha)

    • 大规模机器学习最好的云上运行,这样开发起来更简单,运行速度也更快。

    • 谷歌云机器学习的深度学习框架也用于驱动 Gmail、Google Photos 等产品

    • 易于管理的 no-ops 基础设施

    • 能训练任何大小数据集的模型

    • 使用 TensorFlow 原生深度学习算法

    • 有互动的 Datalab 模型开发设计教程

    • 适用于多种不同类型的数据,与谷歌云平台产品整合

     

    预训练的模型

    • 如果你的模型属于以下几种,可以考虑使用预训练模型,按照使用次数收费。所有这些模型构建起来都有相当大的难度,需要深厚的研究和编程基础,这种工作还是留给专家来做更放心

    • 图像识别

    • 语言检测和翻译

    • 语音识别

    如何选择深度学习框架

    上面说完了谷歌机器学习的实用技巧,也正好说到了 TensorFlow——代表谷歌深度学习的开源框架。现在,开源深度学习框架越来越多,除了 TensorFlow,目前可选的就有 Theano + Lasagne / Keras,Torch,PyTorch,Mxnet / minpy,Chainer,Neon,CNTK,Caffe 和 dynet。

    每个框架都有各自的优势,使得选择哪个框架变得越来越难以权衡。此前 Soumith 的 convnet-benchmarks (https://github.com/soumith/convnet-benchmarks)是很不错的框架间的比较基准,但也已经很久没有更新了。

    为此,前不久 Reddit 用户 m_ke 在 Reddit 机器学习板块发起了讨论:2017 年常用深度学习开源框架的状况会是怎样?

    m_ke 对这个讨论还做了补充说明:

    1.你现在使用哪个框架?

    2.你使用该框架做什么任务(CV / NLP / RL)?

    3.你喜欢该框架的哪些地方?

    4.你是否考虑换个框架?

    5.你现在遇到的最大的瓶颈是什么:内存,计算,还是数据?

    这些问题引起了一些有意思的讨论,以下是摘选:

    用户 sbt_:

    这个问题就像在 emacs 和 vim 之间进行选择。当前的框架在性能方面都没有什么太大的不同,没有哪个能好到你能说它比其他的都好。

    如果你想知道这些库/框架之间有何区别,可以在典型的使用案例(硬件和模型架构)上自己做基准比较。我偏好的可能仍然是 Theano,但我发现 TensorFlow 对我的任务也表现得同样好——选择 Theano 只是因为我对它更熟悉。此外,我两三天前看了下 PyTorch,看起来也非常好。

    用户 feedtheaimbot:

    我个人使用 Lasagne 和 Theano 做研究。它的功能完整,设计良好。我的研究领域包括 RL,CV,贝叶斯推理,Memnets 等,它对所有这些工作都表现良好,哪怕我试图实现一些非常不标准化的想法。

    我唯一的不满是 Theano 的编译时间长的令人生厌。这点能够部分得到解决,至少对合理性检查方面,通过添加一些标志例如 device = cpu。

    我也对 Pytorch 和 minPy 挺感兴趣,特别是我觉得 numpy 很好,有助于加快我的迭代速度。

    用户 miketout:

    对我来说,在 Ubuntu 上安装和使用最简单的是 Neon。我是做模型的,编程和数学都是初学者。不久我写了自己的可组合容器和更高级的模型。我在示例中遇到一些bug,修复了其中一些,并且可能会在某些点提交一些 pull 请求。Neon 有一些非常好的示例,涵盖了最新的一些研究的实现。在尝试 Neon 之前,我安装过 Theano,Tensoflow 和 Keras / Tensorflow,但几乎没有使用过。我认为不考虑设置的话,在易用性上 Keras 和 Neon 差不多。

    当我开始考虑为大规模分布式训练写一点东西,我在打造自己的解决方案之前再次查看,并开始设置 mxnet。Mxnet 支持分布式训练和基于 ZMQ 的分布式KV存储,这正是我想要的。乍看之下它也像 Neon 一样可以直接使用。但在 Windows 和 Ubuntu 16.04 上设置 mxnet 简直就是噩梦,我只能放弃了对本地机器的 CUDA 支持。Amazon 上有一些预安装的示例。

    我的经验是,Neon 最容易设置,在设置模型的难度上可能类似于 Keras,并且完全适应各种任务,包括图像处理、DL 以及其他不需要分布式训练的任务。就目前来说,好像也是 Neon 的性能最好。

    用户 congerous:

    与 Torch 和 Neon 相比,Tensorflow 是最慢的。虽然 Neon 也不是很有吸引力,很像 Chainer 和 Lasagne。Caffe 和 Neon 在图像任务上都很快,但他们不是真正意义上通用目的的框架。只说持久力的话,Theano,Torch / PyTorch,MxNet,TensorFlow / Keras 和 CNTK 应该都会继续增长。

    深度学习框架的基本构成:五大基本要素

    很多人都会遇到该如何选择框架的问题,了解这些框架的基础构造有助于你更好地做出选择。

    常用的框架包括 Theano、TensorFlow、Torch 和 Keras。它们各有千秋,苏黎世联邦理工学院计算机科学系硕士研究生,同时也是 Theano 贡献者(contributor)的 Gokula Krishnan Santhanam 日前撰文详细剖析了这些框架共通的基础构成。

    首先,一个深度学习框架含有以下五个核心组件:

    1. 张量对象(A Tensor Object)

    2. 对该张量对象进行的各种运算(Operations on the Tensor Object)

    3. 计算图和优化(A Computation Graph and Optimizations)

    4. 自动微分工具(Auto-differentiation tools)

    5. BLAS、cuDNN 扩展组件(BLAS / cuBLAS and cuDNN extensions)

    为了向开发者提供尽量简单的接口,大部分深度学习框架通常都会将普通的概念抽象化,这可能是造成许多用户感知不到上述五点核心组件的重要原因。

    下面,我们就来一一看一下这五大组成。

    1. 张量(Tensor Object)

    用张量表示的对象是一个深度学习框架中的核心组件,因为后续的所有运算和优化算法都是基于张量进行的。几何代数中定义的张量是基于向量和矩阵的推广,通俗一点理解的话,我们可以将标量视为零阶张量,矢量视为一阶张量,那么矩阵就是二阶张量。

    举例来说,可以将任意一张RGB彩色图片表示成一个三阶张量,三个维度分别是图片的高度、宽度和色彩数据。下图如果按照RGB三原色表示,就可以拆分为三张红色、绿色和蓝色的灰度图片(见下图中间的三张不同突破),再将这张图用张量表示出来,就是最下方的那张表格。

    图中只显示了前5行、320列的数据,每个方格代表一个像素点,其中的数据[1.0, 1.0, 1.0]即为颜色。假设用[1.0, 0, 0]表示红色,[0, 1.0, 0]表示绿色,[0, 0, 1.0]表示蓝色,那么如图所示,前面5行的数据则全是白色。

    将这一定义进行扩展,我们也可以用四阶张量表示一个包含多张图片的数据集,其中的四个维度分别是:图片在数据集中的编号,图片高度、宽度,以及色彩数据。

    将各种各样的数据抽象成张量表示,然后再输入神经网络模型进行后续处理是一种非常必要且高效的策略,这样做能够统一不同类型的数据,将它们用标准的方式表现出来。此外,当数据处理完成后,还可以将张量转换为其他想要的格式。

    2. 运算

    接下来是对张量对象的数学运算和处理。

    我们可以将神经网络视为对输入张量进行一系列运算从而实现某个目的的过程。这些运算包括简单的矩阵乘法,也可以是卷积、池化和LSTM等稍复杂的运算。而且各框架支持的张量操作通常也不尽相同,详细情况可以查看其官方文档(如下为NumPy、Theano和TensorFlow的说明文档)。

    • NumPy: http://www.scipy-lectures.org/intro/numpy/operations.html

    • Theano: http://deeplearning.net/software/theano/library/tensor/basic.html

    • TensorFlow: https://www.tensorflow.org/api_docs/python/math_ops/

    需要指出的是,大部分的张量操作都是基于类实现的(而且是抽象类),而并不是函数(这一点可能要归功于大部分的深度学习框架都是用面向对象的编程语言实现的)。这种实现思路一方面允许开发者将各种类似的操作汇总在一起,方便组织管理。另一方面也保证了整个代码的复用性、扩展性和对外接口的统一。总体上让整个框架更灵活和易于扩展,为将来的发展预留了空间。

    3. 计算图和优化

    有了张量和基于张量的各种操作之后,下一步就是将各种操作整合起来,输出需要的结果。

    但很可惜,随着操作种类和数量的增多,有可能引发各种意想不到的问题,包括多个操作之间应该并行还是顺次执行,如何协同各种不同的底层设备,以及如何避免各种类型的冗余操作等等。这些问题有可能拉低整个深度学习网络的运行效率或者引入不必要的Bug,而计算图正是为解决这一问题产生的。

    它包含到各种Ops实例的链接,以及操作需要输出哪个操作以及附加信息的关系。不同的框架有不同的方式实现。

    将计算图作为前后端之间的中间表可以带来良好的交互性,开发者可以将Tensor对象作为数据结构,函数/方法作为操作类型,将特定的操作类型应用于特定的数据结构,从而定义出类似MATLAB的强大建模语言。

    需要注意的是,通常情况下开发者不会将用于中间表示得到的计算图直接用于模型构造,因为这样的计算图通常包含了大量的冗余求解目标,也没有提取共享变量,因而通常都会经过依赖性剪枝、符号融合、内存共享等方法对计算图进行优化。

    目前,各个框架对于计算图的实现机制和侧重点各不相同。例如Theano和MXNet都是以隐式处理的方式在编译中由表达式向计算图过渡。而Caffe则比较直接,可以创建一个Graph对象,然后以类似Graph.Operator(xxx)的方式显示调用。

    因为计算图的引入,开发者得以从宏观上俯瞰整个神经网络的内部结构,就好像编译器可以从整个代码的角度决定如何分配寄存器那样,计算图也可以从宏观上决定代码运行时的GPU内存分配,以及分布式环境中不同底层设备间的相互协作方式。除此之外,现在也有许多深度学习框架将计算图应用于模型调试,可以实时输出当前某一操作类型的文本描述。

    4. 自动微分工具

    拥有计算图(computational graph)的另一个好处是,学习阶段的计算梯度变得模块化,简单明了,便于计算。这要归功于chain rule,它们能让你以系统的方式计算函数组成的导数(derivatives)。正如我们所见,神经网络能够被认为是简单的非线性组合,进而产生更加综合性的函数。区分这些函数只是简单地将图形从输出返回到输入。符号微分或自动微分是一种可以在计算图中计算梯度的程序化方法。

    符号微分指的是分析性地计算导数。例如,你能得到关于梯度是什么的表示。为了使用符号微分,你只需要把Value 嵌入到导数中,然后直接使用。不幸的是,一些非线性,比如ReLU (Rectified Linear Units)在一些点是不能微分的。因此,我们以迭代方式计算梯度。由于第二种方法可以普遍使用,大多数计算图包,如计算图工具包(http://rll.berkeley.edu/cgt/) 来实现自动微分。

    推出自己的梯度计算模块通常不是一个好主意,因为由工具包来提供显然更容易,更快速地。所以,要么有自己的计算图工具包和自动分化模块或使用外部包。

    由于每个节点处的导数必须仅相对于其相邻节点计算,所以可以将计算梯度的方法添加到类中并且可以由微分模块调用。

    5. BLAS / cuBLAS和cuDNN扩展

    使用所有上述组件,你可以拥有一个功能齐全的深度学习框架。它将能够将数据作为输入并转换为张量,以有效的方式对它们执行操作、计算梯度以学习并返回测试数据集的结果。然而,问题在于,因为你最有可能在高级语言(Java / Python / Lua)中实现它,所以你可以得到的加速 是有上限的。这是因为即使在高级语言中最简单的操作也比在低级语言中完成时花费更多的时间(CPU周期)。

    在这些情况下,我们可以采取两种不同的方法。

    第一个是来自编译器的另一个类推。编译过程的最后一步是 Assembly中生成的特定的硬件代码。类似地,不是运行以高级语言编写的图,而是在C中生成用于网络的相应代码,并且其被编译和执行。它的代码存储在每个Ops中,并且可以在编译阶段合并在一起。通过包装器 (wrappers)(如pyCUDA和Cython)实现从低级到高级代码数据传输。

    第二种方法是使用像C ++这样的低级语言实现后端,这意味着低级语言 - 高级语言交互内部框架是与前面的方法不同的,并且可以更快,因为我们不需要每次都编译整个图。相反,我们可以使用适当的参数调用编译的方法。

    非最优行为的另一个来源来自低级语言的缓慢实现。编写高效的代码十分困难,我们更好优化了这些方法实现的库。 BLAS或基本线性代数子程序是优化矩阵运算的集合,最初用Fortran 编写。这些可以用于做非常快的矩阵(张量)操作,并且可以提供显著的加速。还有许多其他软件包,如英特尔MKL,ATLAS也执行类似的功能。你可以根据自己的偏好进行选择。

    BLAS包通常是已经优化的,其前提假设是指令将在CPU上运行。在深度学习中,情况并非如此,BLAS可能无法充分利用GPU提供的并行性。为了解决这个问题,NVIDIA发布了针对GPU优化的cuBLAS,现在包括在CUDA工具包中。最后,cuDNN是一个基于cuBLAS的功能集的库,并提供优化的神经网络特定操作,如Winograd卷积和RNN。

    因此,通过使用这些软件包就可以框架中获得显著的加速。加速在DL中十分要,这是你训练神经网络只花费四个小时而不是四天的原因。在快速变化的AI创业公司中,速度就是你能成为领跑的还是追赶别人的关键。

    总结

    现在,你已经了解了不同框架之间的相似的特性,可以更好地认识和使用一个深度学习框架。对于不仅对学会使用深度学习框架感兴趣,了解各个常用框架的内部组成和共性特征,还有助于你自己动手搭建深度框架。

    优秀的工程师/研究员不仅要知道自己该使用哪种工具,还应该知道为什么这个工具才是最好的选择。 

    深度学习框架基本要素编译自:https://medium.com/@gokul_uf/the-anatomy-of-deep-learning-frameworks-46e2a7af5e47#.x8ilbhdqv

     

    【进入新智元公众号,在对话框输入“谷歌MLppt”下载文档】


    【寻找AI独角兽】新智元联手10大资本

    启动2017创业大赛

     

    AI 创业大赛由新智元与10 家主流 AI 创投机构:蓝驰创投、红杉资本中国基金、高瓴智成人工智能基金、蓝湖资本、蓝象资本、IDG资本、高榕资本、中信建投证券、明势资本、松禾远望基金携手发起,由新智元主办,北京市中关村科技园区管理委员会、中关村科技园区海淀园管理委员会支持,是一场聚合了 AI 技术领袖和投资领袖的盛会。新智元向满怀雄心的未来AI独角兽提供强大的创投资源对接机会,顶级风投 TS 等你来拿。http://form.mikecrm.com/gthejw

     

    点击文章下方阅读原文,在线填写报名申请报名表。该报名表为参与评选必填资料。

     

    如有更多介绍资料(例如BP等),可发送至 xzy100@aiera.com.cn,邮件标题请注明公司名称。如有任何咨询问题,也欢迎向该邮箱发信联系。

    大赛咨询,请添加新智元微信号:

     

     

    微信扫一扫
    关注该公众号

  • 相关阅读:
    对WM_NCHITTEST消息的了解+代码实例进行演示(消息产生消息,共24个枚举值)
    windows 下,用CreateWaitableTimer SetWaitableTimer 创建定时器(用轮询的办法保持高精度)
    YUI的模块化开发
    内存管理
    WCF从零学习之WCF概述(一)
    MVC编辑状态两个DropDownList联动
    HashMap的工作原理
    初探performance.timing API
    异步编程
    Nikola的5项依赖注入法则
  • 原文地址:https://www.cnblogs.com/wangxiaocvpr/p/6390441.html
Copyright © 2011-2022 走看看