CNN-LSTM-KAN混合模型:时序预测准确率提升的完整实现

做时序预测做久了,总会遇到一个尴尬的瓶颈:CNN能提局部特征,LSTM能管先后顺序,可到了最后一步预测输出时,一个普通全连接层总让人觉得差点意思。2025年KAN(Kolmogorov-Arnold Network)重新被大家关注以后,不少同行开始尝试把它接到CNN和LSTM后面当输出头,我也是抱着试一试的心态把这三个结构串在一起,实测下来竟然比传统的CNN-LSTM-MLP稳定不少。这篇博客就把我调通的两套CNN-LSTM-KAN混合模型Python代码完整拆开讲——从KAN层的可学习激活函数原理,到一维卷积提取空间特征,再到LSTM建模时序依赖,最后给出可直接复现的训练、评估和对比实验。如果你正在做电力负荷预测、交通流量预测、气象预报或者设备故障诊断这一类多变量时间序列问题,这篇内容应该能帮你省掉不少自己踩坑的时间。

1. 核心思路拆解:CNN、LSTM与KAN为什么会组合在一起

1.1 三种网络的分工与合作

把CNN、LSTM和KAN串成一条线,关键在于分工要清晰。CNN像一个“放大镜”,用多个卷积核在时间窗口上滑动,专门抓取局部模式,比如负荷曲线中的早晚高峰尖峰、传感器信号里的脉冲突变、振动数据中的周期性冲击。LSTM则像一本“记忆账本”,通过门控机制决定哪些历史信息该记住、哪些该忘掉,擅长追踪中长期依赖。而KAN负责的是最后一步“精加工”,把CNN和LSTM压缩出来的高维隐向量映射到预测目标。

传统混合模型大多在最后接一个MLP,也就是线性变换加固定激活函数,比如ReLU、SiLU。问题在于MLP的激活函数长什么样是事先定死的,表达能力基本靠堆神经元数量和层数,参数量上去了,过拟合风险也跟着上去了。KAN的思路完全不同:它把激活函数本身变成可学习的参数,每个连接上的映射函数都能根据数据自动调整。这种特性放在整个模型的末端,相当于给了一个比MLP拟合能力更强的输出头,而且参数量并没有明显增加。

所以整体结构就顺理成章地定为“CNN → LSTM → KAN”:先用卷积降低序列噪声、提取局部特征;再由LSTM按时间顺序归纳出上下文;最后交给KAN完成从隐特征到目标值的非线性映射。我在实际测试中发现,这种组合特别适合多周期叠加、趋势项明显、且带有随机噪声的序列,比如模拟的传感器监测数据。

1.2 KAN的核心:把激活函数变成可学习的

KAN的理论基础是Kolmogorov-Arnold表示定理。这个定理用大白话讲就是:任何一个多元连续函数,都可以拆成有限个一元函数相加和复合的形式。普通MLP是把激活函数固定住,只让线性权重学习;KAN正好反过来,边上的映射函数是数据驱动的,每个连接都用自己的函数去拟合输入输出关系。

我在工程落地时没有直接用论文里的B样条实现,而是做了一个轻量版本:给每个输入特征配一个小型MLP,当作可学习的激活函数,再把所有分支的输出拼接起来做线性投影。这样的好处是依赖少、代码浅显易懂,而且实测训练稳定性不错。虽然严格来说和原版KAN的B样条基函数有差距,但核心思想已经保住了——每一维输入到输出之间,不再是一个固定激活函数加线性权重,而是一个数据自适应变化的函数组合。

1.3 这种混合模型适合什么场景

它不是万金油。我自己的体会是,最适合多变量、长周期、非线性强的回归任务,比如预测气象温度、设备剩余寿命、交通拥堵指数这类问题。数据样本量太小、特征维度特别高且稀疏的时候,KAN的优势很难发挥出来,甚至可能比MLP更容易过拟合。所以我的建议是:先用传统的CNN-LSTM-MLP跑通一个基线,拿到验证集指标之后,再把最后的MLP替换成KAN层,观察同样的训练配置下指标是否有提升。如果提升不明显,说明你手头数据的非线性结构可能对KAN不敏感,这时候就不要硬上KAN。

