使用 Python 进行卫星影像分析的综合指南
实践教程,数据科学|遥感|实践教程
使用 Python 分析卫星影像的不同方法和机器学习技术,以及实践教程和示例。
本文通过实践教程和示例,帮助用户了解使用 Python 分析卫星影像的不同方法以及有监督和无监督的机器学习技术。
内容
- 卫星图像指数
- 卫星图像中的监督学习
- 卫星图像中的无监督学习
- 结论
让我们开始吧✨
卫星图像指数
归一化卫星指数是根据多光谱卫星图像计算的图像。这些图像强调了存在的特定现象,同时减轻了降低图像效果的其他因素。例如,植被指数将健康植被显示为指数图像中的亮色,而不健康植被的值较低,贫瘠地形为暗色。由于地形变化(丘陵和山谷)的阴影会影响图像的强度,因此创建索引时会强调对象的颜色,而不是对象的强度或亮度。
植被指数
NDVI、SAVI 和 VARI 的孙德尔本斯卫星数据,图片由作者提供
为了确定一块土地上的绿色密度,研究人员必须观察植物反射的可见光(VIS)和近红外(NIR)阳光的不同颜色(波长)。一些广泛使用的植被指数是:
- 归一化差异植被指数(NDVI)
- 土壤调整植被指数(SAVI)
- 可见大气阻力指数(VARI)
水指数
MNDWI 和 NDMI od Sundarbans 卫星数据,图片由作者提供
地表水变化是环境、气候和人类活动的一个非常重要的指标。sentinel-2、Landsat 等遥感器在过去四十年里一直在提供数据,这对于提取森林和水等土地覆盖类型很有用。研究人员提出了许多地表水提取技术,其中基于指数的方法因其简单和成本效益高而受到欢迎。一些广泛使用的水指数是:
- 修正的归一化差异水指数
- 归一化差异湿度指数(NDMI)
地质指数
事实证明,卫星图像和航空摄影是支持矿产勘探项目的重要工具。它们可以以多种方式使用。首先,它们为地质学家和野外工作人员提供轨迹、道路、栅栏和居住区的位置。
孙德尔本斯卫星数据的粘土和含铁矿物比例,图片由作者提供
- 粘土矿物比率— 粘土比率是 SWIR1 和 SWIR2 带的比率。这一比率利用了粘土、明矾石等含水矿物吸收光谱中 2.0-2.3 微米部分的辐射这一事实。由于该指数是一个比率,因此可以减轻由于地形造成的光照变化。
- 含铁矿物比率— 含铁矿物比率突出显示含铁物料。它使用 SWIR 波段和近红外波段之间的比率。
使用下面的文章,这是一个关于上述 Sundatbands 卫星数据的卫星指数的实践教程。
卫星图像中的监督学习
监督学习算法如 K-最近邻分类器(KNNC)、支持向量机(SVM)、深度神经网络(DNNs)、卷积神经网络(CNN)广泛应用于土地覆盖分类、多标签分类等领域
使用下面的文章,涵盖不同的卫星影像分类算法。
卫星图像中的无监督学习
无监督学习算法如主成分分析(PCA)、线性判别分析(LDA)、e.t.c 等被用于卫星图像的降维。KMeans、带噪声的基于密度的应用程序空间聚类(DBSCAN)等用于对卫星图像数据进行聚类。
使用下面的文章,涵盖了孙德尔本斯卫星影像的维数减少和聚类。
结论
这篇文章涵盖并帮助读者理解监督和非监督机器学习技术和指数,以分析卫星图像。文章中提到的实践教程可以通过 GitHub 资源库获得。
https://github.com/syamkakarla98/Satellite_Imagery_Analysis https://github.com/syamkakarla98/Hyperspectral_Image_Analysis_Simplified
参考
https://link.springer.com/chapter/10.1007/978-981-15-3338-9_12 https://landsat.gsfc.nasa.gov/landsat-8/landsat-8-bands
随机变量、随机过程及其性质的综合概述(第 1 部分)
在 Unsplash 上由 Klara Avsenik 拍摄的照片
这是一篇由两部分组成的文章。在第 1 部分(这一部分),我将回顾随机变量,随机向量,以及它们的性质。在第 2 部分,我将讨论随机过程及其性质。
随机变量和随机过程在现实世界中扮演着重要的角色。它们广泛应用于机器学习、信号处理、数字通信、统计学等领域。
以下是这篇文章的提纲:
概述
- 概率复习。(第一部分)
- 随机变量。(第一部分)
- 随机变量的性质。(第一部分)
- 概率中的重要定理。(第一部分)
- 随机向量。(第一部分)
- 随机过程。(第二部分)
- 随机过程的性质。(第二部分)
- 不同类别的随机过程。(第二部分)
- 随机过程通过 LTI 系统。(第二部分)
- 机器学习、人工智能、信号处理中的重要随机过程。(第三部分)
托拜厄斯·凯勒在 Unsplash 上的照片
概率复习
概率被定义为一个事件在长期内的相对频率(频率主义者)或现实世界中不确定性或信念的度量(贝叶斯)。要了解更多关于贝叶斯和频率主义的观点,请参考这篇文章。
样本空间被定义为一个实验的所有可能实现的集合,用ω表示。比如抛硬币对应的样本空间是ω= { H,T}(其中 H =头,T =尾)或者掷骰子对应的样本空间是:ω= { 1,2,3,4,5,6}。
概率的三个众所周知的公理如下:
1-任何事件的概率介于 0 和 1 之间。
2-样本空间的概率为 1(它总是发生),即
3-如果 A 和 B 是两个任意事件,那么 A 或 B 的概率计算如下:
∪和∩分别表示逻辑 or 和逻辑 and。
图 1:使用文氏图的联合 B
设 A '是 A 的补,A 是样本空间中不在 A 中的所有元素的集合;那么下面的关系通常是正确的:
图 2:A 的补集的维恩图
图 3:A-B 的维恩图
图 4:A∪B 补码的维恩图
图 1、图 2、图 3 和图 4 分别代表 A 的并集 B、A 的补集、A -B 和 A 的并集 B 的补集的文氏图。文氏图是一种图形和直观的方式来表示集合及其关系。
随机变量
随机变量是样本空间元素到真实直线的映射。它既不是随机的,也不是可变的,但它是一个函数,其定义域是样本空间ω,其值域是ℝ(实数)。
图 5:从样本空间到真实线的映射
随机变量可以是离散的,连续的,或是两者的混合。我用大写字母表示随机变量,小写字母表示其值(有时称为实现)。离散随机变量用概率质量函数(PMF)来表示,概率质量函数是不同 k 值下随机变量 X 等于 k 的概率,例如抛一枚公平硬币对应的 PMF 如下:
作为另一个例子,考虑 PMF 掷出的公平骰子:
连续随机变量取特定值的概率为零。因此,它们不是由 PMF 表示,而是由概率密度函数(PDF)表示,概率密度函数是随机变量 X 在 X 和 x + δ之间的概率,通常用 f(x)表示。
图 PDF 的定义
累积分布函数或 CDF 被定义为随机变量 X 取值小于或等于 X 的概率。它被定义为离散和连续随机变量。
CDF 的一些重要属性如下:
1-是单调递增的。
2-是右连续(参考下图)。
图 CDF 的右连续性
3-随机变量 X 在 a 和 b 之间的概率计算如下:
CDF 和 PDF 可以按如下方式相互关联:
n 个随机变量的联合 CDF 定义类似:
有时我们会希望在给定随机变量 Y 已经发生的情况下,求出随机变量 X 的概率。这是用 P(X |Y)表示的条件概率的一个例子。人们可以认为所有的概率都是有条件的,因为它们取决于样本空间,例如:
上面的等式是正确的,因为样本空间以概率 1 发生,因此,我们不需要显式地写它。给定 Y,X 的条件概率计算如下:
上述等式背后的直觉如下:既然事件 Y 已经在发生,那么样本空间就从ω变为 Y,这就解释了分母。现在我们只关心 X 和 Y 之间常见的结果,这解释了分子。
注: P(X ∩ Y)有时写成 P(X,Y)。
从联合分布中寻找事件的边际概率/密度的过程称为边缘化,其定义如下:
边缘化是一个消除除了利益变量之外的其他变量的过程。这是通过对除感兴趣的随机变量之外的所有其他变量求和/积分来完成的。
综合发展框架的边缘化定义如下:
这意味着要找到 X₁的边际 CDF,我们所要做的就是用联合 CDF 表达式中的∞来代替其他随机变量。从上面的公式可以明显看出这一点,因为任何变量都小于∞的概率为 1。以下是 CDF 的更多属性:
随机变量的性质
在这一节中,我将讨论在统计、机器学习、信号处理等领域广泛使用的随机变量的一些众所周知的性质。
均值、方差和协方差
随机变量 X 的平均值或期望值定义如下:
连续随机变量由 PDF 定义并使用积分计算,而离散随机变量由 PMF 定义并通过求和计算。
方差是随机变量相对于平均值的离差或可变性的度量。方差越大,平均值的分布越广。数学上定义如下:
协方差是两个随机变量相对于彼此的线性可变性的度量。其定义如下:
在上面的等式中,用 X 代替 Y,就可以用协方差得到随机变量的方差。
使用协方差推导方差
假设 X 和 Y 是两个任意随机变量,并且 a 和 b 是两个定标器,那么下面是期望值、方差和协方差的一些重要属性:
协方差、期望和方差的性质
这些属性用简单的英语表达如下:
- 期望值是一个线性算子,因此它满足叠加性质(同质性和可加性(前两行))。
- 给随机变量加一个常数不会改变随机变量的方差。
- 将随机变量乘以常数 a 会将变量的方差乘以a
- 将常数 a 和 b 加到任一随机变量上不会改变它们之间的协方差。
- 将任意一个随机变量乘以常数 a 会将它们之间的协方差乘以 a.
皮尔逊相关
用符号ρ表示的皮尔逊相关或简称相关,度量两个随机变量或向量之间的线性相关。其定义如下:
皮尔逊相关
在某种意义上,皮尔逊相关是两个随机变量之间的归一化协方差。ρ的最大值为+1,表示完全正相关,-1 表示完全负相关,0 表示没有线性相关。
独立性和条件期望
两个随机变量 X 和 Y 被认为是独立的,如果知道了其中一个,你就不会得到关于另一个随机变量的额外信息。回想一下条件概率的定义,就是给定随机变量 Y 已经发生的情况下,随机变量 X 的概率。如果 X 和 Y 是独立的,下面的关系是真的:
独立性的定义
回想一下,条件概率也可以用联合概率和边际概率来定义。因此,独立性的一个更常见的定义是:
用联合概率定义独立性
上面的等式说的是两个随机变量的联合分布等于它们的边值的乘积。
给定随机变量 Y,随机变量 X 的条件期望定义如下:
互斥事件
两个事件 A 和 B 是互斥的,如果它们的交集是空的。
数学上定义为 A ∩ B = ∅,或者 P(A ∩ B ) = 0。
图 8:两个互斥事件的示意图
独立与不相关的随机变量
如果随机变量 X 和 Y 是独立的,那么它们是不相关的(因为它们之间的协方差是零),但是反过来不一定是正确的,除非 X 和 Y 是联合高斯分布,那么独立和不相关是相同的事情。
在本文的第 2 部分中,当我讨论高斯随机过程时,我再次提到了这个概念。
概率中的重要定理
全概率定律 如果 B₁,B₂,。。。,Bₙ这样划分样本空间:
这意味着它们的并集跨越样本空间,并且它们是互斥的(它们的交集是空的)。那么任何事件 A 都可以表示如下:
图 9:全概率定律的文氏图
贝叶斯定理 这是机器学习、信号处理、统计学等领域中应用最广泛的定理之一。它是把给定 B 的条件概率和给定 A 的 B 的条件概率联系起来的一种方法,在另一个世界里,它是把似然和后验分布联系起来的一种技术。其数学定义如下:
图 10:贝叶斯法则
有关贝叶斯定律、后验概率和可能性的更多信息,请参考以下文章和 Youtube 视频。
总期望定律
假设你想知道加州大学洛杉矶分校平均有多少学生喜欢下棋。一种方法是亲自采访每一个学生,用爱下棋的学生人数除以学生总数,得出平均值。然而,这种技术非常繁琐,并且不可扩展。
相反,更实用的方法是按专业/系对学生进行分类,并计算每个系喜欢下棋的学生的平均人数(这可以由多人完成,每个人采访一个系),然后在这些平均人数中找出平均值,得出想要的结果。从数学上来说,这写如下:
总期望定律
这里 y 是划分人的标准(像专业、科室、性别、年龄等)。
中心极限定理(CLT) 中心极限定理指出,如果 X₁、X₂、.。。、Xₙ均为独立同分布随机变量,均值为μ,方差为σ,随机变量 Zₙ定义如下:
当 n 趋于∞(变得很大)时,Zₙ的 CDF 收敛于标准的正常 CDF。关于 CLT 的好处是,它与 X₁、X₂等发行版无关。。。、Xₙ都有,它们可以是离散或连续的随机变量。
随机向量
随机变量的下一个扩展是随机向量。它被定义为有限数量的随机变量的集合。例如, X 是一个随机向量,如下所示:
X 的每个元素都是随机变量,具有一定的概率分布、均值、方差等。随机向量 X 的 CDF 定义如下:
由于 X 的每个元素都是随机变量,因此不同分量之间可能存在相关性,因此我们定义协方差矩阵来捕捉所有元素之间的方差和协方差。
均值和协方差矩阵的定义
因此,协方差矩阵是这样的矩阵,其主对角线上的元素是每个分量的方差,非对角线元素是每两个随机变量之间的协方差。
回想一下皮尔逊相关的定义及其与两个随机变量协方差的关系。上述协方差矩阵可以写成如下形式:
基于皮尔逊相关的协方差矩阵定义
现在,让我们讨论协方差矩阵的性质。
- 它是对称的,因为 X₂的 cov(x₁= x₁).的 Cov(X₂
- 它是半正定的。这意味着:
- 它的所有特征值都是非零的。
高斯随机向量
如果随机变量 X₁,X₂,。。。,Xₙ是联合高斯那么随机向量 x 是高斯随机向量和 X₁,X₂,.。。,Xₙ也是高斯随机变量。
高斯随机向量 X 的 PDF 由其均值向量μ和协方差矩阵 c 表征。其数学定义如下:
高斯随机向量的 PDF
如果一个高斯随机向量有一个对角协方差矩阵,那么它的分量都是独立和不相关的。这是因为每两个元素的协方差为零。
结论
在这篇文章中,我讨论了概率规则,随机变量,随机向量,它们的性质,以及概率论中的重要定理。这是这个两部分文章的第一部分。
在下一部分,我将讨论随机过程,它的性质,随机过程的不同类别,以及通过 LTI 系统的随机过程。
随机变量、随机过程及其性质的综合概述(第 2 部分)
你所需要的关于随机过程和它们的性质
在 Unsplash 上 Matteo Catanese 拍摄的照片
这是一篇由两部分组成的文章。在第 2 部分(这一部分),我将回顾随机过程(随机过程),它们的性质,以及它们对线性时不变(LTI)信道的响应。在第 1 部分中,我讨论了概率、随机变量及其性质。如果您尚未阅读第一部分,请先阅读以下内容:
第一部分是理解这一部分的基础,因为随机过程是随机变量和随机向量的一般扩展。
随机变量和随机过程在现实世界中扮演着重要的角色。它们广泛应用于机器学习、信号处理、数字通信、统计学等领域。
以下是这篇文章的提纲:
概述
- 概率的复习。(第一部分)
- 随机变量。(第一部分)
- 随机变量的性质。(第一部分)
- 概率中的重要定理。(第一部分)
- 随机向量。(第一部分)
- 随机过程。(第二部分)
- 随机过程的性质。(第二部分)
- 不同类别的随机过程。(第二部分)
- 随机过程通过 LTI 系统。(第二部分)
- 机器学习、人工智能、信号处理中的重要随机过程。(第三部分)
照片由 Kunal Shinde 在 Unsplash 上拍摄
随机流程
随机过程 X(w;t)是 t 和 w 的时变函数,其中 t 通常是时间,w 是样本空间的元素(ω)。因此,有两种方法来看待随机过程。
案例一:t(时间)固定,w 在变化:
图 1:固定 t 的随机过程定义
如果 t 固定为 t = tᵢ,那么当 w 变化时,我们得到 I 的每个值的随机变量。因此,如果 w 在变化,随机过程就是随机变量的集合。
情况二:w 不变,t 在变:
图 2:固定 w 的随机过程
如果 w 固定在 wᵢ,那么我们得到一个时域信号或实现。因此,对于固定的 w,随机过程是确定的时域函数。
观察 1: 随机过程中的随机性是由于 w,而不是 t,因此,在随机过程的定义中通常省略 w(假设 w 是变化的);因此,我们有时称随机过程 X(w,t)为 X(t)。
**直觉:**把随机过程想象成一包时域信号(函数、实现),每次你把手放进包里,抓住其中一个信号,但你不知道你拿的是哪一个(这就是随机性的来源)。
**观察二:**你可以把一个随机过程看成一个 n 维随机向量的一般版本,其中 n 趋近于无穷大。
你可以在我的 Youtube 频道上找到更多关于随机过程的信息:
随机过程的性质
随机过程由一些属性描述,例如均值、自相关、互相关、自协方差、功率谱密度和平均功率。
均值,或随机过程 X(t)的平均值(回想一下,由于假设它是变化的,所以符号中遗漏了 w),定义类似于随机变量和随机向量(请参考第 1 部分)。
观察 3: 回想一下当 w 在变化时,一个随机过程对于每个时间 t 都是一个随机变量,因此在每个时间点,随机变量的期望就是均值。一般来说,平均值是时间函数。
随机过程 X(t)的自相关被定义为随机过程 X(t)在不同时间点与其自身(因此单词 auto)的相关性。
图 3:不同时间点的随机过程。
随机过程 X(t)的自协方差被定义为随机过程 X(t)在不同时间点与其自身(因此单词 auto)的协方差。
关于两个随机变量的协方差的定义,请参考第 1 部分的文章(链接在上面的介绍中给出)。
随机过程 X(t)和 Y(t)之间的互相关是两个不同时间点上它们之间相关性的度量。
功率谱密度(PSD)被定义为每个频带中的功率量,并且是自相关函数的傅立叶变换。在下一节讨论广义平稳(WSS)过程时,我将更多地讨论 PSD 和总功率。
如果 t 取实线上的任意值,那么 X(t)称为连续时间随机过程(随机过程),如果 t 是可数集合的成员,那么 X(t)是随机序列。
观测 4: { X(t),t ∈ ℝ}称为连续时间随机过程而{ X(t),t ∈ ℕ}称为离散时间随机过程或随机序列。
不同类别的随机过程
平稳过程
如果过程 X(t)的统计特性(CDF、PDF 等)不随时间变化,则称其为平稳过程。例如,X(t)是静止的当且仅当:
观察值 5: 上式说的是,对于任意 t 和任意δ,平稳过程的 CDF 随时间保持不变。
同样对于平稳过程,X(t₁和 X(t₂的联合分布随时间保持不变。数学上,这定义如下:
平稳过程也称为严格意义上的平稳过程(SSS),如果对 t₁、t₂、。。、tₙ和任何δ,满足以下条件:
一般来说,要证明一个进程是否是 SSS 是非常困难的,因此我们关注较弱的符号。
弱/广义静止(WSS)
如果对于所有 t₁、t₂ ∈ ℝ和所有δ∈ℝ,以下两个条件成立,则 X(t)是 WSS 过程:
观察值 5: 如果一个过程的均值是常数,且其自相关是时滞的函数,则该过程是 WSS(t₁- t₂).时滞通常用τ表示。
从现在开始,我将关注 WSS 过程,因为大多数真实世界的过程都被建模为 WSS 过程。
有关随机过程的更多内容,请访问我的 YouTube 频道:
WSS 过程自相关的性质
1-这是时间滞后的唯一功能。
2-它是一个偶数函数。
3-滞后(τ)为零时的自相关给出平均功率。
4-当时滞为零时,出现自相关的最大值。
5-如果 X(t)是实值随机过程,则自相关是实值函数。
欲了解更多信息,请访问我的 YouTube 频道:
联合 WSS 进程
如果下列两个条件成立,则称两个随机过程 X(t)和 Y(t)是联合 WSS:
观察值 6: 上述两个条件表明,对于联合 WSS 的过程 X(t)和 Y(t ),则每一个都应该是 WSS(常数均值和自相关应该只是时滞的函数),而互相关(第二个条件)应该只是时滞的函数。
功率谱密度
PSD 被定义为 WSS 过程的自相关的傅立叶变换。它用符号 s 表示。
WSS 过程的功率谱密度特性
1-如果 X(t)是实值随机过程,则它是实值函数。
2-它是一个偶数函数。
PSD 曲线下的面积是平均功率。
属性 3 是最重要的一个,因为它提供了三种不同的方法来计算随机过程的平均功率。
观察值 7: 通过对 PSD 曲线下的面积进行积分,计算零点滞后处的自相关函数,计算随机过程的期望平方,从而计算出信号的平均功率。
通过 LTI(线性时不变)系统的随机过程
线性系统由脉冲响应函数 h(t)唯一表示。如果 X(t)和 Y(t)是线性系统的输入和输出,则 Y(t)可以计算为 X(t)和脉冲响应 h(t)的卷积。
图 4:线性系统输入输出关系
如果 X(t)是随机过程并且被输入到 LTI 系统,那么输出 Y(t)也是随机过程。
定理 1: 若 X(t)是 WSS 随机过程,并以脉冲响应 h(t)输入 LTI 系统,则 X(t)和 Y(t)共同为 WSS 过程。
由于 Y(t)是一个 WSS 随机过程,那么它的平均值是常数,它的自相关只是时间滞后的函数。以下是 Y(t)的平均值、自相关性以及 X(t)和 Y(t)之间的互相关性的表达式。
观察值 7: 由于 X(t)是 WSS 过程,因此它具有恒定的平均值,因此 Y(t)的期望值也是恒定的(等式 1)。等式 2 表示 X(t)和 Y(t)之间的互相关只是时滞的函数。等式 3 表示输出的自相关仅是时滞的函数。(等式 1 和 3 声称 Y(t)是 WSS 过程,等式 1、2 和 3 声明 X(t)和 Y(t)共同是 WSS 过程。)
频域分析
假设 H(f)是 LTI 系统的频率响应(脉冲响应的傅立叶变换),Sx(f)和 Sy(f)(输入和输出的自相关的傅立叶变换)分别是输入和输出的功率谱密度,则可以在频域中分析上述方程。
观测 8: 在求联合 X(t)和 Y(t)(方程 5)的功率谱密度时,我们利用了 H(-f)是 H(f)的共轭的性质(傅里叶变换性质。)
结论
在这篇文章中,我讨论了随机过程,它们的性质,不同类别的随机过程,以及通过 LTI 系统的随机过程。在下一部分(第三部分),我将回顾机器学习,人工智能和信号处理中的重要随机过程,如马尔可夫链,高斯随机过程,隐马尔可夫模型(HMM)等。
最小二乘估计的综合研究(上)
普通、约束、多目标和非线性最小二乘。
Lukasz Szmigiel 在 Unsplash 上的照片
最小二乘估计是机器学习、信号处理和统计中使用最广泛的技术之一。这是解决线性回归的常用方法,广泛用于模拟连续结果。
它可以被建模为具有二次成本的 MMSE 估计量或贝叶斯估计量。我已经写了关于机器学习和信号处理中使用的各种估计器的综合文章。请查看以下文章了解更多信息。
我还制作了一系列 YouTube 视频来更深入地了解各种评估技术。请查看并订阅我的 YouTube 频道了解更多信息。
这是一篇由三部分组成的文章,讨论了关于最小二乘估计的所有要点。下面是这篇文章的提纲:
概述
- 普通最小二乘(OLS)估计
- OLS 问题的解决
- 正交原理
- OLS 使用 QR 分解(高级读者)
- 矩阵的最小二乘问题
- 多目标最小二乘法(第二部分)
- 约束最小二乘法(第三部分)
- 非线性最小二乘法(第四部分)
在本文中,我将深入讨论最小二乘,在以后的文章中,我将深入讨论多目标、约束和非线性最小二乘。我还将链接到我在 YouTube 上关于最小二乘主题的视频,以获得更多信息和更全面的解释。
普通最小二乘法(OLS)
假设 A 是一个 m×n 矩阵,其中 m 大于或等于 n (A 是一个高矩阵),那么下面的超定方程组或者有唯一或者无解。
图 1:线性方程
如果 b 是 a 的列的线性组合,唯一的解决方案就会出现,这意味着如果你认为 a 被写成列表示,那么 b 将在 a 的列空间中。另一种解释方式是,有 scaler x₁,x₂。。。,xₙ,使得下面的方程有解。
图 2:线性无关的条件
**注:**要知道为什么如果解存在,那么它是唯一的,考虑最小二乘问题的假设。它声明 A 是高的,并且有线性无关的列,那么它有一个左逆。然后把方程 1 的左右两边乘以 A 的左逆,就得到唯一解了。本文的其余部分解释了如何找到这个解决方案。
注:要了解超定、待定方程组、高、宽矩阵、矩阵的行列解释,请参考以下视频:
如果 Ax = b 无解,那么我们的目标是找到 x,使得它最小化 Ax 和 b 之间的距离的范数。
图 3:最小二乘问题公式化
最小二乘法的列解释:
对于列解释,我们试图找到与向量 b 最接近的 A 列的线性组合。数学上,这可以表示如下:
图 4:最小二乘法的列表示
最小二乘法的行解释;
对于行解释,我们试图最小化对应于 m 个线性方程的 m 个残差的总和。
图 5:最小平方的行表示
r 是残差向量,其中 r 的每个分量对应于线性方程中的一个残差。例如:
图 6:最小二乘法的行表示
最小二乘问题的解
这里我将介绍两种解决 OLS 问题的方法。这两种方法是等效的。
方法 1: 基于组件的符号
图 7:最小二乘解
这种方法是基于将目标函数 J 写成它的分量,然后对目标函数 x 求微分,并将其设置为零。
图 8
**方法二:**矩阵-向量表示法
这种方法是基于将向量的欧氏范数写成向量转置和自身的乘积。
图 9:使用矩阵向量符号的最小二乘解
产生最小二乘问题的解的以下方程被称为标准方程。
图 10:法线方程
方法 1 和 2 产生相同的结果,但是方法 1 是基于元素的格式,而方法 2 给出了更简洁的解决方案。
解决方案的解释
(AᵗA)⁻ A(转置的乘积,a 被称为格拉姆矩阵,并且如果 a 具有线性独立的列,则它是可逆矩阵)被称为矩阵 a 的左伪逆。这意味着:
**注:**若 A 是左可逆矩阵(有线性无关列)最小二乘解存在且唯一。
**注:**要了解更多关于 gram 矩阵、左可逆矩阵和右可逆矩阵的信息,请参考以下视频:
正交原则:
我在“基本参数估计技术文章”中讨论了一般估计量的正交性原理,请参考以下参考资料了解更多信息
但是这里我将在最小平方估计的上下文中引入正交性原理。
正交性原理说明残差与最优估计量正交。
例如,考虑下图:
正交原理
b 是我们想要估计的向量,r 是残差,Ax 是估计量。
图 11:正交条件
现在,为了检查最小二乘解是否是最优解,我们进行如下:
如果 x 是最小二乘解,则正规方程成立,意思是:
因此,正交性原则如下:
其中最后的结果是由于正常的方程。上述等式表明,如果 x 是最小二乘解,则 Ax 与残差正交,因此 Ax 是向量 b 的最佳估计量
OLS 使用 QR 分解(高级题目)
这一节需要接触 QR 分解,这就是为什么我把它归类为一个更高级的主题。有关 QR 方法的信息和逐步解释,请观看以下视频:
我们将首先通过让 A = QR 使用 QR 分解来分解矩阵 A,其中 Q 是正交矩阵,R 是上三角矩阵。然后我们用它的 QR 分解等价物代替 OLS 解中的 A。
图 12:使用 QR 分解的最小二乘解
最后一行表示使用 QR 分解的解决方案。QR 分解提供了一种使用以下算法求解最小二乘法的有效方法:
- 求矩阵 A 的 QR 分解,即 A = QR。
- 计算 Q 转置和 b 的乘积。
- 用回代法解下式(因为 R 是上三角矩阵)。
矩阵的最小二乘问题
假设 A 是 m×n 矩阵,X 是 n×p 矩阵,B 是 m×p 矩阵。然后目标是最小化 Ax-B 的 Frobenius 范数。该问题类似于根据矩阵 X 和 B 的列表示来表示矩阵 X 和 B 之后的向量的最小二乘问题。
**注:**矩阵的欧几里德或弗罗贝纽斯范数定义如下:
其中 aᵢⱼ是矩阵 a 的 iᵗʰ行和 jᵗʰ列的元素 aᵢ是矩阵 a 的 iᵗʰ列上面等式说的是一个矩阵的 Frobenius 范数是每列的欧氏范数之和。 因此结果简化如下:
可以看出,| | AX-B | |(Frobenius 范数的平方)可以写成 p 个普通最小二乘目标函数之和,但是每个目标函数都可以独立最小化。因此,实际上我们正在求解 p 个独立的最小二乘问题,以找到对应于矩阵 x 的 p 列的 p 个最优解。
在更简洁的形式中,该解可以表示如下:
完成第一部分后,请务必查看第二和第三部分。第 2 部分讨论了多目标最小二乘法。第 3 部分讨论了约束最小二乘问题。
结论
在本文中,我讨论了普通的最小二乘问题,解决方案的行和列解释,正交性原则,以及使用 QR 分解的 OLS 解决方案。在下一篇文章中,我将讨论多目标和约束最小二乘问题。
我在之前的一篇关于“基本参数估计技术”的文章中讨论过 OLS(那篇文章的链接在这里给出)。
在我的 YouTube 频道中还有一个完整的关于数值线性代数和优化的系列视频,在其中我详细讨论了所有这些主题。
最小二乘估计的综合研究(下)
普通、约束、多目标和非线性最小二乘。
杰伊·曼特里在 Unsplash 上的照片
在第一部分,我详细讨论了普通最小二乘问题。在这一部分(第二部分),我将回顾多目标最小二乘问题。如果您尚未阅读第一部分,请参考以下文章了解更多信息:
[## 最小二乘估计的综合研究(上)
towardsdatascience.com](/comprehensive-study-of-least-square-estimation-part-1-32d24347f9e3)
更多信息和更详细的解释,请参考我的 YouTube 频道。
https://www.youtube.com/channel/UCjNDIlqrFdKUgSeN9wV-OzQ/featured
多目标最小二乘
假设我们正在寻找一个使多个目标/成本函数变小的解决方案。这个问题被称为多目标优化问题。如果所有的目标函数都是最小二乘问题的形式,那么这个问题就叫做多目标最小二乘问题。
问题定式化
假设我们有 K 个最小二乘目标函数,我们的目标是找到一个使它们都变小的 x。
图 1:多目标最小二乘问题公式化
其中每个 Aᵢ是 mᵢ×n 矩阵,每个 bᵢ是 mᵢ×1 向量。
有许多方法可以解决和制定多目标 LS 问题,但最常用的方法可能是最小化所有目标函数的加权和,其中权重决定每个目标函数的影响或重要性。
图 2:多目标最小二乘问题公式化
其中λ是每个目标函数的权重。这里我介绍两种解决多目标最小二乘问题的方法。
方法一:直接求导 在这种方法中,我们取 Jₜₒₜ关于 x 的导数,并设为零。
图 3:使用直接微分的多目标最小二乘解
虽然这种方法看起来足够简单,但是第二种方法更常见,并且提供了更好的直觉。
方法 1:堆叠矩阵 这是解决多目标 LS 问题的更好方法,因为它利用了 OLS 问题的解决方案,并将问题直接建模为 OLS 问题。
我们首先构建一个新的矩阵 A 和 B,然后使用我们在图 2 中推导出的公式将问题表述为一个简单的 OLS 问题,如下所示。
图 4:使用堆叠矩阵的多目标 LS 解决方案
这种方法仅在堆叠的 A 具有类似于 OLS 的线性独立列的情况下有效,其中它要求矩阵 A 具有线性独立的列(高和左可逆矩阵)。
当堆叠矩阵具有线性独立的列时
如前所述,要使用堆叠矩阵方法,我们需要确保堆叠矩阵是左可逆的或具有线性独立的列,这意味着:
图 5:线性无关列的条件
- 如果矩阵 A₁、A₂、.。。,Aₖ具有线性独立的列,那么堆叠矩阵将具有线性独立的列。
- 然而,堆叠矩阵可以具有线性独立的列,即使所有矩阵 A₁、A₂、.。。,Aₖ具有线性相关的列,并且这在满足以下条件时发生:
假设 A₁是 m₁x n,A₂是 m₂ x n,Aₖ是 mₖx n,则如果每个 m_i 小于或等于 n,但是它们的和大于或等于 n,则堆叠矩阵仍然是高的,并且可以是左可逆矩阵(线性独立的列)。从数学上来说,这意味着:
图 6:线性无关列的条件
吉洪诺夫正则化
假设你正试图解决一个最小二乘问题:
- 矩阵 A 没有线性无关的列。
- 或者我们希望最小化||Ax — b||使得||x||很小(x 的范数很小)。
表述这个问题的一种方法如下:
图 7:正则化最小二乘法
在图 7 中,λ是一个正权重,决定了第二个目标函数相对于第一个目标函数的重要性。如果λ是零,那么我们回到 OLS。如果λ很小,那么我们在第一个目标函数上放置更多的权重。这是通过将主要目标函数的权重归一化为 1 并让λ表示相对权重来公式化多目标问题的常见方式。
为了求解上述方程,我们可以使用方法 1 或方法 2,但为了演示堆叠矩阵方法,我们将使用第二种方法。
图 8:使用堆叠矩阵正则化最小二乘法
在解决图 8 中的上述问题之前,证明堆叠矩阵 A 具有线性独立的列是很重要的。有两种方法可以证明这一点:
- 单位矩阵具有线性无关的列,因此无论 A 是否具有依赖列,堆叠矩阵都具有线性无关的列。
- 按照标准程序证明色谱柱的线性独立性:
图 9:证明堆叠矩阵有线性无关的列
既然堆叠矩阵具有线性独立的列,那么解可以容易地确定如下:
图 10:正则化最小二乘解
想了解更多关于多目标最小二乘法的知识,请参考我的 YouTube 频道。
接下来是什么:
请务必阅读第 3 部分关于约束最小二乘法的文章。
[## 最小二乘估计的综合研究(三)
towardsdatascience.com](/comprehensive-study-of-least-square-estimation-part-3-9ebefbbe8634)
结论
在本文中,我讨论多目标最小二乘问题,在下一部分(第 3 部分)我将讨论约束最小二乘问题。
如果你觉得这篇文章或上一篇文章的任何部分很复杂,请参考我的 YouTube 频道,那里有一系列关于数值线性代数和优化的视频,不需要矩阵代数或优化的先验知识。
最小二乘估计的综合研究(三)
普通、约束、多目标和非线性最小二乘法
威尔·斯图尔特在 Unsplash 上拍摄的照片
这是“最小二乘估计的综合研究”系列文章的第三部分。在前两部分,我讨论了普通最小二乘和多目标最小二乘问题。如果您尚未阅读前两部分,您可以在此查看:
在本文中,我将讨论在机器学习、控制、信号处理和统计中经常出现的约束最小二乘问题。
和以前一样,我想鼓励你看看我的 YouTube 频道上关于数值线性代数和最优化(我有多个关于最小二乘法的视频)、随机过程和参数估计技术的完整系列视频。
https://www.youtube.com/channel/UCjNDIlqrFdKUgSeN9wV-OzQ
约束最小二乘法
约束最小二乘问题试图寻找线性约束最小二乘问题的解。问题的一般形式如下:
图 1:约束最小二乘法
在图 1 中,||Ax-b||称为目标函数,Cx = d 是线性约束集(与 C 的行数一样多)。a 是 m×n,C 是 p×n 矩阵。向量 x、b 和 d 分别是 n×1、m×1 和 p×1。线性约束可以写成如下的 p 个线性方程:
图 2:线性约束
我们称一个向量 x 为最优向量,如果它使目标函数最小,并且满足约束条件。
约束最小二乘问题也可以表述为多目标最小二乘问题,如下所示:
图 3:作为多目标 LS 的约束 LS
上述等式背后的逻辑如下:如果λ非常大,并且我们的目标是最小化两个目标函数的加权和,其中一个目标函数由λ加权。然后我们需要确定乘以λ的东西实际上是零。因此,Cx-d 的范数应该为零,因此 Cx = d。
最优性条件(拉格朗日乘数)
拉格朗日乘子是一种众所周知的解决约束优化问题的强大算法。在本文中,我们使用拉格朗日乘子法来驱动约束最小二乘问题的最优性条件。
假设我们的目标是使用拉格朗日乘数法解决图 1 中给出的一个问题。
- 首先,按如下方式构造拉格朗日函数:
图 4:图 1 的拉格朗日函数
其中 z 是 p×1 个拉格朗日乘数的向量。
- 将 L(x,z)相对于 x 和 z(原始变量和拉格朗日乘数)求微分,并将其设置为零。
图 5:最优性条件
- 最后,将所有内容以更紧凑的形式放在一起,得到了众所周知的约束最小二乘的最优性条件:
图 6:约束 LS 的最优性条件
最优性条件通常被称为 **KKT 条件。**图 6 左侧的矩阵称为 KKT 矩阵。
约束最小二乘解
为了找到最佳 x,我们倾向于求解图 6 中的矩阵向量方程。因此我们需要找到 KKT 矩阵可逆的条件。我们来看看维数:A 是 m x n,C 是 p x n 个矩阵,d 是 p x 1,b 是 m x 1 个向量。因此 KKT 矩阵是一个正方形(p + n) x (p + n)矩阵。为了找到可逆性的条件,我们对平凡的零空间或线性无关的列施加条件。
图 7
将图 7 中顶部的等式乘以 x 转置,并使用底部的等式得出以下结果:
图 8:KKT 矩阵可逆的条件
将图 7 和图 8 中的等式放在一起,我们得出 KKT 矩阵可逆的以下两个条件:
图 9:KKT 矩阵可逆的条件
因此,KKT 矩阵可逆的条件是 A 和 C 的堆叠矩阵应该具有线性独立的列,C 应该具有线性独立的行(请参考 YouTube 视频和关于矩阵和最小二乘法的讲座,以完整掌握这些概念)。
- 如果满足上述条件,则可以找到如下解决方案:
图 10:受限 LS 的解决方案
结论
在本文中,我讨论了约束最小二乘问题。在前两部分中(我讨论了普通最小二乘法和多目标最小二乘法问题,您可以在本文开头找到这些文章的链接)。
在下一部分,我将讨论非线性最小二乘问题。请务必订阅我的 YouTube 频道,获取更多视频和更详细的解释。
压缩无监督的快速文本模型
如何将单词嵌入模型减少 300 倍,同时在下游 NLP 任务上具有几乎相同的性能
FastText 是一种将单词编码为数字向量的方法,由脸书于 2016 年开发。预训练的快速文本嵌入有助于解决文本分类或命名实体识别等问题,并且比 BERT 等深度神经网络更快、更易于维护。然而,典型的快速文本模型是非常巨大的:例如,脸书的英语模型,解压缩后占据了 7GB 的磁盘空间。
在这篇文章中,我展示了 Python 包 compress-fasttext ,它可以将这个模型压缩到 21MB (x300!)在准确性上只有轻微的损失。这使得 fastText 在磁盘或内存有限的环境中更有用。
作者图片:利用 smolness 迷因制作 fastText(由迷因库生成)
在本文的第一部分,我展示了如何使用压缩的 fastText 模型。在第二部分,我解释了 fastText 及其压缩背后的一些数学原理。
怎么用?
使用现有模型
简单用pip install compress-fasttext
就可以安装包了。它基于 fastText 的 Gensim 实现,具有相同的接口。模型可以直接从 web 加载到 Python 中:
import compress_fasttext
small_model = compress_fasttext.models.CompressedFastTextKeyedVectors.load(
'https://github.com/avidale/compress-fasttext/releases/download/v0.0.4/cc.en.300.compressed.bin')
您可以将这个模型视为一个字典,它将任何单词映射到它的 300 维向量表示(也称为嵌入):
print(small_model['hello'])
# [ 1.847366e-01 6.326839e-03 4.439018e-03 ... -2.884310e-02]
# a 300-dimensional numpy array
词义相近的词往往有相似的嵌入。因为嵌入是向量,它们的相似性可以用余弦度量来评估。对于相关的单词(例如“猫”和“狗”),余弦相似度接近 1,而对于不相关的单词,余弦相似度接近 0:
def cosine_sim(x, y):
return sum(x * y) / (sum(x**2) * sum(y**2)) ** 0.5print(cosine_sim(small_model['cat'], small_model['cat']))
# 1.0print(cosine_sim(small_model['cat'], small_model['dog']))
# 0.6768642734684225print(cosine_sim(small_model['cat'], small_model['car']))
# 0.18485135055040858
实际上,你可以使用余弦相似度来查找一个单词的最近邻。例如,我们的压缩 fastText 模型知道 Python 是一种编程语言,并认为它类似于 PHP 和 Java。
print(small_model.most_similar('Python'))
# [('PHP', 0.5253), ('.NET', 0.5027), ('Java', 0.4897), ... ]
在实际应用中,您通常将快速文本嵌入提供给其他模型。例如,您可以在 fastText 上训练一个分类器来区分可食用和不可食用的东西:
import numpy as np
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.base import BaseEstimator, TransformerMixinclass FastTextTransformer(BaseEstimator, TransformerMixin):
""" Convert texts into their mean fastText vectors """
def __init__(self, model):
self.model = model def fit(self, X, y=None):
return self def transform(self, X):
return np.stack([
np.mean([self.model[w] for w in text.split()], 0)
for text in X
])
classifier = make_pipeline(
FastTextTransformer(model=small_model),
LogisticRegression()
).fit(
['banana', 'soup', 'burger', 'car', 'tree', 'city'],
[1, 1, 1, 0, 0, 0]
)classifier.predict(['jet', 'cake'])
# array([0, 1])
有什么型号
一些英语和俄语的模型可以从发布页面下载。对于英语,建议使用25MB 型号,尺寸和精度平衡良好。
作者图片:https://github . com/avidale/compress-fast text/releases/tag/gensim-4-draft截图。
如果你需要其他语言,你可以看看 Liebl Bernhard 的集合,它包含了 101 种语言的压缩快速文本模型。
压缩模型
如果您想要创建自己的压缩模型,您需要安装带有一些额外依赖项的库:
pip install compress-fasttext[full]
首先,您需要加载您将要压缩的模型。如果模型已经使用脸书包进行了训练,则按如下方式加载它:
from gensim.models.fasttext import load_facebook_model
big_model = load_facebook_model('path-to-original-model').wv
否则,如果模型是 Gensim 格式的,则将其加载为
import gensim
big_model = gensim.models.fasttext.FastTextKeyedVectors.load('path-to-original-model')
现在,您可以用三行代码压缩模型:
import compress_fasttext
small_model = compress_fasttext.prune_ft_freq(big_model, pq=True)
small_model.save('path-to-new-model')
如果您愿意,可以使用额外的参数来控制模型的大小:
small_model = compress_fasttext.prune_ft_freq(
big_model,
new_vocab_size=20_000, # number of words
new_ngrams_size=100_000, # number of character ngrams
pq=True, # use product quantization
qdim=100, # dimensionality of quantization
)
通过使用较小的词汇大小和维数,您创建了一个较小的模型,但相对于原始模型降低了其准确性。
它是如何工作的?
相关著作
最初的 fastText 库确实支持模型压缩(甚至有一篇关于它的论文),但是只针对在特定分类任务上训练的监督模型。另一方面, compress-fastText 用于无监督模型,提供可用于多项任务的单词向量。我的作品部分基于 Andrey Vasnetsov 2019 年的文章,部分基于俄罗斯 navec 图书馆。它最初是在我的俄语帖子中描述的。
fastText 可以压缩到什么程度?
FastText 不同于其他单词嵌入方法,因为它将单词的嵌入与字符 n 元语法(即几个连续字符的序列)的嵌入相结合。单词和 n-grams 的嵌入被平均在一起。如果单词不在词汇表中,则它只由 n-grams 组成,这使得 fastText 可以顺利地处理拼写错误的单词、新词和具有丰富词法的语言。
以下伪代码演示了计算过程:
def embed(word, model):
if word in model.vocab:
result = model.vectors_vocab[word]
else:
result = zeros()
n = 1
for ngram in get_ngrams(word, model.min_n, model.max_n):
result += model.vectors_ngrams[hash(ngram)]
n += 1
return result / n
正如你所看到的,所有的信息都来自两个矩阵,vectors_vocab
和vectors_ngrams
,这些矩阵占据了空间。大型矩阵的大小可以通过几种方式来减小:
- 删除矩阵中的大多数行,只保留最常用的单词和 n-gram;
- 存储精度较低的矩阵(
float16
代替float32
); - 将矩阵分成小块,对它们进行聚类,并存储相应聚类的 id,而不是每个块。这叫产品量化;
- 将矩阵因式分解为两个较小矩阵的乘积(不推荐,因为精度低)。
库 compress-fasttext 支持全部四种压缩方式,建议结合前三种。这就是方法prune_ft_freq
实际做的事情。
压缩的型号够好吗?
为了确认压缩后模型仍然保留有用的信息,我们可以使用工具 SentEval 对它们进行评估。该工具包括 17 个下游任务,如短文本分类、文本间语义相似性评估和自然语言推理,以及 10 个诊断任务。对于每项任务,要么直接使用嵌入,要么在顶部使用小型线性模型。我修改了 bow.py 示例以使用 fastText,并使用完整的 7GB 英文版本和其 25MB 压缩版本来执行它。下表显示了两种模型在所有任务中的表现:
作者图片:SentEval 上的模型评估
平均而言,小型号的性能分数是全型号性能的 0.9579,而小型号几乎是全型号的 300 倍。这证实了如果由于某种原因不希望模型太大,那么压缩 fastText 模型并不是一个坏主意。
结论
FastText 是计算有意义的单词嵌入的一种很好的方法,但是典型的 fastText 模型的大小限制了它在移动设备或适度的免费主机上的使用。在 compress-fastText 中收集的方法允许将模型大小减少数百倍,而不会显著影响下游性能。我发布了一个包和压缩模型,可以用来高效地解决各种 NLP 问题。
在未来,我计划发布更多的微型模型,例如一个用于英语和俄语的 45MB BERT 模型。订阅,敬请关注!
这篇文章是由大卫·戴尔(https://daviddale.ru/en)写的,他是 NLP 的研究科学家和聊天机器人的开发者。
如果你在科学论文中提到这篇文章(或文章包),请注明出处:
@misc{dale_compress_fasttext,
author = "Dale, David",
title = "Compressing unsupervised fastText models",
editor = "towardsdatascience.com",
url = "[https://towardsdatascience.com/eb212e9919ca](/eb212e9919ca)",
month = {December},
year = {2021},
note = {[Online; posted 12-December-2021]},
}
ImageNet 数据集中的压缩
理解大数据
深度学习最受欢迎的基准测试的压缩设置
弗兰肯斯坦的数据集怪物?请继续阅读,寻找答案。图片作者。
我最近的一项任务是让更多的人思考有损压缩如何影响他们的深度学习模型[1]。在这个过程中,我花了很多时间使用 ImageNet [2],它完全由 JPEG 文件组成,我开始注意到一些特殊的压缩设置。为了了解这些奇怪设置的系统性,我决定调查整个数据集的压缩设置。在这篇文章中,我报告了我所看到的,包括为什么我认为其中一些设置很奇怪,并展示了我为每个相关的压缩设置计算的统计数据。最后,我展示了通过绘制这些压缩设置的 2D 投影,实际上可以图形化地看到在 ImageNet 的创建过程中涉及到几个不同的来源。
方法学
为了检查图像,我使用了来自 torchjpeg 的read_coefficients
函数。这个函数直接从 JPEG 文件中读取 DCT 系数,不需要解码,允许我检查低层次的细节,比如色度二次采样和量化。这个过程揭示了训练集中的一个图像实际上根本不是 JPEG。这是一个 PNG,有人将其重命名为. JPEG 扩展名。处理训练集总共需要大约 4.5 小时,处理验证集大约需要 10 分钟。处理后,我绘制了结果。我已经在这个要点中提供了所有的数据收集和绘图代码,以及全尺寸的 PDF 绘图。
请注意,所有图表上的 Y 轴都使用对数刻度。
概观
总的来说,ImageNet 中的大多数图像都是“轻度”压缩的,非常小。最常见的图像大小似乎是 500 乘 500 左右,尽管有一些异常值非常大或比例异常。例如,2592 乘 3888(非常大)的图像,或者 500 乘 33 的图像(比例奇怪)。这一点很重要,因为大多数人在预处理过程中将图像的大小调整为 224 乘 224,怪异的纵横比或大得多/小得多的图像会因重采样而产生伪像。
绝大多数图像是彩色图像,不是色度二次采样,而是以质量 96 进行量化。这表示压缩非常轻微,不会对图像产生明显影响。当然这里也有例外,比如 4:1:1 二次采样(非常差)和一些质量< 10 的图像(也非常差)。对于所有这些参数,训练集和测试集之间似乎也存在一些差异。
如果你对我上面使用的术语不熟悉,不要担心,当我们深入研究结果的细节时,我会解释一切。
那巴布亚新几内亚呢?
在我们继续之前:是的,“n02105855/n02105855_2933。JPEG”实际上是一个 PNG,有人把它重命名为. JPEG。下面是:
“n02105855/n02105855_2933。JPEG”图像鸣谢:ImageNet [2]。
在十六进制编辑器中打开它会非常清楚地显示出来:
大 oof。图片作者。
除了指出它比其他类似大小的图像大一个数量级,没有什么可说的了。
颜色
让我们从简单的开始,多少图像是彩色的,多少是灰度的。
颜色结果。图片作者。
相当简单,几乎所有的图像都是彩色的。关于这一点需要注意的是,JPEG 区分了用完全相同的三个颜色通道存储的灰度图像和用一个通道存储的实际灰度图像,我们在这里计算的是后者:加载时只返回一个通道的图像。
图像尺寸
接下来,让我们看看图像尺寸,这部分有一些最有趣的结果。图像大小很难可视化,用图形绘制它们很难理解(我确实有这些图形以及要点中的绘制代码),所以我在热图上绘制了宽度和高度。因为它们很大,为了清晰起见,我把它们裁剪为 1000x1000(全尺寸热图是要点)。这是训练集:
训练集热图。图片作者。
该图中的每个像素代表一个大小,例如位置(10,70)处的像素显示宽度为 10、高度为 70 的图像的数量。更亮的颜色表示更多的图像。
我们可以看到一些有趣的行为。有一个明显的偏好宽度和高度为 500,以及其他一些间隔。从地图的左上角到右下角有一些有趣的对角线。这是同一张图片,但有些东西被贴上了标签:
培训热图已标注。图片作者。
为了使对角线的解释更容易,我覆盖了一组表示纵横比 1:1(红色)、4:3(绿色)和 3:2(蓝色)的线。
具有纵横比的训练热图。图片作者。
我们可以看到这些线对应着这些长宽比。1:1 和 4:3 有道理,但 3:2 我只从 35mm 胶片上知道,所以坦率地说,我很确定它是如何以如此大的数量出现在这里的。
让我们简单看一下验证集的相同热图:
验证集热图。图片作者。
它不仅明显更稀疏(事实上几乎所有的图像都在 500 宽或 500 高的区域),而且长宽比也更合理。这是值得关注的,因为验证集中的大小分布并不反映训练集。
是时候举一些病理学的例子了。下面是一个来自训练集的小图像示例,其大小仅为 20 x 17:
“n07760859/n07760859_5275。JPEG "图像来源:ImageNet [2]
我不知道这应该是什么,缩放没有帮助,我怀疑你的神经网络也能解决这个问题。
这里有一个疯狂的长宽比,它是 500 乘 32:
“n04228054/n04228054_11471。JPEG "图像来源:ImageNet [2]
我觉得是滑雪板?调整到 224x224 大小后,无论有没有中间裁剪,看起来肯定会很奇怪:
“n04228054/n04228054_11471。JPEG”后居中裁剪和调整大小(左)和只调整大小(右)。图片来源:ImageNet [2]
色度子采样
接下来,我们可以看看色度二次采样设置。我将首先解释什么是色度二次采样,如果你熟悉,可以跳过这一部分,然后我将进入结果。
什么是色度子采样? 人类视觉对颜色的微小变化不如对亮度的微小变化敏感。JPEG 压缩利用这一点,通过对颜色信息进行二次采样来节省额外的空间,换句话说,它存储的颜色信息比亮度信息少。该算法通过将给出的标准 RGB 图像转换到 YCbCr 色彩空间来实现这一点。这个颜色空间将像素的亮度或亮度与颜色或*色度分开。*Y 通道存储亮度,并以全分辨率保存。Cb 和 Cr 通道存储颜色信息(大致分别为蓝色和红色),通常会进行下采样。
当我们谈论如何进行下采样时,我们使用以下符号:“4🅰️b”。该方案指的是 4 列 2 行的像素块。“a”表示第一行中颜色样本的数量,“b”表示第二行中变化的这些样本的数量。因此,如果我们有 4:2:2 二次采样,我们说对于每 4 个亮度样本,第一行只有 2 个色度样本,第二行两者都发生变化。我们将此解释为色度通道的宽度是亮度通道的一半,但高度相同。
这个符号起初很奇怪,但是当你习惯于看它的时候就有意义了,在下一节讨论结果的时候,我会完整地解释这个方案的解释。
结果
色度子采样结果。图片作者。
上面你可以看到色度二次采样的结果。这里有几件有趣的事情需要注意,首先是绝大多数图像使用“4:4:4”,这意味着没有子采样。大约 10%使用“4:2:0 ”,这意味着色度通道是宽度和高度的一半。这是实践中最常见的设置,因为它是许多 JPEG 实现中的默认设置,所以如果您正在部署一个将在真实图像上工作的系统,ImageNet 可能对您来说不够有代表性。
真正突出的一点是“4:1:1”图像的数量。这是一个奇怪的问题(实践中不常见),它表明色度通道的宽度只有亮度通道的 1/4(但高度相同)。这将导致图像出现非常明显的退化。还要注意的是,虽然它们仍然只占总图像的一小部分,但是在验证集中的这些图像比在训练集中的要多一个数量级。
这是一个来自训练集的 4:1:1 图像的示例
“n02445715/n02445715_2673。JPEG”。Image credit ImageNet [2]。
请注意,它看起来很糟糕,颜色很大程度上没有意义。
质量
对 JPEG 的大小和保真度影响最大的设置是其质量设置。这实际上是不标准的,但相当普遍,任何导出 JPEG 文件的人可能都熟悉这个滑块,它要求质量从 0 到 100。较低质量的图像看起来更差,但比高质量的图像小得多。和上一节一样,我将首先解释这个质量实际上是什么,然后我们来看看结果。
什么是 JPEG 质量? 当保存一个 JPEG 文件时,它实际上并不是存储像素,而是存储离散余弦变换(DCT)的系数。DCT 被应用于像素以产生变换系数,然后这些系数通过舍入被量化以节省空间。这种舍入是 JPEG 压缩中信息损失的主要来源,也是节省大部分空间的原因。本质上,质量用于控制舍入的数量,因此高质量意味着舍入越少,文件越大。JPEG 通过计算质量因子的矩阵来控制舍入,质量因子用于按元素划分系数。矩阵中较大的条目意味着除法运算后系数较小,因此需要更多的舍入。舍入允许将系数表示为整数,并创建连续的零和重复元素(较低熵表示)。
因为质量是非标准的,所以它不存储在 JPEG 文件中,并且估计质量并不总是简单的。我使用了torch JPEG . quantization . ijg库来计算每个图像从 0 到 100 的每个质量的量化矩阵,直到我找到一个与文件中存储的量化矩阵完全匹配的量化矩阵。这很耗时,而且只有在图像是用 libjpeg 压缩的情况下才有效,幸运的是它们都是。
结果
质量结果。图片作者。
以上是质量结果。我们可以看到质量为 96 的大峰值,表明绝大多数图像都是以这种质量压缩的。96 非常高,不会明显影响图像。这里要注意的有趣的事情是,在训练集中有一小部分非常低质量(通常小于 10)的图像,这些图像几乎会被压缩完全破坏。还要注意验证集的稀疏性,其中训练集覆盖了各种各样的质量(尽管比例很小),这些通常不在验证集中表示。
这是训练集中质量为 3 的图像的示例。
“n02441942/n02441942_6428。JPEG "图像信用 ImageNet [2]
请注意,它只是有些可识别性,颜色基本上消失了。
探索图像的空间
有一件事立即引起了我的注意,那就是 ImageNet 似乎是由几个非常不同的来源组合而成的,有点像科学怪人的数据集。很明显,有一个源经过精心的压缩设置,将默认设置更改为 96 质量和 4:4:4 子采样,并使用 500 乘 500 的图像。然后还有一些其他的,看起来缺乏那种有意的设计,但是它们以足够的数量出现,以至于它们看起来以某种方式相关联。这可能得到了来自不同来源的单一图像的补充,这可以解释一些异常值。了解数据集历史的人可能会证实这一点。
我们实际上可以形象化地描述这一点。为此,我将压缩设置存储为 4D 向量(色度子采样类型、宽度、高度、质量),并使用 UMAP [8]将它们投影到 2D 中。我在训练集上计算了一下,我只使用了 10%的宽度或高度为 500 的图像,因为这些图像往往会控制信号。这是我给一些非常清晰的集群着色后的样子:
突出显示突出集群的图像空间。图片作者。
检查这些集群给我们一个想法,为什么他们分组在一起。橙色群集仅包含以质量 96 压缩的大小为 500 x375 的图像,并且使用 4:4:4 色度子采样。绿色群集包含 375 乘 500 个图像(橙色群集的转置),其他设置相同。红色群集也是一样的,但是有 333 乘 500 个图像。
接下来,让我们通过色度二次采样方案来给这些点着色
由色度子采样方案着色的图像空间。图片作者。
我们得到了一个很好的,清晰的,分离。黄色点为 4:2:0,紫色点为 4:4:4,其余介于两者之间。一个 4:2:2(蓝色)的群集出现在左侧,回头看上面的原始图,现在我们已经确定了它,这个群集更加突出。
按质量给点着色给出了另一个有趣的结果
按质量着色的图像空间。图片作者。
我们可以看到较低的质量在右下方得到了很好的体现。这是 4:2:0 色度二次采样非常突出的同一区域。
如果我不得不根据这些图来猜测,我会说左手边较小的聚类代表一些初始数据来源。它们有相似的参数,只是尺寸不同,而且数量很少。在它们的左侧是从其他来源收集的图像,但具有相似的参数。右手边代表数据收集方法的巨大变化,代表了非常不同的参数。对此要有所保留,因为像 UMAP 这样的投影技术并不能保证完美地模拟空间,这只是我的推测。
结论
尽管 ImageNet 仍然是最受欢迎的计算机视觉数据集,但它的标签[3,4],它的广泛使用[5]及其潜在的社会影响[6,7]已经逐渐为人所知。我想回应这些担忧,同时提出我自己的一个担忧:数据质量。在我最近的论文[1]中,我展示了压缩设置会对深层网络产生巨大的、有时是意想不到的影响。虽然大多数压缩都是轻量级的,但有足够多的离群值值得关注,并且在训练集和验证集之间存在差异。此外,图像大小变化很大,并且包含极端的纵横比,这可能会在调整图像大小以输入到网络时造成问题。基于这一分析,我强烈建议您在下次考虑使用 ImageNet 时考虑这些问题以及它们是否会影响您的性能。这并不是说 ImageNet 在客观上是一个糟糕的数据集,它多年来为社区提供了很好的服务,在某些情况下,它甚至可能有助于这种变化。但是,随着深度学习发展成为一门更精确的科学,对这些问题采取积极的方法并尽早确定它们对您的特定应用是否重要是很好的。
确认
这篇文章的灵感来自于我的研究[1],该研究得到了美国国防高级研究计划局医学研究中心、美国国防高级研究计划局塞马福尔和脸书·艾的独立资助。我还要感谢我的合著者,UMD 的 Abhinav Shrivastava 教授和 Larry Davis 教授以及脸书 AI 的 Ser-Nam Lim 博士所做的贡献。
参考
- 分析和减轻深度学习中的压缩缺陷。arXiv 预印本 arXiv:2011.08932 (2020)。
- 邓,贾,等,“Imagenet:一个大规模的层次图像数据库”2009 年 IEEE 计算机视觉和模式识别会议。Ieee,2009 年。
- 拜尔、卢卡斯等人,《我们对 ImageNet 的使用结束了吗?."arXiv 预印本 arXiv:2006.07159 (2020)。
- 云,桑都,等。“重新标记图像网络:从单标签到多标签,从全球到本地化标签。”arXiv 预印本 arXiv:2101.05022 (2021)。
- 塔格纳、卢卡斯、于尔根·施密德胡伯和蒂洛·施塔代尔曼。“在 imagenet 上优化 cnn 架构是否足够?."arXiv 预印本 arXiv:2103.09108 (2021)。
- Birhane、Abeba 和 Vinay Uday Prabhu。“大型图像数据集:计算机视觉得不偿失的胜利?."IEEE/CVF 计算机视觉应用冬季会议录。2021.
- 杨,,等,〈图像网络中的人脸混淆技术研究〉。arXiv 预印本 arXiv:2103.06191 (2021)。
- 麦金尼斯、利兰、约翰·希利和詹姆斯·梅尔维尔。"统一流形逼近和投影降维."arXiv 预印本 arXiv:1802.03426 (2018)。
使用 Python 的计算流体动力学:层流建模
结晶器的流体力学
使用有限差分法求解单相层流的 2D 纳维尔-斯托克斯方程,并使用基准 lid 空腔试验验证结果
照片由 Unsplash 上的 Amadej Tauses 拍摄
这是结晶器的流体力学系列文章的第一篇。该系列将涵盖化学反应器中的流体动力学、传热、传质和结晶的建模。为了简化教程,模型构建将分阶段进行,首先创建层流流体解算器(文章 1),添加热量和质量传递组件(文章 2),最后求解种群平衡模型以模拟结晶(文章 3)。
本代码是在两个信息丰富的参考文献的帮助下编写的 Lorena Barba 教授的“Navier Stokes 的 12 个步骤”和 Mark Owkes 教授的“编写第一个 CFD 解算器的指南”。如果您已经熟悉流体力学背后的理论和数学,并且想要浏览代码,您可以跳到本文的第 5 节。
1.介绍
流体流动可以在许多自然现象中观察到,从舒缓的瀑布到恼人的咖啡溅到你的电脑键盘上。你在看完你被毁坏的键盘上的咖啡后的第一个想法可能不是“多有趣啊!”但是从另一方面来说,从悬崖上流下的平静而又动态的水自然会唤起一种奇妙的感觉。我们能理解这些情况下的流体流动吗?我们能预测流体在特定条件下如何运动吗?更重要的是,我们能防止未来的咖啡飞溅吗?
回答这些问题的一种方法是在实验室中用实际的流体进行实验,并使用各种成像仪器研究它们的流动特性。这是实验方法。另一种方法包括编写一组可以描述流体流动的方程,应用一组简化的假设和条件,执行一些数学魔术,并推导出一个控制方程,在输入正确的值后,该方程可以为您提供预测流动动态的能力。这是分析方法。
然而,随着计算能力的增加,出现了第三种方法来回答这些问题——数值方法。虽然描述流体流动的方程组对于任意一组条件都是解析不可解的,但是如果你有一台足够强大的计算机,它们的输出肯定是可以计算的。使用这种方法在计算机上研究流体流动的动力学通常被称为计算流体动力学(CFD)。
2.控制方程
那么,这一组能完整描述一种流体如何流动,它们从何而来的方程组是什么呢?在回答前一个问题之前,我们先讨论后一个问题。
考虑一个空间体积固定的 2D 盒子。这就是我们所说的控制体积。
图 1:控制音量
首先,我们将把质量守恒的原理应用于控制容积中的流体。对于不可压缩的流体(大多数液体),这意味着无论什么流体进入盒子都必须离开它。这在流体力学中被称为连续性方程。
其次,我们将把动量守恒的原理应用到控制体积上。与之前的情况相比,这稍微更抽象和复杂,但最终,这简化为不可压缩的纳维尔-斯托克斯方程。
如果我们能够在应用必要的边界条件后同时求解这些偏微分方程(PDEs ),我们将获得作为时间函数的瞬时速度和压力,从而允许我们预测流体将如何流动。然而,在不应用简化假设的情况下,没有解析方法来求解这些方程(以它们的完整形式)。因此,我们求助于数值技术来求解这些方程。
3.数值方法
有各种不同的数值方法来解决偏微分方程,每一个都有自己的一套警告。最简单的方法是有限差分法,其中使用低阶泰勒级数近似将 PDEs 转换为一组代数方程。下面给出一个例子,说明如何将一阶和二阶导数转换成它们的有限差分近似。
虽然这不是在所有情况下模拟流体流动的最佳方法,但我们将继续使用它,因为它简化了结晶器模拟的其他方面,这是本系列文章的最终目标。对于更严格的数值处理,你可能想使用有限体积或有限元方法。
4.代码的组织
代码被组织成三个不同的文件或脚本。第一个“FlowPy.py”包含使用有限差分法对一般输入集求解 PDEs 的代码。使用作为用户界面的“FlowPy_Input.py”脚本向该脚本提供输入。最后,“FlowPy_Visualizer.py”脚本用于在运行模拟后制作流的动力学动画。
5.模拟代码——flow py
用 Python 编写代码的一个优点是,我们可以利用面向对象编程(OOP)来组织和简化代码。这也将使增加传热和传质扩展变得非常简单。因此,代码被组织成各种类和对这些类的对象进行操作的函数。将第 5 节中的代码保存到名为 FlowPy.py 的文件中
步骤 1:导入所需的模块
需要以下模块— numpy 和 *os。*就是这样!
import numpy as np
import os
步骤 2:构建类
我们从边界条件开始,为问题的特定属性创建类。通过应用某些边界条件来求解偏微分方程,这些边界条件指示了流体在区域边界的行为。例如,流过管道的流体将具有零流体速度的壁,以及具有某一特定流速的入口和出口。
数学上,边界条件可以用两种形式表示——狄利克雷和诺依曼边界。前者指定因变量在边界处的值,而后者指定因变量在边界处的导数的值。
因此,我们创建了一个边界类,它有两个属性——类型和值。
class Boundary:
def __init__(self,boundary_type,boundary_value):
self.DefineBoundary(boundary_type,boundary_value)
def DefineBoundary(self,boundary_type,boundary_value):
self.type=boundary_type
self.value=boundary_value
接下来,由边界包围的区域(如管道内部)使用 2D 网格或栅格表示,在栅格中的盒子中心(压力)或盒子表面(速度)计算因变量的值。这被称为交错网格方法。为了表示网格,我们创建了一个名为 *Space 的类。*方法 CreateMesh 为因变量创建一个给定大小的矩阵,方法 SetDeltas 根据指定的域长度和宽度计算差分长度的值。
class Space:
def __init__(self):
pass
def CreateMesh(self,rowpts,colpts):
#Domain gridpoints
self.rowpts=rowpts
self.colpts=colpts #Velocity matrices
self.u=np.zeros((self.rowpts+2,self.colpts+2))
self.v=np.zeros((self.rowpts+2,self.colpts+2))
self.u_star=np.zeros((self.rowpts+2,self.colpts+2))
self.v_star=np.zeros((self.rowpts+2,self.colpts+2))
self.u_next=np.zeros((self.rowpts+2,self.colpts+2))
self.v_next=np.zeros((self.rowpts+2,self.colpts+2))
self.u_c=np.zeros((self.rowpts,self.colpts))
self.v_c=np.zeros((self.rowpts,self.colpts))) #Pressure matrices
self.p=np.zeros((self.rowpts+2,self.colpts+2))
self.p_c=np.zeros((self.rowpts,self.colpts)) #Set default source term
self.SetSourceTerm()
def SetDeltas(self,breadth,length):
self.dx=length/(self.colpts-1)
self.dy=breadth/(self.rowpts-1) def SetInitialU(self,U):
self.u=U*self.u
def SetInitialV(self,V):
self.v=V*self.v
def SetInitialP(self,P):
self.p=P*self.p def SetSourceTerm(self,S_x=0,S_y=0):
self.S_x=S_x
self.S_y=S_y
最后,我们创建一个类流体来表示流体的属性——比如密度(ρ)和粘度(μ)。
class Fluid:
def __init__(self,rho,mu):
self.SetFluidProperties(rho,mu)
def SetFluidProperties(self,rho,mu):
self.rho=rho
self.mu=mu
步骤 3:编写函数来实现有限差分法
如前一节所述,我们首先编写函数,在 2D 域的左、右、上、下边界实现水平速度( u )、垂直速度( v )和压力( p )的边界条件。该函数将接受空间和边界类的对象,并根据这些对象的属性设置边界条件。例如,如果将类型为 Dirichlet 且值为 0 的边界对象作为左边界对象传递,该函数将在左边界设置该条件。
#Note: The arguments to the function are all objects of our defined classes
#Set boundary conditions for horizontal velocity
def SetUBoundary(space,left,right,top,bottom):
if(left.type=="D"):
space.u[:,0]=left.value
elif(left.type=="N"):
space.u[:,0]=-left.value*space.dx+space.u[:,1]
if(right.type=="D"):
space.u[:,-1]=right.value
elif(right.type=="N"):
space.u[:,-1]=right.value*space.dx+space.u[:,-2]
if(top.type=="D"):
space.u[-1,:]=2*top.value-space.u[-2,:]
elif(top.type=="N"):
space.u[-1,:]=-top.value*space.dy+space.u[-2,:]
if(bottom.type=="D"):
space.u[0,:]=2*bottom.value-space.u[1,:]
elif(bottom.type=="N"):
space.u[0,:]=bottom.value*space.dy+space.u[1,:] #Set boundary conditions for vertical velocity
def SetVBoundary(space,left,right,top,bottom):
if(left.type=="D"):
space.v[:,0]=2*left.value-space.v[:,1]
elif(left.type=="N"):
space.v[:,0]=-left.value*space.dx+space.v[:,1]
if(right.type=="D"):
space.v[:,-1]=2*right.value-space.v[:,-2]
elif(right.type=="N"):
space.v[:,-1]=right.value*space.dx+space.v[:,-2]
if(top.type=="D"):
space.v[-1,:]=top.value
elif(top.type=="N"):
space.v[-1,:]=-top.value*space.dy+space.v[-2,:]
if(bottom.type=="D"):
space.v[0,:]=bottom.value
elif(bottom.type=="N"):
space.v[0,:]=bottom.value*space.dy+space.v[1,:]#Set boundary conditions for pressure
def SetPBoundary(space,left,right,top,bottom):
if(left.type=="D"):
space.p[:,0]=left.value
elif(left.type=="N"):
space.p[:,0]=-left.value*space.dx+space.p[:,1]
if(right.type=="D"):
space.p[1,-1]=right.value
elif(right.type=="N"):
space.p[:,-1]=right.value*space.dx+space.p[:,-2]
if(top.type=="D"):
space.p[-1,:]=top.value
elif(top.type=="N"):
space.p[-1,:]=-top.value*space.dy+space.p[-2,:]
if(bottom.type=="D"):
space.p[0,:]=bottom.value
elif(bottom.type=="N"):
space.p[0,:]=bottom.value*space.dy+space.p[1,:]
在我们写有限差分函数之前,我们需要确定一个时间步长来推进模拟。为了确保有限差分法的收敛性,Courant-Friedrichs-Lewy(CFL)标准提供了时间步长的上限,该上限被设置为使用 SetTimeStep 函数进行模拟的时间步长。遵循 CFL 准则可确保在一个时间步长内传播的信息不会超过两个网格元素之间的距离。
def SetTimeStep(CFL,space,fluid):
with np.errstate(divide='ignore'):
dt=CFL/np.sum([np.amax(space.u)/space.dx,\
np.amax(space.v)/space.dy])
#Escape condition if dt is infinity due to zero velocity initially
if np.isinf(dt):
dt=CFL*(space.dx+space.dy)
space.dt=dt
确定时间步长后,我们现在准备实施有限差分方案。为了同时求解连续性方程和纳维尔-斯托克斯方程,我们使用了预测-校正方案,包括以下步骤(更多信息请参考本指南):
- 从无压力影响的初始速度计算星形速度( u和 v*)* 。
- 使用星形速度迭代求解压力泊松方程。
- 根据压力和星形速度计算下一个时间步长的速度。
我们定义了三个不同的函数来执行这三个步骤中的每一步。
此外,定义了一个便利函数,将边界内的速度和压力保存到新变量中,然后可以将这些变量写入文本文件。
def SetCentrePUV(space):
space.p_c=space.p[1:-1,1:-1]
space.u_c=space.u[1:-1,1:-1]
space.v_c=space.v[1:-1,1:-1]
最后,我们定义了两个用于 I/O 目的的函数— MakeResultDirectory 创建一个名为“Result”的目录来存储文本文件,以及 WriteToFile 每隔几次迭代(使用 interval 参数指定)将变量的值保存到一个文本文件中。
def MakeResultDirectory(wipe=False):
#Get path to the Result directory
cwdir=os.getcwd()
dir_path=os.path.join(cwdir,"Result") #If directory does not exist, make it
if not os.path.isdir(dir_path):
os.makedirs(dir_path,exist_ok=True)
else:
#If wipe is True, remove files present in the directory
if wipe:
os.chdir(dir_path)
filelist=os.listdir()
for file in filelist:
os.remove(file)
os.chdir(cwdir)
def WriteToFile(space,iteration,interval):
if(iteration%interval==0):
dir_path=os.path.join(os.getcwd(),"Result")
filename="PUV{0}.txt".format(iteration)
path=os.path.join(dir_path,filename)
with open(path,"w") as f:
for i in range(space.rowpts):
for j in range(space.colpts):
f.write("{}\t{}\t{}\n".format(space.p_c[i,j],space.u_c[i,j],space.v_c[i,j]))
模拟代码部分到此结束。接下来,我们需要编写一个用户界面——即一个脚本,用户可以在其中提供各种输入,如边界条件、初始条件和流体属性。该脚本还将调用 FlowPy.py 文件中定义的函数,并运行模拟。
6.模拟用户界面— FlowPy_Input
这一节比前一节短——大部分繁重的工作已经完成,我们现在只需要利用所有已定义的类和函数来运行模拟!将第 6 节中的代码保存到名为 FlowPy_Input.py 的文件中
首先,我们导入所需的模块,这包括了我们在 FlowPy.py 中定义的所有东西
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from FlowPy import *
例如,在本教程中输入了与盖腔试验(雷诺数=400)相关的输入。在这个试验中,流体被保存在一个有三面刚性墙的 2D 盒中,第四面墙(或盖子)以匀速移动。一旦达到稳定状态,就可以将发展流场的统计数据与基准进行比较。
图 2:盖腔问题设置
我们首先指定描述域的输入变量,然后用这些变量创建一个空间对象。
#### SPATIAL AND TEMPORAL INPUTS
length=4 #Length of computational domain in the x-direction
breadth=4 #Breadth of computational domain in the y-direction
colpts=257 #Number of grid points in the x-direction #KEEP ODD
rowpts=257 #Number of grid points in the y-direction #KEEP ODD#Create an object of the class Space called cavity
cavity=Space()
cavity.CreateMesh(rowpts,colpts)
cavity.SetDeltas(breadth,length)
接下来,指定流体的密度和粘度,并创建一个类流体的对象。
#### FLUID PROPERTIES
rho=1 #Density of fluid
mu=0.01 #Viscosity of fluid#Create an object of the class Fluid called water
water=Fluid(rho,mu)
第三,我们创建边界对象来设置速度和压力边界条件。
#### BOUNDARY SPECIFICATIONS
u_in=1 #Lid velocity
v_wall=0 #Velocity of fluid at the walls
p_out=0 #Gauge pressure at the boundaries#Create objects of the class Boundary having either Dirichlet ("D") or Neumann ("N") type boundaries
flow=Boundary("D",u_in)
noslip=Boundary("D",v_wall)
zeroflux=Boundary("N",0)
pressureatm=Boundary("D",p_out)
最后,指定模拟参数和标志来控制模拟时间、保存文本文件等等。
#### SIMULATION PARAMETERS
time=150 #Simulation time
CFL_number=0.8 #Reduce this if solution diverges
file_flag=1 #Keep 1 to print results to file
interval=100 #Record values in file per interval number of iterations
现在,我们可以编写循环来运行模拟。一般程序如下。在模拟时间完成之前,在每次迭代中执行以下操作:
- 根据 CFL 数标准设置时间步长
- 设置边界条件
- 计算星形速度
- 求解压力泊松方程得到压力场
- 确定下一时间步的速度
- 将结果写入文件(如果文件标志为 1)
- 将时间提前一个等于时间步长的值
#### RUN SIMULATION# Print general simulation information
print("######## Beginning FlowPy Simulation ########")
print("#############################################")
print("# Simulation time: {0:.2f}".format(time))
print("# Mesh: {0} x {1}".format(colpts,rowpts))
print("# Re/u: {0:.2f}\tRe/v:{1:.2f}".format(rho*length/mu,rho*breadth/mu))
print("# Save outputs to text file: {0}".format(bool(file_flag)))## Initialization
# Make directory to store results
MakeResultDirectory(wipe=True)# Initialize counters
t=0
i=0## Run
while(t<time):
#Print time left
sys.stdout.write("\rSimulation time left: {0:.2f}".format(time-t))
sys.stdout.flush() #Set the time-step
SetTimeStep(CFL_number,cavity,water)
timestep=cavity.dt
#Set boundary conditions
SetUBoundary(cavity,noslip,noslip,flow,noslip)
SetVBoundary(cavity,noslip,noslip,noslip,noslip)
SetPBoundary(cavity,zeroflux,zeroflux,pressureatm,zeroflux) #Calculate starred velocities
GetStarredVelocities(cavity,water)
#Solve the pressure Poisson equation
SolvePressurePoisson(cavity,water,zeroflux,zeroflux,\
pressureatm,zeroflux) #Solve the momentum equation
SolveMomentumEquation(cavity,water) #Save variables and write to file
SetCentrePUV(cavity)
if(file_flag==1):
WriteToFile(cavity,i,interval) #Advance time-step and counter
t+=timestep
i+=1
至此,我们已经准备好为任何广义输入集运行模拟。这个难题只剩下一个部分了——可视化工具。
7.可视化工具— FlowPy_Visualizer
运行模拟后生成的文本文件包含原始数字,这些数字本身可能无法提供流体流动的物理图像。然而,一个简单的动画等高线图可以用来结合三个变量——水平速度、垂直速度和压力——并以直观的方式显示它们的时间演变。将此代码保存在一个名为“FlowPy_Visualizer.py”的单独文件中。
和前面一样,首先导入所需的模块。特别是,我们将需要 matplotlib.animation 模块来录制动画。
import numpy as np
import sys
import os
import matplotlib.pyplot as plt
import matplotlib.animation as animation
为了确保创建适当大小的阵列,需要输入与计算域相关的模拟输入。
#### Simulation inputs
rowpts=257
colpts=257
length=4
breadth=4
在移至出图之前,必须将模拟过程中保存的文本文件作为数组导入。为此,我们首先遍历结果目录,存储所有文件名,并确定文件总数以及打印间隔。
#Go to the Result directory
cwdir=os.getcwd()
dir_path=os.path.join(cwdir,"Result")
os.chdir(dir_path)#Go through files in the directory and store filenames
filenames=[]
iterations=[]
for root,dirs,files in os.walk(dir_path):
for datafile in files:
if "PUV" in datafile:
filenames.append(datafile)
no_ext_file=datafile.replace(".txt","").strip()
iter_no=int(no_ext_file.split("V")[-1])
iterations.append(iter_no)#Discern the final iteration and interval
initial_iter=np.amin(iterations)
final_iter=np.amax(iterations)
inter=(final_iter - initial_iter)/(len(iterations)-1)
number_of_frames=len(iterations)
sorted_iterations=np.sort(iterations)
接下来,我们定义一个函数,它可以使用 numpy 中的 loadtxt 函数将文本文件——基于提供的迭代——导入到一个数组中。
def read_datafile(iteration):
#Set filename and path according to given iteration
filename="PUV{0}.txt".format(iteration)
filepath=os.path.join(dir_path,filename) #Load text file as numpy array
arr=np.loadtxt(filepath,delimiter="\t")
rows,cols=arr.shape #Define empty arrays for pressure and velocities
p_p=np.zeros((rowpts,colpts))
u_p=np.zeros((rowpts,colpts))
v_p=np.zeros((rowpts,colpts)) #Organize imported array into variables
p_arr=arr[:,0]
u_arr=arr[:,1]
v_arr=arr[:,2]
#Reshape 1D data into 2D
p_p=p_arr.reshape((rowpts,colpts))
u_p=u_arr.reshape((rowpts,colpts))
v_p=v_arr.reshape((rowpts,colpts))
return p_p,u_p,v_p
是时候开始制作剧情了!在制作图形动画之前,制作一个初始图(用于第 0 次迭代)是一个好主意,这样图形的尺寸、轴、颜色条等都可以固定。此外,用更少的网格点(在本文中是 10 个)绘制流图是一个好主意,这样可以区分箭头。
#Create mesh for X and Y inputs to the figure
x=np.linspace(0,length,colpts)
y=np.linspace(0,breadth,rowpts)
[X,Y]=np.meshgrid(x,y)#Determine indexing for stream plot (10 points only)
index_cut_x=int(colpts/10)
index_cut_y=int(rowpts/10)#Create blank figure
fig=plt.figure(figsize=(16,8))
ax=plt.axes(xlim=(0,length),ylim=(0,breadth))#Create initial contour and stream plot as well as color bar
p_p,u_p,v_p=read_datafile(0)
ax.set_xlim([0,length])
ax.set_ylim([0,breadth])
ax.set_xlabel("$x$",fontsize=12)
ax.set_ylabel("$y$",fontsize=12)
ax.set_title("Frame No: 0")
cont=ax.contourf(X,Y,p_p)
stream=ax.streamplot(X[::index_cut_y,::index_cut_x],Y[::index_cut_y,::index_cut_x],u_p[::index_cut_y,::index_cut_x],v_p[::index_cut_y,::index_cut_x],color="k")
fig.colorbar(cont)
fig.tight_layout()
为了进一步制作这个情节的动画,matplotlib.animation 中的 FuncAnimation 函数将派上用场。它所需要的只是一个函数,可以为迭代提供的值创建一个图。我们定义这样一个函数叫做 animate 。
def animate(i): #Print frames left to be added to the animation
sys.stdout.write("\rFrames remaining: {0:03d}".format(len(sorted_iterations)-i))
sys.stdout.flush() #Get iterations in a sequential manner through sorted_iterations
iteration=sorted_iterations[i] #Use the read_datafile function to get pressure and velocities
p_p,u_p,v_p=read_datafile(iteration) #Clear previous plot and make contour and stream plots for current iteration
ax.clear()
ax.set_xlim([0,length])
ax.set_ylim([0,breadth])
ax.set_xlabel("$x$",fontsize=12)
ax.set_ylabel("$y$",fontsize=12)
ax.set_title("Frame No: {0}".format(i))
cont=ax.contourf(X,Y,p_p)
stream=ax.streamplot(X[::index_cut_y,::index_cut_x],\
Y[::index_cut_y,::index_cut_x],\
u_p[::index_cut_y,::index_cut_x],\
v_p[::index_cut_y,::index_cut_x],\
color="k")
return cont,stream
最后,是时候保存动画并观看一些流体在您的计算机上跳舞了!
print("######## Making FlowPy Animation ########")
print("#########################################")
anim=animation.FuncAnimation(fig,animate,frames=number_of_frames,interval=50,blit=False)
movie_path=os.path.join(dir_path,"FluidFlowAnimation.mp4")
anim.save(r"{0}".format(movie_path))
print("\nAnimation saved as FluidFlowAnimation.mp4 in Result")
首先运行 FlowPy_Input.py 生成模拟数据,然后运行 FlowPy_Visualizer.py 保存模拟视频。
8.结果
下图显示了 Re=400 时盖子空腔基准的动画轮廓和流图。它显示了随着模拟的进行,在中心形成涡流,并最终过渡到稳定状态。
图 3:盖子空腔基准的动画轮廓和流图
还对稳定流的统计数据与 Ghia 等人(1982) 的结果进行了定量比较。具体来说,沿穿过空腔中心的垂直线的水平速度与本文的模拟结果进行了比较。结果显示了合理的一致性。偏差可归因于有限差分格式的较低精度和较小的网格尺寸。
,图 4:基准 1。蓝线代表模拟结果,红点代表 Ghia 等人(1982 年)的结果
图 5:基准 2。蓝线代表模拟结果,红点代表 Ghia 等人(1982 年)的结果
9.结束语
虽然本教程仅包括盖腔测试的模拟,但您可以尝试调整输入和边界条件,以模拟各种不同的单相流问题,如管道中的 Poiseuille 流。
随着 FlowPy 的创建和验证,我们可以进入结晶器建模的下一步——向求解器添加热量和质量传递,这将在下一篇文章中介绍。
FlowPy 代码可在 GitHub 上获得。如有任何问题、建议或任何关于我博客的讨论,请随时通过电子邮件或推特联系我。如果你想对盖腔测试结果做一个定量的基准,给我发一封邮件,我可以分享一个 Jupyter 笔记本的代码。
重要参考:
- 巴尔巴,洛杉矶,&福塞斯,G. F. (2018)。CFD Python:纳维尔-斯托克斯方程的 12 个步骤。开源教育杂志, 2 (16),21。
- Owkes,M. (2020),编写第一个 CFD 求解器的指南
- 吉亚,英国 N. G .,吉亚,k . n .&申正堂(1982)。采用纳维尔-斯托克斯方程和多重网格法的不可压缩流的高精度解计算物理杂志, 48 (3),387–411。
PyTorch 和 TensorFlow 中的计算图
理解大数据
我在之前的文章中解释过深度学习环境中的反向传播算法。这是那篇文章的继续,我建议您阅读那篇文章,以确保您从这篇文章中获得最大的收益。
我将在 PyTorch 和 TensorFlow 中介绍计算图形。这就是允许这些框架为你的神经网络计算梯度的魔力。我将从一些计算图类型的介绍开始,然后是框架的具体细节。
计算图形类型[1]
所有深度学习框架都依赖于创建计算图来计算梯度下降优化所需的梯度值。通常,您必须构建正向传播图,框架会为您处理反向差异。
但是在开始 PyTorch 中的计算图之前,我想讨论一下静态和动态计算图。
静态计算图:
这些通常包括如下两个阶段。
- 阶段 1:定义一个架构(可能有一些原始的流程控制,比如循环和条件)
- 第二阶段:通过它运行大量数据来训练模型和/或进行预测
静态图的优势之一是它允许强大的离线优化/图表调度。这意味着这些通常比动态图更快(在每个用例中差别可能并不明显,这取决于我们的图)。缺点是处理结构化甚至可变大小的数据很难看。
动态计算图:
当执行正向计算时,该图被隐式定义(例如,使用运算符重载)。
动态图的优点是更加灵活。该库侵入性较小,允许交叉构建和评估图形。正向计算是用你最喜欢的编程语言编写的,包括所有的特性和算法。不利的一面是几乎没有时间进行图形优化,如果图形没有变化,那么努力可能会白费。动态图形易于调试。发现代码中的问题要容易得多,因为它允许一行一行地执行代码,并且你可以访问所有的变量。如果你想将深度学习用于行业中的任何真实目的,这绝对是一个非常重要的功能。
PyTorch 使用动态计算图。Tensorflow 允许创建优化的静态图,也具有类似于动态图的热切执行。它是一个命令式的编程环境,可以立即计算操作,而不需要构建图形,操作返回具体的值,而不是构建一个计算图形供以后运行。
现在让我们看看 PyTorch 中的计算图。
PyTorch [7]中的计算图
PyTorch 的核心提供了两个特性:
- n 维张量,类似于 NumPy,但可以在 GPU 上运行。
- 用于建立和训练神经网络的自动微分。
深度学习架构及其训练涉及大量矩阵运算。张量只不过是一个 n 维数组。对于来自 Python 背景的人来说,NumPy 应该敲响了警钟。这是一个非常强大和优化的矩阵运算库。然而,出于深度学习的目的,矩阵是巨大的,并且需要巨大的计算能力。
PyTorch 张量是一个 n 维数组。这个框架提供了很多在这些张量上操作的函数。但是为了加速张量的数值计算,PyTorch 允许使用 GPU,这可以提供 50 倍或更高的加速。PyTorch 张量也可以跟踪计算图形和梯度。
在 PyTorch 中,自动签名包提供了自动微分,以自动计算神经网络中的反向传递。你的网络的前向传递定义了计算图;图中的节点是张量,边是从输入张量产生输出张量的函数。通过该图的反向传播给出了梯度。
PyTorch 中的每个张量都有一个标志:required_grad,它允许从梯度计算中细粒度地排除子图,并可以提高效率。如果 x 是一个张量,它的 x.requires_grad=True,那么 x.grad 是另一个张量,它保持 x 相对于某个标量值的梯度。
从上面的例子可以看出,如果一个操作只有一个输入需要梯度,那么它的输出也需要梯度。反之,只有当所有输入都不需要梯度时,输出也不会需要梯度。
引擎盖下的亲笔签名
从概念上讲,autograd 在您执行操作时保留了创建数据的所有操作的图形记录,为您提供了一个有向无环图,其叶是输入张量,根是输出张量。通过从根到叶跟踪该图,可以使用链式法则(反向传播)自动计算梯度。
在内部,autograd 将这个图表示为函数对象的图,可以应用它来计算图的求值结果。当计算向前传递时,自动签名同时执行请求的计算并建立一个表示计算梯度的函数的图形。每个火炬的 grad_fn 属性。张量是该图的入口点)。当正向传递完成时,在反向传递中评估图形以计算梯度。
如前所述,PyTorch 中的计算图形是动态的,因此在每次迭代中都要从头开始重新创建,这正是允许使用任意 Python 控制流语句的原因,这些语句可以在每次迭代中改变图形的整体形状和大小。你不必在开始训练前对所有可能的路径进行编码——你所跑的就是你与众不同的。
每个本原自签名算子都是作用于张量的两个函数。forward 函数根据输入张量计算输出张量。后向函数接收输出张量相对于某一标量的梯度,并计算输入张量相对于同一标量的梯度。
总之,张量和函数是相互联系的,构成了一个非循环图,它编码了计算的完整历史。每个张量都有一个. grad_fn 属性,该属性引用了创建该张量的函数(用户创建的张量除外,因为它们的 grad_fn 是 None)。如果你想计算导数,你可以调用。张量上的 backward()。调用 backwards 函数后,梯度值作为张量存储在 grad 属性中。
这些概念可以用下图表示。
来源:作者[7]
例如,如果你创建两个张量 a 和 b,后面跟着 c = a/b,c 的 grad_fn 将被 DivBackward,这是/运算符的反向函数。如前所述,这些 grad_fn 的集合构成了反向图。前进和后退函数是 torch . autograd . function 的成员。您可以通过定义 torch . autograded . function 的子类来定义自己的 autograded 运算符
is_leaf:按照惯例,所有 requires_grad 为假的张量都是叶张量。对于 requires_grad 为 True 的张量,如果它们是由用户创建的,它们将是叶张量。这意味着它们不是运算的结果,因此 grad_fn 是 None。只有叶张量在调用 backward()时填充了它们的 grad。要为非叶张量填充 grad,可以使用 retain_grad()。
让我们构建帖子的第 1 部分中使用的计算图示例,并使用 PyTorch 计算梯度。
来源:作者
上面的代码在 PyTorch 中构造了计算图形。让我们看看图中节点的一些属性。
来源:作者
叶子没有 grad_fn 但是会有渐变。非叶节点有 grad_fn 但没有梯度。在调用 backward()之前,没有 grad 值。
我们在上一篇文章中从理论上计算的梯度是使用 PyTorch 计算的,如下所示。
来源:作者
backward()调用后节点的属性如下所示。
来源:作者
如您所见,一旦构建了图形,在 PyTorch 中计算梯度就是一件简单的事情。它会帮你区分。本教程的 jupyter 笔记本可以在 https://github.com/msminhas93/ComputationalGraphs找到
这就完成了 PyTorch 中计算图的讨论。在下一节中,让我们看看 TensorFlow 中的计算图。
张量流中的计算图
Tensorflow 使用数据流图根据各个操作之间的依赖关系来表示计算。这导致了一个低级编程模型,在该模型中,定义数据流图,然后创建一个 TensorFlow 会话来跨一组本地和远程设备运行该图的各个部分。
TensorFlow 中数据流或计算图的示例如下所示。
TensorFlow 中的计算图形示例(来源: Tensorflow 图形指南)
在 Tensorflow 中,任何种类的计算都被表示为 tf 的一个实例。图形对象。这些对象由一组 tf 实例组成。张量物体和 tf。操作对象。在张量流中,tf。张量对象作为边,而 tf。操作充当节点,然后添加到 tf 中。图形实例。
在张量流中,一个 tf。Session()对象存储执行计算的上下文。这是一个运行 TensorFlow 操作的类。会话对象封装了执行操作对象和评估张量对象的环境。
现在,让我们用这篇文章的第一部分中的例子在 Tensorflow 中构建计算图。
我们首先创建四个占位符。TensorFlow 占位符是在会话执行期间提供的张量的代理。它需要 Session.run()、Tensor.eval()或 Operation.run()的 feed_dict 参数。
接下来,我们使用张量流操作,即加法、对数和乘法,从定义的占位符构建示例计算图。
一旦构建了图形,下一步就是在会话中运行它。Python 有一个带语句的**,负责打开和关闭会话。在会话范围内,我们运行 tf.gradients 函数来获取我们的示例所需的梯度。输出如下所示。**
TensorFlow 有一个名为 tensorboard 的实用程序,它给你一个带有许多可视化功能的计算图形的图形表示。上一个示例的图表如下所示。
可以看出,该图与我们在示例图片中构建的图相同。Jupyter 笔记本可以在 https://github.com/msminhas93/ComputationalGraphs找到
接下来,让我们看看静态图和急切执行之间的时间比较。
来源:https://www.tensorflow.org/guide/intro_to_graphs
来源:https://www.tensorflow.org/guide/intro_to_graphs
我们可以清楚地看到这里的性能差异。在这个例子中,静态图比动态图快。
至此,我们结束了“反向传播揭秘”系列。
结论
关键要点如下。
- 反向传播用于计算训练深度学习网络的基于梯度下降的优化所需的梯度。
- 计算梯度的解析表达式很简单,但计算量很大。
- 计算图是表示数学表达式的方法,在深度学习模型的情况下,这些就像描述性语言,给出所需计算的功能描述。
- 深度学习框架,如 PyTorch 和 TensorFlow 等。依赖于这些计算图的创建来实现用于梯度计算的已定义网络的反向传播算法。
最后,这里比较一下 PyTorch 和 TensorFlow 中计算图的表示方式。
来源:作者
我希望你通过阅读这篇文章获得一些知识,并喜欢这篇文章。我很乐意在 LinkedIn上联系。
参考
[1]http://www . cs . Cornell . edu/courses/cs 5740/2017 sp/lectures/04-nn-compgraph . pdf
[2]https://py torch . org/tutorials/beginner/examples _ autogradated/TF _ two _ layer _ net . html
[3]https://www.tensorflow.org/api_docs/python/tf/Graph
https://www.tensorflow.org/guide/intro_to_graphs
https://kth.instructure.com/files/1864796/download?[5]download_frd=1
[6]https://JD Hao . github . io/2017/11/12/py torch-computation-graph/
https://pytorch.org/docs/stable/autograd.html
计算思维和人工智能
人工智能起源简史
马库斯·温克勒在 Unsplash 上的照片
计算思维可以被认为是批判性思维或证据推理的延伸。在某种程度上,它将批判性思维和循证推理系统化。这通常涉及逻辑思维和论证,我们指的是经典的、正式的论证,而不是争吵。我们可以说,这种逻辑思维建立在处理问题的三种基本方法之上:特别思维、演绎思维或归纳思维。
因此,思考似乎是人类的核心,也是足够聪明来解决世界问题的核心。因此,人们开始怀疑我们是否能模拟思维和智力。在 17 世纪,莱布尼茨提出了一种新的语言,characteria universal is,这是一种代表人类思想的语言,其中每个字母代表一些概念,然后这些概念可以通过微积分推理器根据一套逻辑规则进行组合和操作,以计算所有的数学和科学知识。最近,艾伦·图灵开始思考机器,后来被称为图灵机的假设机器,可以解决任何可计算的函数,这似乎为最终的各种演算推理器奠定了一些基础。
生物联系
Robina Weermeijer 在 Unsplash 上拍摄的照片
就在这时,神经生理学家沃伦·s·麦卡洛克和逻辑学家沃尔特·h·皮茨出现了。麦卡洛克以每天喝威士忌和吃冰淇淋到凌晨 4 点而闻名,他对以莱布尼茨逻辑演算的方式为人类大脑建立理论基础感兴趣,并使用这个简单的逻辑基础来构建复杂的神经活动,就像罗素和怀特海的数学原理表明所有的数学都可以从一个简单的逻辑基础建立起来一样。
因此,当他读到图灵 1936 年的论文《论可计算的数字及其在 Entscheidungsproblem 中的应用》时,麦卡洛克认为大脑可以像图灵机一样工作。他进一步推断,神经元链可以通过逻辑规则连接在一起,从而产生思想,就像罗素和怀特海通过将简单的命题连接在一起而建立了所有的数学一样。麦卡洛克和皮茨在他们 1943 年的开创性论文《神经活动中固有思想的逻辑演算》中,利用图灵对计算的数学定义结合逻辑,建立了大脑的计算理论
当时,神经元被认为是大脑中人类思维和智力的组成部分,人们已经研究了一段时间。神经元本身被认为是相对简单的细胞,对多个输入进行一些处理,并产生单个输出尖峰,即动作电位。麦卡洛克和皮茨已经证明了这些尖峰信号可以组合起来进行逻辑和算术运算。
与此同时,几位生物学家在 20 世纪初一直在研究鱿鱼的巨大神经元,生物物理学家艾伦·霍奇金和安德鲁·赫胥黎很快创建了一个神经元的电路模型,作为一组非线性微分方程,以计算细胞膜的电导如何随时间和电压变化。像数学家诺伯特·维纳这样的人开始看到神经元、神经网络和控制系统等生物系统之间的联系。维纳当时在麻省理工学院,他曾保护过皮茨。不久,皮茨还会见了冯·诺依曼,他分别与香农和图灵就智能和机器进行了对话,这些机器也可以模拟编码在神经网络中的那种思维。
https://en.wikipedia.org/wiki/Alan_Turing
事实上,图灵在 1947 年给伦敦数学协会做了一次演讲,他很有先见之明地说:“我们想要的是一台能够从经验中学习的机器。”他接着说:
这就像一个学生从他的老师那里学到了很多,但通过自己的工作又增加了更多。当这种情况发生时,我觉得一个人不得不认为机器显示了智能。”
图灵甚至提出了一个测试,现在称为图灵测试,来衡量一台机器是否可以被认为和人类一样聪明。这项测试基于一种叫做模仿游戏的维多利亚时代的室内游戏,并假设当客观观察者无法区分人类和机器参与者时,机器应该被视为与人类一样聪明。
人工智能
智能机器的想法很快引起了相当多的兴趣。1955 年,计算机科学家约翰·麦卡锡为其创造了“人工智能”一词,并于 1956 年组织了著名的达特茅斯会议,克劳德·香农、马文·明斯基、艾伦·纽厄尔和司马贺等名人出席了会议,标志着人工智能(AI) 领域的诞生。
在计算意义上,人工智能经常在 Russell & Norvig 等教科书中被描述为理性代理或智能代理,这是任何虚拟或物理的实体,可以从其环境中获取感官输入并对其进行解释,将其放入现有知识的上下文中,然后采取行动以最大化其实现目标的机会。
真正的问题是,就像生命本身一样,没有一个好的概括的智力定义。尽管我们在神经生物学方面取得了相当多的进展,但我们仍然不知道人类在做我们认为智能的事情时会做什么。我们所知道的是,人类做一些我们还不能用计算系统自动化的事情。
这些年来,人工智能的受欢迎程度时高时低,随之而来的是智能的定义。最初模仿人类智能的目标很快被称为通用人工智能(也被称为人工通用智能、强人工智能或硬人工智能)。正如图灵本人最初建议的那样,在专业环境或利基应用中简单地拥有“学习机器”这一更温和、更可实现的目标随后被赋予了相应的术语狭义人工智能(也称为人工狭义智能、弱人工智能或软人工智能)。随着时间的推移,这种狭义的人工智能,也就是你简单地拥有一台“学习机器”,也被称为机器学习。
在 Ch 阅读更多关于机器学习的内容。我的书的第 10 页,也可以在 ResearchGate 上公开查看。
[1]作为一个有趣的旁注,当冯·诺依曼在 1945 年发表他的历史性论文“关于 EDVAC 的报告初稿”时,它把第一台提出的现代计算机描述为一台存储程序二进制计算机器。在论文中,他模仿了麦卡洛克和皮茨的神经网络,但用真空管代替了神经元作为逻辑门。发表的论文只有一处引用:麦卡洛克和皮茨 1943 年的论文。
计算思维定义
什么是计算思维和计算问题解决?
计算思维是一套解决复杂问题的技术,可分为三步:问题规格说明、算法表达式、解决方案实现&评估。上面列出了计算思维方法每一步涉及的原则,下面将详细讨论。版权所有里基·j·塞西
计算机科学是对计算过程和信息过程的研究。信息是通过将数据置于特定的上下文中以揭示其含义的处理结果。数据是原始的事实或对自然的观察计算是由某个计算代理执行的某个系统程序对数据的操纵。
一般来说,计算问题需要某种方法或思维方式。这种方法通常被称为计算思维,在许多方面类似于我们关注预测的科学方法。
计算思维步骤:为了使用计算思维进行预测,我们需要定义与问题及其解决方案相关的三个步骤:
- 问题说明:我们从分析问题开始,精确地陈述问题,并建立解决方案的标准。解决方案的计算思维方法通常从将复杂的问题分解成更熟悉或更易处理的子问题开始,有时称为问题分解,经常使用演绎或概率推理。这也可以涉及到抽象和模式识别的思路。更正式地说,我们将在创建模型和模拟中使用这些技术。
- 算法表达式:然后我们需要找到一个算法,一个精确的步骤序列,使用适当的数据表示来解决问题。这个过程使用归纳思维,需要将一个特定的问题转化为一大类类似的问题。这一步有时也被称为算法思维。我们可以进一步将其分为命令式,如过程式或模块化,以及声明式,如功能式,算法解决方案的方法。
- 解决方案实施和评估:最后,我们创建实际的解决方案,并对其进行系统评估,以确定其正确性和效率。这一步还包括查看解决方案是否可以通过自动化或扩展到其他类型的问题而被推广。
我应该在这里补充一点警告:这些计算思维的规则都很好,但它们本身并不是真正的规则;相反,把它们想成是善意的启发,或者经验法则。
这些计算思维的启发法与小学教授的 5 步科学方法的启发法非常相似,后者通常被写成:
- 观察宇宙的某些方面
- 用那些观察来告知一些关于它的假设
- 使用这个假设做一些预测
- 通过实验测试预测,并相应修改假设
- 重复步骤 3 和 4,直到假设不再需要修改
这些是很好的指导方针,但不是强制性的。它们是你可能需要或要求大部分努力的想法的建议,但它不是将你的想法或解决方法归类的过程。
在其核心,所有基础物理科学的中心方面是预测,通常通过实验。如果你能够做出重复的、精确的、定量的预测,这意味着无论你使用过什么样的模型或思维模式,它都是有效的,应该被重新使用。如果是形式方法,很好;如果它不那么正式,但仍然是结构化的和可重复的,并导致正确的计算解决方案,这也很好。
任何让你达到这种状态的结构化思维过程或方法都会被认为是计算思维。你甚至可以把它看作是批判性思维或基于证据的推理的另一种定义,在这种情况下,你的解决方案来自于数据以及你对数据的看法:
数据+如何思考数据=计算思维
从这个意义上说,能够表示数据,然后操纵它,这本身就是一个可计算问题的计算解决方案!
然后,我们可以将程序视为计算解决方案,即可计算功能的解决方案,我们用某种特定的编程语言来表达。我们还知道一个算法是一个有效过程,一系列使用特定数据结构解决特定类型问题的逐步指令,这些数据结构指定了特定的数据表示。
计算思维定义
照片由 Matteo Di Iorio 在 Unsplash 上拍摄
但是在我们用特定的编程语言实现我们的解决方案之前,我们必须为我们正在检查的问题定义一个算法解决方案。让我们看看如何实际找到这样一个计算解决方案,但要注意的是,由于不同的问题需要不同的详细方法,因此每个步骤都需要定制。
计算思维步骤
如上所述,计算思维是一个由三个阶段组成的迭代过程:
- 问题说明:使用抽象、分解、模式识别分析问题并精确陈述,同时建立解决方案的标准
- 算法表达式:使用适当的数据表示和算法设计找到计算解决方案
- 解决方案实施&评估:在推广到其他问题之前,实施解决方案并进行系统测试
计算思维方法的细节
让我们列出五个计算思维原则和伴随的计算机科学思想和软件工程技术的细节,它们可以为这三个步骤中的每一个发挥作用。请注意,这不是一个全面的列表,但具有代表性。
在这种方法中,我们也可以把原则看作是策略,寻找计算解决方案所需的高级概念;这些想法可以被视为特殊的策略,也就是众所周知在许多不同环境下都有效的模式或方法;最后,像工具这样的技术可以在特定的情况下使用。所有这些都是提出问题的最终计算解决方案所需要的。
- 问题说明
- 计算思维原理:模型开发与抽象、分解、模式识别
- 计算机科学思想:问题分析和说明
- 软件工程技术:问题需求文档、问题规范文档、UML 图等。
2.算法表达式
- 计算思维原理:使用数据表示和算法设计的计算问题解决
- 计算机科学理念:通过一些符号系统的数据表示和算法开发,使用模块化、流程控制(包括顺序、选择和迭代)、递归、封装和并行计算来系统地处理信息
- 软件工程技术:流程图、伪代码、数据流图、状态图、类图的类-责任-协作(CRC)卡、序列图的用例等。
3.方案实施&评估
- 计算思维原则:系统测试和概括
- 计算机科学理念:分析效率和性能约束的算法实现、调试、错误检测测试、测量解决方案正确性的评估指标,以及将计算解决方案扩展到其他类型的问题
- 软件工程技术:用编程语言实现、代码审查、重构、使用 JUnit 等工具进行单元和系统测试的测试套件、质量保证(QA)等。
计算思维原则
凯利·西克玛在 Unsplash 拍摄的照片
计算解决方案的第一步,问题规范,依赖于一些基本的计算思维原则。尽管计算思维不是一种正式的推理方法,但它确实包含了一些在所有领域和学科中都有用的基本原则。
它们构成了一种逻辑地、有条理地解决任何领域的任何问题的推理或思考方式!这些基本 原则也是你可以放在简历上的流行语,所以让我们先来深入了解一下更重要的原则,尤其是分解、模式识别和抽象,以及它的表亲概括。
分解简单来说就是将一个复杂的问题分解成更容易处理的部分。如果问题是一些复杂的任务,你可以把它分解成一系列简单的子任务。如果问题涉及一个复杂的系统,你可以把系统分解成一堆更小的子组件。例如,如果你面临着写一篇大而复杂的论文,你可能会选择通过将论文分解成更小的子部分并分别处理每一部分来解决它。
模式识别是在一个问题或一些数据集中发现相似性、趋势或某种规律性的想法。我们可能识别的这些模式帮助我们做出预测或者直接找到解决方案。例如,如果你在高速公路上开车,你注意到左边车道上的车挤在一起,你可能会决定换到右边车道。或者,如果你看到一只股票几个月来持续上涨,你可能会决定买入这只股票。免责声明:相关性不等于因果关系;即使你发现了一个模式,在你真正把钱投入到你的模式之前,你可能想用其他分析来确认或验证这个预测。
如前所述,抽象是忽略你认为不重要的细节的想法。这样,我们就可以优先考虑关于被检查系统的信息。我们可以使用这种抽象的想法来做一些事情,比如制作模型,比如之前提到的代表校园的地图。抽象的另一个例子可能是创建一本书或一部电影的摘要。我们也可以概括形成一个“大图”,忽略一些无关紧要的细节。
像这样的概括允许我们识别看似完全不同的模型的共同特征,从而允许我们将一个解决方案从一个领域调整到一个可能不相关的领域。概括可以帮助我们组织想法或成分,就像我们将一些动物归类为脊椎动物,将另一些归类为无脊椎动物一样。此外,能够识别我们已经识别的模式下的一般原则允许我们将模式和趋势归纳为规则。反过来,这些规则可以直接通知最终的算法,我们将在构建计算解决方案的第二步中使用。
算法表达式:计算问题解决
迈克尔·泽兹奇在 Unsplash 上拍摄的照片
计算求解的第二个步骤,算法表达式,是计算问题求解的核心。数据到信息再到知识的转换可以通过计算问题解决来完成。精确定义问题后,它包括以下三个步骤:
- 数据:结构原始 事实 用于循证推理
- 表示:创建一个问题 抽象 来捕捉系统的相关方面
- 算法:描绘一个在有限时间内解决问题的系统化的 程序
因此,计算问题的解决包括找到数据的适当的表示或上下文,并在算法中使用该表示,一旦问题被清楚地定义,逐步的过程就解决了问题。
数据的上下文化可以被认为是信息的第一近似值,解决方案将数据转换为信息,然后转换为可操作的知识。这个可以在这里进一步看到。
思考信息的一种方式是在某种上下文中的数据。如果上下文是发生的概率,我们就可以用香农的信息测度来结束。如果我们把数据放在一些基于逻辑的推理结构中,我们可以根据证据得出一些结论;这个结论成为我们有用的信息,可以形成可操作知识的基础。我们还可以在一些基于知识的系统中整理这些信息,这些系统是使用知识管理技术管理的。
在我的新书中阅读更多关于香农的信息理论和计算思维,这本书也可以在 ResearchGate 上公开查阅。
深度学习的计算成本和环境影响
一个衡量成本(美元)和二氧化碳排放量(磅)的框架
Holyoke 大坝为马萨诸塞州绿色高性能计算中心提供水力发电。美国公共电力协会在 Unsplash 上拍摄的照片
用于训练最先进的深度学习模型的计算继续呈指数增长,远远超过了摩尔定律的速度。但是它的成本是多少,对环境有什么影响?我将在这篇文章中描述一种近似的方法,这篇文章是文献[1]和[2]的总结。
目标
- 估算培训众所周知的 NLP 模型的云计算成本和碳排放。
- 估计新的最先进的 DL 模型所需的云计算成本和碳排放。
- 将碳排放与普通基准进行比较,如人类平均寿命 1 年或汽车寿命。
非目标
- 我们不包括向用户提供 DL 型号的服务成本。除了交通之外,它们还取决于所服务的地理区域。此外,我们不包括网络和数据存储成本,以及研究人员的工资。
- 功率和计算效率取决于 GPU 的类型。更高效的硬件开发(如 Google Cloud 上提供的 TPU)是一个活跃的研究领域。
能源使用估算
总功耗可以估计为 CPU、内存和 GPU 功耗之和。[1]的作者通过使用他们的开源代码训练每个模型,使用 nvidia-smi 和英特尔电源管理接口等常用工具对 CPU、内存和 GPU 功耗进行采样和平均来测量。g 是使用的 GPU 数量。
训练模型所需的时间取自原始论文。
1.58 是电力使用效率系数(1.58 是 2018 年全球数据中心报告的平均值)。这个乘数因子包括运行模型所需的所有其他能量,主要是冷却。这是可以优化的,例如,谷歌报告其数据中心的 PUE 1.1。
我们将瓦特小时除以 1000 得到千瓦时。
等式计算训练期间的功耗。图片来自[2]
二氧化碳估算
美国环境保护署(EPA)报告称,美国电力消耗产生的平均二氧化碳(单位:磅/千瓦时)(EPA 2018)为:0.954。由于主要的云提供商在可再生能源领域拥有更高的份额,我们将把这个数字减半。在谷歌的案例中,它将接近 0,因为它是一个大量使用可再生能源的用户,并且通过购买绿色能源来抵消碳排放。
各国的可再生能源消耗与云提供商
估价
先发制人和按需成本的 GPU 和 TPU 使用她从谷歌小时。TPU 每小时的成本更高,但对于适合该硬件的工作负载来说,其成本和能效更高。
结果
[1]的作者选择了众所周知的深度学习模型:Transformer、ELMo、BERT 和 GPT-2,以及使用神经架构搜索思想训练多个模型以找到最佳配置的 Evolved Transformer。NAS 可以估算整个研发周期的计算成本,以找到一种新的先进模式。
本研究中使用的 5 种模型。提供的是高级架构、使用的硬件、模型方面和培训时间。图片来自[2]
二氧化碳排放和一些众所周知的深度学习模型的训练的货币成本。TPU 的成本效率要高得多(就 NAS 而言,从 4.4 万美元到 14.6 万美元,而不是几百万美元),而且可能更节能。
模拟训练二氧化碳消耗量与通用基准。图片来自[2]
离别的思绪
现代 ML 训练(和推论,不在本文讨论范围内)导致大量的碳排放和金钱成本。ARK Invest 等金融分析师预测,深度学习的市值将从 2020 年的 2 万亿美元增长到 2037 年的 30 万亿美元[3]。
在这篇文章中,我想提供一些量化排放和成本的框架。当特雷弗·诺亚问格里塔·图恩伯格人们可以做些什么来应对气候变化时,她建议最重要的事情是通知自己,了解情况,并最终推动一场政治运动。
就个人而言,我致力于将模型做得更小以适应移动设备(这对于减少延迟有额外的好处!)、训练多任务模型、多语言模型、报告记忆模型大小和失败(这可以很容易地在 Tensorflow [7]中进行分析)以及密切关注在训练的早期阶段没有显示出有希望的结果的工作。
参考
[1]斯特鲁贝尔,e .,甘内什,a .,&麦卡勒姆,A. (2020)。现代深度学习研究的能源和政策考虑。AAAI 人工智能会议论文集, 34 (09),13693–13696。【https://doi.org/10.1609/aaai.v34i09.7123
[2]斯特鲁贝尔,e .,加内什,a .,&麦卡勒姆,A. (2019)。自然语言处理中深度学习的能源和政策考虑。https://arxiv.org/abs/1906.02243
[4]https://youtu.be/rhQVustYV24?t=303
[5]http://www . cis . upenn . edu/~ BC pierce/papers/carbon-offsets . pdf
[7]https://www . tensor flow . org/API _ docs/python/TF/compat/v1/profiler/profile option builder
计算机视觉:图像形成和表示
计算机视觉入门
诺德伍德主题公司在 Unsplash 上拍摄的照片
1.介绍
作为人类,我们能够如此轻松地感知我们周围的三维世界。想象一下看着一个花瓶。我们可以毫不费力地感知每一片花瓣的形状和半透明性,并可以将花朵从背景中分离出来。
计算机视觉旨在赋予计算机像我们一样理解环境的能力。它专注于通过多幅图像或视频观察世界,并重建物体的形状、强度、颜色分布等属性。
深度学习领域的最新进展使计算机视觉方法能够理解和自动化人类视觉系统可以完成的任务。本文讨论了计算机视觉的介绍性主题,即图像的形成和表示。图像形成将简要介绍图像是如何形成的以及它所依赖的因素。它还将涵盖数码相机中的图像传感管道。文章的后半部分将介绍图像表示,它将解释表示图像的各种方法,并将重点放在可以对图像进行的某些操作上。
2.图像形成
在建模任何图像形成过程中,几何图元和变换对于将三维几何特征投影到二维特征是至关重要的。然而,除了几何特征之外,图像形成还取决于离散的颜色和强度值。它需要知道环境的照明、相机光学、传感器属性等。因此,在讨论计算机视觉中的成像时,本文将集中讨论光度成像。
2.1 光度成像
图 1 给出了图像形成的简单解释。来自光源的光在特定的表面上反射。该反射光的一部分穿过图像平面,经由光学器件到达传感器平面。
图:1。光度成像(Image cr 编辑:Szeliski,计算机视觉:算法与应用 2010)
影响图像形成的一些因素是:
- 光源发出的光的强度和方向。
- 材料和曲面几何以及附近的其他曲面。
- 传感器捕获属性
2.1.1 反射和散射
没有光,图像就不能存在。光源可以是点光源或面光源。当光线照射到表面时,可能会发生三种主要反应-
- 一些光被吸收了。这取决于称为ρ(反照率)的因素。表面的低ρ意味着更多的光将被吸收。
- 一些光被漫反射,这与观察方向无关。遵循朗伯余弦定律反射光的量与 cos(θ)成正比。例如布、砖。
- 一些光被镜面反射,这取决于观察方向。例如镜子。
图 2:反射模型(图片来源:伊利诺伊大学德里克·霍伊姆)
除了上述反射模型,最常见的光散射模型是**双向反射分布函数(BRDF)。**它给出了光被介质从一个方向散射到另一个方向的量度。光的散射可以决定表面的形貌——光滑表面几乎完全在镜面反射方向反射,而随着粗糙度的增加,光往往会衍射到所有可能的方向。最终,如果一个物体的表面是完全漫射的(即朗伯),那么它在整个出射半球看起来都是一样亮的。因此,BRDF 可以提供关于目标样品性质的有价值的信息。
有多种其他着色模型和光线跟踪方法,它们可以通过评估场景的外观来正确理解环境。
2.1.2 颜色
从颜色的角度来看,我们知道可见光只是大电磁光谱的一小部分。
当彩色光到达传感器时,会注意到两个因素:
- 光的颜色
- 表面颜色
Bayer Grid/Filter 是捕捉光线颜色的重要进展。在相机中,不是每个传感器都能捕捉到光的所有三种成分(RGB)。受人类视觉感受器的启发,Bayers 提出了一个网格,其中有 50%的绿色,25 %的红色和 25%的蓝色传感器。
然后使用去马赛克算法获得全色图像,其中周围像素用于估计特定像素的值。
除了 Bayer 滤色器之外,还有许多这样的滤色器被开发来感测颜色。
图 3: (a)图像传感器上的滤波器的拜耳排列。(b)传感器的横截面。(图片来源:https://en.wikipedia.org/wiki/Bayer_filter)
2.2 图像传感管道(数码相机)
光线来自多个光源,在多个表面上反射,最终进入相机,在相机中光子被转换为我们在观看数字图像时看到的(R,G,B)值。
相机中的图像感测流水线遵循图 4 中给出的流程图。
在相机中,光线首先落在镜头上(光学)。接下来是可以指定或调整的光圈和快门。然后光线落在传感器上,传感器可以是 CCD 或 CMOS(下面讨论),然后图像以模拟或数字形式获得,我们得到原始图像。
通常摄像机不会停在这里。他们使用上述主题中提到的去马赛克算法。如果需要或者应用任何其他重要的处理算法,图像被锐化。之后,白平衡和其他数字信号处理任务完成,图像最终被压缩成合适的格式并存储。
图 4:相机中的图像传感管道(图片来源: Szeliski,计算机视觉:算法与应用 2010)
2.2.1 CCD 与 CMOS
相机传感器可以是 CCD 或 CMOS。电荷耦合器件(CCD)中。在每个感测元件处产生电荷,并且该光生电荷从一个像素移动到另一个像素,并且在输出节点处被转换成电压。然后,模数转换器(ADC)将每个像素的值转换成数字值。
互补金属氧化物半导体(CMOS)传感器通过在每个元件内将电荷转换成电压来工作,而不是像 CCD 那样积累电荷。CMOS 信号是数字信号,因此不需要 ADC。CMOS 在当今时代广泛应用于相机中。
图 5: CCD 与 CMOS(图片来源:D. Litwiller,CMOS 与 CCD:成熟的技术,成熟的市场)
2.2.2 数字图像传感器的特性
让我们来看看当你点击相机上的图片时可能会看到的一些属性。
**快门速度:**控制到达传感器的光量
采样间距:定义成像芯片上相邻传感器单元之间的物理间距。
填充因子:有效感应面积大小与理论可用感应面积的比值(水平和垂直采样间距的乘积)
芯片尺寸:芯片的整体尺寸
传感器噪音:传感过程中各种来源的噪音
分辨率:告诉你每个像素指定多少位。
后处理:压缩和存储前使用的数字图像增强方法。
3.0 图像表示
得到一幅图像后,设计出表现图像的方法是很重要的。有各种各样的方式来表现一幅图像。让我们看看最常见的表示图像的方式。
3.1 作为矩阵的图像
表示图像的最简单的方式是矩阵的形式。
图 6:将图像的一部分表示为矩阵(图像鸣谢:IIT、马德拉斯、 NPTEL 计算机视觉深度学习)
在图 6 中,我们可以看到图像的一部分,即时钟,被表示为矩阵。一个相似的矩阵也将表示图像的其余部分。
常见的是,人们用多达一个字节来表示图像的每个像素。这意味着 0 到 255 之间的值表示图像中每个像素的强度,其中 0 表示黑色,255 表示白色。对于图像中的每个颜色通道,生成一个这样的矩阵。在实践中,将 0 和 1 之间的值标准化也很常见(如上图示例所示)。
3.2 图像作为一种功能
图像也可以表示为函数。图像(灰度)可以被认为是一个函数,它接受一个像素坐标并给出该像素的亮度。
可以写成函数f:ℝ→ℝ输出任意输入点(x,y)的强度。强度值可以在 0 到 255 之间,如果值是标准化的,也可以在 0 到 1 之间。
图 7:用函数表示的图像(图像来源:诺亚·斯内夫利,康奈尔大学)
3.2.1 图像变换
当图像被视为功能时,它们可以被转换。函数的变化会导致图像像素值的变化。下面是一些相同的例子。
图 8 图像转换——使图像变亮(来源:诺亚·斯内夫利,康奈尔大学)
在图 8 中,我们希望使图像更亮。因此,对于图像中的每个像素,我们增加相应的强度值。这里我们假设值在 0 到 255 之间。
图 9:图像转换——翻转图像(来源:诺亚·斯内夫利,康奈尔大学)
类似地,图 9 示出了围绕垂直轴翻转图像的函数的变化。
在上面的例子中,变换发生在像素级。我们还可以用其他方法来进行图像转换。
3.2.2 图像处理操作
本质上,有三种主要操作可以在图像上执行。
- 点操作
- 本地操作
- 全球运营
下面是对这些操作的解释。
3.2.2.1 点穴操作
上面显示的图像变换示例是点操作。在这种情况下,输出值仅取决于特定坐标处的输入值。
图 10:点操作。“b”中的输出坐标仅取决于“a”中相应的输入坐标(图片来源:作者)
编辑图像时经常使用的一个非常著名的点操作示例是反转对比度。最简单地说,它将暗像素转换为亮像素,反之亦然。
图 11:反转对比度(图片来源:IIT、马德拉斯、 NPTEL 计算机视觉深度学习)
图 11 显示了反转对比度的应用。帮助我们实现这一目标的点操作如下所述。
图 12:反转对比度的点操作(图片来源:作者)
这里, I(x,y) 代表图像 I 在坐标(x,y)处的亮度值。 Iₘₐₓ 和 Iₘᵢₙ 是指图像 I 的最大和最小亮度值。例如,假设图像 I 的强度在 0 和 255 之间。因此, Iₘₐₓ 和 Iₘᵢₙ 分别变为 255 和 0。您希望翻转某个坐标处的亮度值,比如说(x,y ),其中当前亮度值为 5。通过使用上面的操作,您得到的输出为:(255) — 5 + 0 = 250,这将是坐标(x,y)处亮度的新值。
假设您使用相机点击了一个静态场景。但是由于许多原因,如镜头上的灰尘颗粒、传感器的损坏等等,图像中可能会有噪声。降噪使用点运算可能非常繁琐。一种方法是拍摄多个静态场景,对每个像素的值进行平均,并希望噪声被去除。但是有时,不可能获得一个场景的多个图像,并且不能每次都保证场景的静止。要做到这一点,我们需要从点操作转向局部操作。
【3.2.2.2 本地操作
在本地操作中,如图 13 所示,输出值取决于输入值及其邻居。
图 13:本地操作(图片鸣谢:作者)
理解局部操作的一个简单例子是移动平均线。假设如图 14 所示的图像 I。通过查看图像可以清楚地看到,这是一个放置在黑暗背景中的白色盒子。然而,我们看到图片中的噪声,因为几个像素似乎放错了位置(在图中圈出)。
图 14:图像的相应像素的强度值(使用的来源:Steve Seitz,华盛顿大学)
如何从图像中去除这种噪声?假设图像中有一个 3 X 3 的窗口(可以选择任何大小的窗口)。在图像上移动窗口,取窗口内所有像素的平均值。下面可以看到这方面的演示。操作的最终输出可以在图 15 中看到。
2D 移动平均线(来源:Steve Seitz,华盛顿大学)
图 15:移动平均线的最终输出(图片来源:史蒂夫·塞茨,华盛顿大学)
上述操作是局部操作,因为输出取决于输入像素及其邻居。由于该操作,图像中的噪声像素在输出中被平滑掉。
3.2.2.3 全球运营
顾名思义,在全局操作中,输出像素的值取决于整个输入图像。全局运算的一个例子是傅立叶变换,如图 17 所示
图 16:全球运营(图片鸣谢:作者)
图 17:傅立叶变换的例子(图片来源:Mathworks MATLAB 工具箱)
感谢您的阅读。本文介绍了图像形成及其表示的基础知识。接下来的文章将深入讨论计算机视觉的更多主题。
资源
计算机视觉的深度学习,梵持·N·巴拉苏布拉曼尼安,IIT·海德拉巴
计算机视觉:算法与应用理查德·塞利斯基
CS 4495 计算机视觉,亚伦·博比克,佐治亚理工学院计算系
描述第一表面散射的双向反射分布函数——c . e . Mungan,1998 年夏季
如果你想阅读更多关于计算机视觉的故事,请随时关注并保持更新。
我也写机器学习/人工智能相关的核心话题!