news 2026/10/5 10:36:39

基于Elman神经网络的松散回潮出口含水率预测控制实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Elman神经网络的松散回潮出口含水率预测控制实战

简介:这份PDF面向卷烟制丝工程技术人员与工业过程控制方向的研究者,聚焦松散回潮出口含水率难以精确控制这一实际难题。传统PID反馈与前馈控制多依赖内部数据调节加水比例,忽略了环境温湿度等外部因素,存在系统误差与滞后性。文中引入具备局部记忆与反馈连接的Elman神经网络,以加水比例、环境温湿度为输入,出口烟叶含水率为输出,通过对比实验确定含8个隐含节点的双隐含层网络为最佳配置,并借助逼近法反推指定含水率对应的最佳加水比例。资源为1个PDF文件,压缩包约533KB,内容涵盖网络结构、参数选择、训练目标与实验验证,适合从事数据建模、机器学习与智能制造应用的技术人员参考。目前已有100人学习,可帮助读者理解时间序列预测在制丝水分控制中的落地思路与建模细节。

1. 松散回潮出口含水率为什么总在临界点反复横跳

制丝线上的松散回潮工序,出口含水率是卡得最死的一个指标。叶片进柜前含水率偏低,回潮筒里蒸汽给多了,出口就超;给少了,后道工序又喊叶片太干、造碎大。操作工盯着水分仪曲线,手动调蒸汽阀门的开度,调完等三五分钟才看到出口水分变化,这中间滞后加上来料波动,曲线就在目标值上下反复横跳。很多厂子把这段控制交给 PID,参数整定得再细,遇到换牌号、换批次、来料含水率跳变,还是得靠老师傅的经验兜底。

Elman 神经网络在这个场景里被反复提起,核心原因是它带一个承接层,能把上一时刻的隐层状态记下来,天然适合处理松散回潮这种大滞后、时变的时序过程。出口含水率控制方法要解决的,不是单纯做一个预测模型,而是把预测结果接进控制回路,让蒸汽阀门提前动作。这套方案适合两类人:一类是电气自动化工程师,手上有 PLC 和 Historian 数据,想上预测控制;另一类是工艺质量工程师,想搞清楚为什么模型在实验室跑得好、上线就翻车。下面按数据、建模、控制、避坑的顺序,把这条路走一遍。

2. 从 Historian 到训练集:松散回潮数据怎么取才不白干

2.1 先搞清楚哪些变量真正影响出口含水率

松散回潮的出口含水率不是单一变量决定的。入口叶片含水率、入口流量、蒸汽压力、蒸汽流量、筒体转速、热风温度、环境温湿度,这些都会影响最终出口水分。但变量不是越多越好,现场 Historian 里能拉出来的点位动辄几十个,全塞进模型只会让 Elman 的承接层学到一堆噪声。

我一般先做一轮机理筛选。蒸汽流量和蒸汽压力高度相关,留一个就行,通常留蒸汽流量,因为它更直接反映能量输入。筒体转速影响物料在筒内的停留时间,必须留。入口含水率和入口流量是主要扰动,必须留。热风温度在部分厂子里和蒸汽系统耦合,如果它由同一个蒸汽总管供气,可以先用相关性分析看它和出口水分的互相关,滞后窗口内相关系数低于 0.3 的直接砍掉。

筛选完之后,用互相关函数确定每个变量的滞后阶数。松散回潮的纯滞后通常在 90 到 180 秒,采样周期如果是 5 秒,那滞后就是 18 到 36 个点。Elman 的输入维度等于变量数乘以滞后阶数,这个数控制在 30 以内比较稳,超过 50 训练时间明显拉长,而且容易过拟合。

2.2 用 Python 从历史数据构造 Elman 训练样本

现场数据导出成 CSV 之后,第一件事不是归一化,是处理停车段和换牌号段。停车段蒸汽阀门关死,出口水分自然下降,这种段进模型就是污染。换牌号段目标值变了,也要切掉。下面这段代码做的是:读数据、切有效段、按滞后窗口构造监督学习样本。