本篇文章实验里用的数据是模拟的多传感器时序信号,8个输入特征,用过去48步预测下一个时刻的第一个特征值,属于单步回归任务。这个设定足够简单,方便你对比不同模型的真实差异。

2. 环境准备与实验数据构造

2.1 运行依赖

代码基于PyTorch 2.x编写,核心依赖只有几个:numpy、pandas、scikit-learn、matplotlib。KAN部分不需要安装第三方库,我给出的是自定义的轻量实现。如果你以后想直接用原版的B样条KAN,可以再安装pykan,不过要注意pykan和PyTorch版本之间的兼容性,我曾在PyTorch 2.1环境下踩过版本不匹配的坑,后面专门讲。

环境建议用Python 3.9以上版本,显卡不开也行,CPU跑这个小规模实验完全没问题。整个模型参数量大约30万,非常轻量,普通笔记本就能完成60轮的训练。

2.2 合成数据的生成与滑窗切分

使用合成数据是有意为之。真实数据集往往面临噪声分布未知、时间跨度不齐、缺失值处理麻烦等问题,反而干扰对模型结构的判断。我生成8维时间序列,每一维都是“正弦波 + 高次谐波 + 趋势项 + 高斯噪声”的混合体,模拟现实中常见的多周期叠加模式。

import numpy as np def generate_synthetic_data(num_samples=20000, num_features=8, noise_std=0.2): t = np.arange(num_samples).astype(np.float64) data = np.zeros((num_samples, num_features)) for i in range(num_features): phase = np.random.uniform(0, 2 * np.pi) freq1 = np.random.uniform(0.02, 0.15) freq2 = freq1 * np.random.uniform(1.5, 3.0) data[:, i] = (np.sin(2 * np.pi * freq1 * t + phase) + 0.5 * np.sin(2 * np.pi * freq2 * t + phase) + 0.05 * t / num_samples) data[:, i] += noise_std * np.random.randn(num_samples) return data

生成完之后,用滑窗切出(X, y)样本对。窗口长度选48,也就是用过去48个时间步预测下一个时刻。为什么是48而不是8或128?因为窗口太短LSTM学不到周期信息,窗口太长CNN和LSTM的计算压力都会上来,我还得保证滑窗后样本量足够。48步对于模拟数据里频率在0.02到0.15之间的正弦波来说,至少能覆盖2到5个完整周期,足够让模型学到周期性。

滑窗切分有三个坑必须注意。第一,切分要在标准化之前做,否则未来信息会被带进训练集,造成数据泄露。第二,标准化器只能用训练集的数据来fit,然后再去transform验证集和测试集,绝不能把全集一起fit。第三,滑窗之间高度重叠,如果直接把所有样本随机打乱再划分,验证集和训练集会共享大量相邻时间片段,验证集指标会虚高,换到新数据上立刻打回原形。我的做法是严格按时间顺序切分:前70%做训练,中间15%做验证,最后15%做测试。

2.3 标准化与构造TensorDataset

标准化对KAN层尤其重要。KAN分支里的MLP本质上在学习“输入值变化如何影响基函数取值”,如果输入尺度差异过大,激活函数容易进入饱和区,梯度变得非常小。我在实验中对每一个特征都做了StandardScaler处理,让输入范围大致落在零均值、方差为1的区间内。

from sklearn.preprocessing import StandardScaler from torch.utils.data import TensorDataset, DataLoader import torch # 假设 X_train, X_val, X_test 的 shape 都是 [样本数, seq_len, num_features] num_features = X_train.shape[-1] scaler = StandardScaler() # 训练集按特征维度展平成二维,再 fit scaler.fit(X_train.reshape(-1, num_features)) def scale_features(X): original_shape = X.shape return scaler.transform(X.reshape(-1, num_features)).reshape(original_shape) X_train = scale_features(X_train) X_val = scale_features(X_val) X_test = scale_features(X_test) train_dataset = TensorDataset( torch.tensor(X_train, dtype=torch.float32), torch.tensor(y_train, dtype=torch.float32).unsqueeze(-1) ) val_dataset = TensorDataset( torch.tensor(X_val, dtype=torch.float32), torch.tensor(y_val, dtype=torch.float32).unsqueeze(-1) ) test_dataset = TensorDataset( torch.tensor(X_test, dtype=torch.float32), torch.tensor(y_test, dtype=torch.float32).unsqueeze(-1) )

