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
Files changed (3) hide show
  1. app.py +22 -64
  2. app_helper_functions.py +29 -0
  3. 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'], gran)
124
- X_pred = np.arange(params['length'], params['length'] + test_len, gran)
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, gran) + max(X) + gran), np.append(Y[-1], result['result']), color=c3)
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=5, r2_nodes=0, fc1_nodes=0, steps=20, use_lstm=True, *args, **kwargs):
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
- T = 25
19
- X = []
20
- Y = []
21
- for t in range(len(train) - T):
22
- x = train[t:t + T]
23
  X.append(x)
24
- Y.append(train[t + T])
25
-
26
- X = np.array(X).reshape(-1, T, 1)
27
  Y = np.array(Y)
28
 
29
- i = tf.layers.Input(shape=(T, 1))
30
  if use_lstm:
31
- rnn_layer = tf.layers.LSTM
32
  else:
33
- rnn_layer = tf.layers.GRU
 
 
 
34
  if r2_nodes:
35
- x = rnn_layer(r1_nodes, return_sequences=True)(i)
36
- x = rnn_layer(r2_nodes)(x)
37
- else:
38
- x = rnn_layer(r1_nodes)(i)
39
  if fc1_nodes:
40
- x = tf.layers.Dense(fc1_nodes, activation='relu')(x)
41
- x = tf.layers.Dense(1)(x)
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', #tf.losses.LogCosh(),
53
- optimizer=tf.optimizers.Adamax(lr=0.1) #LogCosh()'sgd'
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
- pred = np.append(pred, p)
72
  last_x = np.roll(last_x, -1)
73
  last_x[-1] = p
74
 
75
- pred = sc.inverse_transform(pred.reshape(-1, 1))
76
-
77
- pred.reshape(-1)
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(pred.reshape(-1)), 'epochs': r.epoch[-1] + 1, 'loss': min(r.history['loss']), 'loss_last': r.history['loss'][-1]}
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')