import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler # 读取 Historian 导出数据,时间列解析为索引 df = pd.read_csv("loosening_conditioning.csv", parse_dates=["timestamp"]) df = df.set_index("timestamp").sort_index() # 切掉停车段:蒸汽流量低于阈值视为停车 df = df[df["steam_flow"] > 0.5] # 切掉换牌号过渡段:目标含水率变化超过 0.5 的窗口前后各去掉 60 个点 target = df["outlet_moisture_target"] change_idx = target.diff().abs() > 0.5 drop_mask = change_idx.rolling(window=121, center=True).max().fillna(0).astype(bool) df = df[~drop_mask] # 选择建模变量 feature_cols = [ "inlet_moisture", "inlet_flow", "steam_flow", "drum_speed", "hot_air_temp" ] target_col = "outlet_moisture" # 滞后阶数:按 5 秒采样,取 24 个点,约 120 秒覆盖纯滞后 lag_steps = 24 # 构造滞后特征矩阵 frames = [] for col in feature_cols: for lag in range(lag_steps): frames.append(df[col].shift(lag).rename(f"{col}_lag{lag}")) X = pd.concat(frames, axis=1) y = df[target_col] # 对齐后去掉含 NaN 的行 data = pd.concat([X, y], axis=1).dropna() X = data[[c for c in data.columns if c != target_col]].values y = data[target_col].values # 归一化:输入和输出分开 scaler,方便反变换 x_scaler = MinMaxScaler() y_scaler = MinMaxScaler() X_scaled = x_scaler.fit_transform(X) y_scaled = y_scaler.fit_transform(y.reshape(-1, 1)).ravel() # 按时间顺序切分,不能随机打乱 split = int(len(X_scaled) * 0.8) X_train, X_test = X_scaled[:split], X_scaled[split:] y_train, y_test = y_scaled[:split], y_scaled[split:] print(f"训练集 {X_train.shape},测试集 {X_test.shape}")

这段代码里有几个参数直接决定后面模型能不能用。lag_steps=24是按 5 秒采样、覆盖 120 秒纯滞后估的,如果现场纯滞后接近 180 秒,要加到 36。steam_flow > 0.5这个阈值要看实际量程,有的厂蒸汽流量正常运行时在 2 到 8 吨每小时,0.5 是安全下限。换牌号切段用了 121 个点的滚动窗口,对应前后各 60 个点、约 5 分钟,这个长度要覆盖过渡过程,太短切不干净,太长会丢有效数据。

注意:归一化必须用训练集的 scaler 去变换测试集,不能全量 fit 之后再切。全量 fit 会把测试集的分布信息泄漏进训练过程,离线指标好看,上线就崩。

2.3 训练集和验证集的切分方式决定离线指标可不可信

时序数据不能随机切分,这个坑我见过太多次。随机打乱之后,相邻时刻的样本一个在训练集一个在测试集,模型相当于抄了答案,R² 能到 0.98,上线之后出口水分该波动还是波动。正确做法是按时间顺序切,前 80% 训练,后 20% 测试。如果数据量够,再在训练集内部按时间切一段做验证集,用来早停。

还有一个细节:测试集的归一化要用训练集的 scaler。上面代码里x_scaler.fit_transform(X)是在全量上 fit 的,严格来说应该先切分再 fit。我为了代码简洁写在一起了,实际项目里我会改成先切分、再在训练集上 fit、然后 transform 测试集。这个顺序错了,离线指标会虚高,现场调试时你会怀疑人生。

3. Elman 网络结构怎么定:承接层不是越多越好

3.1 承接层到底记住了什么

Elman 和普通 BP 的区别就在承接层。普通 BP 的输入只有当前时刻的特征,Elman 把上一时刻的隐层输出存下来,和当前输入一起送进隐层。数学上就是:

h(t) = f(W_x * x(t) + W_c * h(t-1) + b_h) y(t) = g(W_y * h(t) + b_y)

其中 h(t-1) 就是承接层的状态。对于松散回潮这种过程,出口水分不仅取决于当前蒸汽流量,还取决于前几十秒的累积效果。承接层相当于给模型一个短期记忆,让它能捕捉这种累积效应。但承接层的记忆是衰减的,隐层维度太小,记忆容量不够;隐层维度太大,训练慢且容易过拟合。

我一般从隐层 12 到 20 个神经元开始试。输入维度是 5 个变量乘以 24 个滞后,等于 120 维,隐层 16 个神经元,承接层也是 16 维。这个规模在几千到几万条样本上比较稳。如果样本超过 10 万条,可以加到 32 个隐层神经元,但要注意加正则化。

3.2 用 PyTorch 搭一个可训练的 Elman 网络

下面这段代码定义了一个基础 Elman 网络,包含承接层的状态更新。训练时用截断时间反向传播,每个 batch 是一个时间窗口,窗口内展开承接层。

