Word2Vec详解:从CBOW/Skip-gram到负采样手写实现
1. 从独热到稠密Word2Vec出现前词向量到底卡在哪我刚接触CS224n的时候第一反应是词向量不就是把词变成一串数字吗有什么好学的后来真正把Word2Vec从论文到代码走了一遍才意识到这个看似简单的概念背后是整个NLP从符号主义走向分布式表示的分水岭。在Word2Vec出现之前学界和工业界主流的词表示方式有两种。一种是符号化的比如WordNet这种人工构建的知识库把词义组织成树状结构。问题很明显——人工维护成本极高覆盖不了新词而且同义词、上下位关系的颗粒度完全依赖语言学家的主观判断。另一种是统计式的比如独热编码one-hot。把每个词表示成一个词表长度的向量当前词的位置是1其余全是0。这种方式确实简单但两个致命问题一是词表一大向量维度就爆炸十万词表就是十万维二是任意两个词的向量内积永远是0猫和狗、猫和汽车在向量空间里没有任何区别。后来又有一类基于共现矩阵的方法比如把词和上下文窗口内的词统计共现次数建一个词-词矩阵再做SVD降维。这类方法在Word2Vec之前其实已经能产出一批还不错的向量但CS224n课程里反复强调的痛点就在这里共现矩阵的规模随词表平方级增长一个一百万词的语料矩阵动辄上万亿个元素SVD的复杂度根本扛不住。而且这类方法对高频词有天然偏向the和a这种词的共现关系会主导整体分解方向低频词的信息被稀释得非常严重。所以要理解Word2Vec的贡献不能只盯着它给出了一个能算相似度的向量。真正重要的是它提供了另一条完全不同的思路不再统计全语料的共现矩阵而是让模型在预测任务中不断调整词向量参数让语义信息在训练过程的梯度传播里被蒸馏出来。这就是CS224n课程反复强调的distributional semantics分布语义——一个词的意义由它经常出现的上下文决定而Word2Vec是第一套把这个思想用神经网络落地、并且能在海量语料上高效训练的词向量框架。当时课堂上有一句话我记得特别清楚语义不是被定义出来的而是被使用出来的。理解了这一层再看Word2Vec的两个架构和代码实现思路就顺多了。2. CBOW与Skip-gram的前世今生为什么要搞出两套架构2.1 两套架构在做什么Word2Vec论文里给出两种训练架构CBOWContinuous Bag-of-Words和Skip-gram。它们的任务刚好是对称的。CBOW的任务是用上下文预测中心词。比如句子我 喜欢 喝 咖啡窗口半径设为2那么给定我喜欢喝这些上下文词去预测中间的咖啡是什么。Skip-gram反过来给定中心词咖啡去预测它周围的上下文词我喜欢喝。一开始我有个困惑两种架构看起来只是把输入输出对调效果差别会很大吗CS224n的课后作业和论文实验都给了明确结论——差别不小。在词相似度任务上Skip-gram对低频词的表示明显更好CBOW训练速度更快但对高频词的语义刻画更平滑。原因是这样的Skip-gram每个训练样本只涉及一个中心词和它周围的一个上下文词同一个低频词只要出现几次就能领取几次梯度更新而CBOW是把多个上下文词向量先平均再做预测低频词在平均过程里被高频词稀释了梯度更新的强度被摊薄。如果你去读原始论文的Table部分会发现作者在训练时间和准确率之间做了一个帕累托式的权衡想要快选CBOW想要低频词效果好选Skip-gram。实际工程里多数场景选Skip-gram尤其是语料规模中等、词表覆盖不全的时候它的鲁棒性明显更好。2.2 训练瓶颈与两大战术改良但如果你真的去读CS224n讲义里关于Softmax的部分会发现一个现实问题标准的Softmax在做预测时要对整个词表的每个词算一遍分数再归一化词表十万那每个训练样本就要算十万次向量点积。这个计算量在当时2013年的硬件条件下是无法接受的。所以原论文提出了两个优化方向。一个是层级SoftmaxHierarchical Softmax本质上是把词表组织成一棵哈夫曼树预测时从根节点一路走到叶子节点每走一步只需要做一次二分类复杂度从词表大小降到树高也就是对数级别。工程上实现起来其实不复杂但树结构一旦固定词的表示能力受限于树的拓扑而且写起来不如另一个方案简单。另一个是负采样Negative Sampling这也是我们在代码里最常碰到的方案。负采样的思路是既然完整的Softmax太贵那我干脆不计算所有词的归一化概率只把正样本真实的上下文词的分数拉高同时随机抽几个负样本与当前词不相关的词把它们的分数压低。这样一来每次更新只涉及正样本加负样本总共十几个词计算量大幅下降。这里要特别注意负采样的采样分布原文用的是经验分布的三分之四次方[ P(w) \frac{f(w)^{3/4}}{\sum_{u \in V} f(u)^{3/4}} ]其中 (f(w)) 是词 w 在语料中的频率。为什么要加这个0.75次方直接按频率采样的话高频词比如的了是会被反复抽成负样本模型会一直往这些词不出现的方向优化低频词几乎被忽略。加上0.75次方的平滑效应后高频词的采样概率被压低低频词的采样机会被拉高负样本的分布更均匀实验也证明这能稳定提升词向量质量。这个细节是很多开源代码直接copy频次数组然后用torch.multinomial采样看起来很简单但如果你自己从零实现很容易漏掉这个3/4幂次而漏掉之后训练出来的向量在低频词上会有肉眼可见的退化。2.3 高频词降采样容易被忽略的预处理原论文里还有个预处理细节——subsampling即对高频词做随机丢弃。比如一句话里每个词以一定概率被丢弃概率公式大致是[ P_{\text{keep}}(w) \left(\sqrt{\frac{t}{f(w)}} 1\right) \cdot \frac{t}{f(w)} ]其中 t 是人工设定的阈值论文里常用1e-3到1e-5。为什么要做这一步因为的是在这类高频词在语料里出现得太频繁它们提供的语义信息有限却占据了大量的训练时间。丢弃一部分高频词不仅训练速度更快还能让上下文窗口更多聚焦在低频但有意义的词上。我在实现的时候一开始没做这步想着语料不大无所谓。结果训练出来的向量里哈哈啊这类语气词的近义词全是它们自己明显是高频词被重复训练得太多了。后来加上subsampling效果立刻改善。所以如果你想复现一个看起来正常的Word2Vec结果subsampling不是可选项几乎是必选项。3. 从零手写Skip-gram数据流与负采样的完整实现3.1 为什么建议手写一遍而不是直接调库我知道现在有Gensim这种封装得很好的库一行Word2Vec(sentences)就能跑出词向量。但CS224n的作业之所以设计成手写核心目的是让你理解每个模块存在的理由。如果你只会调库你永远不知道损失函数里那个负采样项到底在优化什么也不知道学习率设置不合理时loss曲线会表现出什么样的病态形态。下面我给出一个完整的Skip-gram 负采样的PyTorch实现从数据准备到训练再到相似度评测每段都会解释关键点。代码目标是运行在CPU上语料选用小型英文语料词表控制在几千词级别方便快速迭代。3.2 数据预处理从原始文本到词频表和训练样本import re from collections import Counter, defaultdict import random import math import torch import torch.nn as nn import torch.nn.functional as F corpus_raw [ the quick brown fox jumps over the lazy dog, the dog barks at the cat, cats and dogs play in the yard, a quick brown mouse runs away, ] def tokenize(text): text text.lower().strip() tokens re.findall(r\w, text) return tokens sentences [tokenize(s) for s in corpus_raw] # 统计词频建立词到索引的映射 word_count Counter() for sent in sentences: word_count.update(sent) vocab_size len(word_count) word2idx {word: i for i, (word, _) in enumerate(word_count.items())} idx2word {i: word for word, i in word2idx.items()}这里有个小决策词表直接用了全部去重后的词没有设最小词频阈值。实际项目里对出现次数小于5的词通常直接替换成UNK。原因有二一是这些词学不出稳定的表示五六个样本根本不可能撑起一个可靠的向量方向二是它们在负采样环节还会造成样本扰动。不过我这个小语料就无所谓了。接下来构建训练样本。Skip-gram里每个中心词和窗口内的每个上下文词构成一对训练样本。窗口大小可以设为非对称即左侧看2个右侧看2个也可以设成对称比如window2表示左右各2个。这里我做一下随机窗口处理对每个中心词实际采样的窗口半径在1到window之间随机目的有些类似subsampling——给离中心词更近的词更大权重同时减少重复样本的过度拟合。window 2 train_pairs [] for sent in sentences: for center_pos, center_word in enumerate(sent): w random.randint(1, window) start max(0, center_pos - w) end min(len(sent), center_pos w 1) for context_pos in range(start, end): if context_pos center_pos: continue context_word sent[context_pos] train_pairs.append((word2idx[center_word], word2idx[context_word]))3.3 负采样概率表0.75幂次的实际写法训练之前要生成负采样概率表。严谨的写法是维护一个weights数组然后每次负采样时用torch.multinomial从全词表里抽。考虑到词表不大我直接构建一个概率张量freq torch.tensor([word_count[word] for word in idx2word], dtypetorch.float32) freq_powered freq ** 0.75 neg_sample_probs freq_powered / freq_powered.sum() def sample_negatives(batch_size, num_neg5): # 每个样本抽 num_neg 个负样本返回形状 (batch_size, num_neg) return torch.multinomial(neg_sample_probs, num_neg * batch_size, replacementTrue)注意一个容易出错的地方正样本里中心词和上下文词不能成为自身的负样本。torch.multinomial不会感知当前上下文词是谁所以如果抽中了同一个词通常有两种处理方式一是直接跳过并重新抽二是把概率置零。实现中为了方便可以在损失计算时把负样本中与被预测上下文词相同的索引mask掉。但说实话在小语料里这个碰撞概率很低一般直接忽略也不会影响最终质量。3.4 模型前向嵌入层做查表Skip-gram模型本身极其简单一张词嵌入表查中心词向量再查上下文词向量算点积。这里不用写什么forward里的复杂结构核心就是两个nn.Embeddingnn.Embedding本质就是一张可学习的查表一个做中心词一个做上下文词。class SkipGramNegSampling(nn.Module): def __init__(self, vocab_size, embed_dim): super().__init__() self.center_embed nn.Embedding(vocab_size, embed_dim) self.context_embed nn.Embedding(vocab_size, embed_dim) def forward(self, center_idx, context_idx, negative_idx): # center_idx: (batch_size,) # context_idx: (batch_size,) # negative_idx: (batch_size, n_neg) center_vec self.center_embed(center_idx) # (B, D) context_vec self.context_embed(context_idx) # (B, D) pos_score torch.sum(center_vec * context_vec, dim1) # (B,) pos_loss -torch.log(torch.sigmoid(pos_score) 1e-8) neg_vec self.context_embed(negative_idx) # (B, n_neg, D) neg_score torch.bmm(neg_vec, center_vec.unsqueeze(2)).squeeze(2) # (B, n_neg) neg_loss -torch.log(torch.sigmoid(-neg_score) 1e-8).sum(dim1) return (pos_loss neg_loss).mean()解释一下为什么负样本的分数要取负再进sigmoid。我们期望正样本的点积尽量大负样本的点积尽量小。用sigmoid(-score)把分数越小、损失越小这件事转化成了标准的二分类损失形式——把正样本当作1负样本当作0。所以整个损失本质上就是把中心词-上下文词对当成正类把中心词-随机词对当成负类做一个逻辑回归。这个视角非常关键理解了它你就不会再好奇为什么这里用的不是MSE或者别的损失了。3.5 训练循环学习率、梯度更新与子图释放训练循环非常简单但有两个细节需要经验。第一个是学习率。Adam优化器默认学习率0.001在这个任务上通常可以但如果loss出现剧烈震荡多半是学习率偏大。我会先用torch.optim.SGD配0.05学习率跑两轮看趋势然后切Adam配0.001。真实项目里我通常对嵌入矩阵用更大的学习率因为嵌入参数更新相对稀疏但这属于后话。第二个是torch.no_grad()。在评测相似度、或者用训练好的中心词向量做下游任务时一定要包上torch.no_grad()否则梯度图会累积内存被一点点吃光。我见过不少人训练时正常一跑评测就爆内存十有八九是没关梯度追踪。epochs 200 lr 1e-3 model SkipGramNegSampling(vocab_size, embed_dim64) optimizer torch.optim.Adam(model.parameters(), lrlr) batch_size 128 n_neg 5 for epoch in range(epochs): random.shuffle(train_pairs) total_loss 0.0 for i in range(0, len(train_pairs), batch_size): batch train_pairs[i: i batch_size] center_idx torch.tensor([p[0] for p in batch], dtypetorch.long) context_idx torch.tensor([p[1] for p in batch], dtypetorch.long) negative_idx sample_negatives(len(batch), n_neg) optimizer.zero_grad() loss model(center_idx, context_idx, negative_idx) loss.backward() optimizer.step() total_loss loss.item() if epoch % 20 0: print(fEpoch {epoch}, Loss {total_loss / max(len(train_pairs) // batch_size, 1):.4f})如果你训练完之后发现loss在震荡但下降趋势不明确不要急着调网络结构先查看两个东西一是batch_size和数据顺序带来的梯度噪声二是学习率是否过冲。Skip-gram这种浅模型绝大多数训练异常都是超参问题而不是模型问题。3.6 相似度评测注意方向性训练结束后最常用的评测是词相似度。把中心词向量拿出来和另一个词的向量做余弦相似度。def cos_sim(a, b): return torch.cosine_similarity(a.unsqueeze(0), b.unsqueeze(0)) def query(target, topk5): target_vec model.center_embed.weight[word2idx[target]] sims torch.cosine_similarity(target_vec.unsqueeze(0), model.center_embed.weight) top_indices sims.argsort(descendingTrue)[1: topk1] return [(idx2word[i.item()], sims[i].item()) for i in top_indices] with torch.no_grad(): print(query(dog))这里有个很值得留意的现象对同一个词用中心词向量查上下文词表和用上下文词向量查中心词表得到的相似度排序常常不一样。原因在于Skip-gram训练时中心词和上下文词的参数是两套独立的表它们只是通过梯度被拉到相近位置但并没有完全对齐。工程上最后取词向量时很多人直接取center_embed就完事了如果你的下游任务表现不佳可以试试把两套向量拼接或者取平均。原始论文里的最终词向量通常取中心词向量但不同任务的最优选择并不绝对。4. 训练完才知道的坑一个实验五连坑的排查记录4.1 训练集过小相似度结果迷惑一开始我用上面那个只有四句话的语料跑实验结果query(dog)出的top1不是cat也不是bark而是dog自己虽然已经排除了目标词本身但语义上毫无区分度。原因很简单语料太小每个词出现的次数少得可怜向量之间基本没有稳定的共现关系。要让Word2Vec有效语料规模至少得上万句。CS224n作业里用的text8语料大概170MB训练出来的效果才谈得上语义。但这里有个实际矛盾小语料上跑模型的整个训练过程很快方便调试代码逻辑等逻辑通了再换大语料就能避免在调试期浪费大量算力。4.2 window_size设置的歧义不同实现里window_size定义不同。有的实现把window2解释成左右各2个词有的是窗口总长度不超过2。我在最初写数据生成代码时窗口边界计算用了center_pos - w到center_pos w结果w2时上下文窗口内包含了中心词自己虽然我把相等的位置跳过了但窗口边界如果取错甚至会把中心词左边的词漏掉。最终的规范写法是左边2个右边2个共4个上下文去重中心句本身。这点写进代码前最好先想清楚否则训练出的样本比例会偏移。4.3 负采样数量不是越多越好负样本数量n_neg设成5是论文里的默认值但很多人随手改成50或100以为负样本越丰富越好。实测下来n_neg越大每个正样本对受到的信号压制次数越多模型会把更多精力用于压低随机词分数而不是区分正样本和相近词。对语义区分度反而有伤害。CS224n的练习里给出的取值范围是2到10超过15以后收益基本为负。如果你的语料噪声特别大可以适度提升到10但别盲目加。4.4 词向量方向的不可解释性训练完成后整个词向量空间是各向异性的不同方向并不等价。中文里好和坏在某些维度上距离很近在另一些维度上又几乎重合。这不是bug而是分布式表示的固有特性——向量的方向只代表帮助模型完成任务的方向并不存在一个人类的意义坐标系。所以做下游任务之前通常要做向量均值中心化或对齐操作否则直接用原始向量做聚类结果会被整体偏移主导。我发现一个很实用的经验把训练好的词向量全体减去均值后再做归一化相似度匹配的稳定性会明显提升。原因在于训练过程中高频词向量通常占据了一个公共方向中心化能去除这个方向上的偏置。4.5 复现论文效果为什么那么难最后踩的一个大坑是想复现论文里的语义类比效果比如king - man woman ≈ queen。这个小语料里几乎不可能出现这种结果。原因很简单类比推理本质上是向量的线性运算能捕捉到可叠加的语义维度而这种维度需要大规模语料才能稳定涌现。CS224n课上展示的经典案例背后是数十亿词的语料和精心调过的超参。如果你在小语料上跑得到的更多是垃圾进垃圾出。我把这个踩坑过程整理成表格方便后面自己翻看现象根因处理办法相似度top1全是目标词自己语料过小停用词或目标词频率过高加大语料规模加入subsamplingloss下降后又反弹学习率过大调小学习率或换SGD热身低频词向量和随机向量没区别样本数太少负采样占比过大降低n_neg提升迭代轮数word2idx里没UNK遇到新词报错词表覆盖不全加UNK token并设最小词频可视化时不同类词混在一起没有中心化/归一化预处理去均值单位化5. 从Word2Vec到ELMo、BERT一条被继承的表示学习路线很多教程写到词向量训练完就结束了但CS224n这门课真正有价值的部分其实在后面——它能帮你建立一个清晰的演进坐标系。Word2Vec证明了词义可以从预测任务中涌现但它有一个绕不开的硬伤每个词只对应一个固定向量多义词没有分开表示。bank在river bank和bank account里用的是同一个向量这在很多下游任务里是致命的。后来ELMo的思路是对每个词学习一组向量再根据当前上下文赋予不同权重动态组合BERT更进一步用Transformer把整句话的上下文信息编码进每个位置的向量里。但你需要理解的是这些模型的底层逻辑和Word2Vec是一致的仍然是通过预测任务BERT里是掩码语言模型来学表示仍然靠梯度传播把上下文信息蒸馏到表示向量里。Word2Vec种下的预测式表示学习这颗种子并没有被推翻只是长成了更大的树。所以在实现层面你在手写Word2Vec时积累的这些经验——欠拟合与过拟合的判断、嵌入表的参数更新、负样本的采样分布、多义词的表示冗余——在转向预训练模型时依然全部适用。区别只是把两层的浅网络换成了十二层的Transformer把负采样换成了更复杂的训练目标但调参的直觉和排查问题的思路是一脉相承的。从我个人的实际感受来说Word2Vec是整个NLP领域里最适合手推一遍手写一遍的模型。它的数学相对简单代码量适中但是涉及了词表处理、采样分布、梯度训练、向量评价等一整套流程。把这套流程走通之后无论是去看Gensim源码还是去读BERT的代码都会觉得顺畅很多。如果你的学习路径也是从CS224n入门我的建议很直白不要跳过作业不要只跑通就直接下一章多问自己几个为什么多去改一改超参观察效果变化这个模型的全部价值都会在这种折腾里体现出来。

