CSYS5030 Week 05 The JIDT Software 讲课总结

CSYS5030 Week 05 讲课总结:The JIDT Software

课程:CSYS5030 — Information Theory and Self-Organisation 讲师:Associate Professor Joseph Lizier 对应模块:Module 5 - The JIDT software 来源:Week 05 seminar 字幕 + Canvas Module 5 页面 Tutorial 覆盖:Items 3、5(确保 JIDT 装好、AutoAnalyser 跑通)→ Item 7(bias & variance,开始扩展 JIDT 生成的代码)→ 继续做 optional assignment 或 Item 8(extension:用 JIDT 重做之前的练习)

这一讲是全课程的转折点。前 4 周的入门模块(entropy / mutual information / conditional mutual information)收尾,从这周开始进入第二模块 empirical analysis with information theory(Week 5–8,为期 4 周),开始处理真实世界、往往是连续值的数据。这周本身没有引入新理论,重心是把 JIDT 装起来、跑通,为接下来几周的 estimator、统计显著性内容打地基。老师特意把这周内容留得比较轻,专门空出第一小时来做 weeks 1–4 的答疑,因为 mutual information / conditional mutual information 是贯穿全课程的关键概念。


零、课程大版图:三大板块走到哪了

板块 周数 内容 关键词
1. Introduction to Information Theory Week 1–4(已完成) 熵、互信息、条件互信息的基本概念与性质 entropy, MI, CMI
2. Empirical Analysis with Information Theory Week 5–8(本周起) 用这些度量分析真实数据集,处理连续值数据的 estimator、统计显著性 JIDT、estimators、significance testing
3. Information Processing in Complex Systems Week 9–13 多变量数据集里信息如何被存储、传递,如何反推有向网络结构 storage, transfer, network inference

老师的说法:第二板块后半段会开始更系统地用这些度量给自己的数据集提问,理解数据里的关系与动态;第三板块则是深挖多变量系统,是全课程应用的高峰。


一、这周课堂安排与几件 Admin 事项

  • 第一小时:纯答疑,针对 weeks 1–4 的材料。Module 页面要求课前把问题写下来发到 Menti 链接上(也可以给别人的问题点赞,老师按票数从高到低回答),课上先分组 brainstorm 5 分钟,方向有三类:理论问题、想重讲/深挖的 tutorial 题、怎么把这些度量用到数据上。老师说甚至可能把整个第一小时都留给这个。
  • Module 页面说明:这周内容故意留得轻,一是给前四周基础内容留巩固时间,二是让大家继续做 assessment 1(optional calculation exercises)。
  • 第二小时:JIDT 概览 + 现场装机,Alex 和老师会在教室里巡场帮忙排错;如果已经装好且跑通了,可以直接跳去做 tutorial 任务或可选的 extension/练习,不用干等。
  • 不再做每节课开头的小 poll 了。
  • 本周三(周中)因为学校罢工,tutorial 临时改到 Zoom 上(下周恢复线下)。
  • 学校在做期中 teacher check-in 问卷,tutorial 里会留时间填;学生代表(Jeet Amit Shah)也可以用来反馈不方便直接跟老师说的问题。

二、答疑回顾:Week 1–4 内容再梳理

2.1 "一比特信息 = 把不确定性砍一半" —— 轮盘赌例子

问题:一比特信息让不确定性减半,这个说法怎么理解?和别的底数(base 3、base 4)什么关系?

从 pointwise mutual information 出发:

这是在比较看到 之后的后验概率与完全不看 的先验概率。当 时:

也就是说,知道 之后,我们观察到那个 的可能性变成了原来的两倍。

轮盘赌类比:假设一个理想化的轮盘,36 个数字,单双数(实际上是红黑)各占一半。

  • 不知道颜色时:
  • 已知这次转出来的是黑色(而 4 恰好是黑色数字):黑

告诉你"是黑色"这一个比特的信息,直接排除了一半的可能数字(不可能是 1、3、5……),所以说这一比特信息把不确定性砍了一半。

