深度学习在制造业供应链销量预测的应用

一、业务背景

        笔者去年完成了一个课题:用数据挖掘技术对经销商提货进行预测。这里是对提货量预测而不是对销量预测,是因为我司产品销售渠道主要是经销商,经销商的销售行为容易受销售政策影响,如果对销售订单数据进行预测,从业务上来说就没有意义,但是提货行为反应了真实的需求,所以是对提货单数据预测。

        对提货量进行预测的意义在于:1、需求的准确性提高--提升分仓的周转率进而提升总仓的周转率;2、提升生产计划准确性;3、提升物流转运效率。

        实际业务是销售部每月开一次计划会,对产品系列预测,然后再分摊到各SKU。本次项目的目的是通过历史数据建模而给出SKU级别的预测。

二、技术选型

2.1 算法

        销量预测是一个非常传统且历史悠久的命题,在各行各业都是非常头疼的问题,特别是按单生产的制造业。从供应链的角度来看,需求预测是供应链的发起端,如果这个地方偏差太大,会造成‘牛鞭效应’。

        销量预测技术分为三个类型:1、统计学时序预测;2、机器学习;3、深度学习。

        统计学经典方法包括:指数平滑、ARIMA、Holt-Winters

        机器学习方法包括:Xgboost、 GBDT、 Lightgbm、 Randomforest

        深度学习方法包括:RNNS(RNN及相关变体) 、CNN 、Transformer

       以下是三种方法的对比:1、统计学方法对于较简单的数据集有不错的效果,但是面对当前这个时代复杂的数据,是远远不够的。2、机器学习方法在各类竞赛中取得了不错的成绩,但是它对特征工程的技能要求较高,如果工程师对业务理解不深刻或者对特征提不够全面,导致预测稳定性比较差。3、深度学习在NLP领域取得了突破性的发展,同样是时序数据,自然而然被应用在了销量预测场景,而且近几年的竞赛中深度学习有超过机器学习的趋势。

        以我个人的理解,销量本质是时间序列数据,如果要对其预测,模型必须要能捕捉到各变量在时间轴上与销量的关系,对于这种捕捉深层次关系的问题,深度学习是最适合的算法。

2.2 实现框架

        通过调研我研究了以下开源框架:

        gluonts,

        neuralforecast,

        pytorch_forecasting,

        hyperts,

        针对同样的数据集,在每个框架内用不同的算法进行预测,包括以下算法:

        deepar

        deep_factor

        deepstate

        n-beats

        RNN

        LSTM

        tft

        transformer

        lstnet

        最终测试的结果是:在hyperts框架下用n-beats算法能够在较短训练时间下取得较准确的结果。n-beats开创了一个新的结构,即仅使用全连接网络实现时间序列预测。该结构基于向前和向后的残差链接以及全连接层堆栈(这个相当于是GBDT的残差连接)。该体系结构具有许多理想的属性,这些属性可以解释,可以在不修改大量目标域的情况下适用,并且训练迅速。

论文地址:https://arxiv.org/pdf/1905.10437.pdf

 2.3 硬件环境

CPU:i9 12900K

GPU:3080TI*2

Python:3.7.9

TensorFlow-GPU:2.2.0

CUDA:11.2

三、建模过程

3.1 数据集

        选取一个分仓的A类sku共81款,拉出近四年的所有提货历史数据,颗粒度是天。数据集主要包含:日期、提货量、sku。 数据集直接从SAP导出,质量很高,不需要做清洗。

        业务部门的需求是预测二个月。

3.2 预处理   

1、有部分SKU并不是每天都有提货业务,所以需要对空白日期补0。

 2、有的SKU一天之内有多笔提货业务,要合并数据。

3.3 超参数搜索

hyperts自带超参数搜索模式:MCTSSearcher、 RandomSearcher、 EvolutionSearcher;但是从实际建模过程来看还是不够,比如还有一些超参数也需要搜索:每次迭代内的建模次数、评估指标、验证集大小、搜索模式、训练集大小、模型融合数、批次大小。

我的解决方案是将上述参数随机化:

max_trials_random = random.choice(trial)
eval_size_random = random.choice(eval)
searcher_random = random.choice(serch)
reward_metric_random = random.choice(metric)
num_folds_random = random.choice(fold)
forecast_train_data_periods_random = random.choice(data_periods)
ensemble_size_random = random.choice(enemble)
batch_size_random = random.choice(batch)

3.4 颗粒度

理论上可以预测月、周、天,从实际情况来看,预测天的精度更高。业务部门要求预测两个月,可以转换成预测60天然后加和即可。

3.5 评估指标

mae: 平均绝对误差

mse:均方误差

rmse:均方根误差

smape:对称平均绝对百分比误差

特别注意mape,当实际值为0时,这个指标接近无穷大,所以没有使用。

msle:均方对数误差,特别适合处理响应变量具有较宽范围且包含大量零或接近零值的数据集。

