hmmlearn实战:HMM模型选型、数据格式与训练避坑全指南

做时序数据分析的时候,很多时候表面看到的数据背后其实藏着一层看不见的状态在驱动。比如语音信号里不同的音素交替出现,比如股票价格背后牛熊切换,再比如用户行为序列里那些没被直接观察到的意图变化。这种“观测可见、状态隐藏”的序列建模问题,隐马尔可夫模型(HMM)是经典解法,而 hmmlearn 就是 Python 里训练 HMM 最省心的库。这篇文章我直接讲实操,从模型选型到数据格式,从训练细节到调参避坑,把 hmmlearn 跑通 HMM 的完整链路拆开揉碎。

1. 为什么是 HMM,为什么选 hmmlearn

1.1 HMM 在解决什么问题

先对齐一下概念。HMM 假设你看到的数据序列是由一条看不见的“状态链”生成的。每个时刻系统处于某个离散状态,状态按照转移概率矩阵跳转;每个状态下又会按照发射概率产生一个可观测的输出。我们的目标,就是根据观测序列反推出状态序列,或者估计出模型参数,让模型尽可能好地解释数据。

拿一个我实际做过的场景举例。某套设备的状态监测系统里,传感器返回的是连续振动幅值,但设备本身其实只有“正常”“磨损”“即将故障”三种离散工况。振动幅值是连续的观测,工况就是隐藏状态。HMM 恰好能同时完成两件事:一是估计出三种工况各自对应的振动分布,二是根据一段振动序列判断当前最可能处于哪种工况。这类问题用 hmmlearn 来处理,代码量非常小,而且不需要你自己推导 EM 算法。

1.2 hmmlearn 的定位与优势

hmmlearn 最早是从 scikit-learn 里拆分出来的独立库,专门做隐马尔可夫模型,在 PyPI 上可以直接安装。它不是最通用的概率编程框架(比如 PyMC 那种),而是聚焦 HMM 这一件事,开箱即用。

我推荐它的核心原因有三个:

第一,API 设计非常接近 scikit-learn 的习惯,fit()、predict()、score()一脉相承,熟悉 sklearn 的人几乎零学习成本。

第二,内置了三种常用的发射分布模型:GaussianHMM适合观测值是连续向量的场景,MultinomialHMM适合观测值是离散符号的场景,GMMHMM在连续观测但单高斯拟合不够时可以上。

第三,模型训练用的是经典的 Baum-Welch 算法(本质是 EM 算法),前向-后向计算和参数更新全都封装好了,你只需要把数据喂进去。

安装也很简单:

pip install hmmlearn

依赖的 numpy、scikit-learn 等库会自动带上。如果是在 conda 环境里,直接conda install -c conda-forge hmmlearn也行。

2. 动手前先选型:三种模型怎么挑

2.1 GaussianHMM:连续观测值的主力

大多数实际问题里,观测值都不是简单的离散符号,而是连续数值,甚至是多维向量。比如语音的 MFCC 特征、股票收益率、传感器读数。GaussianHMM假设每个隐藏状态下的观测向量服从一个多元高斯分布,每个状态都有自己的均值向量和协方差矩阵。

它在 hmmlearn 里用的参数是covariance_type,有四种选择:spherical、diag、full、tied。

我用一个表格把这几种协方差类型的差别和适用场景列清楚:

类型参数数量适用场景备注
spherical每个状态一个方差标量特征各维度独立且方差相等参数最少,训练最快,但假设太强
diag每个状态一个对角协方差特征各维度独立但方差不同最常用,平衡了自由度和稳定性
full每个状态一个完整协方差矩阵特征维度之间存在相关性参数多,要求数据量大,否则容易过拟合
tied所有状态共享同一个完整协方差矩阵状态差异主要体现在均值上用协方差刻画全局噪声水平,常见于信号处理

我自己在项目里最常用的是diag,因为多维特征之间通常没有那么强的耦合关系,强行用full在小数据集上反而会把协方差矩阵估计得奇奇怪怪。

2.2 MultinomialHMM:离散观测值的场景

如果观测值是离散符号,比如 NLP 里的词性序列、DNA 序列里的碱基、用户点击行为里的页面编号,那就用MultinomialHMM。它每个状态下对应一个类别分布,也就是每个符号在该状态下出现的概率。

需要注意的是,MultinomialHMM 的输入数据必须是非负整数编码。也就是说,你要先把原始符号映射成0, 1, 2, ...这样的索引,否则模型会直接报错。

