Repository: fastmachinelearning/hls4ml
Issue: Convert simple LSTM model to hls

I want to map a very simple LSTM model to the ZCU104. First I added the the board support to the .json file and added the template of the board similarly to the ZCU104. Then I started with the following code.
```
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
from pandas import read_csv
import math
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error

df = pd.read_csv('dataset.csv')

dataset = df.iloc[:,1].values
dataset = dataset.reshape(-1,1)
dataset = dataset.astype('float32')      # (144, 1)

scaler = MinMaxScaler(feature_range=(0,1))
dataset = scaler.fit_transform(dataset)

timestamp=10
dataX = []
dataY = []
for i in range(len(train)-timestamp-1):
    a = train[i:(i+timestamp),0]
    dataX.append(a)
    dataY.append(train[i+timestamp,0])
trainX = np.array(dataX)
trainY = np.array(dataY)

timestep=10
dataX = []
dataY = []
for i in range(len(test)-timestamp-1):
    a = test[i:(i+timestamp),0]
    dataX.append(a)
    dataY.append(test[i+timestamp,0])
testX = np.array(dataX)
testY = np.array(dataY)

trainX = np.reshape(trainX,(trainX.shape[0],1,trainX.shape[1]))
testX = np.reshape(testX,(testX.shape[0],1,testX.shape[1]))

model = Sequential()
model.add(LSTM(10, input_shape=(1, timestamp))) # 10 lstm neuron(block)
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=50, batch_size=1)

trainPredict = model.predict(trainX)
testPredict = model.predict(testX)

trainPredict = scaler.inverse_transform(trainPredict)
trainY = scaler.inverse_transform([trainY])
testPredict = scaler.inverse_transform(testPredict)
testY = scaler.inverse_transform([testY])

trainScore = math.sqrt(mean_squared_error(trainY[0], trainPredict[:,0]))
print('Train Score: %.2f RMSE' % (trainScore))
testScore = math.sqrt(mean_squared_error(testY[0], testPredict[:,0]))
print('Test Score: %.2f RMSE' % (testScore))

import hls4ml
import os
os.environ['PATH'] = '/home/user/Xilinx/Vivado/2020.1/bin:' + os.environ['PATH']

hls4ml.model.optimizer.get_optimizer('output_rounding_saturation_mode').configure(layers=['Activation'])
hls4ml.model.optimizer.get_optimizer('output_rounding_saturation_mode').configure(rounding_mode='AP_RND')
hls4ml.model.optimizer.get_optimizer('output_rounding_saturation_mode').configure(saturation_mode='AP_SAT')

hls_config = hls4ml.utils.config_from_keras_model(model, 
                                                granularity='model',
                                                default_precision="ap_fixed<8,2>",
                                                default_reuse_factor=1)
print(hls_config)

hls_model = hls4ml.converters.convert_from_keras_model(model,
                                                        io_type="io_stream",                                                        
                                                        hls_config=hls_config,
                                                        output_dir='lstm_model/hls4ml_8b_rf1',
                                                        project_name="lstm_hls",
                                                        backend='VivadoAccelerator',
                                                        part='xczu7ev-ffvc1156-2-e')
```

