尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

异构图把运输成本算到边级:PyG 预测落地路线

异构图把运输成本算到边级:PyG 预测落地路线 异构图把运输成本算到边级PyG 预测落地路线【免费下载链接】pytorch_geometricGraph Neural Network Library for PyTorch项目地址: https://gitcode.com/GitHub_Trending/py/pytorch_geometric做物流的都被「拍脑袋报价」坑过。PyTorch GeometricPyG把图神经网络用在供应链上的思路很直接供应商、仓库、客户、产品装进同一张异构图让消息沿关系传播再对「仓库→客户」这条边做运输成本预测。本文面向有 Python/PyTorch 基础、想给自家物流网络做成本预测的工程师按五个落地决策走一遍全链路。为什么 Excel 算不清这笔账一条新开线路模型没参与定价上线首月多花 37 万。事后复盘发现报价只看了承运商的历史均价完全没考虑上游传导供应商产能不足导致某仓缺货改走另一条运输线客户延期索赔。这类「A 表的事影响 B 表的数」在单表视图里根本看不到SQL 关联三张表也拼不出传导路径——这是表格方案的结构性缺陷。图的价值是把实体和关系画在同一张纸上让影响沿边传播。PyG 的HeteroData异构数据容器节点和边都按「类型 索引」寻址负责装这张图。它和传统多表方案的差别对比项多表方案ERP/WMSPyGHeteroData组织方式每张业务实体一张表节点按类型存data[warehouse].x关系表达外键 JOIN边也按类型存edge_index是 2×E 索引特征更新视图重跑原地改 tensor跨实体传导靠 SQL 关联消息沿边传播逐跳聚合边类型不用穷举所有组合只保留有业务语义的几条边类型业务含义是否保留(supplier, supplies, warehouse)供应商给仓库供货保留(warehouse, transports, customer)仓库向客户发运保留预测目标就在这条边(warehouse, stores, product)仓库存储品类保留(customer, similar_to, customer)客户聚类产物删无业务语义建图就几行节点特征从 ERP/WMS 取现成字段做 z-score 归一化缺特征的纯关系型节点先用独热 ID 顶上去import torch from torch_geometric.data import HeteroData data HeteroData() data[supplier].x torch.randn(120, 8) # 产能、区位、历史履约率 data[warehouse].x torch.randn(30, 8) # 库容、周转天数、租金 data[customer].x torch.randn(5000, 8) # 下单频次、账期、区域 data[product].x torch.randn(300, 8) # 体积重、温层、单价 data[supplier, supplies, warehouse].edge_index sup_wh_idx data[warehouse, transports, customer].edge_index wh_cust_idx data[warehouse, stores, product].edge_index wh_prod_idx仓库自带的examples/hetero/hetero_link_pred.py用的是「用户-评分-电影」图把节点名换成供应链实体结构完全通用可以先跑通它的骨架再替换。编码器怎么配SAGEConv to_hetero 展开异构模型结论边级预测 节点编码 端点向量拼接 小 MLP。先给每个节点编码成向量再取边两个端点的向量拼起来输出标量。写模型时只写一个「同质 GNN」to_hetero异构转换器按data.metadata()自动给每种边类型配独立参数。⚠️ 这里有个坑SAGEConv的输入维度写-1由数据自动推断to_hetero才能顺利展开写死维度反而要手动对齐每种类型。from torch_geometric.nn import SAGEConv, to_hetero class GNNEncoder(torch.nn.Module): def __init__(self, hidden, out): super().__init__() self.conv1 SAGEConv((-1, -1), hidden) # -1: 输入维度自动推断 self.conv2 SAGEConv((-1, -1), out) def forward(self, x, edge_index): return self.conv2(self.conv1(x, edge_index).relu()) class EdgeDecoder(torch.nn.Module): def __init__(self, hidden): super().__init__() self.lin1 torch.nn.Linear(2 * hidden, hidden) self.lin2 torch.nn.Linear(hidden, 1) def forward(self, z_dict, edge_label_index): row, col edge_label_index z torch.cat([z_dict[warehouse][row], z_dict[customer][col]], dim-1) return self.lin2(self.lin1(z).relu()).view(-1) model_encoder to_hetero(GNNEncoder(64, 64), data.metadata(), aggrsum)解码器输出拼好后过lin2得到标量。训练就是普通 MSE 回归F.mse_loss(pred, edge_label) Adam评估同时算 RMSE 和 MAE方便对到业务口径测试集 MAE 0.8 千元/单乘以月单量 10 万就是「模型平均偏差 ≈ 80 万元/月」——这个数拿去跟现在的固定报价比才知道该不该让模型出价。判断好坏只看 test splitval 上的数字只用来早停。时间轴怎么切时序采样防未来泄漏结论运输关系每天在变「上周新开的一条线路」不该出现在本周的训练里所以要按时序切边采样本身也要受时间约束。数据切分用RandomLinkSplit随机链路切分把边划成训练/验证/测试三组注意rev_edge_types必须带上反向边否则反向边会泄漏到训练集回归任务传neg_sampling_ratio0.0不需要负样本from torch_geometric.transforms import RandomLinkSplit train_data, val_data, test_data RandomLinkSplit( num_val0.1, num_test0.1, neg_sampling_ratio0.0, # 回归任务不造负样本 edge_types[(warehouse, transports, customer)], rev_edge_types[(customer, rev_transports, warehouse)], )(data)真正干活的是LinkNeighborLoader关键是temporal_strategylast每跳采样只取截断时刻之前的邻居从机制上挡住未来信息from torch_geometric.loader import LinkNeighborLoader loader LinkNeighborLoader( datadata, num_neighbors[5, 5], edge_label_index((warehouse, transports, customer), edge_index), edge_label_timeedge_time - 1, # 减 1防止采样到当前时刻本身的边 time_attrtime, temporal_strategylast, batch_size256, shuffleTrue, )edge_label_time edge_time - 1这个「减 1」别省不减的话预测时点当刻的边本身可能落进采样范围等于偷看答案。时序这块比模型本身更容易出错examples/hetero/recommender_system.py就是按时间戳切分再训练的完整参考。如果任务从回归换成链路预测预测哪些线路会新开loader 里加neg_samplingdict(modebinary, amount2)造负样本评估换LinkPredPrecision(k)/LinkPredRecall(k)torch_geometric.metricsPrecision10 可解读为「给每条线路推荐 10 个候选合作方平均有几个真发生了往来」召回率回答「真实合作被推荐列表覆盖了多少」。负样本比例对 PrecisionK 影响很大值得单独调。大图怎么扛分布式切图与跨机拉取节点过百万、单机装不下时torch_geometric/distributed/提供两级扩展离线阶段Partitioner切分器把节点和特征按分片落盘在线阶段DistNeighborLoader绑定本分片本地邻居直接读跨分片邻居走 RPC 从远端拉。效果是采样开销从「全图」降到「本机分片 一跳远程」训练吞吐随机器数近似线性扩展。对大客户订单边动辄上亿的供应链网络这一步基本是必选项。线上怎么跑torch.jit 脚本化部署结论torch.jit.script导出后推理侧不再依赖 Python 训练环境做法可参考仓库的examples/jit/gin.py。scripted torch.jit.script(model) torch.jit.save(scripted, supply_chain_model.pt) loaded torch.jit.load(supply_chain_model.pt) pred loaded(x_dict, edge_index_dict, edge_label_index)导出的是「编码器 解码器」整体输入仍是x_dict/edge_index_dict线上服务把特征拼装好直接喂入如果线上只更新编码器特征变了但解码关系不变也可以只导编码器单独服务。落地前检查⚠️ 先确认边类型清单预测目标那条边(warehouse, transports, customer)必须保留反向边要在RandomLinkSplit的rev_edge_types里声明否则训练集泄漏边上的时间戳字段要对齐time_attredge_label_time的减 1 别省线上别用 train 指标做决策MAE 要挂在 test split 上换算成钱再跟固定报价比节点过百万就切分Partitioner离线跑一次采样耗时能差一个数量级【免费下载链接】pytorch_geometricGraph Neural Network Library for PyTorch项目地址: https://gitcode.com/GitHub_Trending/py/pytorch_geometric创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表