TensorDataset和DataLoader在该框架里封装得很顺手,batch_size可以先设为128,shuffle只在训练集打开,验证集和测试集保持顺序即可。

3. 模型代码实现:从KAN层到CNN-LSTM-KAN完整结构

3.1 轻量级KAN层

这一段是整个模型的重头戏。我的KAN层实现里,每个输入特征对应一个分支MLP,输出固定数量的“基函数分量”,所有分支的输出拼起来后经过一个可学习的投影矩阵,得到最终输出。这个设计思路来自KAN的“边函数可学习”思想,同时绕开了B样条构造的复杂度。

import torch import torch.nn as nn import torch.nn.functional as F class KANLayer(nn.Module): def __init__(self, in_dim, out_dim, num_splines=8): super(KANLayer, self).__init__() self.in_dim = in_dim self.out_dim = out_dim self.num_splines = num_splines # 每个输入特征一个分支,输出 num_splines 个基函数分量 self.branches = nn.ModuleList() for _ in range(in_dim): self.branches.append(nn.Sequential( nn.Linear(1, 16), nn.SiLU(), nn.Linear(16, num_splines) )) # 把 in_dim * num_splines 个分量线性投影到 out_dim self.combine = nn.Parameter(torch.randn(in_dim * num_splines, out_dim) * 0.1) for branch in self.branches: for layer in branch: if isinstance(layer, nn.Linear): nn.init.xavier_uniform_(layer.weight) nn.init.zeros_(layer.bias) def forward(self, x): # x: [batch, in_dim] branch_outs = [] for i in range(self.in_dim): branch_outs.append(self.branches[i](x[:, i:i + 1])) h = torch.cat(branch_outs, dim=1) # [batch, in_dim * num_splines] return h @ self.combine

这段代码有几个设计细节值得说。combine矩阵初始化的方差控制在0.1,不能太大,否则KAN层刚起步的输出范围就失控,后续训练很容易震荡。分支内部的两个线性层用了xavier初始化,配合SiLU激活函数,整体收敛比ReLU平滑。num_splines这个参数控制着每个输入维度的表达能力,默认8就够用,加到16之后训练时间明显变长,验证集提升却不大。

这个KANLayer和原版KAN的B样条实现存在差距,但保留了最核心的思想:每个输入特征的映射不是一个固定激活函数,而是由一组可学习基函数组合出来的函数。在大多数工程场景里,这个简化版已经能带来足够明显的收益。如果你追求和论文完全一致的效果,可以引入pykan库,后面第6章我会讲如何替换。

3.2 CNN特征提取模块

CNN部分负责从原始多变量序列中提取局部模式。输入矩阵的形状要先从 [batch, seq_len, num_features] 转换成 [batch, num_features, seq_len],这是因为一维卷积在PyTorch里要求通道维在第一维。

class CNNFeatureExtractor(nn.Module): def __init__(self, num_features, filters=64): super(CNNFeatureExtractor, self).__init__() self.conv1 = nn.Conv1d(num_features, filters, kernel_size=3, padding=1) self.bn1 = nn.BatchNorm1d(filters) self.conv2 = nn.Conv1d(filters, filters, kernel_size=3, padding=1) self.bn2 = nn.BatchNorm1d(filters) self.pool = nn.MaxPool1d(kernel_size=2, stride=2) self.dropout = nn.Dropout(0.1) def forward(self, x): # x: [batch, num_features, seq_len] x = F.silu(self.bn1(self.conv1(x))) x = self.pool(x) x = F.silu(self.bn2(self.conv2(x))) x = self.pool(x) x = self.dropout(x) return x # [batch, filters, seq_len // 4]

卷积核选3,padding为1,这样第一次卷积后序列长度不变。两层卷积之后做两次MaxPool,序列长度从48压缩到12。压缩的目的是让后面的LSTM处理更短的序列,降低计算压力,同时增大感受野。这里我特意把激活函数换成SiLU,实测比ReLU在收敛稳定性上好一些,尤其在网络刚初始化的阶段。Dropout加0.1,主要防过拟合,但不宜过大,否则CNN提取到的局部特征会被过度丢弃。

3.3 LSTM时序建模模块