2.3 GMMHMM:连续观测值更复杂的分布

有些场景下,单个高斯分布描述不清楚状态内的观测分布。比如语音识别中,同一个音素在不同人的发音下可能会呈现双峰或多峰分布,单高斯拟合效果不好。GMMHMM在每个状态下用混合高斯模型(GMM)来建模发射概率,每个状态内部可以有多个高斯成分。

它的额外参数是n_mix,表示每个状态用几个高斯成分。代价是参数数量暴涨,训练时间明显变长,而且更容易陷入局部最优。我的建议是:先用GaussianHMM跑通,如果score明显偏低或者业务上有理由相信分布是多峰的,再换GMMHMM。

3. 训练 HMM 的核心细节:从数据准备到 fit

3.1 数据格式:最重要也最容易翻车的地方

hmmlearn 对训练数据的格式要求非常严格,这一点新手几乎必踩。fit()方法接受的X是一个二维数组,形状是[n_samples, n_features],其中n_samples是所有观测时间步的总数,n_features是每一步观测向量的维度。

关键在于:如果你有多个独立的观测序列,不能简单地把它们拼接成一个大数组,那样会让模型把上一个序列的结尾和下一个序列的开头连在一起,学到根本不存在的转移关系。正确的做法是用numpy.nan作为序列之间的分隔符,让模型知道每个序列在哪里结束、下一条从哪里开始。

直接看代码:

import numpy as np from hmmlearn import hmm # 模拟两个独立序列:每个序列 100 个时间步,每步 2 维特征 seq1 = np.random.randn(100, 2) seq2 = np.random.randn(100, 2) # 中间用 nan 行分隔 X = np.vstack([seq1, np.full((1, 2), np.nan), seq2]) # 对应的序列长度数组(hmmlearn 0.3.0 之后也支持这种方式) lengths = [100, 100]

关于lengths参数,我想多说一句。hmmlearn 在不同版本里对序列长度的处理方式略有变化。旧版本要求你必须传lengths,新版本开始支持NaN分隔后自动推断。我建议在实际项目中两者都写上,兼容性最好,也方便别人阅读你的代码。

如果你只有一个长序列,那就不需要NaN分隔,直接传二维数组即可。

对于MultinomialHMM,数据格式要求是二维整数数组,每个元素是一个离散符号的整数索引。同样,多个序列之间用-1作为分隔符(注意不是NaN,因为整数数组里NaN会被强制转成-1,所以规范做法就是直接放-1)。

3.2 初始化模型的关键参数

创建模型对象时,最核心的参数是n_components,也就是隐藏状态的数量。这个参数你不能让程序自动选,必须你自己根据业务去定。

怎么定?三个思路:

一是领域知识。设备监测就知道有几种工况,语音就知道有几十个音素,直接拿这个数去初始化。

二是数据探索。把观测值做聚类,看看分成几类时轮廓系数最高,用这个数作为n_components的参考。

三是模型比较。分别用不同的n_components训练模型,比较score的结果,选对数似然提升不再明显的那个数。

n_iter控制 EM 算法最大迭代次数,默认是 10,我在项目里通常设到 50 到 100,避免迭代次数不够导致收敛不充分。tol是对数似然增益的容忍度,默认 1e-2,如果你的数据量很大,可以调小到 1e-4,让模型收敛得更精细。

还有一个经常被人忽略的初始化细节:hmmlearn会自动初始化转移矩阵和发射参数。如果你没有指定startprob_prior、transmat_prior之类的先验参数,它用的是均匀分布加一个小的伪计数。对于大多数任务问题不大,但如果你对初始状态分布有先验知识,可以手动塞进去。

model = hmm.GaussianHMM( n_components=3, covariance_type="diag", n_iter=50, tol=1e-4, random_state=42, )

random_state我强烈建议固定。因为 EM 算法对随机初始化敏感,不同种子可能收敛到不同的局部最优解,固定种子能保证结果可复现。

3.3 训练:fit 之后看什么

调用model.fit(X, lengths)之后,训练就完成了。但这里有一个关键点:hmmlearn 的fit()在 0.3.0 版本之前会自动用KMeans对观测数据聚类来初始化发射概率的均值,导致训练结果很大程度上依赖初始聚类点。如果你发现两次训练结果差异很大,可以先检查版本,再用固定random_state压住随机性。

训练完成后,检查模型学到的参数是验证训练是否合理的一步。