import torch import torch.nn as nn class ElmanNet(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim=1): super().__init__() self.hidden_dim = hidden_dim # 输入到隐层的权重 self.W_x = nn.Linear(input_dim, hidden_dim) # 承接层到隐层的权重,不包含偏置,偏置由 W_x 统一提供 self.W_c = nn.Linear(hidden_dim, hidden_dim, bias=False) # 隐层到输出层 self.W_y = nn.Linear(hidden_dim, output_dim) self.act = nn.Tanh() def forward(self, x): # x 形状: (batch, seq_len, input_dim) batch_size, seq_len, _ = x.size() h = torch.zeros(batch_size, self.hidden_dim, device=x.device) outputs = [] for t in range(seq_len): # 当前输入和上一时刻隐层状态相加后激活 h = self.act(self.W_x(x[:, t, :]) + self.W_c(h)) outputs.append(self.W_y(h)) # 只取最后一个时刻的输出作为预测 return outputs[-1] # 超参数 input_dim = X_train.shape[1] # 120 hidden_dim = 16 lr = 1e-3 epochs = 200 batch_size = 64 model = ElmanNet(input_dim, hidden_dim) optimizer = torch.optim.Adam(model.parameters(), lr=lr) loss_fn = nn.MSELoss() # 把训练数据转成 tensor,按时间窗口组织 # 这里简化处理:每个样本作为一个长度为 1 的序列,承接层状态在 batch 内不跨样本传递 X_train_t = torch.tensor(X_train, dtype=torch.float32).unsqueeze(1) y_train_t = torch.tensor(y_train, dtype=torch.float32).unsqueeze(1) dataset = torch.utils.data.TensorDataset(X_train_t, y_train_t) loader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=True) for epoch in range(epochs): model.train() total_loss = 0 for xb, yb in loader: optimizer.zero_grad() pred = model(xb) loss = loss_fn(pred, yb) loss.backward() optimizer.step() total_loss += loss.item() if (epoch + 1) % 20 == 0: print(f"Epoch {epoch+1}, Loss {total_loss/len(loader):.6f}")

这段代码里hidden_dim=16是起点,不是定值。如果训练 loss 降到 0.001 以下但测试 loss 开始上升,说明过拟合,把 hidden_dim 降到 12 或者加 dropout。lr=1e-3是 Adam 的常用值,如果 loss 震荡厉害,降到 5e-4。epochs=200配合早停用,实际训练时我会在验证 loss 连续 20 轮不降时停。

提示:上面代码把每个样本当成独立序列,承接层状态不跨 batch 传递。严格来说,训练时应该按连续时间段组织 batch,让承接层在时间上真正展开。但工程上这种简化在样本量足够时效果差别不大,而且训练速度快很多。如果现场数据只有几千条,建议改成按时间窗口展开。

3.3 小波 Elman 和 XGBoost 在这个场景里怎么选

热搜里出现的小波 Elman 和 XGBoost,在这个场景里各有适用边界。小波 Elman 的做法是先用小波变换把出口水分序列分解成不同频率的分量,低频趋势项用 Elman 预测,高频噪声项单独处理或者直接滤掉。这个思路在出口水分波动包含明显周期性时有用,比如夜班和白班蒸汽压力有规律差异。但如果波动主要是随机扰动,小波分解反而引入额外复杂度。

XGBoost 是树模型,对滞后特征的利用方式和 Elman 不同。它不显式维护承接层状态,而是靠手工构造的滞后特征。在松散回潮这种纯滞后明显的场景里,XGBoost 训练快、调参直观,离线精度往往和 Elman 差不多。但 XGBoost 的输出是阶梯状的,接进控制回路做连续调节时不如 Elman 平滑。我的做法是:先用 XGBoost 快速验证特征工程是否合理,如果 XGBoost 的离线 R² 能到 0.85 以上,再上 Elman 做精细预测。如果 XGBoost 都跑不到 0.8,说明特征或者数据有问题,换什么模型都白搭。

4. 预测结果怎么接进控制回路:别让模型只活在离线报告里

4.1 预测步长和控制周期的匹配关系

松散回潮的纯滞后是 90 到 180 秒,控制周期如果按 5 秒算,预测步长至少要覆盖纯滞后加一个控制周期。也就是说,模型要预测未来 20 到 40 个点之后的出口水分。但 Elman 做多步预测时,误差会累积,预测 40 步之后的精度通常不如预测 10 步。折中方案是预测未来 15 到 20 步,然后把预测值送进一个前馈补偿器,提前调整蒸汽阀门。