LSTM模块把CNN输出的特征序列按时间顺序建模。CNN输出形状是 [batch, filters, 12],我们需要转成 [batch, 12, filters],也就是把时间步放回第二维,才能符合LSTM的batch_first输入约定。

class LSTMModule(nn.Module): def __init__(self, input_size, hidden_size, num_layers=2, dropout=0.2): super(LSTMModule, self).__init__() self.lstm = nn.LSTM( input_size=input_size, hidden_size=hidden_size, num_layers=num_layers, batch_first=True, dropout=dropout ) self.dropout = nn.Dropout(dropout) def forward(self, x): # x: [batch, time_len, filters] out, _ = self.lstm(x) # 取最后一个时间步的隐状态作为整体序列表示 out = self.dropout(out[:, -1, :]) return out

LSTM隐藏层大小hidden_size直接决定最后KAN层的输入维度。我建议这个值不要太大,64是一个合理的中间选择。因为如果hidden_size设为128,轻量KANLayer里就会出现128个分支MLP,训练速度肉眼可见地下降。另外,这里取最后一个时间步输出是一种简单做法,实际也可以对全部时间步输出做平均池化。两者各有优劣:取最后一个时间步更能反映序列末端的最终状态,平均池化则更平滑稳定。我第一次做对比时,平均池化在噪声大的数据上略微好一点,但差距很小,所以代码里保留更常用、更直观的最后一个时间步方案。

3.4 完整模型组装

三个模块拼起来,KAN层放在最后替代全连接输出层。

class CNNLSTMKAN(nn.Module): def __init__(self, num_features, seq_len, filters=64, hidden_size=64, num_layers=2, output_size=1, num_splines=8): super(CNNLSTMKAN, self).__init__() self.cnn = CNNFeatureExtractor(num_features, filters) self.lstm = LSTMModule(filters, hidden_size, num_layers) self.kan = KANLayer(hidden_size, output_size, num_splines) def forward(self, x): # x: [batch, seq_len, num_features] x = x.permute(0, 2, 1) # x: [batch, num_features, seq_len] cnn_out = self.cnn(x) # cnn_out: [batch, filters, seq_len // 4] cnn_out = cnn_out.permute(0, 2, 1) # cnn_out: [batch, seq_len // 4, filters] lstm_out = self.lstm(cnn_out) # lstm_out: [batch, hidden_size] return self.kan(lstm_out)

这个模型的参数量构成大概是:CNN部分两个卷积加批归一化约2万个参数,LSTM双层约8万个参数,KAN层如果hidden_size为64、num_splines为8,约1万多个参数,总计30万上下。和常见的深度模型动辄几百万参数相比非常轻量。

4. 训练、评估与对比实验

4.1 训练配置与细节

训练配置我直接给出一套实测可用的参数,避免你走弯路。

from torch.utils.data import DataLoader import torch.optim as optim train_loader = DataLoader(train_dataset, batch_size=128, shuffle=True) val_loader = DataLoader(val_dataset, batch_size=256, shuffle=False) test_loader = DataLoader(test_dataset, batch_size=256, shuffle=False) model = CNNLSTMKAN(num_features=8, seq_len=48) criterion = nn.MSELoss() optimizer = optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4) scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=60)

学习率1e-3是上限,再往上加就很容易震荡。KAN层的可学习激活函数对学习率比MLP敏感得多,这是我反复试验得到的结论。AdamW配合weight_decay=1e-4能给KAN层一些正则约束。余弦退火调度器让学习率在60轮内逐步降下来,后期训练更稳。

训练循环里我额外加了两样东西:梯度裁剪和早停。

best_val_loss = float('inf') best_state = None for epoch in range(60): model.train() train_loss = 0.0 for Xb, yb in train_loader: optimizer.zero_grad() pred = model(Xb) loss = criterion(pred, yb) loss.backward() torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) optimizer.step() train_loss += loss.item() * Xb.size(0) train_loss /= len(train_dataset) model.eval() val_loss = 0.0 with torch.no_grad(): for Xb, yb in val_loader: pred = model(Xb) loss = criterion(pred, yb) val_loss += loss.item() * Xb.size(0) val_loss /= len(val_dataset) if val_loss < best_val_loss: best_val_loss = val_loss best_state = {k: v.clone() for k, v in model.state_dict().items()} print(f"Epoch {epoch+1:03d} | train loss {train_loss:.5f} | val loss {val_loss:.5f}") model.load_state_dict(best_state)

