Spaces:
Runtime error
Runtime error
Krzysiek111
commited on
Commit
·
517420b
1
Parent(s):
dc6621d
refactoring part1 - minor perf updates, removed single letter names, moved functions to separate files
Browse files- app.py +22 -64
- app_helper_functions.py +29 -0
- predict.py +33 -49
app.py
CHANGED
@@ -1,10 +1,15 @@
|
|
1 |
-
import streamlit as st
|
2 |
-
import numpy as np
|
3 |
import matplotlib.pyplot as plt
|
|
|
4 |
import seaborn as sns
|
|
|
5 |
|
|
|
6 |
from predict import predict_series
|
7 |
|
|
|
|
|
|
|
|
|
8 |
#TODO: Refactor this module
|
9 |
|
10 |
st.set_page_config(page_title='RNN Playground')
|
@@ -69,46 +74,10 @@ elif choice == 1:
|
|
69 |
""")
|
70 |
|
71 |
else:
|
72 |
-
|
73 |
-
gran = 0.25
|
74 |
-
test_len = 8
|
75 |
st.sidebar.header('User Input Parameters')
|
76 |
-
|
77 |
-
|
78 |
-
def user_input_features():
|
79 |
-
predefined_sets = {'length': [30, ], 'period': [1.34, ], 'amplitude': [0.64, ], 'growth': [0.04, ],
|
80 |
-
'amplitude_growth': [0.03, ], 'r1_nodes': [20, ], 'r2_nodes': [20, ], 'fc1_nodes': [34, ]}
|
81 |
-
|
82 |
-
data, nn = {}, {}
|
83 |
-
st.sidebar.header('Dataset:')
|
84 |
-
data['length'] = st.sidebar.slider('Training data length', 20, 50, 28)
|
85 |
-
data['period'] = st.sidebar.slider('Period of the wave', 0.75, 2.0, 1.0)
|
86 |
-
data['growth'] = st.sidebar.slider('Values growth', -0.25, 0.25, 0.0)
|
87 |
-
data['amplitude'] = st.sidebar.slider('Amplitude', 0.25, 1.75, 1.0)
|
88 |
-
data['amplitude_growth'] = st.sidebar.slider('Amplitude growth', -0.01, 0.1, 0.0)
|
89 |
-
data['noise'] = st.sidebar.slider('Noise', 0.0, 1.0, 0.0)
|
90 |
-
st.sidebar.header('Model setup')
|
91 |
-
nn['use_lstm'] = st.sidebar.radio('Select the type of Recurrent Neuron to use', ['LSTM', 'GRU']) == 'LSTM'
|
92 |
-
nn['r1_nodes'] = st.sidebar.slider('Number of nodes in the first RNN layer', 1, 30, 13)
|
93 |
-
nn['r2_nodes'] = st.sidebar.slider('Number of nodes in the second RNN layer', 0, 30, 0)
|
94 |
-
nn['fc1_nodes'] = st.sidebar.slider('Number of nodes in the fully connected RNN layer', 0, 40, 10)
|
95 |
-
nn['steps'] = len(np.arange(0, test_len, gran))
|
96 |
-
|
97 |
-
#if st.sidebar.button('Load one of the pretested configurations'):
|
98 |
-
#i = st.sidebar.selectbox('Select:', [-1, 0])
|
99 |
-
#i = int(np.random.rand(len(predefined_sets['length']))) # Selecting one pretested configuration
|
100 |
-
#data.update({k: predefined_sets[k][i] for k in set(data) & set(predefined_sets)})
|
101 |
-
#nn.update({k: predefined_sets[k][i] for k in set(nn) & set(predefined_sets)})"""
|
102 |
-
|
103 |
-
|
104 |
-
return data, nn
|
105 |
-
|
106 |
-
|
107 |
-
params, setup = user_input_features()
|
108 |
-
|
109 |
-
st.header("""Refactoring & performance updates in progress!
|
110 |
-
please be back in a few days""")
|
111 |
-
|
112 |
st.subheader("Instructions:")
|
113 |
st.write("""
|
114 |
1. Modify the dataset by using the sliders in the Dataset group on the left on the screen.
|
@@ -119,24 +88,17 @@ else:
|
|
119 |
6. Have fun!
|
120 |
\n""")
|
121 |
|
|
|
122 |
st.subheader("Generated data:")
|
123 |
-
X = np.arange(0, params['length'],
|
124 |
-
X_pred = np.arange(params['length'], params['length'] + test_len,
|
125 |
-
|
126 |
-
|
127 |
-
def generate_wave(x_set):
|
128 |
-
return np.sin(x_set / params['period']) * (1 + params['amplitude_growth'] * x_set) * params[
|
129 |
-
'amplitude'] + x_set * params['growth'] + params['noise']*np.random.randn(len(x_set))
|
130 |
-
|
131 |
-
|
132 |
-
Y = generate_wave(X)
|
133 |
-
Y_pred = generate_wave(X_pred)
|
134 |
|
|
|
|
|
135 |
X_pred, Y_pred = np.append(X[-1], X_pred), np.append(Y[-1], Y_pred)
|
136 |
|
|
|
137 |
c1, c2, c3 = '#1e4a76', '#7dc0f7', '#ff7c0a' # colors
|
138 |
-
# sns.scatterplot(x=X, y=Y, color=c1)
|
139 |
-
# st.pyplot()
|
140 |
fig, ax = plt.subplots()
|
141 |
sns.lineplot(x=X, y=Y, color=c1)
|
142 |
sns.lineplot(x=X_pred, y=Y_pred, color=c2, linestyle=':')
|
@@ -146,38 +108,34 @@ else:
|
|
146 |
plt.ylabel('Sample value')
|
147 |
st.pyplot(fig)
|
148 |
st.write("The plot presents generated train and test data. Use the sliders on the left to modify the curve.")
|
149 |
-
|
150 |
-
|
151 |
-
def local_css(file_name):
|
152 |
-
with open(file_name) as f:
|
153 |
-
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
|
154 |
local_css("button_style.css")
|
155 |
-
|
156 |
st.subheader('Predicted data:')
|
157 |
reminder = st.text('Press the train and predict button on the sidebar once you are ready with the selections.')
|
158 |
|
159 |
-
|
160 |
if st.sidebar.button('Train and Predict'):
|
161 |
setup['values'] = list(Y)
|
162 |
reminder.empty()
|
163 |
|
|
|
164 |
waiters = list()
|
165 |
waiters.append(st.text('Please wait till the train and predict process is finished.'))
|
166 |
waiters.append(st.image('wait.gif'))
|
167 |
waiters.append(st.text("""The process should take around 20-60 seconds."""))
|
168 |
-
|
169 |
result = predict_series(**setup)
|
170 |
-
|
171 |
_ = [waiter.empty() for waiter in waiters]
|
|
|
|
|
172 |
fig, ax = plt.subplots()
|
173 |
sns.lineplot(x=X_pred, y=Y_pred, color=c2, linestyle=':')
|
174 |
sns.lineplot(x=X, y=Y, color=c1)
|
175 |
-
sns.lineplot(np.append(X[-1], np.arange(0, test_len,
|
176 |
plt.legend(['Train data', 'Test data', 'Predicted data'], loc=3)
|
177 |
plt.xlabel('Sample number')
|
178 |
plt.ylabel('Sample value')
|
179 |
st.pyplot(fig)
|
180 |
|
|
|
181 |
st.write("The prediction isn't good enough? Try to change settings in the model setup or increase the dataset length.")
|
182 |
st.write('Training took {} epochs, Mean Squared Error: {:.2e}'.format(result['epochs'], result['loss']))
|
183 |
#st.write('Training took {} epochs, Mean Squared Error {}, last loss {}'.format(result['epochs'], result['loss'], result['loss_last']))
|
|
|
|
|
|
|
1 |
import matplotlib.pyplot as plt
|
2 |
+
import numpy as np
|
3 |
import seaborn as sns
|
4 |
+
import streamlit as st
|
5 |
|
6 |
+
from app_helper_functions import generate_wave, local_css, user_input_features
|
7 |
from predict import predict_series
|
8 |
|
9 |
+
points_granularity = 0.25
|
10 |
+
test_len = 8
|
11 |
+
|
12 |
+
|
13 |
#TODO: Refactor this module
|
14 |
|
15 |
st.set_page_config(page_title='RNN Playground')
|
|
|
74 |
""")
|
75 |
|
76 |
else:
|
77 |
+
# Print instructions
|
|
|
|
|
78 |
st.sidebar.header('User Input Parameters')
|
79 |
+
params, setup = user_input_features(test_len, points_granularity)
|
80 |
+
st.header("""Refactoring & performance updates in progress!""")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
st.subheader("Instructions:")
|
82 |
st.write("""
|
83 |
1. Modify the dataset by using the sliders in the Dataset group on the left on the screen.
|
|
|
88 |
6. Have fun!
|
89 |
\n""")
|
90 |
|
91 |
+
# Generate and present generated data
|
92 |
st.subheader("Generated data:")
|
93 |
+
X = np.arange(0, params['length'], points_granularity)
|
94 |
+
X_pred = np.arange(params['length'], params['length'] + test_len, points_granularity)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
|
96 |
+
Y = generate_wave(X, params)
|
97 |
+
Y_pred = generate_wave(X_pred, params)
|
98 |
X_pred, Y_pred = np.append(X[-1], X_pred), np.append(Y[-1], Y_pred)
|
99 |
|
100 |
+
# TODO: move plotting to separate funtion
|
101 |
c1, c2, c3 = '#1e4a76', '#7dc0f7', '#ff7c0a' # colors
|
|
|
|
|
102 |
fig, ax = plt.subplots()
|
103 |
sns.lineplot(x=X, y=Y, color=c1)
|
104 |
sns.lineplot(x=X_pred, y=Y_pred, color=c2, linestyle=':')
|
|
|
108 |
plt.ylabel('Sample value')
|
109 |
st.pyplot(fig)
|
110 |
st.write("The plot presents generated train and test data. Use the sliders on the left to modify the curve.")
|
|
|
|
|
|
|
|
|
|
|
111 |
local_css("button_style.css")
|
|
|
112 |
st.subheader('Predicted data:')
|
113 |
reminder = st.text('Press the train and predict button on the sidebar once you are ready with the selections.')
|
114 |
|
115 |
+
# Calc and post-calc flow
|
116 |
if st.sidebar.button('Train and Predict'):
|
117 |
setup['values'] = list(Y)
|
118 |
reminder.empty()
|
119 |
|
120 |
+
# Waiters - contains what should be shown pior to receiving results - it's removed afterwards
|
121 |
waiters = list()
|
122 |
waiters.append(st.text('Please wait till the train and predict process is finished.'))
|
123 |
waiters.append(st.image('wait.gif'))
|
124 |
waiters.append(st.text("""The process should take around 20-60 seconds."""))
|
|
|
125 |
result = predict_series(**setup)
|
|
|
126 |
_ = [waiter.empty() for waiter in waiters]
|
127 |
+
|
128 |
+
# Plot results
|
129 |
fig, ax = plt.subplots()
|
130 |
sns.lineplot(x=X_pred, y=Y_pred, color=c2, linestyle=':')
|
131 |
sns.lineplot(x=X, y=Y, color=c1)
|
132 |
+
sns.lineplot(np.append(X[-1], np.arange(0, test_len, points_granularity) + max(X) + points_granularity), np.append(Y[-1], result['result']), color=c3)
|
133 |
plt.legend(['Train data', 'Test data', 'Predicted data'], loc=3)
|
134 |
plt.xlabel('Sample number')
|
135 |
plt.ylabel('Sample value')
|
136 |
st.pyplot(fig)
|
137 |
|
138 |
+
# Print statistics
|
139 |
st.write("The prediction isn't good enough? Try to change settings in the model setup or increase the dataset length.")
|
140 |
st.write('Training took {} epochs, Mean Squared Error: {:.2e}'.format(result['epochs'], result['loss']))
|
141 |
#st.write('Training took {} epochs, Mean Squared Error {}, last loss {}'.format(result['epochs'], result['loss'], result['loss_last']))
|
app_helper_functions.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import streamlit as st
|
3 |
+
|
4 |
+
def user_input_features(test_len, points_granularity):
|
5 |
+
data, nn = {}, {}
|
6 |
+
st.sidebar.header('Dataset:')
|
7 |
+
data['length'] = st.sidebar.slider('Training data length', 20, 50, 28)
|
8 |
+
data['period'] = st.sidebar.slider('Period of the wave', 0.75, 2.0, 1.0)
|
9 |
+
data['growth'] = st.sidebar.slider('Values growth', -0.25, 0.25, 0.0)
|
10 |
+
data['amplitude'] = st.sidebar.slider('Amplitude', 0.25, 1.75, 1.0)
|
11 |
+
data['amplitude_growth'] = st.sidebar.slider('Amplitude growth', -0.01, 0.1, 0.0)
|
12 |
+
data['noise'] = st.sidebar.slider('Noise', 0.0, 1.0, 0.0)
|
13 |
+
st.sidebar.header('Model setup')
|
14 |
+
nn['use_lstm'] = st.sidebar.radio('Select the type of Recurrent Neuron to use', ['LSTM', 'GRU']) == 'LSTM'
|
15 |
+
nn['r1_nodes'] = st.sidebar.slider('Number of nodes in the first RNN layer', 1, 30, 13)
|
16 |
+
nn['r2_nodes'] = st.sidebar.slider('Number of nodes in the second RNN layer', 0, 30, 0)
|
17 |
+
nn['fc1_nodes'] = st.sidebar.slider('Number of nodes in the fully connected RNN layer', 0, 40, 10)
|
18 |
+
nn['steps'] = len(np.arange(0, test_len, points_granularity))
|
19 |
+
|
20 |
+
return data, nn
|
21 |
+
|
22 |
+
|
23 |
+
def generate_wave(x_set, params):
|
24 |
+
return np.sin(x_set / params['period']) * (1 + params['amplitude_growth'] * x_set) * params[
|
25 |
+
'amplitude'] + x_set * params['growth'] + params['noise']*np.random.randn(len(x_set))
|
26 |
+
|
27 |
+
def local_css(file_name):
|
28 |
+
with open(file_name) as f:
|
29 |
+
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
|
predict.py
CHANGED
@@ -1,98 +1,82 @@
|
|
1 |
-
import tensorflow.keras as tf
|
2 |
import numpy as np
|
3 |
from sklearn.preprocessing import StandardScaler
|
|
|
4 |
|
5 |
verbose = 0
|
6 |
|
7 |
# TODO: Refactor this module
|
8 |
|
9 |
-
def predict_series(values, r1_nodes=
|
10 |
-
|
11 |
train = np.array(values)
|
12 |
-
|
13 |
train_last_value = train[-1]
|
14 |
train = train[1:] - train[:-1]
|
15 |
sc = StandardScaler()
|
16 |
train = sc.fit_transform(train.reshape(-1, 1))
|
17 |
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
for t in range(len(train) - T):
|
22 |
-
x = train[t:t + T]
|
23 |
X.append(x)
|
24 |
-
Y.append(train[t +
|
25 |
-
|
26 |
-
X = np.array(X).reshape(-1, T, 1)
|
27 |
Y = np.array(Y)
|
28 |
|
29 |
-
|
30 |
if use_lstm:
|
31 |
-
rnn_layer =
|
32 |
else:
|
33 |
-
rnn_layer =
|
|
|
|
|
|
|
34 |
if r2_nodes:
|
35 |
-
|
36 |
-
x = rnn_layer(r2_nodes)(x)
|
37 |
-
else:
|
38 |
-
x = rnn_layer(r1_nodes)(i)
|
39 |
if fc1_nodes:
|
40 |
-
|
41 |
-
|
42 |
-
model = tf.models.Model(i, x)
|
43 |
-
|
44 |
-
# TODO: optimize execution time
|
45 |
-
"""lr_schedule = tf.optimizers.schedules.ExponentialDecay(
|
46 |
-
initial_learning_rate=0.2,
|
47 |
-
decay_steps=10,
|
48 |
-
decay_rate=0.8)
|
49 |
-
optimizer = tf.optimizers.Ftrl(learning_rate=0.001, learning_rate_power=-0.1)"""
|
50 |
|
|
|
51 |
model.compile(
|
52 |
-
loss='mse',
|
53 |
-
optimizer=
|
54 |
-
)
|
55 |
-
|
56 |
-
callbacks = [tf.callbacks.EarlyStopping(patience=150, monitor='loss', restore_best_weights=True)]
|
57 |
|
|
|
58 |
r = model.fit(
|
59 |
X, Y,
|
60 |
epochs=500,
|
61 |
callbacks=callbacks,
|
62 |
verbose=verbose,
|
63 |
-
validation_split=0.0
|
64 |
-
)
|
65 |
-
pred = np.array([])
|
66 |
-
last_x = X[-1]
|
67 |
|
|
|
|
|
68 |
|
69 |
for _ in range(steps):
|
70 |
p = model.predict(last_x.reshape(1, -1, 1))[0, 0]
|
71 |
-
|
72 |
last_x = np.roll(last_x, -1)
|
73 |
last_x[-1] = p
|
74 |
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
pred[0] = train_last_value + pred[0]
|
79 |
-
|
80 |
-
for i in range(1, len(pred)):
|
81 |
-
pred[i] += pred[i-1]
|
82 |
|
|
|
|
|
83 |
|
84 |
-
result = {'result': list(
|
85 |
return result
|
86 |
|
87 |
|
88 |
if __name__ == "__main__":
|
|
|
89 |
from time import time
|
90 |
t1 = time()
|
91 |
-
verbose = 2
|
92 |
data = np.sin(np.arange(0.0, 28.0, 0.35)*2)
|
93 |
result = predict_series(data, steps=66, r1_nodes=14, r2_nodes=14, fc1_nodes=20)
|
94 |
print('exec time: {:8.3f}'.format(time()-t1))
|
95 |
-
#print(result['result'][:2])
|
96 |
print(print(result['epochs'], result['loss']))
|
97 |
import seaborn as sns
|
98 |
sns.lineplot(x=range(30), y=data[-30:], color='r')
|
|
|
|
|
1 |
import numpy as np
|
2 |
from sklearn.preprocessing import StandardScaler
|
3 |
+
from tensorflow import keras
|
4 |
|
5 |
verbose = 0
|
6 |
|
7 |
# TODO: Refactor this module
|
8 |
|
9 |
+
def predict_series(values, r1_nodes=10, r2_nodes=0, fc1_nodes=0, steps=20, use_lstm=True, seq_length = 15, *args, **kwargs):
|
10 |
+
# TODO: simplify and optimize creating windows
|
11 |
train = np.array(values)
|
|
|
12 |
train_last_value = train[-1]
|
13 |
train = train[1:] - train[:-1]
|
14 |
sc = StandardScaler()
|
15 |
train = sc.fit_transform(train.reshape(-1, 1))
|
16 |
|
17 |
+
X, Y = [], []
|
18 |
+
for t in range(len(train) - seq_length):
|
19 |
+
x = train[t:t + seq_length]
|
|
|
|
|
20 |
X.append(x)
|
21 |
+
Y.append(train[t + seq_length])
|
22 |
+
X = np.array(X).reshape(-1, seq_length, 1)
|
|
|
23 |
Y = np.array(Y)
|
24 |
|
25 |
+
# TODO: Add SimpleRNN
|
26 |
if use_lstm:
|
27 |
+
rnn_layer = keras.layers.LSTM
|
28 |
else:
|
29 |
+
rnn_layer = keras.layers.GRU
|
30 |
+
|
31 |
+
model = keras.Sequential()
|
32 |
+
model.add(rnn_layer(r1_nodes, return_sequences=bool(r2_nodes)))
|
33 |
if r2_nodes:
|
34 |
+
model.add(rnn_layer(r2_nodes))
|
|
|
|
|
|
|
35 |
if fc1_nodes:
|
36 |
+
model.add(keras.layers.Dense(fc1_nodes, activation='relu'))
|
37 |
+
model.add(keras.layers.Dense(1))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
|
39 |
+
# TODO: optimize execution time
|
40 |
model.compile(
|
41 |
+
loss='mse',
|
42 |
+
optimizer=keras.optimizers.Adamax(lr=0.2))
|
|
|
|
|
|
|
43 |
|
44 |
+
callbacks = [keras.callbacks.EarlyStopping(patience=150, monitor='loss', restore_best_weights=True)]
|
45 |
r = model.fit(
|
46 |
X, Y,
|
47 |
epochs=500,
|
48 |
callbacks=callbacks,
|
49 |
verbose=verbose,
|
50 |
+
validation_split=0.0)
|
|
|
|
|
|
|
51 |
|
52 |
+
predictions = np.array([])
|
53 |
+
last_x = X[-1]
|
54 |
|
55 |
for _ in range(steps):
|
56 |
p = model.predict(last_x.reshape(1, -1, 1))[0, 0]
|
57 |
+
predictions = np.append(predictions, p)
|
58 |
last_x = np.roll(last_x, -1)
|
59 |
last_x[-1] = p
|
60 |
|
61 |
+
predictions = sc.inverse_transform(predictions.reshape(-1, 1))
|
62 |
+
predictions.reshape(-1)
|
63 |
+
predictions[0] = train_last_value + predictions[0]
|
|
|
|
|
|
|
|
|
64 |
|
65 |
+
for i in range(1, len(predictions)):
|
66 |
+
predictions[i] += predictions[i-1]
|
67 |
|
68 |
+
result = {'result': list(predictions.reshape(-1)), 'epochs': r.epoch[-1] + 1, 'loss': min(r.history['loss']), 'loss_last': r.history['loss'][-1]}
|
69 |
return result
|
70 |
|
71 |
|
72 |
if __name__ == "__main__":
|
73 |
+
# Code for debugging/testing
|
74 |
from time import time
|
75 |
t1 = time()
|
76 |
+
# verbose = 2
|
77 |
data = np.sin(np.arange(0.0, 28.0, 0.35)*2)
|
78 |
result = predict_series(data, steps=66, r1_nodes=14, r2_nodes=14, fc1_nodes=20)
|
79 |
print('exec time: {:8.3f}'.format(time()-t1))
|
|
|
80 |
print(print(result['epochs'], result['loss']))
|
81 |
import seaborn as sns
|
82 |
sns.lineplot(x=range(30), y=data[-30:], color='r')
|