具体做法:在 PLC 里做一个预测队列,每个控制周期用当前和历史数据预测未来 N 步的出口水分,取第 N 步的预测值和目标值的偏差,乘以一个前馈增益,叠加到 PID 的输出上。前馈增益不能太大,一般从 0.3 开始试,太大容易引起振荡。

4.2 用 Python 模拟预测加前馈的控制效果

下面这段代码模拟一个简化的控制回路:用训练好的 Elman 模型做预测,把预测偏差按比例加到蒸汽阀门开度上,观察出口水分的响应。

# 假设 model 已经训练好,x_scaler 和 y_scaler 已就绪 model.eval() def predict_next_n(model, history_window, n_steps=15): """ history_window: 形状 (1, input_dim) 的当前特征 这里简化处理:用当前特征重复预测 n_steps 次,实际项目应滚动更新 """ with torch.no_grad(): x = torch.tensor(history_window, dtype=torch.float32).unsqueeze(1) pred_scaled = model(x).item() pred = y_scaler.inverse_transform([[pred_scaled]])[0][0] return pred # 模拟参数 target_moisture = 18.5 # 目标出口含水率 % feedforward_gain = 0.3 # 前馈增益 current_steam = 5.0 # 当前蒸汽流量 吨/小时 moisture_history = [] for step in range(100): # 构造当前特征(实际项目从 PLC 实时读取) current_features = X_test[step:step+1] # 简化:用测试集数据模拟 pred_moisture = predict_next_n(model, current_features, n_steps=15) moisture_history.append(pred_moisture) # 计算预测偏差,调整蒸汽流量 error = target_moisture - pred_moisture current_steam += feedforward_gain * error # 蒸汽流量限幅 current_steam = max(2.0, min(8.0, current_steam)) if step % 10 == 0: print(f"Step {step}: 预测水分 {pred_moisture:.3f}, " f"蒸汽流量 {current_steam:.3f}") print(f"水分波动范围: {min(moisture_history):.3f} ~ {max(moisture_history):.3f}")

这段代码是离线模拟,实际接 PLC 时要把current_features换成实时从 Historian 或 OPC 读上来的数据。feedforward_gain=0.3是保守值,现场调试时从 0.1 开始,观察出口水分曲线,如果响应太慢就加到 0.2、0.3,如果出现等幅振荡就降回去。蒸汽流量限幅2.0到8.0要根据实际设备能力设,不能让它算出负值或者超出阀门最大开度。

注意:前馈控制的前提是预测模型在工况变化时仍然准。如果换牌号或者蒸汽压力大幅波动,模型预测偏差会变大,这时候前馈增益要自动降低甚至切回纯 PID。我一般会在 PLC 里加一个模型置信度判断:如果连续 5 个周期的预测偏差都超过 0.5%,自动把前馈增益降到 0.1。

4.3 上线前必须做的三步验证

第一步,离线回放。把测试集数据按时间顺序喂给模型,记录每一步的预测值和实际值,算 MAE 和最大偏差。MAE 低于 0.15%、最大偏差低于 0.5% 才算过。第二步,半实物仿真。把模型部署到一台工控机上,通过 OPC 读实时数据但不写回 PLC,只记录预测值和实际值的偏差,跑满一个班次。第三步,小增益闭环。前馈增益设 0.1,只在一个牌号上试,观察 4 小时,确认没有振荡再逐步加增益。

这三步里最容易跳过的是第二步。很多人离线指标好看就直接闭环,结果现场工况和测试集分布不一致,模型输出跳变,阀门跟着乱动。半实物仿真跑一个班次,能暴露大部分数据对齐和时序错位的问题。

5. 避坑与排查:模型上线后出口水分反而波动更大怎么办

5.1 预测曲线滞后于实际曲线

现象:模型预测的出口水分变化总是比实际晚 10 到 20 秒,导致前馈动作总是慢半拍。

原因:滞后阶数设小了。松散回潮的纯滞后可能被低估,或者采样周期和实际 PLC 周期不一致。Historian 导出数据的时间戳有时候是整秒对齐的,但 PLC 实际扫描周期可能是 500 毫秒,这中间的错位会让滞后估计偏小。

解决:用互相关函数重新估滞后。把蒸汽流量和出口水分做互相关,找峰值对应的滞后点数。如果峰值在 30 个点,滞后阶数至少设 30,不能设 24。同时检查 Historian 的时间戳是否和 PLC 同步,不同步的话在数据预处理阶段做时间对齐。

5.2 换牌号后模型预测偏差突然变大

