对“熵”一知半解?带你揭开“熵”的神秘面纱

本文介绍了熵的概念,从香农的通信理论出发,探讨了信息熵在无损编码中的应用,通过实例解释了如何通过概率分布计算最小平均编码大小,并与交叉熵损失函数相联系。文章旨在帮助读者理解熵的本质和重要性。

大家好啊,我是董董灿。

你还记得是在什么时候了解的“熵”这个概念吗?现在还能说清楚这个概念是什么意思吗?

也许记得物理热力定律的你,会说“熵代表物质的混乱程度,在热力学零度时,熵为零"。

也许记得化学熵变的你,会说“同一类物质,摩尔质量越大,结构越复杂,熵值越大”。

或者你会用一个小实验来说明什么是熵。当把一滴墨水滴到一杯水中后,墨水会慢慢地扩散,此时水杯中的熵是在变大。

熵,代表了物质混乱程度,或者说是无序状态,又或者说是不可预测性,又或者是信息量。

接下来的几篇文章,我会试着从熵的概念出发,详解熵的原理,以及在神经网络中,交叉熵损失函数的意义。

本文将揭开“熵”的神秘面纱。(查看Noki大佬的博客,本文翻译后有改动,翻译:董董灿)

1、谁发明了熵

1948年,克劳德·香农在他的论文《通信的数学理论》中引入了信息熵的概念。

当时,香农正在寻找一种方法,来有效地对要发送的信息进行编码,同时确保发送过程中,不丢失任何信息。

通俗点讲,就是将一个信息发送到接收方,中间尽可能的不丢失任何信息。

香农根据消息的平均长度来衡量信息的发送效率。这时,他思考怎么用一种最小的数据结构来表示原始数据,同时要求不能有信息丢失。

也就是说,目的地的解码器必须能够无损地恢复原始消息。

就好比我们打电话,讲话的一方发出的语音,在经过语音信号调制->传输->解调之后,需要无损的到达接听方。

在这个信息传递的例子里,香农将熵定义为从源发送到目的地时,一个消息的无损编码的最小可能的平均大小。

这个定义很重要,有点绕?没关系,先看一个人人都懂的例子。

2、如何进行高效无损编码?