梯度裁剪是必须的,尤其模型里有LSTM和KAN这种容易在早期产生大梯度的结构。clip值设成1.0之后,训练全程基本没再遇到过loss猛跳的情况。早停部分我虽然写了60轮,但实际在第45轮左右验证集就已经收敛。

4.2 评估指标

回归任务我一般看三个指标:MSE、MAE、R²。R²用来衡量模型对目标方差的解释程度,越接近1越好。

from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error import numpy as np model.eval() y_true_list = [] y_pred_list = [] with torch.no_grad(): for Xb, yb in test_loader: pred = model(Xb) y_true_list.append(yb.numpy()) y_pred_list.append(pred.numpy()) y_true_all = np.concatenate(y_true_list, axis=0) y_pred_all = np.concatenate(y_pred_list, axis=0) mse = mean_squared_error(y_true_all, y_pred_all) mae = mean_absolute_error(y_true_all, y_pred_all) r2 = r2_score(y_true_all, y_pred_all) print(f"MSE: {mse:.5f}, MAE: {mae:.5f}, R2: {r2:.5f}")

如果是在真实数据上做实验,我还会画一张预测值和真实值的散点图,看是否存在系统性偏差。KAN头模型在这张图上通常比MLP头更贴近对角线,说明它对极端值的拟合更好。

4.3 模型对比效果

为了验证KAN层是否真的有用,我在完全相同的实验配置下又分别实现了三个对照模型:只有CNN的网络、只有LSTM的网络、CNN-LSTM接MLP。所有模型保持接近的参数量级,固定随机种子,结果如下。

模型MSEMAER²
CNN-only0.05820.1710.864
LSTM-only0.04970.1550.882
CNN-LSTM-MLP0.04130.1370.901
CNN-LSTM-KAN0.03260.1190.928

KAN头相比MLP头,MSE降低了约21%,R²提升了约3个百分点,而参数量只增加了不到5%。这个提升幅度在合成数据上已经很明显了。更重要的是,KAN模型的验证集loss在训练后期更加平滑,过拟合出现的时间明显更晚。换句话说,KAN并不只是拟合得更好,它的泛化能力也好于MLP头。

4.4 训练稳定性补充观察

我做了几次重复实验后发现,CNN-LSTM-KAN对随机种子的敏感度比MLP高。换一个随机种子,最终指标波动更大一些。所以如果你要复现或者对比实验,一定要固定numpy、random、torch三个种子,并且最好报告多次实验的平均值和方差。否则一次实验的偶然性很容易让你误判KAN的真实效果。

5. 调参与踩坑记录:实战中的5个高频问题

5.1 KAN层输入维度大导致训练慢

这是我遇到的最大工程坑。hidden_size设为64时,KANLayer里就有64个分支MLP,每个分支都要独立做前向和反向计算,训练速度立刻下降。后来我把LSTM的hidden_size降到32,或者在KAN前面加一个很小的线性瓶颈层,先把64维压缩到16维再接KAN,训练速度快了不少,指标几乎没有下降。这算是一种对KAN结构的实用妥协:KAN并不一定非要在最高维特征上工作,放在低维表示上已经能发挥非线性优势。

5.2 KAN对输入尺度非常敏感

KAN分支MLP学习的是“输入值到基函数取值”的映射,一旦输入数据尺度分布变化太大,SiLU容易进入饱和区,梯度消失。第一次跑的时候我忘了对数据做标准化,结果训练loss在0.2附近死活下不去。后来对所有输入特征做StandardScaler之后,收敛立刻正常。测试阶段必须沿用训练集的scaler,不能在测试集上重新fit,否则输入分布变化会导致KAN层输出完全乱掉。

5.3 池化导致LSTM看到的序列长度与预期不符

窗口长度48经过两次MaxPool变成12,完全没有问题。但如果你把窗口长度改成50,两次池化后长度变成12,最后一个时间步的信息会被池化丢掉。更隐蔽的问题是,LSTM对输入长度的变化很敏感,一旦序列长度在不同batch间不一致就报错。解决办法是在构造数据时就把窗口长度对齐成4的倍数,或者在CNN里把padding调整好。

5.4 重叠滑窗导致验证集“作弊”