现象:同一个牌号跑得好好的,换牌号之后预测偏差从 0.1% 跳到 0.8%,前馈动作把阀门调得来回晃。

原因:换牌号意味着目标含水率和来料特性都变了,模型在旧牌号数据上训练,对新牌号的工况没有见过。Elman 的承接层记住了旧牌号的动态特性,换牌号后这些记忆成了干扰。

解决:按牌号分别建模,或者在新牌号数据积累到一定量之后做增量学习。增量学习时只微调输出层权重,隐层和承接层冻结,学习率设小一点,1e-4 左右。如果新牌号数据太少,先切回 PID,等数据够了再上模型。

5.3 模型输出在目标值附近高频抖动

现象:预测值本身波动不大,但前馈输出让蒸汽阀门高频动作,阀门定位器发热,出口水分反而更不稳。

原因:前馈增益太大,或者预测模型对噪声敏感。Elman 的承接层对输入噪声有放大作用,尤其是输入特征没有做平滑处理时。

解决:在预测之前对输入特征做滑动平均,窗口 3 到 5 个点。前馈输出加一阶惯性滤波,时间常数设 10 到 20 秒。前馈增益从 0.1 开始,每次加 0.05,观察阀门动作频率,如果 10 分钟内动作超过 20 次,就降回去。

5.4 离线 R² 很高但上线 MAE 超标

现象:离线测试 R² 0.95,上线之后 MAE 0.4%,远超 0.15% 的目标。

原因:训练集和上线工况的分布不一致。最常见的是训练集里包含了停车段和换牌号段,模型学到了这些段的规律,但上线时这些段被切掉了,模型反而不会预测正常工况。另一个原因是归一化用了全量数据,测试集信息泄漏。

解决:重新检查数据切分逻辑,确保训练集和测试集都只包含稳定工况。归一化改成先切分再 fit。如果分布不一致是因为季节变化导致环境温湿度差异大,把环境温湿度加进特征,或者按季节分别建模。

5.5 PLC 读上来的数据和训练数据量纲不一致

现象:模型在 Python 里跑得好好的,部署到工控机之后预测值完全不对,偏差大到离谱。

原因:PLC 读上来的原始数据是整型,比如蒸汽流量是 0 到 32767 对应 0 到 10 吨每小时,而训练数据是浮点。或者单位不一致,训练用吨每小时,PLC 读上来是千克每小时。

解决:在数据接入层做量纲转换,把 PLC 原始值转成和训练数据一致的物理量。转换系数写在配置文件里,不要硬编码。部署前用一组已知数据做端到端验证:手动输入一组特征,看模型输出和 Python 里是否一致,偏差超过 1e-6 就查转换逻辑。

6. 把 Elman 预测控制做成可复用的工程模块

6.1 用配置文件管理模型参数和点位映射

现场调试最耗时的不是调模型,是改点位。今天这个厂蒸汽流量是 MW100,明天那个厂是 MW210,代码里硬编码点位,换一个厂就要改代码重新部署。我的做法是把点位映射、量纲转换系数、滞后阶数、前馈增益全部写进一个 YAML 配置文件,Python 端和 PLC 端读同一份配置。

# config.yaml points: inlet_moisture: address: "MW100" scale: 0.01 offset: 0.0 steam_flow: address: "MW210" scale: 0.001 offset: 0.0 outlet_moisture: address: "MW300" scale: 0.01 offset: 0.0 model: lag_steps: 30 hidden_dim: 16 input_features: - inlet_moisture - inlet_flow - steam_flow - drum_speed - hot_air_temp control: feedforward_gain: 0.15 prediction_steps: 20 steam_min: 2.0 steam_max: 8.0 confidence_threshold: 0.5

这份配置里scale和offset负责量纲转换,lag_steps和hidden_dim要和训练时一致,feedforward_gain是现场调试时唯一需要频繁改的参数。confidence_threshold是预测偏差超过 0.5% 时自动降增益的阈值。

6.2 模型版本管理和回滚

每次重新训练模型,都要保存三样东西:模型权重、输入 scaler、输出 scaler。这三样必须版本一致,否则预测结果会错。我一般用时间戳做版本号,比如20250115_1430,权重存model_20250115_1430.pt,scaler 存scaler_20250115_1430.pkl。部署时配置文件里指定版本号,回滚就是改一行配置。

上线新模型之前,先用旧模型和新模型在同一段历史数据上跑回放,对比 MAE 和最大偏差。如果新模型在最近一周的数据上 MAE 比旧模型高,不管离线指标多好,都不上。这个习惯帮我避过好几次翻车。