要澄清的误解:这不代表每次获得 1 bit 信息都会像上面这样干净利落地排除一半选项。更一般的情况下,拿到新信息可能只是重新分配各个结果的概率(有些概率升、有些降),不一定真的把一半选项直接排除。但只要信息量算出来正好是 1 bit,从信息量的角度看,它和"排除一半选项"这件事是等价的——这只是一个帮助建立直觉的类比,不是字面意义上都会发生的事。

换底数(base)会怎样:上面的推导完全不依赖字母表大小(36 这个数字根本没出现在推导里),所以换成 base 3 或 base 4 的字母表,"1 bit ⟺ 后验/先验概率比为 2"这个结论照样成立。真正被换掉的是对数的底:如果用 而不是 ,单位就不再叫"bit",而是 base-4 下的"1 unit",这时候 1 unit 对应的是概率比变成 4,不再是"砍一半",而是"砍到 1/4"。换句话说:bit(用 )永远对应"概率比 2 / 砍一半",换了底数只是换了这个比例数字与单位名称,原理不变。

2.2 除了 Shannon 信息,还有别的度量家族吗?—— Rényi 熵

答案:有,但这门课只用 Shannon 信息这一家族。

  • 目前学过的四个基础量——entropy、conditional entropy、mutual information、conditional mutual information——全部都建立在 Shannon information content 之上。后面会学到的 transfer entropy 之类的新名词,本质上也只是"条件互信息用到时间序列上的特例",不是新的公理体系。
  • Week 2 提到过,熵/信息内容可以从几条公理推出来,老师这次只重复了其中两条:随着样本概率降低而单调递增,以及具备可加性/链式法则(additivity / chain rule)。
  • 其他家族(比如 Rényi 熵,把概率取幂而不是直接用,像 、)满足不同的公理组合,在某些场景下更合适,但回答的是不同的问题——呼应老师常说的"信息论就是关于问题和答案"。这门课选 Shannon 家族,是因为它的公理最贴合我们想要的"不确定性/惊讶程度"这个基本概念。

2.3 记号规则:逗号、分号、条件竖线怎么摆

这是个常见易错点,规则总结如下:

度量 可以有几个逗号(joint) 可以有几个分号 可以有几个条件竖线 \mid
Entropy 任意多个 0 个(分号在熵里没有意义) 最多 1 个
Mutual Information 分号两侧各自可以任意多个 恰好 1 个(分隔"要问信息的两组变量") 最多 1 个
  • 条件变量(竖线右边)本身也可以是多变量的(有很多逗号),但条件竖线本身只能出现一次。
  • 分号运算符只会出现在条件竖线的左边——因为我们问的是"两组变量之间、在已知第三组变量条件下"的信息量。
  • 超过两个变量的"互信息"推广(比如三变量、四变量共享的信息)确实存在,Week 8 会简单提一句,但老师明确说这没有很好的、公认的定义,这门课不会深入。

2.4 条件互信息 = "先固定、再平均"(Week 4 内容的再确认)

再次强调 的构造方式:

  1. 先固定 取某个具体值 ,在这个特定情境下算一个"普通"互信息,只是所有概率都换成条件于 的版本。
  2. 这个值依赖于具体是哪个 ,所以对所有可能的 按 加权平均,就得到整体的条件互信息。
  3. 等价地,可以把 里所有出现 的概率项都换成"条件于 "的版本(比如 换成 ),这样重新整理出来的式子,就是我们平时看到的 公式。

2.5 Pointwise Mutual Information 手算实例:Guess Who 的 horns & eyebrows

这是 Week 3 tutorial(Guess Who / "kooky" 角色卡)里的经典例子,这次老师现场带大家重新过了一遍手算过程,很值得记下来。

24 个角色的 2×2 列联表(是否有角(horns)× 是否有眉毛(eyebrows)):

eyebrows = yes eyebrows = no 行合计
horns = yes 3 2 5
horns = no 8 11 19
列合计 11 13 24

问题:已知一个角色既有角、又有眉毛,"有角"这件事给了我们多少关于"有眉毛"的信息(pointwise mutual information)?

  • :只看"horns=yes"这一行, 个里有眉毛,共 个,所以是 。
  • :全表里有眉毛的角色共 个,共 个,所以是 。