假设您想从东京向纽约发送一条消息,消息的内容是今天东京的天气状况——“今天东京天气良(Today, Tokyo's weather is fine)”。

如果直接把这段话发送过去,大多数人可能都会觉得效率不高。

这是因为,无论发送方还是接收方,都知道发送的是东京的天气,而且是今天的,因此就没必要在消息中将“Today”,“Tokyo”等字眼发送过去,只需要将天气状况是“好”还是“不好”发送过去即可。

于是有了下面的消息发送方式。

这么发送,消息短了很多,但有没有更好的办法呢?

如果你是一位程序员,你的第一反应肯定是将信息进行二进制编码,这有点像one-hot编码(这里有个你肯定能理解的one-hot)。

我们将天气“好”编码为0,天气“不好”编码为1发送过去。这样,接收方接收到0,就知道“今天东京的天气好”,接收到1就知道“今天东京的天气不好”。

那么,这种消息传递方式是无损的吗?

没错,是无损的,因为在这种情况下,只有两种可能的消息类型:“好”和“不好”,接收方可以无损的接收到全部信息。

但如果我们还想发送“阴天”或“雨天”这种天气状态,使用1 位数字进行二进制编码显然是不够的了。

那么我们就要考虑使用 2 位数字来进行编码。

如上图利用两位二进制编码,现在可以表达所有的情况,此时发送消息只需要 2 位。

但这种方法有一些问题:从语义上来说,“多云”和“下雨”都代表“不好”,貌似“不好”这个选项是多余的,我们把它删除。

在上面的编码中,“Fine”是“00”,但不需要第二个零,这是因为我们可以制定如下规则:当第一位为零时,定义为“晴天”,第一位为1时,定义为“阴天”或“雨天”。

于是编码变成了下面这样:

第一位表示“Fine or not”,第二位表示“阴天或雨天”。

但又出现了一个问题,东京可能会下雪,而现在的编码无法传达这样的天气。怎么办?

我们可以添加第三位并将其用于“雨”和“雪”的情况。

将“Rainy”从 11 更改为 110,将“Snow"改为 111,因为 110 与 111 明显不同,但当多个编码相继发送时,11 会产生歧义。

例如,如果我们使用 11 表示“Rainy”,使用 111 表示“Snow”,则 5 位值“11111”可能表示“Rainy,Snow”或“Snow,Rainy”。因此,我们使用 110 表示“Rainy”,这样我们就可以使用“110111”表示“Rainy, Snow”,使用“111110”表示“Snow, Rainy”,此时没有任何歧义。

因此,编码现在使用第一位表示“晴天”,第二位表示“阴天或其他”,第三位表示“雨或雪”。

例如,“010110111”表示“晴、阴、雨、雪”。“110010111”的意思是“雨、晴、阴、雪”。

如果你看到这能够看懂,恭喜你,你已经在理解熵的路上迈出了第一步。

接着我们继续,还记得香农将熵定义为“无损编码的最小可能的平均编码大小”吗?

接下来看看如何计算平均编码大小。

3、如何计算平均编码大小

假设使用上面讨论的编码方案向纽约发送天气消息。

正常情况下,我们可以通过积累大量的天气数据来预测某天东京天气的概率,这就像是天气预报。

假设我们知道某天东京的天气概率分布如下图:有60%的概率天气是晴天,38%的概率是多云,1%的概率是雨天,1%的概率是雪。

然后,我们可以计算从东京到纽约发送消息所使用的平均位数。

(0.6×1位)+(0.38×2位)+(0.01×3位)+(0.01×3位)=1.42位

通过上述编码,我们平均每条消息使用 1.42 位个数字(比特)。

因此,平均位数取决于概率分布和消息编码(我们为每种消息类型使用多少位)。

而如果东京的雨雪较多,则平均编码大小将会有很大不同。

(0.1 x 1 位)+(0.1 x 2 位)+(0.4 x 3 位)+(0.4 x 3 位)=2.7 位

在这种情况下,将平均使用 2.7 位来编码消息。在这种情况下,可以通过更改编码以使用更少的位数来减少“雨”和“雪”的平均编码大小。

上述编码平均需要 1.8 位,这比之前的编码产生的大小要小得多。

尽管这种编码产生较小的平均编码大小,但我们失去了先前编码方案中良好的语义含义(即,第一位表示“好与否”,第二位表示“等”)。没关系,因为我们只关心平均编码大小,我们既不担心编码的语义,也不担心解码的难易程度。

我们现在知道如何计算平均编码大小。但是我们如何知道我们的编码是否是实现最小平均编码大小的最佳编码呢?

4、寻找最小的平均编码大小

假设我们有以下概率分布。我们如何计算每种消息类型的最小无损编码大小?

“Rainy”所需的最小编码大小是多少?我们应该使用多少位?

假设我们使用 1 位来编码“Rainy”,因此 0 表示“Rainy”。在这种情况下,我们必须对其他消息类型使用至少 2 位,以使整个编码明确。

这并不是最佳选择,因为“晴天”和“多云”等消息类型发生的频率更高。我们应该为它们保留1位编码,以使平均编码大小更小。因此,我们应该为“Rainy”使用超过 1 位,因为它出现的频率要低得多。

如下所示,编码是明确的,但平均大小不是理论上的最小值,因为我们对更频繁的消息类型(例如“Fine”和“Cloudy”)使用了更多位。

那么使用 2 位来表示“Rainy”怎么样?让我们交换“Rainy”和“Fine”之间的编码。

这种编码与前一种编码具有相同的问题,因为我们对更频繁的消息类型(“多云”)使用更多的位。

事实上,如果“Rainy”使用 3 位,我们平均可以实现最小编码大小。

如果我们使用 4 位来表示“Rainy”,我们的编码就会变得多余。因此,3 位是“Rainy”的正确编码大小。一切都很好,但是这个过程涉及太多的试验和错误,无法找到正确的编码大小。

给定概率分布,是否有任何简单的方法来计算从源发送到目的地的消息的无损编码的最小可能平均大小。

换句话说,我们如何计算熵?

5、如何计算熵

假设我们有 8 种消息类型,每种消息类型发生的概率均等 (⅛ = 12.5%)。我们需要对它们进行无歧义编码的最小位数是多少?

我们需要多少位来编码 8 个不同的值?

1 位可以编码 0 或 1(2 个值)。添加另一个位会使容量加倍,因为 2 位 = 2x2 = 4 个值(00、01、10 和 11)。因此,8 个不同的值需要 3 位 = 2x2x2 = 8(000、001、010、011、100、101、110 和 111)。

我们无法减少任何消息类型的任何位。如果我们这样做,就会引起歧义。此外,我们不需要超过 3 位来编码 8 个不同的值。

一般来说,当我们需要用位表示N个不同的值时,我们需要

位,我们不需要更多。

例如:

换句话说,如果某种消息类型发生 N 次中的 1 次,则上述公式给出所需的最小大小。由于P=1/N是消息的概率,同样的事情可以表示为:

让我们将这些知识与计算最小平均编码大小(以位为单位)(即熵)结合起来:

P(i) 是第 i 个消息类型的概率。

这个公式看着是不是很熟悉?在深度学习中,交叉熵损失函数便是由这个公式继承而来。

这个公式简直简洁和美到窒息,这个公式没有魔法,仅仅使用了每种消息类型的最小编码大小来计算平均编码大小。

如果你看到这,仍然都能看懂,恭喜你,你基本了解了熵的本质。

接下来,通过一个使用天气预报场景的示例来巩固理解。

所以,熵是:

(0.5 x 1 位)+(0.25 x 2 位)+(0.125 x 3 位)+(0.125 x 3 位)=1.75 位

6、熵的类比

熵有很多类比:无序、不确定性、不可预测性、信息量等等。

如果熵很高(平均编码大小很大),则意味着我们有很多概率较小的消息类型。因此,每次新消息到达时,您都会期望与以前的消息不同的类型。你可能会将其视为一种混乱、不确定性或不可预测性。

当出现概率比其他消息类型小得多的消息类型时,它会显得令人惊讶,因为平均而言,你会期望其他更频繁发送的消息类型。

此外,罕见的消息类型比频繁的消息类型具有更多的信息,因为它消除了许多其他概率并告诉我们更具体的信息。

在天气场景中,如果我们之前没有任何信息,通过发送概率为 12.5% 的“雨”,我们将概率分布(“晴、多云、雪”)的不确定性降低了 87.5%。如果我们改为发送“Fine”(50%),我们只会将不确定性减少 50%。

如果熵很高,则平均编码大小很重要,这意味着每条消息往往具有更多(特定)信息。同样,这就是为什么高熵与无序、不确定性、惊喜、不可预测性和信息量相关。

低熵意味着大多数时候我们收到的是更可预测的信息,这意味着更少的混乱、更少的不确定性、更多的可预测性和更少的(具体)信息。

如果你一个星期没有打扫房间,发现房间变得很乱,不要自责自己变懒了,这只是房间的熵变高了。宇宙的规律就是从无序到有序,宇宙在膨胀,物质分散的越来越均匀,宇宙尚且如此,何况自己的房间呢?

所以,安心啦,继续游戏吧。

<think>好的,我现在需要帮助一位OpenCV和Python基础较弱的初学者。首先,用户希望用详细的语言解释问题,所以我要确保回答清晰易懂,避免使用专业术语,或者在必要时解释术语。 用户提到对问题一知半解,可能需要从基础概念开始。例如,如果用户问如何读取图像,我需要分步骤说明,包括安装库、导入库、读取图像的代码示例,以及每个参数的作用。同时,要解释可能出现的常见错误,比如文件路径错误,以及如何处理这些错误。 考虑到用户Python基础较差,代码示例应尽量简单,避免复杂的语法结构。可能需要解释基本的Python语法,比如如何导入模块、调用函数等。此外,应该提醒用户注意代码缩进、括号的使用等常见问题。 对于OpenCV特定的知识点,比如BGR和RGB的颜色空间差异,需要详细说明为什么OpenCV使用BGR格式,以及如何在显示图像时转换颜色空间。可能还需要对比其他库如Matplotlib的处理方式,帮助用户理解不同之处。 用户可能会对图像处理的基本操作(如灰度转换、边缘检测)感兴趣,这时需要逐步解释每个步骤的目的、使用的函数及其参数。例如,在讲解Canny边缘检测时,要解释阈值的作用,如何调整参数以获得更好的效果,并提供示例代码和预期输出。 另外,用户可能遇到的实际问题,如图像显示不出来的情况,需要给出排查步骤:检查路径是否正确,图像是否成功加载,窗口是否正确创建等。同时,提供异常处理的方法,比如使用try-except块捕获异常,帮助用户调试代码。 在解释概念时,使用类比或生活中的例子可能更有助于理解。例如,将图像矩阵比作网格,每个网格点代表一个像素,像素值表示颜色强度。这样可以帮助用户建立直观的理解。 最后,鼓励用户动手实践,通过修改代码参数观察变化,加深理解。同时,推荐一些学习资源,如官方文档、教程网站或入门书籍,帮助用户系统学习。 总结来说,回答需要耐心细致,步骤分解明确,代码示例简单,概念解释通俗,并提供实际问题的解决方法,帮助用户逐步建立信心和基础知识。</think>以下是针对OpenCV初学者的详细解答框架,我们从最基础的安装到第一个图像处理示例逐步说明: --- ### 一、OpenCV环境安装 1. **安装Python** 推荐使用Python 3.6+版本 官网下载地址:https://www.python.org/downloads/ 2. **安装OpenCV库** 打开命令行输入: ```bash pip install opencv-python ``` *注:这个命令会安装OpenCV的主模块,如果需要完整功能(如视频编解码),使用 `opencv-python-headless`* --- ### 二、第一个OpenCV程序:读取显示图像 ```python # 1. 导入库 import cv2 # 2. 读取图像(注意路径中的斜杠方向) image = cv2.imread("test.jpg") # 替换为你的图片路径 # 3. 检查是否读取成功 if image is None: print("⚠️ 图像加载失败!请检查路径是否正确") else: # 4. 创建窗口并显示图像 cv2.namedWindow("My First OpenCV Window", cv2.WINDOW_NORMAL) cv2.imshow("My First OpenCV Window", image) # 5. 等待按键(0表示无限等待) cv2.waitKey(0) # 6. 销毁所有窗口 cv2.destroyAllWindows() ``` #### 💡 关键点解释: 1. **图像路径问题** - 建议将图片与代码放在同一目录 - 或使用绝对路径:`C:/Users/Name/Pictures/test.jpg`(注意斜杠方向) 2. **颜色空间差异** OpenCV默认使用**BGR格式**(蓝绿红),而其他库(如Matplotlib)使用RGB格式。如果需要用Matplotlib显示: ```python import matplotlib.pyplot as plt plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) plt.show() ``` --- ### 三、基础图像操作 #### 1. 获取图像信息 ```python print("图像尺寸:", image.shape) # 输出 (高度, 宽度, 通道数) print("像素总数:", image.size) print("数据类型:", image.dtype) # 通常是uint8(0-255范围) ``` #### 2. 转换为灰度图 ```python gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) cv2.imshow("Gray Image", gray_image) ``` #### 3. 保存图像 ```python cv2.imwrite("gray_image.jpg", gray_image) # 保存为JPEG格式 ``` --- ### 四、常见问题解决方案 #### ❌ 问题1:窗口一闪而过 ```python # 在cv2.imshow()之后必须添加等待 cv2.waitKey(0) # 0表示按任意键继续 # 或者设置等待时间(单位:毫秒) cv2.waitKey(3000) # 显示3秒后自动关闭 ``` #### ❌ 问题2:图像显示为纯色 检查图像是否加载成功: ```python if image is None: print("加载失败!常见原因:") print("1. 路径中包含中文或特殊字符") print("2. 文件扩展名不匹配(如保存为.jpg却用.png读取)") ``` --- ### 五、学习路线建议 1. **基础阶段** - 图像读写与显示 - 颜色空间转换(BGR↔RGB,BGR↔GRAY) - 绘制几何图形(直线、矩形、文字) 2. **进阶阶段** - 图像滤波(高斯模糊、中值滤波) - 边缘检测(Canny算子) - 轮廓查找与特征提取 3. **实战项目** - 人脸检测(使用Haar级联分类器) - 二维码识别 - 简单视频处理(读取摄像头/视频文件) --- ### 六、推荐学习资源 1. **官方文档** OpenCV官方中文文档:https://woshicver.com/ 2. **实战教程** - 哔哩哔哩:搜索"OpenCV Python教程" - GitHub项目:opencv/opencv 官方示例 3. **工具推荐** - Jupyter Notebook:交互式编程方便调试 - VS Code + Python插件:智能提示提升效率 --- 如果具体遇到某个问题(如图像处理效果不理想、函数参数不理解等),欢迎提供具体代码和现象描述,我可以给出针对性指导! 😊
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董董灿是个攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值