用最快的时间过一遍深度学习基础,每个组件的设计原理、公式、代码都尽可能的详细。
1 没有深度学习之前?
假如我们要识别一个图像中是否有猫? 我们根本编写不出这种代码。那我们就逆向思维一下。
直接从数据出发,让数据告诉我们是否有猫?
思考?
1 从数据中学习规律,这也是从数据的本源。这有点像函数拟合,在数学上,可以进行函数拟合又有那些方法呢?各自优缺点对比呢?
2 用什么的结构?才能够从数据中学习到我们关心的X和y之间的关系?
3 除了神经网络,还有什么结构可以做万能函数近似器?
1.1 起源
人类就一直渴望能从数据中分析出预知未来的窍门
机器是否可以思考+ 神经网络
神经是通过正向强化来学习的,即赫布理论 。赫布理论是感知机学习算法的原型,并成为支撑今日深度学习的随机梯度下降算法的基石:强化合意的行为、惩罚不合意的行为,最终获得优良的神经网络参数。
赫布理论指的是两个神经元或者神经元系统,如果总是同时兴奋,就会形成一种‘组合’,其中一个神经元的兴奋会促进另一个的兴奋。
神经网络一贯的原则是:
- 交替使用线性处理单元与非线性处理单元,它们经常被称为“层”。
- 使用链式法则(即反向传播)来更新网络的参数。
1.2 发展
近些年神经网络能够发展的重要原因是:
- 优秀的容量控制方法,如丢弃法,使大型网络的训练不再受制于过拟合(大型神经网络学会记忆大部分训练数据的行为)。这是靠在整个网络中注入噪声而达到的,如训练时随机将权重替换为随机的数字 [4]。
- 注意力机制解决了另一个困扰统计学超过一个世纪的问题:如何在不增加参数的情况下扩展一个系统的记忆容量和复杂度。注意力机制使用了一个可学习的指针结构来构建出一个精妙的解决方法 [5]。也就是说,与其在像机器翻译这样的任务中记忆整个句子,不如记忆指向翻译的中间状态的指针。由于生成译文前不需要再存储整句原文的信息,这样的结构使准确翻译长句变得可能。
- 记忆网络 [6]和神经编码器—解释器 [7]这样的多阶设计使得针对推理过程的迭代建模方法变得可能。这些模型允许重复修改深度网络的内部状态,这样就能模拟出推理链条上的各个步骤,就好像处理器在计算过程中修改内存一样。
- 另一个重大发展是生成对抗网络的发明 [8]。传统上,用在概率分布估计和生成模型上的统计方法更多地关注于找寻正确的概率分布,以及正确的采样算法。生成对抗网络的关键创新在于将采样部分替换成了任意的含有可微分参数的算法。这些参数将被训练到使辨别器不能再分辨真实的和生成的样本。生成对抗网络可使用任意算法来生成输出的这一特性为许多技巧打开了新的大门。例如生成奔跑的斑马 [9]和生成名流的照片 [10] 都是生成对抗网络发展的见证。
- 许多情况下单块GPU已经不能满足在大型数据集上进行训练的需要。过去10年内我们构建分布式并行训练算法的能力已经有了极大的提升。设计可扩展算法的最大瓶颈在于深度学习优化算法的核心:随机梯度下降需要相对更小的批量。与此同时,更小的批量也会降低GPU的效率。如果使用1,024块GPU,每块GPU的批量大小为32个样本,那么单步训练的批量大小将是32,000个以上。近年来李沐 [11]、Yang You等人 [12]以及Xianyan Jia等人 [13]的工作将批量大小增至多达64,000个样例,并把在ImageNet数据集上训练ResNet-50模型的时间降到了7分钟。与之相比,最初的训练时间需要以天来计算。
- 并行计算的能力也为至少在可以采用模拟情况下的强化学习的发展贡献了力量。并行计算帮助计算机在围棋、雅达利游戏、星际争霸和物理模拟上达到了超过人类的水准。
- 深度学习框架也在传播深度学习思想的过程中扮演了重要角色。Caffe、 Torch和Theano这样的第一代框架使建模变得更简单。许多开创性的论文都用到了这些框架。如今它们已经被TensorFlow(经常是以高层API Keras的形式被使用)、CNTK、 Caffe 2 和Apache MXNet所取代。第三代,即命令式深度学习框架,是由用类似NumPy的语法来定义模型的 Chainer所开创的。这样的思想后来被 PyTorch和MXNet的Gluon API 采用,后者也正是本书用来教学深度学习的工具。
思考:
1 通俗地讲,模型的容量是指其拟合各种函数的能力。容量低的模型很难拟合训练集,容量高的模型可能会过拟合,当一个模型训练误差很小而泛化误差较大时,可以降低模型的容量,控制容量有很多方法,在《深度学习》书籍上有,比如选择假设空间、层数,减少一些层中间神经元的数量,还有正则化来解决。
1.3. 成功案例
1.4 特点
机器学习研究如何使计算机系统利用经验改善性能。它是人工智能领域的分支,也是实现人工智能的一种手段。在机器学习的众多研究方向中,表征学习关注如何自动找出表示数据的合适方式,以便更好地将输入变换为正确的输出,而本书要重点探讨的深度学习是具有多级表示的表征学习方法。在每一级(从原始数据开始),深度学习通过简单的函数将该级的表示变换为更高级的表示。因此,深度学习模型也可以看作是由许多简单函数复合而成的函数。当这些复合的函数足够多时,深度学习模型就可以表达非常复杂的变换。
相对其它经典的机器学习方法而言,深度学习的不同在于:对非最优解的包容、对非凸非线性优化的使用,以及勇于尝试没有被证明过的方法。
1.5 小结
- 机器学习研究如何使计算机系统利用经验改善性能。它是人工智能领域的分支,也是实现人工智能的一种手段。
- 作为机器学习的一类,表征学习关注如何自动找出表示数据的合适方式。
- 深度学习是具有多级表示的表征学习方法。它可以逐级表示越来越抽象的概念或模式。
- 深度学习所基于的神经网络模型和用数据编程的核心思想实际上已经被研究了数百年。
- 深度学习已经逐渐演变成一个工程师和科学家皆可使用的普适工具。
参考:
http://zh.d2l.ai/chapter_introduction/deep-learning-intro.html
就是一本很单薄的书介绍用的。在线看的
2 预备知识
2.1
3 深度学习基础
3.1 线性回归
由于线性回归和softmax回归都是单层神经网络,它们涉及的概念和技术同样适用于大多数的深度学习模型。
线性回归就是为了解决拟合函数,得到好参数,进而预测的应用。
线性回归包括模型、模型训练(训练数据、损失函数、优化算法)、模型预测。
3.2 一个简单的线性回归代码实现
3.4 sofmax回归
处理输出数据为离散型情况,在多分类问题中有很好解释。
使用softmax运算后可以更方便地与离散标签计算误差。我们已经知道,softmax运算将输出变换成一个合法的类别预测分布。使得其对离散值输出可以每个给予一定值。
3.4.5 交叉熵损失函数
定义各种模型在数据集上表现,分类结果是否正确?或者是用来使用更适合衡量两个概率分布差异的测量函数。
3.8 多层感知机
仅包含输出层的单层神经网络,无论加多少层都是与单层神经网络等价的。
因为全连接层只是对数据做仿射变换(affine transformation),而多个仿射变换的叠加仍然是一个仿射变换。
解决问题的一个方法(也就是说,有其它方法做变换?)是引入非线性变换,例如对隐藏变量使用按元素运算的非线性函数进行变换,然后再作为下一个全连接层的输入。这个非线性函数被称为激活函数(activation function)。
1 也就是说,有其它变换方法来让全连接层不只是对数据仿射变换? 或者说为什么要解决这个问题?
* 换一种变换
* 结合其它变换
* 全连接层都直接改,不需要变换?
2 只有单层神经网络是不是仅仅就是一个线性变换呢?
啥是线性变换?
从一个空间映射到另一个空间,保持加法和数乘关系。
下面我们介绍几个常用的激活函数
3.8.2.1 Relu函数
ReLU函数只保留正数元素,并将负数元素清零。
还有sigmoid以及tanh还有
3.8.3 多层感知机
3.11 模型选择、欠拟合和过拟合
们将探究模型训练中经常出现的两类典型问题:一类是模型无法得到较低的训练误差,我们将这一现象称作欠拟合(underfitting);另一类是模型的训练误差远小于它在测试数据集上的误差,我们称该现象为过拟合(overfitting)。在实践中,我们要尽可能同时应对欠拟合和过拟合。虽然有很多因素可能导致这两种拟合问题,在这里我们重点讨论两个因素:模型复杂度和训练数据集大小
也就是说说,有其它方法来解决过拟合和欠拟合的事情?
3.12 权重衰减
本节介绍应对过拟合问题的常用方法:权重衰减(weight decay)
1 它怎么解决过拟合?
2 还有其他方法解决过拟合?
3 过拟合能否形式化呢?
4
就是在损失函数中加一项,但是效果未知,只能够做实验。
3.13 丢弃法
问题:在机器学习的模型中,如果模型的参数太多,而训练样本又太少,训练出来的模型很容易产生过拟合的现象。
解决方法:随机丢弃隐藏层单元,
原理:
它为什么可以搞定过拟合?
(1)取平均的作用: 先回到标准的模型即没有dropout,我们用相同的训练数据去训练5个不同的神经网络,一般会得到5个不同的结果,此时我们可以采用 “5个结果取均值”或者“多数取胜的投票策略”去决定最终结果。例如3个网络判断结果为数字9,那么很有可能真正的结果就是数字9,其它两个网络给出了错误结果。这种“综合起来取平均”的策略通常可以有效防止过拟合问题。因为不同的网络可能产生不同的过拟合,取平均则有可能让一些“相反的”拟合互相抵消。dropout掉不同的隐藏神经元就类似在训练不同的网络,随机删掉一半隐藏神经元导致网络结构已经不同,整个dropout过程就相当于对很多个不同的神经网络取平均。而不同的网络产生不同的过拟合,一些互为“反向”的拟合相互抵消就可以达到整体上减少过拟合。
(2)减少神经元之间复杂的共适应关系: 因为dropout程序导致两个神经元不一定每次都在一个dropout网络中出现。这样权值的更新不再依赖于有固定关系的隐含节点的共同作用,阻止了某些特征仅仅在其它特定特征下才有效果的情况 。迫使网络去学习更加鲁棒的特征 ,这些特征在其它的神经元的随机子集中也存在。换句话说假如我们的神经网络是在做出某种预测,它不应该对一些特定的线索片段太过敏感,即使丢失特定的线索,它也应该可以从众多其它线索中学习一些共同的特征。从这个角度看dropout就有点像L1,L2正则,减少权重使得网络对丢失特定神经元连接的鲁棒性提高。
(3)Dropout类似于性别在生物进化中的角色:物种为了生存往往会倾向于适应这种环境,环境突变则会导致物种难以做出及时反应,性别的出现可以繁衍出适应新环境的变种,有效的阻止过拟合,即避免环境改变时物种可能面临的灭绝。
1 目的是为什么?解决过拟合
2
3.14 正向传播
1 这种计算图是认真的吗?这不就是数据流动图吗?
3.14.3 反向传播
3.15 数值稳定性和模型初始化
3.15.2. 随机初始化模型参数
在神经网络中,通常需要随机初始化模型参数。下面我们来解释这样做的原因。
- 深度模型有关数值稳定性的典型问题是衰减和爆炸。当神经网络的层数较多时,模型的数值稳定性容易变差。
- 我们通常需要随机初始化神经网络的模型参数,如权重参数。
5 卷积神经网络
1 那卷积不就是提取特征了吗?也就是说原来特征不好咯?
2 卷积操作到底意味着什么?有什么直观含义吗? (在看这篇文章有问题https://www.jianshu.com/p/3286d4a061ca)
3
5.1.2 二维卷积层
- 卷积神经网络就是含卷积层的网络。
- LeNet交替使用卷积层和最大池化层后接全连接层来进行图像分类。
5.2 填充和字幅
5.5 卷积神经网络
5.6 深度卷积网络(AlexNet)
我们在上一节看到,神经网络可以直接基于图像的原始像素进行分类。这种称为端到端(end-to-end)的方法节省了很多中间步骤。然而,在很长一段时间里更流行的是研究者通过勤劳与智慧所设计并生成的手工特征。这类图像分类研究的主要流程是:
- 获取图像数据集;
- 使用已有的特征提取函数生成图像的特征;
- 使用机器学习模型对图像的特征分类。
计算机视觉流程中真正重要的是数据和特征。也就是说,使用较干净的数据集和较有效的特征甚至比机器学习模型的选择对图像分类结果的影响更大。机器学习的理论优美而又有用。
那么AlexNet做了什么呢?
- AlexNet与LeNet结构类似,但使用了更多的卷积层和更大的参数空间来拟合大规模数据集ImageNet。它是浅层神经网络和深度神经网络的分界线。
- 虽然看上去AlexNet的实现比LeNet的实现也就多了几行代码而已,但这个观念上的转变和真正优秀实验结果的产生令学术界付出了很多年。
5.7 使用重复元素的网络(VGG)
VGG块的组成规律是:连续使用数个相同的填充为1、窗口形状为3×33×3的卷积层后接上一个步幅为2、窗口形状为2×22×2的最大池化层。卷积层保持输入的高和宽不变,而池化层则对其减半
5.8 网络中的网络()
前几节介绍的LeNet、AlexNet和VGG在设计上的共同之处是:先以由卷积层构成的模块充分抽取空间特征,再以由全连接层构成的模块来输出分类结果。其中,AlexNet和VGG对LeNet的改进主要在于如何对这两个模块加宽(增加通道数)和加深。本节我们介绍网络中的网络(NiN)[1]。它提出了另外一个思路,即串联多个由卷积层和“全连接”层构成的小网络来构建一个深层网络。
5.9 含并行连结的网络(GoogLeNet)
5.10 批量归一化
通常来说,数据标准化预处理对于浅层模型就足够有效了。随着模型训练的进行,当每层中参数更新时,靠近输出层的输出较难出现剧烈变化。但对深层神经网络来说,即使输入数据已做标准化,训练中模型参数的更新依然很容易造成靠近输出层输出的剧烈变化。这种计算数值的不稳定性通常令我们难以训练出有效的深度模型。
批量归一化的提出正是为了应对深度模型训练的挑战。在模型训练时,批量归一化利用小批量上的均值和标准差,不断调整神经网络中间输出,从而使整个神经网络在各层的中间输出的数值更稳定。批量归一化和下一节将要介绍的残差网络为训练和设计深度模型提供了两类重要思路。
《深度学习》对于卷积网络
先上一段话
9.1 卷积运算
看书的时候,我有疑问
1 卷积运算到底是什么? 有什么直观含义吗? 有人说是丢两个色子,然后看形成4的概率。
2 卷积运算的可交换性?有什么重要作用嘛?这里都可以对其中的任意运算,判断其交换性/分配律等等各种规律。运算有一元和n院,代数之间都是二元乃至多元运算。
3
9.2 动机
稀疏交互我认为是全连接的程度,程度高,自然每个中间变量收到输入的影响大,程度低,影响小。 全连接是矩阵乘法?卷积是部分矩阵乘法?可以参考这部分解释https://blog.csdn.net/jacke121/article/details/79182130
卷积层本来就是全连接的一种简化形式:不全连接+参数共享,同时还保留了空间位置信息。这样大大减少了参数并且使得训练变得可控。
全连接就是个矩阵乘法,相当于一个特征空间变换,可以把有用的信息提取整合。再加上激活函数的非线性映射,多层全连接层理论上可以模拟任何非线性变换。但缺点也很明显: 无法保持空间结构
参数共享是说只有一个卷积核,而且远小于原输入数据,那么自然卷积核的参数都是共享的。这种共享是好的嘛?卷积核的大小也是需要作为参数的吧?根本就是一种信号的过滤而已。
对于卷积,参数共享的特殊形式使得神经网络层具有对平移 等变 ( equivariance ) 的性质。如果一个函数满足输入改变,输出也以同样的方式改变这一性质,我们就说 它是等变 (equivariant) 的。
9.3 池化
经典CNN模型和加了层数的对比
池化作用: 池化能够帮助输入的表 示近似 不变(invariant)
如何实现的:局部平移不变性是一个很有用的性质,尤其是当我们关心某个特征是否出现 而不关心它出现的具体位置时。池化就能够保留这种特征。
一篇对理论分析关于池化的
A Theoretical Analysis of Feature Pooling in Visual Recognition, Y-Lan Boureau, Jean Ponce, Yann LeCun
在这篇文章中,作者的贡献点主要有三个:1.研究不同pooling操作的分类能力;2.影响pooling操作的因素;3.不同类型的pooling的统一之处
最终得出结论是:Pooling 可以把联合特征转变为一个更重要的表示,同时忽略其他无关的细节。
9.4 卷积和池化作为一种无限强的先验
9.5 卷积函数一些变体
首先,当我们提到神经网络中的卷积时,我们通常是指由多个并行卷积组成的 运算。这是因为具有单个核的卷积只能提取一种类型的特征,尽管它作用在多个空 间位置上。我们通常希望网络的每一层能够在多个位置提取多种类型的特征。
- 1 如果我们只想在输出的每个方向上每间隔 s 个像素进行采样,可以通过定义不同的卷积函数实现
- 2 有三种填充方式,包括有效/相同/全卷积。
- 3 在一些情况下,我们并不是真的想使用卷积,而是想用一些局部连接的网络层
- 4 局部连接: 不进行参数共享,仅仅是一些局部连接的网络层
- ,卷积:非全连接+参数共享
- 全连接的比较:全连接
是否可以结合呢? 这些变体
9.6 结构化输出
可以通过选择卷积的不同来输出不一样的数据
9.7 数据类型
卷积除了可以处理输入样例都有相同空间维度的情况,还可以处理可变的空间尺度的输入。
一些例子:
9.8 高效的卷积算法
1 部分就跟那个矩阵乘法一样,如何快速执行卷积是一个重要的方法。如何将加快运算2
9.9 随机或无监督的特征
- 随机初始化
- 手动设计他们
- 无监督标准来学习
这三种对比
1这三种分别是什么?怎么做的? 原理是什么?
2 有没有更好的?用机器学习首先学习卷积出来?
3
CNN公认的缺陷
1 尽管 CNN 已经取得了 state-of-the-art 的地位,但是仍然存在一些问题:over-parameters:大量的参数进行反向传播,数学上难以解释;numerous tricks:复杂的网络结构、Dropout 等让网络变得难以理解;sensitivitity:受到攻击时鲁棒性差
CNN的可解释性
来自网络的说法
划分为三个大类:
1. 在建模之前的可解释性方法(包括有数据可视化方法)
2. 建立本身具备可解释性的模型(包括有基于规则的方法/基于单个特征的方法/基于实例的方法/稀疏性方法/单调性方法)
3. 在建模之后使用可解释性方法对模型作出解释
1. 隐层分析方法 (有一篇论文搞这个的)Visualizing and Understanding Convolutional Networks,还有一篇CVPR 2017上发表《Network Dissection:Quantifying.Interpretability.of.Deep.VisualRepresentations
2. 模拟/代理模型
3. 敏感性分析方法)
来自综述的说法
1这一部分可以明显的作为自己做实验时候的参照,就是从表现和内部机理两个方面解释自己模型的优越性。
网上关于CNN源代码
https://www.jiqizhixin.com/articles/2018-05-29
1
所涉及的主要步骤如下:
读取输入图像。
准备滤波器。
卷积层:使用滤波器对输入图像执行卷积操作。
ReLU 层:将 ReLU 激活函数应用于特征图(卷积层的输出)。
最大池化层:在 ReLU 层的输出上应用池化操作。
堆叠卷积层、ReLU 层和最大池化层。
1 读它的一些问题https://www.jiqizhixin.com/articles/2018-05-29
2 这些是操作,如何理论化?
3
图卷积网络部分内容(来自网上https://tkipf.github.io/graph-convolutional-networks/)
图+卷积网络(目的是学习图结构+图特征)只要我们是为了表示学习,那我们
1 GCNs Part1:定义
2 x
图神经网络可解释性
https://www.infoq.cn/article/1ogx48ssvcfppejgtmew
https://towardsdatascience.com/towards-explainable-graph-neural-networks-45f5e3912dd0 (这篇更经典一些)
深度学习的注意力机制
1 注意力机制是为了解决什么问题而提出来的?
2、软性注意力机制的数学原理;
3、软性注意力机制、Encoder-Decoder框架与Seq2Seq
4、自注意力模型的原理
定义:自注意力模型在我看来是在同一层网络的输入和输出(不是模型最终的输出)之间,利用注意力机制“动态”地生成不同连接的权重,来得到该层网络输出的模型。
将Source中的构成元素想象成是由一系列的<Key,Value>数据对构成,此时给定Target中的某个元素Query,通过计算Query和各个Key的相似性或者相关性,得到每个Key对应Value的权重系数,然后对Value进行加权求和,即得到了最终的Attention数值。所以本质上Attention机制是对Source中元素的Value值进行加权求和,而Query和Key用来计算对应Value的权重系数。
一言以蔽之:根据yi计算其与x中某些xi的相似度,进而赋予不同的xi不同权重,然后预测时,这些权重会集中注意力。
这tm的不就是特征重要性重新分配吗?
过程:
1 计算query和key的相似度
2 引入类似softmax对第一阶段的数值进行转化
3 进行加权求和即可
1 这是一种思想,
2 那么其计算相似度肯定有很多很多方法对吧?
3 权重分配肯定有不同级别的,有神经元级别的,有layer级别的,还有模型级别的。
self Attention模型(注意力机制的变体)
一般任务的Encoder-Decoder框架中,输入Source和输出Target内容是不一样的,比如对于英-中机器翻译来说,Source是英文句子,Target是对应的翻译出的中文句子,Attention机制发生在Target的元素Query和Source中的所有元素之间。而Self Attention顾名思义,指的不是Target和Source之间的Attention机制,而是Source内部元素之间或者Target内部元素之间发生的Attention机制,也可以理解为Target=Source这种特殊情况下的注意力计算机制。其具体计算过程是一样的,只是计算对象发生了变化而已,所以此处不再赘述其计算过程细节
6 循环神经网络
与之前介绍的多层感知机和能有效处理空间信息的卷积神经网络不同,循环神经网络是为更好地处理时序信息而设计的。它引入状态变量来存储过去的信息,并用其与当前的输入共同决定当前的输出。
- 使用循环计算的网络即循环神经网络。
- 循环神经网络的隐藏状态可以捕捉截至当前时间步的序列的历史信息。
- 循环神经网络模型参数的数量不随时间步的增加而增长。
- 可以基于字符级循环神经网络来创建语言模型。
《深度学习》书籍带循环神经网络的学习
定义:循环神经网络(recurrent neural network)或 RNN (Rumelhart et al., 1986c) 是一类用于处理序列数据的神经网络
感觉是马尔科夫链的模型展现。
与CNN不同的是,RNN的参数共享是输出的每一项是前一项的函数。每一项对先前的输出应用相同的更新规则而产生。
那RNN不就很适合处理图数据,因为图上自然就是各种数据堆叠的,每个节点都只跟附近产生关系。
10.1 展开计算图
其基本的表达式如下,专门用来处理序列数据
这个公式可以用两种不同的方法绘制。如下图左右侧。
10.2 循环神经网络
其有一些重要的设计模型:
一个典型的模型图如图所示
其计算公式如下
但是反向传播更新W,V的时候,训练代价很大,怎么办呢?
1 很明显,最简单的RNN只考虑了上个时间片的隐节点状态ht-1。那肯定就有长期依赖包括LSTM,
10.2.1 导师驱动过程和输出循环网络
10.10 长短期记忆和其他门控RNN
循环网络最有效的是门控RNN,包括长短期记忆(LSTM)和门控循环单元(GRU)。
1 为了能否让RNN学的更久,LSTM引入门控机制用来控制特征流通和损失
先看一组关于RNN和LSTM的对照图
《深度学习》自编码器学习
定义:自编码器(autoencoder)是神经网络的一种,经过训练后能尝试将输入复制到 输出。
组成:该网络可以看作由两部分组成:一个由函数 h = f(x) 表示的编码器和一个生成重构的解码器 r = g(h)。
它如何学习?相反,我 们不应该将自编码器设计成输入到输出完全相等。这通常需要向自编码器强加一些 约束,使它只能近似地复制,并只能复制与训练数据相似的输入。这些约束强制模型考虑输入数据的哪些部分需要被优先复制,因此它往往能学习到数据的有用特性
14.1 欠完备自编码器
学习的一种方法:从自编码器获取有用特征得一个方法就是限制 h (编码后)的维度比 x(输入数据) 小.
loss函数定义:
14.1 正则编码器
有稀疏编码器和去噪自编码器,还有惩罚导数作为正则等德国。
14.3 表示能力、层的大小和深度
14.5 去噪自编码器
《深度学习》深度生成模型
20.1 玻尔兹曼机