相关新闻

C语言核心语法与工程实践深度解析

C语言核心语法与工程实践深度解析

1. C语言基础语法全景解析作为计算机科学领域的"元老级"语言,C语言至今仍是系统编程、嵌入式开发等领域的基石。我在十多年的开发经历中发现,许多开发者虽然能写出运行代码,但对基础语法的理解往往停留在表面。本文将用工程视角拆解…

2026/10/15 9:29:26 阅读更多 →
制造业AI网关:协议翻译+语义对齐+安全沙箱实战

制造业AI网关:协议翻译+语义对齐+安全沙箱实战

1. 项目概述:这不是在搭API网关,而是在给工厂装“AI神经系统”“AI网关制造业?MAI Gateway行业落地方案与实践”——这个标题乍看像技术名词堆砌,但我在长三角三家汽车零部件厂、两家智能装备企业连续蹲点半年后,彻底明…

2026/10/15 9:28:26 阅读更多 →
MC9S12XS128指令集查询指南:编码、寻址与周期数解析

MC9S12XS128指令集查询指南:编码、寻址与周期数解析

简介:MC9S12XS128 是飞思卡尔(现 NXP)面向智能车等场景常用的微控制器,其指令集速查文档正是为汇编开发者和嵌入式爱好者整理的精简工具。文档以 docx 格式呈现,共 1 个文件,压缩包仅 30KB,轻量…