两种读法:

  1. 概率比读法:知道"有角"之后,这个角色"有眉毛"的可能性变成了原来的约 1.31 倍——比值越大,信息量越大。
  2. 惊讶量差值读法: 是"看到有眉毛"这件事本身带来的惊讶;减去 (已知有角之后,看到有眉毛还剩多少惊讶),两者的差就是从"有角"这件事里得到的、关于"有眉毛"的信息。

这个例子之所以比之前讲的轮盘赌例子更有代表性,是因为轮盘赌那个例子里每个具体取值算出来的 pointwise 信息量都一样(不够有区分度);而 horns/eyebrows 这种真实一点的列联表,不同取值组合的 pointwise 信息量是不一样的,更能体现"pointwise"的意义。

2.6 Maximum Likelihood Estimation(MLE)与 Bias / Variance ——下周内容预告

这是这次答疑里信息量最大的一段,提前给下周"estimators"做铺垫。

我们目前一直在用的,其实就是 MLE(又叫 plug-in estimator):

  • 从一批样本里,数出 的每个取值出现了多少次,除以总样本数,直接当作概率代入熵/互信息的公式——这就叫 plug-in estimator,因为是把从数据里数出来的频率直接"插"进公式里。
  • 这样算出来的值,在统计学上正好等于最大似然估计值(maximum likelihood estimate),所以这个估计量也叫 MLE。

关键认知:

  • 如果我们有真实的概率分布,可以直接精确计算熵/互信息——这是"计算"。
  • 如果我们只有一批有限样本,并从中估计概率再代入公式,得到的就只是估计值,不是真值——这是"估计"。
  • MLE 给出的值是"在拿到这批数据的前提下,最可能"的取值,但拿到的数据本身是随机的,所以这个估计值本身也是一个随机变量,真实值可能落在它两侧的某个范围里。

Bias(偏差)与 Variance(方差):

  • Bias:估计量平均偏离真实值的程度——理想情况下希望即使样本量不大,偏差也很小。
  • Variance:换一批同样大小的新样本重新估计,得到的值波动有多大——理想情况下希望波动小,不会一批数据一个样。
  • 举例(呼应前几周抛硬币的活动):理论上抛一枚公平硬币,每次结果的自信息应该正好是 1 bit。但如果只抛 10 次去估计正反面概率,很可能不是刚好 5:5(比如 4:6 或 3:7),这样算出来的信息量估计值就会偏离真实的 1 bit——这就是小样本下 plug-in 估计量的系统性问题,后面几周会讲怎么修正这种偏差。

2.7 熵越大,平均要问的问题越多

问题:需要的比特数越多,是不是就意味着要问更多问题才能确定一个变量的取值?

回答:在"熵"(平均意义)这个层面上是对的。如果一个变量平均有 4 bits 的不确定性,并且你每次都问最优的 50/50 二分问题,那平均下来需要问 4 次才能确定它的值。但对某一次具体的取值,所需问题数可能比平均值多或少——比如之前赛马的例子里,有一匹马 50% 概率获胜,只需要 1 个问题就能确定它是否获胜,但确定别的马是否获胜可能需要更多问题,平均下来落在中间。

2.8 还想多巩固 entropy/information 的直觉?

老师给的三个方向:

  1. 课程里散落的 extension 活动(比如英语文本 parsing 的练习)以及没有打分的 optional assignment/exercise,答案会在后续几周公布。
  2. 选读材料里附带的习题,比如经典教材 Cover & Thomas——但要注意这本书的习题偏向编码理论的视角,风格和这门课不完全对齐,需要自己甄别哪些题目和课程要求的角度接近。
  3. 讨论区:optional calculation exercises 配了专门的讨论帖,可以在这里提问、讨论解读,有需要澄清的问题老师和助教会介入。

三、JIDT 是什么

