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"这个结论照样成立。真正被换掉的是对数的底:如果用
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 内容的再确认)
再次强调
- 先固定
取某个具体值 ,在这个特定情境下算一个"普通"互信息,只是所有概率都换成条件于 的版本。 - 这个值依赖于具体是哪个
,所以对所有可能的 按 加权平均,就得到整体的条件互信息。 - 等价地,可以把
里所有出现 的概率项都换成"条件于 "的版本(比如 换成 ),这样重新整理出来的式子,就是我们平时看到的 公式。
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.31 倍——比值越大,信息量越大。
- 惊讶量差值读法:
是"看到有眉毛"这件事本身带来的惊讶;减去 (已知有角之后,看到有眉毛还剩多少惊讶),两者的差就是从"有角"这件事里得到的、关于"有眉毛"的信息。
这个例子之所以比之前讲的轮盘赌例子更有代表性,是因为轮盘赌那个例子里每个具体取值算出来的 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 的直觉?
老师给的三个方向:
- 课程里散落的 extension 活动(比如英语文本 parsing 的练习)以及没有打分的 optional assignment/exercise,答案会在后续几周公布。
- 选读材料里附带的习题,比如经典教材 Cover & Thomas——但要注意这本书的习题偏向编码理论的视角,风格和这门课不完全对齐,需要自己甄别哪些题目和课程要求的角度接近。
- 讨论区: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:步骤与排坑指南
- 下载:在 JIDT Wiki 的 Installation 页面选 option 2,下载最新发行版的 zip 包。高级用户也可以 clone / fork git 仓库,但发行包里带编译好的二进制,省得自己用 ANT 构建。
- 解压:解压到一个"靠谱"的位置。Mac
用户尤其要避开 Downloads 和 Documents 目录(原因见 5.2 的排坑)。
- 如果在教室电脑上装,可以直接解压到 U 盘,下次课或换电脑还能接着用。
- 老师以后如果更新了代码(比如为课程加新例子或新函数),直接把新发行包解压覆盖旧的就行。
- 检查依赖: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 页面特意强调:很多问题就是忘了重启,重启一下往往就好了。
- 依赖 1 明确指 JDK,不是 JRE:命令行能跑
- Python 依赖:见 Module 0 里 Python 的说明,最关键的是 JPype——它负责桥接到后台的 Java 库。64 位机器上不要装 32 位 Python!(MATLAB 用户不需要检查这些额外依赖。)
- Platform Check Notebook:把这个 notebook 下载到 JIDT
解压目录下的
demos/python文件夹,然后逐个 cell 运行,它会自动检查每一项依赖是否就绪。最容易踩的坑是:Python 解释器的位数(32-bit / 64-bit)必须和操作系统架构一致——如果之前装的是 32 位 Python,后面全都跑不通,需要重装 64 位版本。 - 还是卡住: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 为例)
沿左侧面板从上到下依次完成:
- 选择度量:这次选 Mutual Information。
- 选择 estimator:目前只学过离散数据上的估计方式,所以先选离散(discrete)estimator——连续值的 estimator 是接下来几周的内容。
- 选择数据文件:分发包
demos/data目录下自带一批样例 CSV,格式和之前 Scissors-Paper-Rock 用的一样——行是样本,列是变量,以%开头的行当注释处理。如果自己的数据不是这个格式,也没关系,先用样例文件生成一版代码,之后回头把"读数据"那一步换成自己的读取逻辑就行。 - 指定 source / target 列号:0-based 索引,默认是第 0 列到第 1 列,也可以改成别的列组合。
- 填写 estimator 参数:对离散估计器,最关键的参数是字母表大小 / base。这里有个现场翻车的演示:数据实际上是 4 进制的(取值范围 0–3),但参数默认填的是 base = 2,直接报错——提示数据超出了预期的取值范围,必须把参数改成与数据匹配的 base = 4。
- 点 Generate code and compute。
5.4 演示结果:两组数字说明"参数/建模方式一变,结论完全不同"
用来演示的样例数据是 two coupled discrete columns(10000
行、2 列、base = 4):
| 计算方式 | 结果 | 解读 |
|---|---|---|
| 按样本对应位置(第 |
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 代码都遵循同一套流程,以后自己扩展代码时可以按这个模板改:
- 环境初始化:通过 JPype 设置好 JIDT
所在的路径,启动后台的 Java 虚拟机(JVM),连接到
infodynamics.jar这个 Java 类库。这一段以后每次用 JIDT 都原样贴到 notebook 最上面的 cell 里执行一次即可。 - 读取数据:默认从上面选定的 CSV 文件里加载数据。如果自己的数据格式不一样,只需要替换这一步的读取逻辑,后面的步骤照抄不用改。
- 构造 calculator 对象并传入参数:比如
base=4这种参数,GUI 里填的数字会原样反映到这里,不需要自己再去查文档格式怎么写。 - 初始化(
initialise()):为计算做准备;更复杂的 calculator(以后几周会遇到)在这一步能设置的东西更多。同一个对象可以重新 initialise 来清空数据、复用来做下一次计算,不用每次都重新构造对象。 - 添加数据(
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 的系统性偏差。
复习清单:
- Plug-in estimator = Maximum Likelihood Estimator:直接把样本频率当概率代入公式;算出来的值是"给定这批数据后最可能"的值,但仍然是估计,不是真值。
- Bias(估计值平均偏离真值的程度)和 Variance(换批样本后估计值的波动程度)是评价一个 estimator 好坏的两个核心指标——小样本、plug-in 方式容易在两者上都吃亏。
- 记号规则:entropy 里逗号(joint)可以任意多,条件竖线最多 1 个;mutual information 必须恰好 1 个分号,竖线最多 1 个,分号只出现在竖线左边;两个以上变量的"互信息"没有公认定义(Week 8 才会略提)。
- 1 bit ⟺ 后验/先验概率比为 2,与字母表大小无关;换底数只是换单位和对应的比例数字,不改变原理。
- Pointwise mutual information 手算流程:构造列联表 → 算条件概率与边际概率 → 取 log 比值(Guess Who 例子里 horns→eyebrows 得到 0.39 bits)。
- JIDT 装机三件套:release 二进制 zip(而不是自己 clone
源码编译)+ 完整 JDK(不是只有 JRE,记得配
JAVA_HOME)+ Platform Check Notebook(重点检查 Python 位数是否与系统架构匹配)。 - Auto Analyser 只是脚手架:数据格式(CSV,行=样本、列=变量)、列号(0-based)、尤其是 base/字母表大小这些参数必须自己对齐数据实际情况,填错会直接报错或者算出没有意义的数字。
- 同一份数据、不同的样本配对方式(是否引入时间滞后)可以得出完全不同的互信息结论——这是接下来讲统计显著性和 estimator 选择的重要动机。