Here I get the following error, which I fail to understand:
```
Interpreting Sequential
Topology:
Layer name: lstm_input, layer type: InputLayer, input shapes: [[None, 1, 10]], output shape: [None, 1, 10]
Layer name: lstm, layer type: LSTM, input shapes: [[None, 1, 10]], output shape: [None, 10]
Layer name: dense, layer type: Dense, input shapes: [[None, 10]], output shape: [None, 1]
Creating HLS model

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In [23], line 1
----> 1 hls_model = hls4ml.converters.convert_from_keras_model(model,
      2                                                         io_type="io_stream",                                                        
      3                                                         hls_config=hls_config,
      4                                                         output_dir='lstm_model/hls4ml_8b_rf1',
      5                                                         project_name="lstm_hls",
      6                                                         backend='VivadoAccelerator',
      7                                                         part='xczu7ev-ffvc1156-2-e')

File ~/.local/lib/python3.8/site-packages/hls4ml/converters/__init__.py:217, in convert_from_keras_model(model, output_dir, project_name, input_data_tb, output_data_tb, backend, hls_config, **kwargs)
    213 config['HLSConfig']['Model'] = _check_model_config(model_config)
    215 _check_hls_config(config, hls_config)
--> 217 return keras_to_hls(config)

File ~/.local/lib/python3.8/site-packages/hls4ml/converters/keras_to_hls.py:374, in keras_to_hls(config)
    369 #################
    370 ## Generate HLS
    371 #################
    373 print('Creating HLS model')
--> 374 hls_model = ModelGraph(config, reader, layer_list, input_layers, output_layers)
    375 return hls_model

File ~/.local/lib/python3.8/site-packages/hls4ml/model/graph.py:319, in ModelGraph.__init__(self, config, data_reader, layer_list, inputs, outputs)
    316 self._make_graph(layer_list)
    318 for flow in self.config.flows:
--> 319     self.apply_flow(flow)

File ~/.local/lib/python3.8/site-packages/hls4ml/model/graph.py:368, in ModelGraph.apply_flow(self, flow, reapply)
    365         return
    367 self._applied_flows.append(applied_flows)
--> 368 self._apply_sub_flow(flow, applied_flows)

File ~/.local/lib/python3.8/site-packages/hls4ml/model/graph.py:377, in ModelGraph._apply_sub_flow(self, flow_name, applied_flows)
    375 for sub_flow in flow.requires:
    376     if sub_flow not in applied_flows.keys():
--> 377         self._apply_sub_flow(sub_flow, applied_flows)
    379 if len(flow.optimizers) > 0:
    380     applied_passes = optimize_model(self, flow.optimizers)

File ~/.local/lib/python3.8/site-packages/hls4ml/model/graph.py:380, in ModelGraph._apply_sub_flow(self, flow_name, applied_flows)
    377         self._apply_sub_flow(sub_flow, applied_flows)
    379 if len(flow.optimizers) > 0:
--> 380     applied_passes = optimize_model(self, flow.optimizers)
    381 else:
    382     applied_passes = set()

File ~/.local/lib/python3.8/site-packages/hls4ml/model/optimizer/optimizer.py:286, in optimize_model(model, passes)
    284 for node in model.graph.values():
    285     if opt.match(node):
--> 286         res = opt.transform(model, node)
    287         applied_passes.add(opt_name)
    288         if res:

File ~/.local/lib/python3.8/site-packages/hls4ml/backends/template.py:20, in Template.transform(self, model, node)
     19 def transform(self, model, node):
---> 20     formatted_template = self.format(node)
     21     node.set_attr(self.attribute_name, formatted_template)
     22     return False

File ~/.local/lib/python3.8/site-packages/hls4ml/backends/vivado/passes/recurrent_templates.py:99, in RecurrentConfigTemplate.format(self, node)
     97 params['act_t'] = '{}_config{}'.format(node.get_attr('activation'), node.index)
     98 params['strategy'] = node.get_attr('strategy')
---> 99 params['static'] = 'true' if node.attributes['static'] else 'false'
    100 params['recr_type'] = node.class_name.lower()
    101 params['RECR_TYPE'] = node.class_name

File ~/.local/lib/python3.8/site-packages/hls4ml/model/attributes.py:54, in AttributeDict.__getitem__(self, key)
     53 def __getitem__(self, key):
---> 54     return self.attributes[key]

KeyError: 'static'
```

Any help please I need it urgently


Changed files:
hls4ml/backends/vivado_accelerator/vivado_accelerator_backend.py

diff --git a/hls4ml/backends/vivado_accelerator/vivado_accelerator_backend.py b/hls4ml/backends/vivado_accelerator/vivado_accelerator_backend.py
index f49ab2ee..016800a9 100644
--- a/hls4ml/backends/vivado_accelerator/vivado_accelerator_backend.py
+++ b/hls4ml/backends/vivado_accelerator/vivado_accelerator_backend.py
@@ -8,6 +8,7 @@ from hls4ml.report import parse_vivado_report
 class VivadoAcceleratorBackend(VivadoBackend):
     def __init__(self):
         super(VivadoBackend, self).__init__(name='VivadoAccelerator')
+        self._register_layer_attributes()
         self._register_flows()
 
     def build(