JIDT(Java Information Dynamics Toolkit) 是这门课接下来会一直用的软件工具:

  • 一个独立实现了目前学过的所有信息论度量的工具包,同时还打包了课程后半段会用到的更高级度量,比如 transfer entropy。
  • 同时支持离散数据和连续值数据,针对不同数据类型内置了不同的 estimator(这是接下来几周的重点)。
  • 底层用 Java 写的,但绝大多数同学(几乎全班)用 Python,通过 JPype 这个库桥接到 Java 后台,MATLAB 用户也有对应支持。
  • 分发包里还包含:自动生成代码的 GUI 工具(Auto Analyser)、完整文档、Wiki、大量 demo、源码、单元测试、自动构建脚本,以及一篇介绍工具的论文预印本 PDF。
  • 设计上大量用了 Java interface,意味着以后想换一种 estimator(比如从离散换成连续值的估计方式),接口是统一的,切换起来很快——这也是接下来几周要讲的重点内容。

Module 页面的一句实话:在离散数据上算 entropy 和 MI 时,JIDT 相比我们前四周自己写的简单估计代码暂时看不出什么优势——它的价值要等到后面处理更复杂的度量和估计器时才会体现出来。

另外注意:JIDT 的离散 calculator 只接受整数,取值范围必须是 0 到 alphabetSize-1。

本周视频讲座结构(Module 页面):

Part 内容 对应 Item
1 Overview Item 2
2 Installation Item 2(配合 Item 3 的安装说明)
3 Contents of distribution Item 4
4 AutoAnalyser GUI Item 5
5 Usage paradigm (discrete) Item 6

老师在页面上注明:视频里某些属性的弹出说明是不对的,以 GUI 实际显示为准。

参考阅读(非必读):Lizier (JIDT) 论文的 Section III 和 IV;Bossomaier et al. §3.4.1(到 3.4.1.2 为止)和 §3.4.2(到 3.4.2.1 为止)——后者更深,不会全部用到。


四、安装 JIDT:步骤与排坑指南

  1. 下载:在 JIDT Wiki 的 Installation 页面选 option 2,下载最新发行版的 zip 包。高级用户也可以 clone / fork git 仓库,但发行包里带编译好的二进制,省得自己用 ANT 构建。
  2. 解压:解压到一个"靠谱"的位置。Mac 用户尤其要避开 Downloads 和 Documents 目录(原因见 5.2 的排坑)。
    • 如果在教室电脑上装,可以直接解压到 U 盘,下次课或换电脑还能接着用。
    • 老师以后如果更新了代码(比如为课程加新例子或新函数),直接把新发行包解压覆盖旧的就行。
  3. 检查依赖:Installation 页面列的依赖里,只需要看 1 和 5(2–4 是给高级用户的)。
    • 依赖 1 明确指 JDK,不是 JRE:命令行能跑 java 不够,还必须能跑 javac。
    • 64 位机器必须装 64 位 Java。
    • Mac:brew install openjdk
    • Windows:去 Oracle 官网下载。
    • Linux:用发行版自带的包管理器。
    • 装完后设置 JAVA_HOME 环境变量指向 Java 所在位置(不熟悉的话搜 "set JAVA_HOME" + 你的系统)。
    • ⚠️ 装完 Java 或改完环境变量后,一定要重启 Python notebook / VS Code / 终端等。Module 页面特意强调:很多问题就是忘了重启,重启一下往往就好了。
  4. Python 依赖:见 Module 0 里 Python 的说明,最关键的是 JPype——它负责桥接到后台的 Java 库。64 位机器上不要装 32 位 Python!(MATLAB 用户不需要检查这些额外依赖。)
  5. Platform Check Notebook:把这个 notebook 下载到 JIDT 解压目录下的 demos/python 文件夹,然后逐个 cell 运行,它会自动检查每一项依赖是否就绪。最容易踩的坑是:Python 解释器的位数(32-bit / 64-bit)必须和操作系统架构一致——如果之前装的是 32 位 Python,后面全都跑不通,需要重装 64 位版本。
  6. 还是卡住:tutorial 时段会有现场支持;另外 Alex 会在周四晚安排一个专门的 Zoom drop-in session,去之前记得先把 platform check notebook 的运行结果准备好,方便远程诊断问题。

五、Auto Analyser:用 GUI 生成计算代码

5.1 这是什么、为什么存在