2026/10/15 9:28:26 阅读更多 →

最新新闻

车辆稳定性分析与相平面法Matlab实现

车辆稳定性分析与相平面法Matlab实现

1. 项目背景与核心价值车辆稳定性分析是汽车动力学研究的核心课题之一。在紧急避障或高速过弯工况下,驾驶员最直接的体感就是车辆是否"听话"——专业术语称为横摆稳定性。传统单指标分析往往难以全面反映车辆动态特性,而相平面分析法通过构建质…

2026/10/15 10:16:15 阅读更多 →
单元化多活架构下的路由穿透治理:Sharding Key 绑定与跨机房 RPC 拦截

单元化多活架构下的路由穿透治理:Sharding Key 绑定与跨机房 RPC 拦截

在大型互联网交易系统向“三地五中心”单元化异地多活(Cell Architecture)演进的征途上,架构师最害怕的往往不是某个机房被整体挖断光缆这种“显性灾难”,而是一种无声无息寄生在代码调用链中的“隐性慢性毒药”——跨单元路由穿透…

2026/10/15 10:16:15 阅读更多 →
为什么异构DDL不能原样执行?KFS类型映射与语法重构解析

为什么异构DDL不能原样执行?KFS类型映射与语法重构解析

在某大型医院的数据同步项目中,260条同步链路同时运行,源端涉及Oracle、MySQL、SQL Server、KES V8R6、Vastbase等10多种数据库,并持续向目标库汇聚数据。 在这样的环境里,把数据同步过去并不难。真正让链路“卡住”的&#xff0c…