print("初始状态概率:", model.startprob_) print("转移概率矩阵:\n", model.transmat_) print("各状态均值:\n", model.means_) print("各状态协方差:\n", model.covars_)

一个有业务意义的模型,学出来的转移矩阵对角线元素通常会偏大,因为状态本身有惯性,不太会疯狂跳来跳去。如果对角线特别小,说明数据里状态切换非常频繁,要么状态数量设多了,要么观测噪声太大。各状态的均值应该明显分得开,如果两个状态的均值向量几乎一样,说明其中一个状态是多余的。

4. 实操一个完整的训练流程

4.1 准备模拟数据

为了把流程走通,我构造一个简单的模拟场景:三状态系统,每个状态产生不同均值的二维高斯观测。两个状态有清晰区分,第三个状态和第一个有轻微重叠,这样可以检验模型的判别能力。

import numpy as np import matplotlib.pyplot as plt from hmmlearn import hmm # 定义真实状态数和观测分布 true_means = np.array([ [-2.0, 0.0], [2.0, 0.0], [0.0, 4.0], ]) covars = np.array([[[0.5, 0.4], [0.4, 0.5]]] * 3) # 生成两个独立序列 lengths = [200, 300] obs = [] for T in lengths: states = [] seq_obs = [] state = 0 for t in range(T): # 模拟一个简单的状态转移:大部分时间留在当前状态,偶尔切换 if np.random.rand() < 0.03: state = np.random.choice(3) states.append(state) seq_obs.append(np.random.multivariate_normal(true_means[state], covars[state])) obs.append(np.array(seq_obs)) X = np.vstack([obs[0], np.full((1, 2), np.nan), obs[1]])

注意这里我在两个序列之间插入了nan行,这是 hmmlearn 组合多条序列的标准姿势。

4.2 训练并观察收敛情况

model = hmm.GaussianHMM( n_components=3, covariance_type="full", n_iter=100, tol=1e-4, random_state=42, ) model.fit(X, lengths)

训练结束后,先看模型是否收敛。可以打印model.monitor_查看收敛信息:

print("收敛是否成功:", model.monitor_.converged) print("迭代次数:", model.monitor_.iter) print("历史对数似然增益:", model.monitor_.history[-5:])

如果converged是False,说明 100 次迭代内没有达到tol的收敛条件。这不是报错,但通常意味着你需要增加n_iter,或者数据本身的似然增长已经非常平缓。对于大数据集,对数似然的增长曲线后期会非常缓慢,tol设成默认值可能永远不收敛,这时候调大tol到 1e-2 反而更实际,因为继续迭代带来的提升已经可以忽略。

4.3 解码:预测每个时刻的状态

predict用的是维特比算法,也就是给定观测序列和模型参数,求最可能的一条状态路径。

states_pred = model.predict(X)

这里X是包含nan分隔行的完整数组。predict返回的是一个长度等于X.shape[0]的一维数组,每个位置对应一个时刻的预测状态。需要注意的是,nan分隔行对应的预测状态是需要忽略的,实际处理中可画图时直接跳过。

对比预测状态和真实状态(如果模拟数据里有真实状态标签)的时候,要注意 HMM 的状态编号和真实状态编号不一定一一对应。模型学到的状态 0、1、2 和真实的状态 0、1、2 可能经过了一次置换。所以计算准确率之前,先做一个状态映射,或者直接算聚类一致性指标(比如 ARI),更科学。

4.4 评估模型:score 的用法和误区

score返回的是对数似然log P(X | model),也就是模型解释这份观测数据有多好。注意这个值是负数,而且会随着序列长度变大而变大(绝对值更大),所以不能拿不同长度序列的score直接比较。

ll = model.score(X, lengths) print("对数似然:", ll)

如果你要用score来选择模型(比如比较不同的n_components),应该在同一份数据上做交叉验证或者留一序列评估,保证比较的公平性。还有一种方式是计算 BIC 或 AIC,把模型复杂度惩罚进去,hmmlearn 没有内置这个功能,但你可以自己算:

n_params = model.n_features * model.n_components * 2 + model.n_components * model.n_components bic = -2 * ll + n_params * np.log(np.sum(lengths))

这里n_params的估算比较粗略,严格来说还要加上协方差矩阵的参数数量,但对于模型选择的参考足够了。

5. 常见报错与避坑实录

5.1 “Input array must be 2-dimensional”

这个报错几乎是新手第一课。hmmlearn 不接受一维数组作为观测序列输入。就算你每个时间步只有一个维度的观测值,X也必须是二维的,形状为[n_samples, 1]。解决办法是加一个reshape(-1, 1)。

