昇腾CANN elec-ops-prediction 仓:电力负荷预测深度实践

昇腾CANN elec-ops-prediction 仓:电力负荷预测深度实践 前言你管一个园区的供电调度室的大屏上要你预测未来 24 小时的负荷走势。传统方案用 LSTM但推理一次要 500ms而且批量预测时吞吐上不去。这其实是典型的时序预测问题。elec-ops-prediction 是 CANN 针对电力场景优化的推理算子库预处理、推理、后处理一条龙。这篇文章深度实践带你跑通电力负荷预测的完整推理流程。电力负荷预测的业务需求先说电力系统要什么预测的时间尺度预测类型时间范围用途精度要求超短期0~4 小时实时调度15 分钟短期4~72 小时日前调度1 小时中期72 小时~2 周检修安排1 天长期2 周~1 年规划1 周输入特征电力负荷预测常用的特征# 输入特征的 Python 表示features{# 历史负荷history_load:[100,105,98,...],# 过去 N 个点的负荷# 时间特征hour_of_day:14,# 当前小时 (0-23)day_of_week:2,# 星期几 (0-6)month:6,# 月份 (1-12)is_holiday:0,# 是否假日# 气象特征temperature:28.5,# 温度humidity:65,# 湿度# 经济特征industrial_index:1.02,# 工业指数}elec-ops-prediction 配方内容# elec-ops-prediction 仓库elec-ops-prediction/ ├── ops/ │ ├── feature_extraction/# 特征提取算子│ │ ├── sliding_window.py │ │ ├── time_features.py │ │ └── lag_features.py │ ├── inference/# 推理算子│ │ ├── lstm_predict.py │ │ ├── transformer_predict.py │ │ └── xgboost_predict.py │ └── postprocessing/# 后处理算子│ ├── inverse_norm.py │ └── smoothing.py ├── models/# 预训练模型│ ├── lstm_24h.om │ ├── transformer_24h.om │ └── ensemble_24h.om ├── configs/# 配置文件│ ├── short_term.yaml │ └── medium_term.yaml └── tests/ └── test_inference.py推理流程Step 1数据接入# step1_data_loader.pyimportpandasaspdimportnumpyasnpfromdatetimeimportdatetimedefload_power_data(filepath,start_timeNone,end_timeNone): 加载电力负荷数据 Args: filepath: CSV 文件路径 start_time: 开始时间 end_time: 结束时间 dfpd.read_csv(filepath,parse_dates[timestamp])dfdf.set_index(timestamp)ifstart_time:dfdf[df.indexstart_time]ifend_time:dfdf[df.indexend_time]returndfdefload_from_scada(scada_host,meter_id,start_time,end_time): 从 SCADA 系统加载实时数据 SCADA: Supervisory Control And Data Acquisition # 连接 SCADAclientSCADAClient(hostscada_host)# 查询历史数据query{meter_id:meter_id,start_time:start_time.isoformat(),end_time:end_time.isoformat(),interval:5min# 5分钟粒度}dfclient.query_historical(query)dfdf.set_index(timestamp)returndf[load]# 只取负荷列defload_from_api(api_url,start_date,end_date): 从能源管理系统 API 加载 importrequests responserequests.get(api_url,params{start_date:start_date,end_date:end_date})dataresponse.json()dfpd.DataFrame(data[measurements])df[timestamp]pd.to_datetime(df[timestamp])dfdf.set_index(timestamp)returndf[load]# 使用# df load_from_scada(scada.company.com, METER_001,# datetime(2024, 1, 1), datetime(2024, 1, 2))# print(df.head())Step 2特征工程# step2_feature_engineering.pyimportnumpyasnpimportpandasaspdfromdatetimeimportdatetimedefextract_time_features(timestamps):提取时间特征featurespd.DataFrame(indextimestamps)# 时间周期特征sin/cos 编码避免突变features[hour_sin]np.sin(2*np.pi*timestamps.hour/24)features[hour_cos]np.cos(2*np.pi*timestamps.hour/24)features[day_sin]np.sin(2*np.pi*timestamps.dayofyear/365)features[day_cos]np.cos(2*np.pi*timestamps.dayofyear/365)features[week_sin]np.sin(2*np.pi*timestamps.dayofweek/7)features[week_cos]np.cos(2*np.pi*timestamps.dayofweek/7)returnfeaturesdefextract_lag_features(load_series,lags[1,2,3,24,48,168]): 提取滞后特征前 N 个时间点的负荷 Args: lags: 滞后的时间步数 featurespd.DataFrame(indexload_series.index)forlaginlags:features[flag_{lag}]load_series.shift(lag)# 滚动统计特征features[rolling_mean_24h]load_series.rolling(24*12,min_periods1).mean()# 24小时滑动平均features[rolling_std_24h]load_series.rolling(24*12,min_periods1).std()features[rolling_max_24h]load_series.rolling(24*12,min_periods1).max()features[rolling_min_24h]load_series.rolling(24*12,min_periods1).min()returnfeaturesdefextract_weather_features(temperature,humidity):提取气象特征featurespd.DataFrame()features[temperature]temperature features[humidity]humidity# 派生特征features[temp_squared]temperature**2# 温度的非线性效应features[temp_humidity]temperature*humidityreturnfeaturesdefbuild_feature_matrix(load_series,weather_df,timestampsNone): 构建完整的特征矩阵 Args: load_series: 历史负荷 Series weather_df: 气象数据 DataFrame timestamps: 时间戳可选 # 1. 时间特征iftimestampsisNone:timestampsload_series.index time_featuresextract_time_features(timestamps)# 2. 滞后特征lag_featuresextract_lag_features(load_series)# 3. 气象特征weather_featuresextract_weather_features(weather_df[temperature],weather_df[humidity])# 4. 合并featurespd.concat([time_features,lag_features,weather_features],axis1)# 5. 填充 NaNfeaturesfeatures.fillna(methodbfill).fillna(methodffill)returnfeatures# 使用# features build_feature_manager(load_series, weather_df)# print(features.shape) # (n_samples, n_features)Step 3推理调用 OM# step3_inference.pyimporttorchimportatbimportnumpyasnpclassElectricityPredictor:电力负荷预测器def__init__(self,model_path,history_len168): Args: model_path: OM 模型路径 history_len: 历史窗口长度默认 7 天 * 24 小时 self.history_lenhistory_len self.modelatb.create_inference_model(model_pathmodel_path,devicenpu:0)defpredict(self,features,prediction_horizon24): 预测未来 N 小时的负荷 Args: features: 特征矩阵 (history_len prediction_horizon, n_features) prediction_horizon: 预测步数 Returns: predictions: 预测值数组 (prediction_horizon,) # 1. 转为 tensorxtorch.from_numpy(features.values).float()# 2. 确保 shape 正确 (1, history_len horizon, n_features)ifx.dim()1:xx.unsqueeze(0)# 3. 转 NPUxx.npu()# 4. 推理withtorch.no_grad():outputself.model(x)# 5. 转 numpypredictionsoutput.squeeze(0).cpu().numpy()# 只取预测部分returnpredictions[-prediction_horizon:]defpredict_iterator(self,features,prediction_horizon24,step1): 迭代预测逐步预测每次预测下一步 all_predictions[]# 初始输入current_featuresfeatures[:self.history_len].copy()foriinrange(0,prediction_horizon,step):# 预测下一步next_predself.predict(current_features,step)[0]all_predictions.append(next_pred)# 更新输入窗口滑动# 这里省略实现细节...returnnp.array(all_predictions)defbatch_predict(predictor,feature_list): 批量预测多用户/多园区 results[]# Padding 到最大长度max_lenmax(len(f)forfinfeature_list)padded[]forfinfeature_list:iflen(f)max_len:ff.pad_to(max_len)padded.append(f)# Stack 成 batchbatchtorch.stack([torch.from_numpy(f.values)forfinpadded])# 推理outputspredictor.model(batch.npu())returnoutputs.cpu().numpy()# 使用predictorElectricityPredictor(transformer_24h.om)# 单次预测predictionspredictor.predict(features,prediction_horizon24)print(fPredictions:{predictions.shape})# Predictions: (24,)Step 4后处理# step4_postprocessing.pyimportnumpyasnpimportpandasaspddefinverse_normalize(predictions,mean,std):反归一化returnpredictions*stdmeandefapply_business_constraints(predictions,min_load0,max_load10000): 应用业务约束 Args: min_load: 最小负荷 max_load: 最大负荷 predictionsnp.clip(predictions,min_load,max_load)returnpredictionsdefsmooth_predictions(predictions,window3): 平滑预测结果前后滑动平均 returnpd.Series(predictions).rolling(window,centerTrue).mean().valuesdefaggregate_to_hour(predictions,original_freq15min): 聚合成小时粒度 # 假设 predictions 是 15 分钟粒度的# 每 4 个点平均成一个小时n_hourslen(predictions)//4aggregated[]foriinrange(n_hours):hour_avgnp.mean(predictions[i*4:(i1)*4])aggregated.append(hour_avg)returnnp.array(aggregated)defformat_output(predictions,start_time,freq1H):格式化输出indexpd.date_range(startstart_time,periodslen(predictions),freqfreq)dfpd.DataFrame({timestamp:index,predicted_load:predictions})returndf# 完整的后处理流程defpostprocess_pipeline(predictions,start_time,mean,std,smoothTrue,aggregateTrue):后处理流水线# 1. 反归一化predictionsinverse_normalize(predictions,mean,std)# 2. 平滑ifsmooth:predictionssmooth_predictions(predictions,window3)# 3. 业务约束predictionsapply_business_constraints(predictions,min_load0,max_load10000)# 4. 聚合到小时如果有需要ifaggregate:predictionsaggregate_to_hour(predictions)# 5. 格式化输出outputformat_output(predictions,start_time)returnoutput部署实例# deployment.pyfromdatetimeimportdatetime,timedeltaclassElectricityPredictionService:电力负荷预测服务def__init__(self,config):# 加载配置self.history_hoursconfig[history_hours]self.prediction_hoursconfig[prediction_hours]self.model_pathconfig[model_path]# 加载模型self.predictorElectricityPredictor(self.model_path,history_lenself.history_hours)# 加载归一化参数self.load_meanconfig[load_mean]self.load_stdconfig[load_std]defpredict(self,current_time): 预测 current_time 之后 N 小时的负荷 # 1. 获取历史数据end_timecurrent_time start_timeend_time-timedelta(hoursself.history_hours)history_dataload_from_scada(scada.company.com,METER_001,start_time,end_time)# 2. 读取气象预报weatherload_weather_forecast(current_time,current_timetimedelta(hoursself.prediction_hours))# 3. 特征工程featuresbuild_feature_matrix(history_data,weather)# 4. 推理predictionsself.predictor.predict(features.values,prediction_horizonself.prediction_hours)# 5. 后处理outputpostprocess_pipeline(predictions,current_time,self.load_mean,self.load_std)returnoutput# 使用config{history_hours:168,# 7 天历史prediction_hours:24,# 预测 24 小时model_path:transformer_24h.om,load_mean:5000,load_std:1500}serviceElectricityPredictionService(config)# 执行预测current_timedatetime.now()resultservice.predict(current_time)print(result.head())性能数据模型推理延迟批量吞吐精度 (MAPE)LSTM12ms5003.2%Transformer18ms3502.8%XGBoost5ms12004.1%Ensemble25ms3002.5%Transformer 精度最好但延迟稍高XGBoost 最快适合实时要求高的场景Ensemble 综合最优总结elec-ops-prediction 的使用路径数据接入SCADA / API / 数据库特征工程时间特征 滞后特征 气象特征推理单模型或 Ensemble后处理反归一化 → 平滑 → 业务约束关键要点时序特征用 sin/cos 编码避免周期性突变预测频率高、单次数据量小Batch 设置要平衡用电高峰期延迟敏感Transformer 更稳仓库地址https://atomgit.com/cann/elec-ops-prediction附录电力负荷预测的常见模型对比模型精度 (MAPE)推理延迟训练时间适用场景LSTM3.2%12ms2h短期预测Transformer2.8%18ms4h短期/中期Informer2.5%25ms6h长序列XGBoost4.1%5ms30min实时调度LightGBM3.8%4ms20min超短期选型建议超短期分钟级用 LightGBM短期小时级用 Transformer中期用 Informer。附录elec-ops-prediction 的配置详解推理配置参数说明推荐值batch_size批大小1~8history_len历史窗口168 (7天)prediction_horizon预测步长24~96use_fp16混合精度true优化建议batch_size推理频率高分钟级用 batch1频率低小时级可以 batch1history_len短期预测 168 小时中期预测 720 小时30天use_fp16开启后延迟降低 30%精度几乎不变