2026/10/15 10:16:15 阅读更多 →
反向海淘代购系统开发实录:从业务链路到可运行代码

反向海淘代购系统开发实录:从业务链路到可运行代码

从"人工一单一询"到"全链路自动化流水线",中间隔着的不是业务想象力,而是十几个必须做对的技术决策。这篇文章把一套反向海淘代购系统的架构、核心模块和踩坑点一次性讲透,代码可直接运行。一、先定义问题:反…

2026/10/15 10:16:15 阅读更多 →
AI 第一次同时给出账本和传票:Anthropic 报出 168 亿美元季度收入,八个州把 OpenAI 告了

AI 第一次同时给出账本和传票:Anthropic 报出 168 亿美元季度收入,八个州把 OpenAI 告了

数据口径:2026-10-13 至 10-15 的公开信息(整理时间以数据源最新可核日期为准)。均为聚合站点单源条目,未经一手核实的标"据报道";与前几篇重复的结论(agent 最小权限、星数刷量识别、小模型降本…

2026/10/15 10:16:15 阅读更多 →
新能源汽车热管理系统Simulink建模与仿真实践

新能源汽车热管理系统Simulink建模与仿真实践

1. 项目背景与核心价值在新能源汽车快速发展的今天,热管理系统设计正面临前所未有的挑战。传统燃油车的热管理相对简单,主要关注发动机冷却和空调系统。而电动车和混合动力车型需要管理电池、电机、电控等多套系统的热交换,还要兼顾不同驱动模…

2026/10/15 10:15:14 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/15 9:49:14 阅读更多 →