Auto Analyser 是 JIDT 自带的一个图形界面工具,用来生成计算代码。老师的原话是:在 Generative AI 出现之前,这基本上就是"当年版本的 Gen AI"——目的是让大家不用一开始就纠结底层代码细节,能快速跑起一个计算,再在生成的代码基础上修改扩展。

5.2 启动方式

  • 最简单:直接双击 JIDT 解压目录顶层的 infodynamics.jar 文件,会弹出选择"要估计哪种度量"的菜单。
  • 如果双击没反应,常见原因是没有单独安装 JRE。两个解决办法:按 Installation wiki 页面装 JRE;或者不装 JRE,纯在 Python/MATLAB 里启动——运行 demos/AutoAnalyser 目录下对应的 launchAutoAnalyser.py(或 .m、.sh)脚本。

Module 页面 Item 5 列出的平台排坑清单:

平台 症状 解决办法
Mac 双击 jar 提示 "Unable to locate a Java Runtime",即使已经装了 JDK、设了 JAVA_HOME 可能是 Homebrew 的配置问题,在终端建一个符号链接:sudo ln -sfn /opt/homebrew/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk
Mac 提示 "Security Issue"(jar 不是来自已验证的开发者) 右键 jar → Open,再去 System Settings → Privacy & Security 点 Open Anyway;还不行就退回到终端里运行 demos/AutoAnalyser/launchAutoAnalyser.sh
Mac JIDT 放在 Downloads 或 Documents 下时,选数据文件时看不到 demos/data 里的文件(只在双击 jar 启动时出现,命令行启动没问题) 系统没给文件访问权限。要么把 JIDT 挪出这两个目录,要么去 System Preferences → Security → Privacy → Full Disk Access,把 /System/Library/CoreServices/Jar Launcher.app 加进去
Linux "For security reasons, running the file 'infodynamics.jar' has been blocked" 右键 jar → Open With → Other Application → Custom Application → 填 '/usr/bin/java' -jar → 勾 Set as default → OK

5.3 操作步骤演示(以 Mutual Information 为例)

沿左侧面板从上到下依次完成:

  1. 选择度量:这次选 Mutual Information。
  2. 选择 estimator:目前只学过离散数据上的估计方式,所以先选离散(discrete)estimator——连续值的 estimator 是接下来几周的内容。
  3. 选择数据文件:分发包 demos/data 目录下自带一批样例 CSV,格式和之前 Scissors-Paper-Rock 用的一样——行是样本,列是变量,以 % 开头的行当注释处理。如果自己的数据不是这个格式,也没关系,先用样例文件生成一版代码,之后回头把"读数据"那一步换成自己的读取逻辑就行。
  4. 指定 source / target 列号:0-based 索引,默认是第 0 列到第 1 列,也可以改成别的列组合。
  5. 填写 estimator 参数:对离散估计器,最关键的参数是字母表大小 / base。这里有个现场翻车的演示:数据实际上是 4 进制的(取值范围 0–3),但参数默认填的是 base = 2,直接报错——提示数据超出了预期的取值范围,必须把参数改成与数据匹配的 base = 4。
  6. 点 Generate code and compute。

5.4 演示结果:两组数字说明"参数/建模方式一变,结论完全不同"

用来演示的样例数据是 two coupled discrete columns(10000 行、2 列、base = 4):

计算方式 结果 解读
按样本对应位置(第 行 X 对第 行 Y)算 MI 0.0007 bits 几乎没有信息——同一时刻两列看起来"没关系"
打开 time difference 属性(把数据当时间序列,比较滞后一步的关系) 1.0002 bits 信息量陡增——两列真正的耦合关系体现在"滞后一步",而不是同一行对齐

这组对比其实是在给下周的内容打埋伏:同一份数据、换一种"怎么配对样本"的方式,结论可以天差地别——这也是为什么之后会专门花时间讲 estimator 的选择和统计显著性检验,而不是拿到一个数字就直接下结论。

5.5 生成的产物

点击 Generate 之后:

  • 右侧面板同时给出 Java、Python、MATLAB 三种语言的等价代码(这门课重点看 Python)。
  • 代码会被写入 demos/AutoAnalyser 目录下的 calculator.py(和 MATLAB 版的 .m 文件)。Mac 上有时候写文件会报错(状态栏提示无法写入),这不影响使用,直接从界面里手动复制粘贴代码出来即可。

