导读:为什么诺贝尔物理奖会颁给AI科学家呢?或许这篇文章可以给一些线索。
本文总结:
在机器学习中,计算机通过示例进行学习,使其能够解决过于模糊和复杂而无法通过分步说明进行管理的问题。
Hopfield 用一种相当于物理学中自旋系统能量的属性来描述网络的整体状态。
系统使用统计物理学分析各个组件可以共同存在的状态,并计算出它们发生的概率。有些状态比其他状态更有可能发生;这取决于可用能量的数量,这在 19 世纪物理学家路德维希·玻尔兹曼 (Ludwig Boltzmann) 的一个方程中有所描述
由于物理学为机器学习的发展贡献了工具,因此有趣的是,物理学作为一个研究领域也受益于人工神经网络。中包括使用机器学习来筛选和处理发现希格斯粒子所需的大量数据。其他应用包括降低碰撞黑洞引力波测量中的噪声,或寻找系外行星。
他们利用物理学来寻找信息中的模式
许多人都体验过计算机如何翻译语言、解释图像甚至进行合理的对话。但可能不太为人所知的是,这种技术长期以来对研究非常重要,包括对大量数据的分类和分析。机器学习的发展在过去十五到二十年里呈爆炸式增长,它利用了一种称为人工神经网络的结构。如今,当我们谈论人工智能时,我们通常指的就是这种技术。
尽管计算机无法思考,但机器现在可以模仿记忆和学习等功能。今年的物理学奖得主帮助实现了这一点。他们利用物理学的基本概念和方法,开发了利用网络结构处理信息的技术。
机器学习不同于传统软件,传统软件的工作原理类似于一种食谱。软件接收数据,根据清晰的描述进行处理并产生结果,就像有人收集原料并按照食谱加工,制作出蛋糕一样。与此不同,在机器学习中,计算机通过示例进行学习,使其能够解决过于模糊和复杂而无法通过分步说明进行管理的问题。一个例子是解释图片以识别其中的物体。
模仿大脑
人工神经网络使用整个网络结构来处理信息。其灵感最初来自于对大脑工作原理的理解。20 世纪 40 年代,研究人员开始围绕大脑神经元和突触网络背后的数学原理进行推理。另一个谜题来自心理学,这要归功于神经科学家唐纳德·赫布的假说,即学习是如何发生的,因为神经元之间的联系在协同工作时会得到加强。
后来,人们尝试通过建立计算机模拟的人工神经网络来重现大脑网络的功能。在这些神经网络中,大脑的神经元由赋予不同值的节点模拟,突触由节点之间的连接表示,这些连接可以变得更强或更弱。唐纳德·赫布的假设仍然被用作通过称为训练的过程更新人工网络的基本规则之一。
图一:闭环调控驱动静止脑片中的振荡。
20 世纪 60 年代末,一些令人沮丧的理论结果让许多研究人员怀疑这些神经网络永远不会有任何实际用途。然而,人们对人工神经网络的兴趣在 20 世纪 80 年代被重新唤醒,当时有几项重要的想法产生了影响,其中包括今年获奖者的研究成果。
联想记忆
想象一下,你正在努力记住一个很少使用的非常不寻常的单词,比如电影院和演讲厅里常见的倾斜地板。你搜索记忆。它类似于ramp ...也许是rad...ial?不,不是那个。Rake ,就是这样!
这种通过搜索相似单词来找到正确单词的过程让人想起物理学家约翰·霍普菲尔德 (John Hopfield) 于 1982 年发现的联想记忆。霍普菲尔德网络可以存储模式,并有一种方法可以重新创建这些模式。当网络获得不完整或略有失真的模式时,该方法可以找到最相似的存储模式。
霍普菲尔德之前曾利用他的物理学背景探索分子生物学的理论问题。当他被邀请参加一次神经科学会议时,他接触到了对大脑结构的研究。他对所学内容非常着迷,并开始思考简单神经网络的动态。当神经元共同作用时,它们会产生新的强大特性,而这些特性对于只关注网络各个组成部分的人来说是无法察觉的。
1980 年,霍普菲尔德离开了普林斯顿大学,他的研究兴趣让他远离了物理学同事们的研究领域,他搬到了美国大陆的另一边。他接受了加州理工学院(位于南加州帕萨迪纳)的化学和生物学教授职位。在那里,他可以免费使用计算机资源进行实验并发展他的神经网络思想。
然而,他并没有放弃物理学的基础,物理学激发了他去理解由许多小组件共同作用的系统如何产生新的有趣现象。他特别受益于对磁性材料的了解,这些材料由于原子自旋而具有特殊的特性——这种特性使每个原子都成为一个微小的磁铁。相邻原子的自旋相互影响;这可以形成自旋方向相同的域。他能够利用描述自旋相互影响时材料如何发展的物理学,创建一个具有节点和连接的模型网络。
网络以横向方式保存图像
Hopfield 构建的网络的节点都通过不同强度的连接连接在一起。每个节点都可以存储一个单独的值——在 Hopfield 的第一部作品中,这个值可以是 0 或 1,就像黑白图片中的像素一样。
Hopfield 用一种相当于物理学中自旋系统能量的属性来描述网络的整体状态;能量是使用一个公式计算的,该公式使用了节点的所有值以及它们之间连接的所有强度。Hopfield 网络的编程方法是将图像输入到节点,节点的值被赋予黑色 (0) 或白色 (1)。然后使用能量公式调整网络的连接,以便保存的图像获得较低的能量。当另一个模式被输入到网络中时,有一个规则是逐个检查节点,并检查如果该节点的值发生变化,网络是否具有较低的能量。如果结果发现如果黑色像素变为白色,能量就会降低,它会改变颜色。这个过程一直持续到不可能找到任何进一步的改进。当达到这一点时,网络通常会重现它所训练的原始图像。
如果您只保存一个模式,这可能看起来并不那么引人注目。也许您想知道为什么不直接保存图像本身并将其与正在测试的另一幅图像进行比较,但 Hopfield 的方法很特别,因为可以同时保存多张图片,并且网络通常可以区分它们。
霍普菲尔德将搜索网络中保存的状态比作将球滚过山峰和山谷,摩擦力会减慢球的运动速度。如果球掉落在某个特定位置,它将滚入最近的山谷并停在那里。如果网络获得的模式接近于已保存的模式之一,它将以同样的方式继续向前移动,直到它最终到达能量景观中的山谷底部,从而找到其记忆中最接近的模式。
Hopfield 网络可用于重新创建包含噪声或已被部分删除的数据。
Hopfield 和其他人继续完善 Hopfield 网络功能的细节,包括可以存储任何值的节点,而不仅仅是零或一。如果将节点视为图片中的像素,它们可以有不同的颜色,而不仅仅是黑色或白色。改进的方法使得保存更多图片成为可能,即使它们非常相似,也可以区分它们。只要信息是由许多数据点构建的,就可以识别或重建任何信息。
Hopfield概念代码示例:
import numpy as np
import matplotlib.pyplot as plt
def image_to_vector(image):
vector = image.flatten()
vector = np.where(vector == 0, -1, 1)
return vector
def vector_to_image(vector, shape):
image = np.where(vector == -1, 0, 1)
return image.reshape(shape)
def train_hopfield(patterns):
num_neurons = patterns[0].size
W = np.zeros((num_neurons, num_neurons))
for p in patterns:
W += np.outer(p, p)
np.fill_diagonal(W, 0)
return W / num_neurons
def energy(state, W):
return -0.5 * np.dot(state, np.dot(W, state))
def update_state(state, W):
new_state = state.copy()
for i in range(len(state)):
h = np.dot(W[i], new_state)
s = 1 if h >= 0 else -1
# 检查能量是否降低
original_energy = energy(new_state, W)
new_state[i] = s
new_energy = energy(new_state, W)
if new_energy > original_energy:
new_state[i] = state[i]
return new_state
def run_hopfield(initial_state, W, max_steps=100):
state = initial_state.copy()
for _ in range(max_steps):
new_state = update_state(state, W)
if np.array_equal(new_state, state):
break
state = new_state
return state
# 原始图像
pattern = np.array([
[1, 0, 1],
[0, 1, 0],
[1, 0, 1]
])
# 训练网络
vector_pattern = image_to_vector(pattern)
patterns = [vector_pattern]
W = train_hopfield(patterns)
# 有噪声的输入
noisy_pattern = np.array([
[1, 1, 1],
[0, 0, 0],
[1, 1, 1]
])
vector_noisy = image_to_vector(noisy_pattern)
# 恢复图像
recovered_vector = run_hopfield(vector_noisy, W)
recovered_image = vector_to_image(recovered_vector, pattern.shape)
# 显示图像
fig, axs = plt.subplots(1, 3, figsize=(9, 3))
axs[0].imshow(pattern, cmap='gray')
axs[0].set_title('原始图像')
axs[0].axis('off')
axs[1].imshow(noisy_pattern, cmap='gray')
axs[1].set_title('有噪声的图像')
axs[1].axis('off')
axs[2].imshow(recovered_image, cmap='gray')
axs[2].set_title('恢复的图像')
axs[2].axis('off')
plt.show()
使用十九世纪物理学进行分类
记住一个图像是一回事,但解释它所描绘的内容则需要更多努力。
即使是很小的孩子也能指着不同的动物自信地说出它是狗、猫还是松鼠。他们偶尔可能会说错,但很快他们几乎每次都能说对。即使没有看到任何图表或物种或哺乳动物等概念的解释,孩子也能学会这一点。在遇到每种动物的几个例子后,不同的类别在孩子的脑海中就形成了。人们通过体验周围的环境,学会识别猫、理解单词或进入房间并注意到某些东西发生了变化。
当霍普菲尔德发表关于联想记忆的文章时,杰弗里·辛顿正在美国匹兹堡的卡内基梅隆大学工作。他之前曾在英格兰和苏格兰学习过实验心理学和人工智能,他想知道机器是否能学会以类似于人类的方式处理模式,找到自己的类别来对信息进行分类和解释。辛顿与他的同事特伦斯·塞诺夫斯基一起从霍普菲尔德网络开始,并利用统计物理学的思想对其进行扩展,构建出了一些新的东西。
统计物理学描述的是由许多相似元素组成的系统,例如气体中的分子。追踪气体中的所有单个分子是困难的,甚至是不可能的,但可以将它们作为一个整体来考虑,以确定气体的总体特性,如压力或温度。气体分子以不同的速度在其体积中扩散,并仍然具有相同的集体特性,这有很多潜在的方式。
可以使用统计物理学分析各个组件可以共同存在的状态,并计算出它们发生的概率。有些状态比其他状态更有可能发生;这取决于可用能量的数量,这在 19 世纪物理学家路德维希·玻尔兹曼 (Ludwig Boltzmann) 的一个方程中有所描述。Hinton 的网络利用了该方程,该方法于 1985 年以引人注目的玻尔兹曼机 (Boltzmann machine)的名称发表。
识别同一类型的新示例
玻尔兹曼机通常与两种不同类型的节点一起使用。信息被馈送到一组节点,这些节点称为可见节点。其他节点形成隐藏层。隐藏节点的值和连接也对整个网络的能量有贡献。
该机器通过应用规则来运行,每次更新一个节点的值。最终,机器将进入一种状态,其中节点的模式可以改变,但整个网络的属性保持不变。然后,每个可能的模式将具有特定的概率,该概率由网络能量根据玻尔兹曼方程确定。当机器停止时,它已经创建了一个新的模式,这使得玻尔兹曼机成为生成模型的早期例子。
玻尔兹曼机可以学习——不是通过指令,而是通过给出的例子。它通过更新网络连接中的值进行训练,以便在训练时输入可见节点的示例模式在机器运行时具有最高的出现概率。如果在训练过程中多次重复相同的模式,则该模式的概率甚至更高。训练还会影响输出与机器训练的示例相似的新模式的概率。
经过训练的玻尔兹曼机能够识别出它之前未见过的信息中的熟悉特征。想象一下,当你遇到朋友的兄弟姐妹时,你立刻就能看出他们一定是亲戚。同样,如果一个全新的示例属于训练材料中的某个类别,玻尔兹曼机也能识别它,并将其与不相似的材料区分开来。
在其原始形式中,波尔兹曼机效率相当低,需要很长时间才能找到解决方案。当它以各种方式开发时,事情变得更加有趣,而欣顿一直在探索这一点。后来的版本已经变得稀疏,因为一些单元之间的连接已被移除。事实证明,这可能会使机器更有效率。
20 世纪 90 年代,许多研究人员对人工神经网络失去了兴趣,但 Hinton 是继续在该领域工作的研究人员之一。他还帮助开启了令人兴奋的新一轮成果热潮;2006 年,他与同事 Simon Osindero、Yee Whye Teh 和 Ruslan Salakhutdinov 开发了一种使用一系列逐层叠加的玻尔兹曼机对网络进行预训练的方法。这种预训练为网络中的连接提供了更好的起点,从而优化了其训练以识别图片中的元素。
波尔兹曼机通常用作大型网络的一部分。例如,它可以根据观众的喜好推荐电影或电视剧。
玻尔兹曼机概念代码示例:
import numpy as np
class RBM:
def __init__(self, n_visible, n_hidden, learning_rate=0.1):
self.n_visible = n_visible # 可见层节点数
self.n_hidden = n_hidden # 隐藏层节点数
self.learning_rate = learning_rate
# 初始化权重和偏置
self.weights = np.random.normal(0, 0.01, size=(self.n_visible, self.n_hidden))
self.visible_bias = np.zeros(self.n_visible)
self.hidden_bias = np.zeros(self.n_hidden)
def sigmoid(self, x):
return 1.0 / (1 + np.exp(-x))
def train(self, data, epochs=1000):
"""
使用对比散度(Contrastive Divergence,CD)算法训练RBM
"""
num_samples = data.shape[0]
for epoch in range(epochs):
# 正相位:从数据计算隐藏层概率
pos_hidden_probs = self.sigmoid(np.dot(data, self.weights) + self.hidden_bias)
pos_hidden_states = (pos_hidden_probs > np.random.rand(num_samples, self.n_hidden)).astype(float)
pos_associations = np.dot(data.T, pos_hidden_probs)
# 负相位:从隐藏层重构可见层,再计算隐藏层
neg_visible_probs = self.sigmoid(np.dot(pos_hidden_states, self.weights.T) + self.visible_bias)
neg_hidden_probs = self.sigmoid(np.dot(neg_visible_probs, self.weights) + self.hidden_bias)
neg_associations = np.dot(neg_visible_probs.T, neg_hidden_probs)
# 更新权重和偏置
self.weights += self.learning_rate * (pos_associations - neg_associations) / num_samples
self.visible_bias += self.learning_rate * np.mean(data - neg_visible_probs, axis=0)
self.hidden_bias += self.learning_rate * np.mean(pos_hidden_probs - neg_hidden_probs, axis=0)
# 可选:计算重构误差
if epoch % 100 == 0:
error = np.mean((data - neg_visible_probs) ** 2)
print(f"Epoch {epoch}: Reconstruction error = {error}")
def run_visible(self, data):
"""
给定可见层输入,计算隐藏层的激活概率
"""
hidden_probs = self.sigmoid(np.dot(data, self.weights) + self.hidden_bias)
return hidden_probs
def run_hidden(self, data):
"""
给定隐藏层输入,计算可见层的激活概率
"""
visible_probs = self.sigmoid(np.dot(data, self.weights.T) + self.visible_bias)
return visible_probs
def sample_hidden(self, visible):
"""
从可见层采样隐藏层状态
"""
hidden_probs = self.run_visible(visible)
hidden_states = (hidden_probs > np.random.rand(self.n_hidden)).astype(float)
return hidden_states
def sample_visible(self, hidden):
"""
从隐藏层采样可见层状态
"""
visible_probs = self.run_hidden(hidden)
visible_states = (visible_probs > np.random.rand(self.n_visible)).astype(float)
return visible_states
def generate(self, n_samples, n_steps=1000):
"""
从随机初始化开始,生成新样本
"""
samples = []
visible = (np.random.rand(self.n_visible) > 0.5).astype(float)
for _ in range(n_samples):
for _ in range(n_steps):
hidden = self.sample_hidden(visible)
visible = self.sample_visible(hidden)
samples.append(visible.copy())
return np.array(samples)
# 示例数据:简单的二进制模式
data = np.array([
[1, 1, 0, 0], # 模式A
[1, 0, 1, 0], # 模式B
[1, 0, 0, 1], # 模式C
[0, 1, 1, 0], # 模式D
[0, 1, 0, 1], # 模式E
[0, 0, 1, 1], # 模式F
])
# 创建RBM实例
rbm = RBM(n_visible=4, n_hidden=2, learning_rate=0.1)
# 训练RBM
rbm.train(data, epochs=1000)
# 从训练好的RBM中生成新样本
generated_samples = rbm.generate(n_samples=5, n_steps=500)
print("Generated samples:")
print(generated_samples)
机器学习,现在和未来
凭借自 20 世纪 80 年代以来的工作,约翰·霍普菲尔德 (John Hopfield) 和杰弗里·辛顿 (Geoffrey Hinton) 为 2010 年左右开始的机器学习革命奠定了基础。
我们现在所见证的发展是通过获取可用于训练网络的大量数据以及计算能力的大幅提升而实现的。当今的人工神经网络通常非常庞大,由多层构成。这些被称为深度神经网络,其训练方式称为深度学习。
快速浏览一下霍普菲尔德 1982 年发表的关于联想记忆的文章,可以对这一发展提供一些看法。在这篇文章中,他使用了一个有 30 个节点的网络。如果所有节点都相互连接,则有 435 个连接。节点有自己的值,连接有不同的强度,总共有不到 500 个参数需要跟踪。他还尝试过一个有 100 个节点的网络,但考虑到他当时使用的计算机,这太复杂了。我们可以将其与当今的大型语言模型进行比较,这些模型被构建为可以包含超过一万亿(一百万亿)参数的网络。
目前,许多研究人员正在开发机器学习的应用领域。哪一个领域最有前景还有待观察,同时围绕这项技术的开发和使用的伦理问题也引发了广泛的讨论。
由于物理学为机器学习的发展贡献了工具,因此有趣的是,物理学作为一个研究领域也受益于人工神经网络。机器学习长期以来一直应用于我们可能熟悉的领域,从以前的诺贝尔物理学奖中可以看出。其中包括使用机器学习来筛选和处理发现希格斯粒子所需的大量数据。其他应用包括降低碰撞黑洞引力波测量中的噪声,或寻找系外行星。
近年来,该技术也开始用于计算和预测分子和材料的特性,例如计算决定其功能的蛋白质分子结构,或确定哪种新材料可能具有最佳特性,以用于更高效的太阳能电池。