## I. 前言

。除了LSTM以外，这个网站还囊括了其他大多机器学习以及深度学习模型的具体讲解，配图生动，简单易懂。

## II. CNN-LSTM

CNN-LSTM模型搭建如下：

```class CNN_LSTM(nn.Module):
def __init__(self, args):
super(CNN_LSTM, self).__init__()
self.args = args
self.relu = nn.ReLU(inplace=True)
# (batch_size=30, seq_len=24, input_size=7) ---> permute(0, 2, 1)
# (30, 7, 24)
self.conv = nn.Sequential(
nn.Conv1d(in_channels=args.in_channels, out_channels=args.out_channels, kernel_size=3),
nn.ReLU(),
nn.MaxPool1d(kernel_size=3, stride=1)
)
# (batch_size=30, out_channels=32, seq_len-4=20) ---> permute(0, 2, 1)
# (30, 20, 32)
self.lstm = nn.LSTM(input_size=args.out_channels, hidden_size=args.hidden_size,
num_layers=args.num_layers, batch_first=True)
self.fc = nn.Linear(args.hidden_size, args.output_size)
def forward(self, x):
x = x.permute(0, 2, 1)
x = self.conv(x)
x = x.permute(0, 2, 1)
x, _ = self.lstm(x)
x = self.fc(x)
x = x[:, -1, :]
return x```

`nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)`

`nn.Conv1d(in_channels=args.in_channels, out_channels=args.out_channels, kernel_size=3)`

PyTorch中一维卷积的输入尺寸为：

`input(batch_size, input_size, seq_len)=(30, 7, 24)`

`input(batch_size, seq_len, input_size)=(30, 24, 7)`

`x = x.permute(0, 2, 1)`

`nn.Conv1d(in_channels=args.in_channels, out_channels=args.out_channels, kernel_size=3)`

`(30, 32, 24-3+1)=(30, 32, 22)`

`(30, 32, 22-3+1)=(30, 32, 20)`

`input(batch_size, seq_len, input_size)`

`input(batch_size=30, input_size=32, seq_len=20)`

`x = x.permute(0, 2, 1)`

```def forward(self, x):
x = x.permute(0, 2, 1)
x = self.conv(x)
x = x.permute(0, 2, 1)
x, _ = self.lstm(x)
x = self.fc(x)
x = x[:, -1, :]
return x```

## 3.1 数据处理

```def nn_seq(args):
seq_len, B, num = args.seq_len, args.batch_size, args.output_size
print('data processing...')
# split
train = dataset[:int(len(dataset) * 0.6)]
val = dataset[int(len(dataset) * 0.6):int(len(dataset) * 0.8)]
test = dataset[int(len(dataset) * 0.8):len(dataset)]
m, n = np.max(train[train.columns[1]]), np.min(train[train.columns[1]])
def process(data, batch_size, step_size):
data = data.values.tolist()
seq = []
for i in range(0, len(data) - seq_len - num, step_size):
train_seq = []
train_label = []
for j in range(i, i + seq_len):
for c in range(2, 8):
x.append(data[j][c])
train_seq.append(x)
for j in range(i + seq_len, i + seq_len + num):
train_seq = torch.FloatTensor(train_seq)
train_label = torch.FloatTensor(train_label).view(-1)
seq.append((train_seq, train_label))
# print(seq[-1])
seq = MyDataset(seq)
seq = DataLoader(dataset=seq, batch_size=batch_size, shuffle=False, num_workers=0, drop_last=False)
return seq
Dtr = process(train, B, step_size=1)
Val = process(val, B, step_size=1)
Dte = process(test, B, step_size=num)
return Dtr, Val, Dte, m, n```

## 3.2 模型训练/测试

```def train(args, Dtr, Val, path):
model = CNN_LSTM(args).to(args.device)
loss_function = nn.MSELoss().to(args.device)
print('training...')
epochs = 50
min_epochs = 10
best_model = None
min_val_loss = 5
for epoch in range(epochs):
train_loss = []
for batch_idx, (seq, target) in enumerate(Dtr, 0):
seq, target = seq.to(args.device), target.to(args.device)
y_pred = model(seq)
loss = loss_function(y_pred, target)
train_loss.append(loss.item())
loss.backward()
optimizer.step()
# validation
val_loss = get_val_loss(args, model, Val)
if epoch + 1 >= min_epochs and val_loss < min_val_loss:
min_val_loss = val_loss
best_model = copy.deepcopy(model)
print('epoch {:03d} train_loss {:.8f} val_loss {:.8f}'.format(epoch, np.mean(train_loss), val_loss))
model.train()
state = {
'model': best_model.state_dict(), 'optimizer': optimizer.state_dict()}
torch.save(state, path)
def test(args, Dte, path, m, n):
model = CNN_LSTM(args).to(args.device)
model.eval()
pred = []
y = []
for batch_idx, (seq, target) in enumerate(Dte, 0):
seq = seq.to(args.device)
target = list(chain.from_iterable(target.tolist()))
y.extend(target)
y_pred = model(seq)
y_pred = list(chain.from_iterable(y_pred.data.tolist()))
pred.extend(y_pred)
y, pred = np.array(y), np.array(pred)
y = (m - n) * y + n
pred = (m - n) * pred + n
print('mape:', get_mape(y, pred))
# plot
x = [i for i in range(1, 151)]
x_smooth = np.linspace(np.min(x), np.max(x), 900)
y_smooth = make_interp_spline(x, y[150:300])(x_smooth)
plt.plot(x_smooth, y_smooth, c='green', marker='*', ms=1, alpha=0.75, label='true')
y_smooth = make_interp_spline(x, pred[150:300])(x_smooth)
plt.plot(x_smooth, y_smooth, c='red', marker='o', ms=1, alpha=0.75, label='pred')
plt.grid(axis='y')
plt.legend()
plt.show()```