我注意到单纯用一个指标效果并不好,于是将上面的4个指标组合起来使用,代码如下:

 # 选取较优模型索引值
    top_6 = result_list.sort_values(by='sum_abs').head(10)  # round_epo*0.5
    top_5 = top_6.sort_values(by='rmse').head(8)  # round_epo*0.4
    top_4 = top_5.sort_values(by='mae').head(6)  # round_epo*0.3
    top_3 = top_4.sort_values(by='smape').head(5)  # round_epo*0.2
    top_2 = top_3.sort_values(by='mse').head(3)
    top_1 = top_2.sort_values(by='sum_abs').head(1)

但是在有些场景下,只用msle也能取得不错的效果。

3.6 主要代码

# 模型实例
        experiment = make_experiment(train_data=train_data.copy(),
                                     task='univariate-forecast',
                                     mode='dl',
                                     max_trials=max_trials_random,
                                     eval_size=eval_size_random,
                                     searcher=searcher_random,  # random,mcts,evolution
                                     freq='D',
                                     reward_metric=reward_metric_random,  # ,,,,mse,mae,rmse,mape,,,,,
                                     # dl_forecast_window=35,
                                     # dl_forecast_length=7,
                                     # dl_forecast_horizon=7,
                                     # early_stopping_round=40,
                                     timestamp='date',
                                     cv=True,
                                     num_folds=num_folds_random,
                                     verbose=1,
                                     # log_level='INFO',
                                     search_space=custom_search_space,
                                     forecast_train_data_periods=forecast_train_data_periods_random,
                                     ensemble_size=ensemble_size_random,
                                     )
        # 跑模型
        model = experiment.run(epochs=1500,
                               batch_size=batch_size_random,
                               final_train_epochs=1500,
                               )

3.7 集成模型

这里借鉴了集成的思想,用不同的超参数生成N个模型,将模型保存在list中,然后将筛选过后的模型(根据需要可以是20、30或更多)结果求平均值。也尝试了加权平均,但是总体效果还是简单平均比较好。这样做的目的是让预测值更稳定。

    result_pre_end = pd.DataFrame(columns=['sku', 'week1', 'week2', 'week3', 'week4', 'sum'])
    sku = mat
    week1 = result_pre['week1'].mean()
    week2 = result_pre['week2'].mean()
    week3 = result_pre['week3'].mean()
    week4 = result_pre['week4'].mean()
    sum_pre = result_pre['sum'].mean()
    new_row = {'sku': mat, 'week1': week1, 'week2': week2, 'week3': week3, 'week4': week4, 'sum': sum_pre}
    result_pre_end = result_pre_end.append(new_row, ignore_index=True)
    result_pre_end['sku']=result_pre_end['sku'].astype(int)

四、结果

 训练集截止到7.17   ,预测期间为 7.17-9.10,每一行代表一个sku,共81个sku。准确率=预测/实际 ,越接近1预测越准。

预测未来两个月,准确率超过80%(80%-120%这个区间内都算80%)的有47个,占比58%,超过60%的有67个,占比82%。具体结果如下:

准确率
2023-29
(7.17-7.23)
2023-30
(7.24-7.30)
2023-31
(7.31-8.6)
2023-32
(8.7-8.13)
28天总量8.14-8.208.21-8.278.28-9.39.4-9.1029-56天总量
46%106%247%83%83%97%74%140%83%93%
89%153%74%77%90%92%132%108%82%100%
125%116%73%100%99%106%154%131%77%109%
69%83%69%70%73%102%143%80%55%84%
114%105%60%132%94%174%159%99%64%106%
121%77%63%72%78%107%58%141%70%83%
71%92%89%143%93%104%136%139%83%110%
86%90%94%135%98%226%150%153%82%141%
60%163%62%237%107%96%89%393%142%141%
91%57%126%229%106%221%278%95%119%147%
104%217%104%86%113%82%80%123%227%108%
84%78%77%203%94%82%66%148%83%87%
91%301%62%59%84%64%78%122%80%81%
81%82%92%114%90%50%102%116%96%83%
102%154%241%62%97%25%109%246%153%95%
110%162%65%108%101%94%58%101%58%72%
138%105%108%293%146%261%108%124%60%114%
73%109%201%185%121%132%143%117%71%111%
75%32%50%74%51%66%203%159%57%91%
92%180%110%144%124%157%143%181%111%142%
71%88%120%202%107%146%340%166%83%151%
76%152%64%100%88%139%175%179%302%184%
56%75%99%138%84%121%158%208%211%168%
149%85%50%101%83%70%119%136%98%100%
57%93%92%176%92%75%139%122%86%99%
117%144%99%156%125%187%323%613%103%203%
124%80%71%182%100%103%294%166%43%95%
55%85%90%104%80%79%78%120%65%81%
121%104%65%76%89%88%67%59%114%80%
77%62%123%107%85%91%113%71%62%80%
52%335%88%112%100%157%50%156%274%108%
59%89%122%78%83%100%107%132%86%104%
139%127%115%272%146%133%120%350%118%147%
40%77%152%95%77%84%135%154%150%123%
57%52%140%73%69%56%19%178%49%41%
69%71%134%99%88%149%186%58%66%90%
143%93%90%150%113%119%131%108%104%114%
127%282%165%228%183%369%208%126%68%132%
65%100%104%96%91%98%174%113%115%119%
76%45%129%27%57%78%49%117%46%65%
80%57%53%103%68%72%88%80%26%53%
83%67%73%93%78%61%127%134%72%88%
71%64%81%123%80%134%105%227%127%137%
263%322%354%62%149%89%34%#DIV/0!34%60%
54%61%55%87%62%53%73%125%73%74%
47%74%107%104%74%137%71%99%85%93%
97%104%84%102%95%32%87%103%44%53%
58%79%160%115%90%97%78%109%130%100%
59%64%68%87%69%119%86%100%51%83%
64%54%92%105%73%58%78%39%58%55%
87%53%83%114%78%74%163%140%257%130%
68%55%82%102%73%157%101%89%84%101%
50%94%93%103%79%65%72%102%69%74%
126%106%56%267%105%142%71%81%63%81%
64%48%48%73%56%140%68%57%47%66%
71%64%71%53%63%72%107%103%71%85%
51%35%67%58%50%50%91%102%63%71%
59%51%48%63%55%64%346%56%43%67%
75%54%71%94%70%87%101%54%51%69%
70%57%90%88%75%73%101%81%60%76%
74%69%106%109%86%98%106%60%72%80%
59%105%56%91%72%172%117%64%81%94%
57%84%102%83%79%72%136%136%107%106%
49%66%93%89%71%93%71%105%68%82%
52%65%120%116%78%79%86%111%145%100%
42%62%91%57%58%53%71%124%92%77%
59%137%80%62%77%110%97%91%71%90%
56%35%140%54%59%151%70%76%116%96%
59%94%73%62%70%83%67%120%88%85%
42%57%2183%36%58%218%55%61%218%91%
101%76%51%76%71%164%221%110%82%123%
90%38%70%77%61%86%94%91%59%80%
47%66%63%78%62%112%88%135%126%113%
74%62%113%93%81%102%65%69%159%87%
46%96%128%69%75%72%166%135%92%105%
45%42%63%107%56%42%173%52%91%69%
109%56%94%94%85%58%60%52%133%66%
47%82%83%65%69%65%49%68%134%73%
64%54%63%208%73%156%95%551%50%100%
47%75%137%42%62%125%49%68%32%54%
48%24%91%134%50%88%79%56%132%78%
71%60%62%48%59%120%42%98%8%27%

五、总结

5.1 该课题的意义

1、我司目前没有专人对sku做预测,用模型来预测可以使得该工作自动化。在后期可以直接打通SAP ,成为跑MRP的依据,直接指导生产和采购计划。

2、第四部分的结果发给业务部门领导,得到的反馈是非常有实用价值,从正确率上来说,人工经验很难达到模型的水平。

本次结果速度和准确度都超过了人工水平。

5.2 主要工作

1、对提货业务和数据的调研。

2、框架和算法选型。

3、参数调优:hyperts框架个性化调优,神经网络参数调优,滑动窗口,预测颗粒度。

4、模型筛选:用mse\rmse\smape\mae\msle 构建模型筛选逻辑

5、模型集成:借鉴随机森林的思想,集合N个base_model取平均值

5.3 经验总结

1、由于n-beats算法是由全连接层组成,不需要大量参数,实际证明也是如此,一般情况下8000个以上的参数就能取得较好的效果,而且在CPU上跑模型比在GPU上快很多,在参数很少的情况下CPU计算开销GPU更少。

2、n-beats算法特点,吸取了统计学和机器学习的优点,结合深度学习的强大表征能力,使得该算法速度快效果好。它的模型结构实际上是非常符合销售业务的本质,即趋势+周期,它将时序数据分解为趋势、周期然后分别预测,再加和输出。

3、如果只跑单次模型,一分钟内就可完成,但是准确率忽高忽低,如果用集成的方法,20分钟跑20个模型,再筛选后集成准确率能提高很多,但是训练时间就增加了。

4、销量的业务逻辑其实很复杂:市场需求,宏观经济环境,竞争对手,自身产品价格,经销商的发展等等,今年的销量和去年的销量可能在本质上不是同样的情形。在建模的时候发现,训练集中越是远的数据预测精度越不准,离预测点越近的数据可靠性比较高。

5、在建模后期,只使用msle一个指标筛选,该指标完美解决了实际值有0,且数据scale较大的问题。

6、NLP技术深刻的影响了销量预测领域,很对论文都是从NLP中吸收灵感,这可能也是一个突破方向。

5.4展望

1、预测准确率和建模速度还有提升的空间

2、对于预测长周期问题还需进一步研究,比如n-hits算法

3、在目前的框架中还不支持未来未知协变量(比如半年之后的产品市场占有率)

以上问题在未来还需要继续研究。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值