六、生成代码的固定结构(五步走)

不管具体计算什么度量,Auto Analyser 生成的 Python 代码都遵循同一套流程,以后自己扩展代码时可以按这个模板改:

  1. 环境初始化:通过 JPype 设置好 JIDT 所在的路径,启动后台的 Java 虚拟机(JVM),连接到 infodynamics.jar 这个 Java 类库。这一段以后每次用 JIDT 都原样贴到 notebook 最上面的 cell 里执行一次即可。
  2. 读取数据:默认从上面选定的 CSV 文件里加载数据。如果自己的数据格式不一样,只需要替换这一步的读取逻辑,后面的步骤照抄不用改。
  3. 构造 calculator 对象并传入参数:比如 base=4 这种参数,GUI 里填的数字会原样反映到这里,不需要自己再去查文档格式怎么写。
  4. 初始化(initialise()):为计算做准备;更复杂的 calculator(以后几周会遇到)在这一步能设置的东西更多。同一个对象可以重新 initialise 来清空数据、复用来做下一次计算,不用每次都重新构造对象。
  5. 添加数据(addObservations())+ 计算(compute):可以多次调用 addObservations() 把多组观测加进同一次计算(比如 Scissors-Paper-Rock 里按对局场次分别添加),最后调用计算方法拿到结果。默认算出来的是 average 值;如果想要每个样本各自的 pointwise 值(比如 pointwise mutual information),需要用别的方式取,这是接下来几周会讲到的内容。

七、Tutorial 安排

  • 已经把 JIDT 装好、跑通上面两个演示数字的同学,可以直接跳到 Item 7(第一个 extension item)。
  • Item 8 是可选的 extension:把前几周用自建工具库做过的练习,换成用 JIDT 重新做一遍,用来对照、巩固。
  • 这周 tutorial 正式的任务是围绕答疑里提到的 bias / variance 话题展开,用 notebook 对 Auto Analyser 自动生成的代码做一些延伸练习。
  • Optional calculation exercises 继续开放,截止日期 Sep 6(见 Canvas Assignments),不计分,用来自我检验对前四周内容的理解。

八、下周预告 & 本周复习清单

下周(Week 6) 正式进入 information-theoretic estimators:会系统讲不同 estimator 的种类、bias / variance 的严格定义,以及怎么修正 plug-in estimator 的系统性偏差。

复习清单:

  1. Plug-in estimator = Maximum Likelihood Estimator:直接把样本频率当概率代入公式;算出来的值是"给定这批数据后最可能"的值,但仍然是估计,不是真值。
  2. Bias(估计值平均偏离真值的程度)和 Variance(换批样本后估计值的波动程度)是评价一个 estimator 好坏的两个核心指标——小样本、plug-in 方式容易在两者上都吃亏。
  3. 记号规则:entropy 里逗号(joint)可以任意多,条件竖线最多 1 个;mutual information 必须恰好 1 个分号,竖线最多 1 个,分号只出现在竖线左边;两个以上变量的"互信息"没有公认定义(Week 8 才会略提)。
  4. 1 bit ⟺ 后验/先验概率比为 2,与字母表大小无关;换底数只是换单位和对应的比例数字,不改变原理。
  5. Pointwise mutual information 手算流程:构造列联表 → 算条件概率与边际概率 → 取 log 比值(Guess Who 例子里 horns→eyebrows 得到 0.39 bits)。
  6. JIDT 装机三件套:release 二进制 zip(而不是自己 clone 源码编译)+ 完整 JDK(不是只有 JRE,记得配 JAVA_HOME)+ Platform Check Notebook(重点检查 Python 位数是否与系统架构匹配)。
  7. Auto Analyser 只是脚手架:数据格式(CSV,行=样本、列=变量)、列号(0-based)、尤其是 base/字母表大小这些参数必须自己对齐数据实际情况,填错会直接报错或者算出没有意义的数字。
  8. 同一份数据、不同的样本配对方式(是否引入时间滞后)可以得出完全不同的互信息结论——这是接下来讲统计显著性和 estimator 选择的重要动机。