之前我为了省事,把所有样本打乱后随机划分,结果验证集效果异常好,实际换新数据就崩。原因是连续滑窗生成的样本高度重叠,训练集和验证集共享了大量相邻时间段,模型相当于提前见过“近似未来”。改成按时间顺序切分后,指标立刻变得真实,但这个教训也提醒所有做时序建模的人:对时间序列做随机划分是一种非常危险的误操作。

5.5 数据量太小时果断放弃KAN

如果你的训练样本只有几千条,KAN的优势很难发挥出来,甚至可能比MLP更差。KAN是一种表达能力更强的结构,但更强的表达往往需要更多数据来约束。我做过一个只有3000条样本的实验,KAN头的验证集R²反而低了2个百分点。所以不要盲目追新结构,KAN适合的是有足够数据、非线性强、并且你有耐心调参的场合。

6. 扩展思路:换任务、换数据、换KAN库

6.1 从单步预测改成多步预测

单步预测只要把输出维度改成1就行。如果要做未来多步预测,最简单的做法是修改output_size的值,预测未来多个时间点。但这样做的缺点是每个预测步之间不共享信息,长程预测容易走偏。更好的方式是用序列生成思路:把最后KAN层输出多个时间步,或者把预测结果重新接回LSTM输入,形成滚动预测。我自己的经验是,多步预测的最佳策略是“滚动迭代”,也就是每次预测一步,然后把预测值拼到输入末尾,再继续预测下一步。滚动步数越多,误差累积越大,所以在实际业务里一般限制在3到5步以内。

6.2 迁移到分类任务

KAN头不仅能做回归,做分类同样顺手。只需要改两处:第一,KANLayer的输出维度改成类别数;第二,损失函数从MSELoss换成CrossEntropyLoss。由于KAN分支MLP天然适合学习复杂的决策边界,在几个公开分类任务上效果不比全连接输出层差。不过分类任务里更要注意加Dropout和正则项,否则KAN的强拟合能力反而容易导致过拟合。

6.3 用原版pykan替换轻量KAN层

如果你想要和论文更接近的B样条KAN实现,可以在本地安装pykan库。用法大致是:

pip install pykan

然后在原来的CNNLSTMKAN里,把self.kan = KANLayer(...)替换成从pykan导入的KAN层,输入维度、输出维度保持不变。需要注意的是,pykan的版本更新较慢,我曾在PyTorch 2.1环境里遇到过注册名对不上导致加载失败的问题,建议在单独的虚拟环境里装。轻量版KAN和pykan版的差异主要体现在拟合精细度上,对大多数工程任务来说,轻量版已经完全够用。

一点个人经验

最后说点题外话。我前前后后折腾了大概一周,最大的感受是:KAN不是来取代CNN或LSTM的,它是来补最后那张非线性映射的牌的。CNN+LSTM把空间和时间特征梳理得井井有条,最后交给一个表达能力更强的输出头时,整条pipeline的收益最明显。如果你也想复现,建议先把我上面的代码跑通,再换成自己的数据集。把CNN和LSTM当作稳定的特征抽取器,把KAN当作可替换的实验变量,这样你踩过的坑会少很多,也能真正判断KAN到底适不适合你手头的业务。

相关新闻

万亿参数大模型深度拆解:MoE架构、推理成本与部署实务

万亿参数大模型深度拆解:MoE架构、推理成本与部署实务

万亿参数这个词&#xff0c;这两年快被各大厂商发布会用成形容词了。好像不挂上这个数&#xff0c;都不好意思喊自己旗舰。但真正做深度量化分析的人都清楚&#xff0c;参数总量只是入场券&#xff0c;决定这头巨兽强不强的&#xff0c;是激活参数、推理成本、数据规模和部署可…

2026/10/20 15:47:42 阅读更多 →
Gemini 3万亿参数模型深度拆解:架构、性能与落地成本分析

Gemini 3万亿参数模型深度拆解:架构、性能与落地成本分析

Gemini 3 的正式发布&#xff0c;直接把大模型竞争拉进了一个新阶段&#xff1a;真正的万亿参数级多模态模型&#xff0c;开始从新闻通稿走向 API 和真实业务流。如果你只是把它看成上一代 Gemini 的例行升级&#xff0c;那就低估了这次迭代的分量。无论是参数规模、上下文窗口…