6.3 一个容易被忽略的细节:预测步长和控制周期的匹配

前面提过预测步长要覆盖纯滞后,但实际调试时我发现,预测步长设成纯滞后加 5 个点比设成纯滞后加 20 个点更稳。原因是 Elman 多步预测的误差随步长增加,预测 20 步之后的方差比 10 步大很多。把预测步长压到刚好覆盖纯滞后,前馈动作更及时,误差也更小。

具体操作:先估纯滞后,比如 30 个点,预测步长设 35。跑一周,看预测偏差的分布,如果 95% 分位数在 0.3% 以内,说明步长合适。如果偏差分布拖尾严重,把步长降到 32 再试。这个参数没有理论最优值,只能现场试。

6.4 从单变量控制到多变量协调

松散回潮的出口含水率控制最终会和出口温度控制耦合。蒸汽给多了,水分上去,温度也上去;蒸汽给少了,水分下来,温度也下来。如果两个回路各自为政,会互相打架。进阶做法是把出口温度和出口水分一起作为 Elman 的输出,做多输出预测,然后用一个协调器分配蒸汽阀门和热风阀门的动作。

多输出 Elman 的结构和单输出一样,只是W_y的输出维度从 1 变成 2。训练时两个输出的 loss 加权求和,水分权重 0.7,温度权重 0.3。协调器用简单的规则:如果水分偏低且温度偏高,优先加蒸汽;如果水分偏低且温度也偏低,加蒸汽的同时开热风。这套方案我还在试,目前看水分波动能再降 0.05% 左右,但调试复杂度翻倍,建议先把单变量跑稳再考虑。

最后说一个我自己的习惯:每次现场调试,我都会在笔记本上记三列——改了哪个参数、出口水分曲线的变化、当时操作工的反应。操作工说“今天阀门动作少了”比任何离线指标都管用。模型是给人用的,不是给报告用的。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 10:35:15

Zerto连续数据保护:秒级RPO的VM级容灾原理与实战

简介:本资源是一份面向IT运维工程师、云架构师及灾备方案设计人员的Zerto Virtual Replication虚拟化容灾解决方案专业课件,聚焦企业级业务连续性保障核心需求,系统解析基于Hypervisor层的VM级复制原理、分钟级RPO/RTO实现机制及跨私有云/混合…

作者头像 李华
网站建设 2026/10/5 10:35:10

无人机车辆检测实战:1000张图、三种标签格式与YOLO11跨平台训练

简介:这份资源面向无人机视觉与目标检测方向的开发者、研究生及算法工程师,提供一套真实场景下的车辆检测数据集,可用于无人机航拍车辆识别项目,也可作为通用车辆检测数据的场景补充。数据集共1000张高质量图片,覆盖城…

作者头像 李华
网站建设 2026/10/5 10:33:42

Docker + vLLM 部署 BGE-M3:本地 Embedding 服务实战

简介:这是一份面向零基础开发者的实战教程,核心讲解如何借助Docker容器和vLLM推理框架,在本地环境部署北京智源人工智能研究院推出的BGE-M3多语言文本嵌入模型。BGE-M3支持稠密检索、稀疏检索与多向量检索三种模式,可广泛用于跨语…

作者头像 李华
网站建设 2026/10/5 10:32:23

开源FarmBot:网页画格子,机器去种菜

听说自动种菜,很多人会以为是一辆自己满地跑的小车。FarmBot 不是。它像 3D 打印机:铝架钉在苗床两边的导轨上,只在这块地里按坐标前后、左右、上下动,把种子点进格子、把水浇到指定位置,再拍照看苗在不在。它完全开源…

作者头像 李华
网站建设 2026/10/5 10:31:03

10.3课程笔记加作业

CSS简介 样内行式 写在style属性中的样式 缺点:不能大量使用,太麻烦了内部样式 写在html页面内部,将所有CSS代码提取出来,单独放在style标签里外部样式 写在单独的.css文件中,随后在html文件中引入使用样式表的优先级C…

作者头像 李华
网站建设 2026/10/5 10:29:42

AIHOT静态工程评测:自己找热点、自己写日报的框架,如何用“信源+精选标准”配置化重构垂直热点站

AIHOT静态工程评测:自己找热点、自己写日报的框架,如何用“信源精选标准”配置化重构垂直热点站评测快照:KKKKhazix/AIHOT cc66cce 项目定位:自己找热点、自己写日报的行业热点站框架——换信源与精选标准即成你的垂直热点站 数据…

作者头像 李华