X = X_1d.reshape(-1, 1)

5.2 出现 NaN 分隔后 predict 结果出现奇怪的负值或大整数

如果用的是MultinomialHMM,序列之间用-1分隔后,predict结果里可能会出现一个额外状态值,用来对应分隔符的位置,这个值本身没有业务含义。过滤掉即可:

valid_idx = np.all(np.isfinite(X), axis=1) states_clean = states_pred[valid_idx]

5.3 训练时直接崩掉,报协方差矩阵奇异

这个问题的核心是某个状态下的协方差矩阵变成了半正定甚至奇异矩阵,通常是数据量不足、特征维度太高、或者某个状态几乎没有数据点分配到。解决思路有几个:

第一,改用covariance_type="diag",减少协方差矩阵的自由参数。

第二,检查是否有某个状态在迭代中逐渐失去了所有数据点。如果是,把n_components调小,或者手动调整初始均值,让各状态的初始覆盖更均匀。

第三,如果数据确实太少,可以调大min_covar参数(默认是 1e-3),给协方差矩阵的对角线加一个小的正则项。

5.4 随机种子带来的结果不可复现

我把random_state当成项目中不可省略的参数,不是因为它能提高精度,而是因为它能让你在调参过程中拿到可复现的结果。否则同样的代码跑两遍,训练出来的模型参数不同,排查问题时非常气人。提交代码或者写文档时,一定要写明用的是哪个种子。

5.5 状态数量选多了

很多同学觉得n_components越大越好,实际上不是。状态多了之后,模型容易把一些本来属于同一状态的观测强行拆成几个状态,导致状态之间区分度低,而且转移矩阵变得稀疏甚至出现毫无意义的转移。我通常会用 BIC 来辅助判断,状态数在 BIC 曲线的最低点附近就是比较合理的选择。当然最终还要看业务解释性——你分出来的状态能不能对上实际业务含义,对不上的状态再多也是噪声。

6. 我自己用 hmmlearn 的几个经验

这套流程我在几个项目里都跑过,说几个可能是文档里不会明说、但非常影响体验的细节。

一个是fit的输入数据最好提前做标准化或者归一化。hmmlearn 的单高斯发射模型对特征的尺度很敏感,如果某个特征的值域是 0 到 1,另一个特征的值域是几千到几万,协方差矩阵会很难估计,score的提升也会很别扭。我一般先做StandardScaler或者MinMaxScaler,这样训练稳定性和收敛速度都会好很多。

另一个是多序列训练时的lengths处理。我踩过一次坑,在官方文档和 GitHub issue 里翻到过好几种说法,最后确认下来:lengths必须是一维整数数组,每个元素是每个序列的步数,而且所有长度之和必须等于X中有效样本数(不含nan行)。如果你用的是NaN分隔,那么lengths可以省略,但要小心版本兼容性。

还有一个经验是关于预测结果的可视化。我习惯在训练完成后把predict得到的状态序列画成阶梯图,叠加在原始观测序列上。这样一眼就能看出状态切分是否符合业务直觉。很多时候模型训练指标不错,但画出来才发现状态切换非常频繁、毛刺特别多,这通常说明观测噪声太大或者状态数不合适,比单纯看score直观得多。

最后补充一句,hmmlearn 对于大多数中小规模序列建模任务已经完全够用,但如果你的序列特别长(几十万步以上)或者状态数特别多(几十个甚至上百个),训练速度会成为一个瓶颈。这时候可以考虑用GaussianHMM加spherical协方差跑一版快速验证,再换回更精细的模型调优,不要一上来就上最复杂的配置。

相关新闻

工程数据异常值判定与处理:从统计到机器学习的完整实战指南

工程数据异常值判定与处理:从统计到机器学习的完整实战指南

干过工程数据分析的人&#xff0c;恐怕都遇到过这种场景&#xff1a;一组好好的应力测试数据&#xff0c;突然蹦出两个离谱的峰值&#xff1b;传感器采集的温度曲线&#xff0c;凌晨三点莫名跳变到两百多度&#xff1b;疲劳试验的位移记录里&#xff0c;出现一个反向的负值。你…

2026/10/20 8:32:01 阅读更多 →
STM32F107 USB HOST读写U盘全攻略:枚举、Mass Storage与FatFs

STM32F107 USB HOST读写U盘全攻略:枚举、Mass Storage与FatFs

