从时间序列数据中,训练LSTM模型的过程中,有哪些重难点?首先,时间序列数据不是直接的"样本",如何构造出"样本"?本文从这个角度出发,讨论再关的问题。
1、滑动窗口构造数据集
原始商品长时间序列:D1,D2,D3,D4,D5,D6,D7,... \\text{D1},\\text{D2},\\text{D3},\\text{D4},\\text{D5},\\text{D6},\\text{D7},\\dotsD1,D2,D3,D4,D5,D6,D7,...
采用固定窗口切分:
-
回看历史长度 T=3\boldsymbol{T = 3}T=3(使用过去3天数据作为输入序列)
-
预测步数 KaTeX parse error: Can't use function '\(' in math mode at position 13: \boldsymbol{\̲(̲\boldsymbol{\(H...(预测后续连续4天)
窗口1:历史(D1,D2,D3) → 预测(D4,D5,D6,D7)
窗口2:历史(D2,D3,D4) → 预测(D5,D6,D7,D8)
2、样本生成规则
从上述原始数据集中构造出样本集
针对单一商品,窗口每向后滑动一次,生成一条训练样本。
演示规模参数:
- 总样本数量 N=10\boldsymbol{N = 10}N=10
- 每日特征数 F=2\boldsymbol{F = 2}F=2(特征1:当日销量;特征2:是否节假日)
示例包含3个商品:商品0、商品1、商品2。不同商品原始时序长度不一致,最终滑动生成10条样本:
| 样本编号 | 属于哪个商品 | 历史窗口(输入) | 需要预测未来4天(标签y) |
|---|---|---|---|
| 0 | 商品0 | D1,D2,D3 | D4,D5,D6,D7 |
| 1 | 商品0 | D2,D3,D4 | D5,D6,D7,D8 |
| 2 | 商品0 | D3,D4,D5 | D6,D7,D8,D9 |
| 3 | 商品1 | D1,D2,D3 | D4,D5,D6,D7 |
| 4 | 商品1 | D2,D3,D4 | D5,D6,D7,D8 |
| 5 | 商品1 | D3,D4,D5 | D6,D7,D8,D9 |
| 6 | 商品1 | D4,D5,D6 | D7,D8,D9,D10 |
| 7 | 商品2 | D1,D2,D3 | D4,D5,D6,D7 |
| 8 | 商品2 | D2,D3,D4 | D5,D6,D7,D8 |
| 9 | 商品2 | D3,D4,D5 | D6,D7,D8,D9 |
说明:商品1原始时序更长,包含D10,因此额外生成样本6;商品0、商品2时序截止到D9,无法构造该窗口。
3、X_train:输入张量
形状:X_train.shape=(10,3,2)\boldsymbol{X\_train.shape=(10,3,2)}X_train.shape=(10,3,2)
索引规则:X_train[样本号, 历史时序位置, 特征序号]
以样本0(商品0,历史D1,D2,D3):
python
X_train[0] = [
[D1销量, D1是否节假日],
[D2销量, D2是否节假日],
[D3销量, D3是否节假日]
]
样本7(商品2,历史D1,D2,D3):
python
X_train[7] = [
[D1销量, D1是否节假日],
[D2销量, D2是否节假日],
[D3销量, D3是否节假日]
]
每一条
X_train[k]对应一条独立时序样本;不同商品、不同滑动窗口相互独立。
4、y_train:标签张量
形状:y_train.shape=(10,4)\boldsymbol{y\_train.shape=(10,4)}y_train.shape=(10,4)
索引规则:y_train[样本号, 预测步]
python
y_train[0] = [D4销量, D5销量, D6销量, D7销量] # 样本0未来4天真值
y_train[1] = [D5销量, D6销量, D7销量, D8销量] # 样本1未来4天真值
y_train[2] = [D6销量, D7销量, D8销量, D9销量]
y_train[3] = [D4销量, D5销量, D6销量, D7销量]
......
y_train[9] = [D6销量, D7销量, D8销量, D9销量]
5、切片语法 y_train[:, i] 演示
: 代表选取全部样本;i 固定选取第 iii 个预测步。
示例取 KaTeX parse error: Can't use function '\(' in math mode at position 1: \̲(̲i=0\)(预测未来第1天):
python
target = y_train[:, 0]
# target.shape = (10,)
target = [
y_train[0,0], # 样本0 D4销量
y_train[1,0], # 样本1 D5销量
y_train[2,0], # 样本2 D6销量
y_train[3,0], # 样本3 D4销量
y_train[4,0], # 样本4 D5销量
y_train[5,0], # 样本5 D6销量
y_train[6,0], # 样本6 D7销量
y_train[7,0], # 样本7 D4销量
y_train[8,0], # 样本8 D5销量
y_train[9,0] # 样本9 D6销量
]
6、训练逻辑:多独立模型基础循环
对给定下标 iii,提取单列标签作为目标,执行训练:
python
model.fit(X_train, target)
完整循环逻辑:
python
# 演示案例 range(4);真实业务预测16天改为 range(16)
for i in range(4):
# \(i=0\):学习历史序列 → 预测未来第1天
# i=1:学习历史序列 → 预测未来第2天
target = y_train[:, i]
# 新建模型并训练
model.fit(X_train, target)
7、方案A:多个独立单输出LSTM
原理:循环依次取出每一列标签,分别训练独立模型 。
模型0预测未来第1天,模型1预测未来第2天......一共训练4个模型(业务场景16个)。
简易完整代码:
python
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
# 模拟维度
N, T, F, H = 10, 3, 2, 4
X_train = np.random.rand(N, T, F)
y_train = np.random.rand(N, H)
pred_result = []
def build_single_model():
model = Sequential()
model.add(LSTM(16, input_shape=(T, F)))
model.add(Dense(1)) # 单输出
model.compile(optimizer="adam", loss="mse")
return model
# 循环训练H个独立模型
for i in range(H):
target = y_train[:, i]
model = build_single_model()
model.fit(X_train, target, epochs=20, verbose=0)
pred = model.predict(X_train, verbose=0)
pred_result.append(pred)
# 拼接得到 (N,H) 的预测矩阵
pred_matrix = np.concatenate(pred_result, axis=1)
print(pred_matrix.shape) # (10,4)
特点:各预测任务参数独立、互不干扰;代价是多次训练,耗时更高。
8、方案B:单模型一体多输出LSTM(改造方案)
原理:不切片标签,直接使用完整二维标签 y_train (10,4);
一个模型输入历史序列,一次性输出4个预测值,对应未来连续4天销量。
简易完整代码:
python
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
N, T, F, H = 10, 3, 2, 4
X_train = np.random.rand(N, T, F)
y_train = np.random.rand(N, H)
def build_multi_model():
model = Sequential()
model.add(LSTM(16, input_shape=(T, F)))
model.add(Dense(H)) # 一次性输出H维
model.compile(optimizer="adam", loss="mse")
return model
model = build_multi_model()
model.fit(X_train, y_train, epochs=20, verbose=0)
pred_matrix = model.predict(X_train, verbose=0)
print(pred_matrix.shape) # (10,4)
特点:仅训练一次,速度更快;远近预测任务共享LSTM权重,存在梯度竞争。