= 16
bs = 3
c_in = 12
seq_len = 2
c_out = torch.rand(bs, c_in, seq_len)
xb =100, n_layers=2, bias=True, rnn_dropout=0.2, bidirectional=True, fc_dropout=0.5)(xb).shape, [bs, c_out])
test_eq(RNN(c_in, c_out, hidden_size
test_eq(RNN(c_in, c_out)(xb).shape, [bs, c_out])=100, n_layers=2, bias=True, rnn_dropout=0.2, bidirectional=True, fc_dropout=0.5)(xb).shape, [bs, c_out])
test_eq(RNN(c_in, c_out, hidden_size
test_eq(LSTM(c_in, c_out)(xb).shape, [bs, c_out]) test_eq(GRU(c_in, c_out)(xb).shape, [bs, c_out])
RNNs
These are RNN, LSTM and GRU PyTorch implementations created by Ignacio Oguiza - oguiza@timeseriesAI.co
GRU
GRU (c_in, c_out, hidden_size=100, n_layers=1, bias=True, rnn_dropout=0, bidirectional=False, fc_dropout=0.0, init_weights=True)
Same as nn.Module
, but no need for subclasses to call super().__init__
LSTM
LSTM (c_in, c_out, hidden_size=100, n_layers=1, bias=True, rnn_dropout=0, bidirectional=False, fc_dropout=0.0, init_weights=True)
Same as nn.Module
, but no need for subclasses to call super().__init__
RNN
RNN (c_in, c_out, hidden_size=100, n_layers=1, bias=True, rnn_dropout=0, bidirectional=False, fc_dropout=0.0, init_weights=True)
Same as nn.Module
, but no need for subclasses to call super().__init__
from tsai.basics import *
= 'NATOPS'
dsid = 16
bs = get_UCR_data(dsid, return_split=False)
X, y, splits = [None, [TSCategorize()]]
tfms = TSDatasets(X, y, tfms=tfms, splits=splits)
dsets = TSDataLoaders.from_dsets(dsets.train, dsets.valid, bs=bs, num_workers=0, shuffle=False)
dls = LSTM(dls.vars, dls.c)
model = Learner(dls, model, metrics=accuracy)
learn 1, 3e-3) learn.fit_one_cycle(
epoch | train_loss | valid_loss | accuracy | time |
---|---|---|---|---|
0 | 1.743440 | 1.633068 | 0.361111 | 00:01 |
= RNN(c_in, c_out, hidden_size=100,n_layers=2,bidirectional=True,rnn_dropout=.5,fc_dropout=.5)
m print(m)
print(count_parameters(m))
m(xb).shape
RNN(
(rnn): RNN(3, 100, num_layers=2, batch_first=True, dropout=0.5, bidirectional=True)
(dropout): Dropout(p=0.5, inplace=False)
(fc): Linear(in_features=200, out_features=2, bias=True)
)
81802
torch.Size([16, 2])
= LSTM(c_in, c_out, hidden_size=100,n_layers=2,bidirectional=True,rnn_dropout=.5,fc_dropout=.5)
m print(m)
print(count_parameters(m))
m(xb).shape
LSTM(
(rnn): LSTM(3, 100, num_layers=2, batch_first=True, dropout=0.5, bidirectional=True)
(dropout): Dropout(p=0.5, inplace=False)
(fc): Linear(in_features=200, out_features=2, bias=True)
)
326002
torch.Size([16, 2])
= GRU(c_in, c_out, hidden_size=100,n_layers=2,bidirectional=True,rnn_dropout=.5,fc_dropout=.5)
m print(m)
print(count_parameters(m))
m(xb).shape
GRU(
(rnn): GRU(3, 100, num_layers=2, batch_first=True, dropout=0.5, bidirectional=True)
(dropout): Dropout(p=0.5, inplace=False)
(fc): Linear(in_features=200, out_features=2, bias=True)
)
244602
torch.Size([16, 2])
Converting a model to TorchScript
= LSTM(c_in, c_out, hidden_size=100, n_layers=2, bidirectional=True, rnn_dropout=.5, fc_dropout=.5)
model eval()
model.= torch.rand(1, c_in, 50)
inp = model(inp)
output print(output)
tensor([[-0.0287, -0.0105]], grad_fn=<AddmmBackward0>)
Tracing
# save to gpu, cpu or both
= torch.jit.trace(model.cpu(), inp)
traced_cpu print(traced_cpu)
"cpu.pt")
torch.jit.save(traced_cpu,
# load cpu or gpu model
= torch.jit.load("cpu.pt")
traced_cpu
test_eq(traced_cpu(inp), output)
!rm "cpu.pt"
LSTM(
original_name=LSTM
(rnn): LSTM(original_name=LSTM)
(dropout): Dropout(original_name=Dropout)
(fc): Linear(original_name=Linear)
)
Scripting
# save to gpu, cpu or both
= torch.jit.script(model.cpu())
scripted_cpu print(scripted_cpu)
"cpu.pt")
torch.jit.save(scripted_cpu,
# load cpu or gpu model
= torch.jit.load("cpu.pt")
scripted_cpu
test_eq(scripted_cpu(inp), output)
!rm "cpu.pt"
RecursiveScriptModule(
original_name=LSTM
(rnn): RecursiveScriptModule(original_name=LSTM)
(dropout): RecursiveScriptModule(original_name=Dropout)
(fc): RecursiveScriptModule(original_name=Linear)
)
Converting a model to ONNX
import onnx
# Export the model
# model being run
torch.onnx.export(model.cpu(), # model input (or a tuple for multiple inputs)
inp, "cpu.onnx", # where to save the model (can be a file or file-like object)
=True, # store the trained parameter weights inside the model file
export_params=False,
verbose=13, # the ONNX version to export the model to
opset_version=True, # whether to execute constant folding for optimization
do_constant_folding= ['input'], # the model's input names
input_names = ['output'], # the model's output names
output_names ={
dynamic_axes'input' : {0 : 'batch_size'},
'output' : {0 : 'batch_size'}} # variable length axes
)
# Load the model and check it's ok
= onnx.load("cpu.onnx")
onnx_model
onnx.checker.check_model(onnx_model)
# You can ignore the WARNINGS below
import onnxruntime as ort
= ort.InferenceSession('cpu.onnx')
ort_sess = ort_sess.run(None, {'input': inp.numpy()})
out
# input & output names
= ort_sess.get_inputs()[0].name
input_name = ort_sess.get_outputs()[0].name
output_name
# input dimensions
= ort_sess.get_inputs()[0].shape
input_dims print(input_name, output_name, input_dims)
test_close(out, output.detach().numpy())!rm "cpu.onnx"