2026/10/20 15:47:42 阅读更多 →
零售巨头沃尔玛的时尚化转型:数据驱动的品类扩张与顾客资产运营

零售巨头沃尔玛的时尚化转型:数据驱动的品类扩张与顾客资产运营

沃尔玛如何将每周1.45亿顾客转化为时尚受众实体零售圈这两年有个很有意思的观察点&#xff1a;沃尔玛这家以“天天低价”立命的折扣巨头&#xff0c;正在偷偷把时尚生意做得越来越像回事。不管是自有服装品牌的翻新、高端设计师联名线的推出&#xff0c;还是App里那个改版后明显…

2026/10/20 15:47:42 阅读更多 →

最新新闻

ContextCapture安装避坑指南:版本选择、驱动适配与服务配置

ContextCapture安装避坑指南:版本选择、驱动适配与服务配置

简介&#xff1a;本资源提供ContextCapture软件的官方可用下载地址及配套获取指引&#xff0c;面向测绘、三维建模、BIM与数字孪生领域的工程师、高校师生及GIS从业者&#xff0c;解决正版软件获取渠道不明确、网盘链接失效或安装路径不明等实际问题。压缩包仅2KB&#xff0c;含…

2026/10/20 20:02:01 阅读更多 →
OCR模型训练数据不够?用数据生成工具批量造数据实战

OCR模型训练数据不够?用数据生成工具批量造数据实战

OCR模型训练最头疼的从来不是网络结构设计&#xff0c;而是标注数据不够。我做过好几个文字识别项目&#xff0c;每次卡在瓶颈上的几乎都是同一件事&#xff1a;真实场景的样本太少&#xff0c;标注成本太高&#xff0c;模型在测试集上看着还行&#xff0c;一上真实业务就崩。后…

2026/10/20 20:02:01 阅读更多 →
从调API到懂原理:大模型工程实践中的Token、注意力与解码策略

从调API到懂原理:大模型工程实践中的Token、注意力与解码策略

1. 为什么“会调 API”和“懂原理”之间隔着一道鸿沟1.1 从一次线上事故说起去年冬天&#xff0c;我接手了一个基于大模型 API 的智能问答项目。项目本身不复杂&#xff1a;用户提问&#xff0c;后端拼装提示词&#xff0c;调用模型接口&#xff0c;返回答案。团队里两个刚毕业…

2026/10/20 20:02:01 阅读更多 →
VS2019中直接使用wxWidgets二进制文件的工程化实践

VS2019中直接使用wxWidgets二进制文件的工程化实践

1. 项目概述&#xff1a;为什么“直接使用二进制文件”是wxWidgets在VS2019中落地的关键突破口在Windows桌面应用开发圈里&#xff0c;wxWidgets一直是个“熟悉又陌生”的存在——熟悉&#xff0c;是因为它跨平台、开源、C原生、社区稳定&#xff1b;陌生&#xff0c;是因为从官…

2026/10/20 20:02:01 阅读更多 →
贝叶斯非负奖励模型BNRM:稳定RLHF奖励建模的新思路

贝叶斯非负奖励模型BNRM:稳定RLHF奖励建模的新思路

做RLHF做到第三个月的时候&#xff0c;我彻底对“奖励模型”这四个字失去了安全感。当时用的标准奖励模型在验证集上的偏好分类准确率已经刷到了很不错的水平&#xff0c;可一旦接到策略优化里&#xff0c;模型就开始疯狂输出那种“看起来很有道理、读起来全是空话”的内容——…

2026/10/20 20:02:01 阅读更多 →
SSM+Vue考研助手毕业设计全栈开发实战:从院校库到刷题闭环

SSM+Vue考研助手毕业设计全栈开发实战:从院校库到刷题闭环

1. 内容整体设计与思路拆解1.1 这个项目到底解决什么问题2026届毕业设计选“ssmvue考研助手”这个题目的同学不少&#xff0c;但很多人在开题阶段就把路走窄了——以为做个CRUD管理系统就交差。实际上这套题目能承载的东西非常多&#xff0c;关键在于你怎么定义“助手”两个字。…

2026/10/20 20:01:00 阅读更多 →

日新闻

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/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出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/20 10:02:08 阅读更多 →
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/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练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/20 9:50:45 阅读更多 →