简介&#xff1a;基于STM32F107的USB主机读写U盘完整工程包&#xff0c;面向嵌入式开发者和相关课程设计/毕业设计人员&#xff0c;帮助解决在Cortex-M3平台通过USB主机模式挂载U盘并读写文件的实际问题。工程以ST官方固件库与FatFS文件系统为两条主线&#xff0c;覆盖HAL/LL库…

2026/10/20 8:32:01 阅读更多 →
壹牛NFT数藏系统源码拆包:从盲盒到二级市场的完整链路

壹牛NFT数藏系统源码拆包:从盲盒到二级市场的完整链路

简介&#xff1a;这是一套面向NFT数字艺术藏品平台开发者与创业团队的数藏系统源码&#xff0c;采用全开源方式交付&#xff0c;适合具备一定前后端基础、希望快速搭建或二次开发数字藏品平台的工程师参考使用。压缩包共2004个文件&#xff0c;约245.13MB&#xff0c;以1286个j…

2026/10/20 8:32:01 阅读更多 →

最新新闻

四轮转向联合仿真与滑模控制:从模型搭建到参数整定

四轮转向联合仿真与滑模控制:从模型搭建到参数整定

2. 四轮转向联合仿真&#xff1a;从模型搭建到滑模控制落地四轮转向&#xff08;4WS&#xff09;这几年在车辆动力学圈子里热度一直没降过&#xff0c;低速机动性、高速稳定性这两顶帽子扣上去&#xff0c;几乎所有做底盘控制的人都绕不开。但真正动手做过联合仿真的朋友应该都…

2026/10/20 9:19:43 阅读更多 →
GESP二级选择判断备考:高频考点、破题技巧与避坑清单

GESP二级选择判断备考:高频考点、破题技巧与避坑清单

GESP二级的选择判断&#xff0c;向来是被很多人低估的一块。有人觉得编程题才是主角&#xff0c;选择题随便蒙蒙就完了&#xff0c;结果成绩出来&#xff0c;编程题写得还可以&#xff0c;客观题却错了一堆&#xff0c;等级直接拉低一个档次。我自己当年备考二级的时候&#xf…

2026/10/20 9:19:43 阅读更多 →
嘉立创EDA网络机制详解:从飞线到敷铜的PCB设计避坑指南

嘉立创EDA网络机制详解:从飞线到敷铜的PCB设计避坑指南

开头嘉立创EDA上手其实不难&#xff0c;新手画个双层板&#xff0c;原理图拉几条线&#xff0c;导入PCB&#xff0c;跟着飞线把线连完&#xff0c;板子就算出来了。但很多人卡在一个很基础的概念上——网络。你看飞线是虚线&#xff0c;点上去能高亮一堆引脚&#xff0c;但为什…

2026/10/20 9:19:43 阅读更多 →
AI翻车视频爆火背后:观众看的不是成品,而是人机缠斗

AI翻车视频爆火背后:观众看的不是成品,而是人机缠斗

成品没人看、翻车刷屏&#xff0c;这个“播放量超5000万”的现象我在几个交流群里都聊到过。很多人羡慕那个数字&#xff0c;但没搞明白&#xff1a;观众看的根本不是AI生成的内容&#xff0c;而是一个人试图控制AI时暴露出来的狼狈、荒诞和不可预测。AI短剧成品当然有人做&…

2026/10/20 9:19:43 阅读更多 →
低QPS系统如何降本?从资源画像到弹性伸缩的实践指南

低QPS系统如何降本?从资源画像到弹性伸缩的实践指南

1. 面对这个面试题&#xff0c;先想明白面试官在考察什么前阵子面了一家金融科技公司的后端岗位&#xff0c;二面的时候面试官抛了个问题&#xff1a;假如当前系统QPS只有100&#xff0c;你作为负责人&#xff0c;怎么把成本降下来&#xff1f;听到这个题我愣了一下&#xff0c…

2026/10/20 9:19:43 阅读更多 →
大数据可视化模板实战:从选型、数据接入到问题排查

大数据可视化模板实战:从选型、数据接入到问题排查

简介&#xff1a;面向数据分析师、产品经理、市场运营及企业决策者的大数据可视化模板合集&#xff0c;包含近25套大屏统计模板&#xff0c;重点解决大屏场景下数据展示单调、图表类型缺失与响应式适配难等实际问题&#xff0c;支持业务监控、市场分析和运营报告等需求。压缩包…

2026/10/20 9:18:33 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →