Huseyin Kaya commited on
Commit
45d9b0c
·
unverified ·
2 Parent(s): 4a409e5 66d2895

Merge pull request #15 from app2scale/ui_updates

Browse files
agent/dashboard/__init__.py CHANGED
@@ -4,16 +4,22 @@ route_order = ["/","data","training","testing","inference"]
4
 
5
  @solara.component
6
  def Page():
7
- with solara.VBox() as main:
8
  solara.Markdown(md_text="""
9
  ## Welcome
10
  This web page is created to demonstrate the model-based auto-scaling
11
  approach developed in "AI-based Auto-Scaling and Tuning" project.
 
 
 
12
 
13
  * In [Data](/data) tab, you can investigate the raw data.
14
  * In [Training](/training), you can build a model on the raw data.
15
  * [Testing](/testing) tab is used to evaluate the performance of the trained model.
16
  * Finally, [Inference](/inference) tab provides a simulation environment to test the model.
17
- """)
18
 
19
- return main
 
 
 
 
 
4
 
5
  @solara.component
6
  def Page():
7
+ with solara.Row():
8
  solara.Markdown(md_text="""
9
  ## Welcome
10
  This web page is created to demonstrate the model-based auto-scaling
11
  approach developed in "AI-based Auto-Scaling and Tuning" project.
12
+ The model-based approach used a historical data containing the state
13
+ of the application such as replica and cpu-limit, as well as some metrics
14
+ measured from Prometheus.
15
 
16
  * In [Data](/data) tab, you can investigate the raw data.
17
  * In [Training](/training), you can build a model on the raw data.
18
  * [Testing](/testing) tab is used to evaluate the performance of the trained model.
19
  * Finally, [Inference](/inference) tab provides a simulation environment to test the model.
 
20
 
21
+ ### Training
22
+ Training data is obtained from historical data collected from monitoring a target Kubernetes
23
+ deployment.
24
+ ![Training](/static/public/training.png)
25
+ """)
agent/dashboard/training.py CHANGED
@@ -39,9 +39,11 @@ def LossPlot(data, render_count):
39
  "xAxis": {
40
  "type": "category",
41
  "data": data['epoch'],
 
42
  },
43
  "yAxis": {
44
  "type": "value",
 
45
  },
46
  "series": [
47
  {
@@ -63,14 +65,6 @@ def LossPlot(data, render_count):
63
  def force_render():
64
  local_state.value['render_count'].set(1 + local_state.value['render_count'].value)
65
 
66
- @solara.component
67
- def FilterPanel(df):
68
- with solara.Column(gap="0px"):
69
- solara.CrossFilterReport(df, classes=["py-2"])
70
- for col in ['replica','cpu','expected_tps','previous_tps']:
71
- if col in df.columns:
72
- solara.CrossFilterSelect(df, configurable=False, column=col)
73
-
74
  @solara.component
75
  def ExecutePanel(df):
76
  filter, set_filter = solara.use_cross_filter(id(df))
@@ -112,38 +106,52 @@ def ExecutePanel(df):
112
  force_render()
113
  local_state.value['model'].set(model)
114
  solara.Button(label='Train', on_click=trigger_training)
115
- LossPlot(local_state.value['loss_plot_data'].value, local_state.value['render_count'].value)
 
 
 
116
 
117
 
118
  @solara.component
119
- def ParameterSelection(df):
120
  def select_input_cols(selected_cols):
121
  local_state.value['input_cols'].set(selected_cols)
122
  def select_output_cols(selected_cols):
123
  local_state.value['output_cols'].set(selected_cols)
124
 
125
- with solara.Row():
126
- with solara.Columns([50,50]):
127
- with solara.Column():
128
- solara.SelectMultiple(label='Input cols', all_values=list(df.columns),
 
 
 
129
  values=local_state.value['input_cols'].value,
130
  on_value=select_input_cols)
131
- solara.SelectMultiple(label='Output cols', all_values=list(df.columns),
132
  values=local_state.value['output_cols'].value,
133
  on_value=select_output_cols)
134
- solara.Select(label="Optimizer", values=["Adam"],
135
- value=local_state.value['optimizer_name'].value,
136
- on_value=local_state.value['optimizer_name'].set)
137
-
138
  solara.Select(label="Model", values=["Perceptron","NetSingleHiddenLayer"],
139
  value=local_state.value['model_name'].value,
140
  on_value=local_state.value['model_name'].set)
141
-
 
 
142
  solara.Select(label="Loss", values=['mape'],
143
  value=local_state.value['loss_name'].value,
144
  on_value=local_state.value['loss_name'].set)
145
-
146
- with solara.Column():
 
 
 
 
 
 
147
  solara.SliderFloat(label='Training ratio',
148
  value=local_state.value['trn_ratio'].value, min=0, max=1,
149
  on_value=local_state.value['trn_ratio'].set,
@@ -156,23 +164,24 @@ def ParameterSelection(df):
156
  value=local_state.value['batch_size_val'].value, min=1, max=256,
157
  on_value=local_state.value['batch_size_val'].set,
158
  thumb_label=True)
159
- solara.SliderInt(label='Max epoch',
160
- value=local_state.value['max_epoch'].value, min=1, max=1000,
161
- on_value=local_state.value['max_epoch'].set,
162
- thumb_label=True)
163
- solara.SliderFloat(label="Learning rate log10",
164
- value=local_state.value['learning_rate_log10'].value,
165
- min=-4, max=1, step=0.01,
166
- on_value=local_state.value['learning_rate_log10'].set)
167
- solara.InputInt(label='random seed', value=local_state.value['seed'].value,
168
- on_value=local_state.value['seed'].set)
169
-
 
170
 
171
-
172
 
173
  @solara.component
174
  def Page():
175
  df = state.value['data']
 
176
  dff = df
177
  filtered_cols = []
178
  if len(local_state.value['input_cols'].value) > 0:
@@ -181,10 +190,15 @@ def Page():
181
  filtered_cols += local_state.value['output_cols'].value
182
  if len(filtered_cols) > 0:
183
  dff = df[filtered_cols]
184
- with solara.Columns([40,30,30]):
185
- ParameterSelection(df)
186
- FilterPanel(dff)
187
- solara.CrossFilterDataFrame(dff, items_per_page=10)
188
- ExecutePanel(dff)
 
 
 
 
 
189
 
190
 
 
39
  "xAxis": {
40
  "type": "category",
41
  "data": data['epoch'],
42
+ "name": "epoch",
43
  },
44
  "yAxis": {
45
  "type": "value",
46
+ "name": "loss",
47
  },
48
  "series": [
49
  {
 
65
  def force_render():
66
  local_state.value['render_count'].set(1 + local_state.value['render_count'].value)
67
 
 
 
 
 
 
 
 
 
68
  @solara.component
69
  def ExecutePanel(df):
70
  filter, set_filter = solara.use_cross_filter(id(df))
 
106
  force_render()
107
  local_state.value['model'].set(model)
108
  solara.Button(label='Train', on_click=trigger_training)
109
+ with solara.Card(title="Loss History", margin=1, elevation=10,
110
+ subtitle="""Once you start training, you can monitor the training and validation losses in this plot.
111
+ """):
112
+ LossPlot(local_state.value['loss_plot_data'].value, local_state.value['render_count'].value)
113
 
114
 
115
  @solara.component
116
+ def ParameterSelection(df, attributes):
117
  def select_input_cols(selected_cols):
118
  local_state.value['input_cols'].set(selected_cols)
119
  def select_output_cols(selected_cols):
120
  local_state.value['output_cols'].set(selected_cols)
121
 
122
+ with solara.lab.Tabs():
123
+ with solara.lab.Tab("I/O"):
124
+ with solara.Card(title="Input/Output Selection", margin=1, elevation=10,
125
+ subtitle="""Select which attributes of the data are to be used as input/output of the
126
+ machine learning model. Selected attributes will be reflected to the dataframe on the right,
127
+ immediately."""):
128
+ solara.SelectMultiple(label='Input features', all_values=attributes,
129
  values=local_state.value['input_cols'].value,
130
  on_value=select_input_cols)
131
+ solara.SelectMultiple(label='Output features', all_values=attributes,
132
  values=local_state.value['output_cols'].value,
133
  on_value=select_output_cols)
134
+ with solara.lab.Tab("PARAMETERS"):
135
+ with solara.Card(title="Model Training Parameters", margin=1, elevation=10,
136
+ subtitle="""Select the machine learning model, optimizer, loss and various hyper-parameters
137
+ used in the training."""):
138
  solara.Select(label="Model", values=["Perceptron","NetSingleHiddenLayer"],
139
  value=local_state.value['model_name'].value,
140
  on_value=local_state.value['model_name'].set)
141
+ solara.Select(label="Optimizer", values=["Adam"],
142
+ value=local_state.value['optimizer_name'].value,
143
+ on_value=local_state.value['optimizer_name'].set)
144
  solara.Select(label="Loss", values=['mape'],
145
  value=local_state.value['loss_name'].value,
146
  on_value=local_state.value['loss_name'].set)
147
+ solara.SliderFloat(label="Learning rate (log10)",
148
+ value=local_state.value['learning_rate_log10'].value,
149
+ min=-4, max=1, step=0.01,
150
+ on_value=local_state.value['learning_rate_log10'].set)
151
+ solara.SliderInt(label='Max epoch',
152
+ value=local_state.value['max_epoch'].value, min=1, max=1000,
153
+ on_value=local_state.value['max_epoch'].set,
154
+ thumb_label=True)
155
  solara.SliderFloat(label='Training ratio',
156
  value=local_state.value['trn_ratio'].value, min=0, max=1,
157
  on_value=local_state.value['trn_ratio'].set,
 
164
  value=local_state.value['batch_size_val'].value, min=1, max=256,
165
  on_value=local_state.value['batch_size_val'].set,
166
  thumb_label=True)
167
+ solara.SliderInt(label='random seed', value=local_state.value['seed'].value, min=0, max=1000,
168
+ on_value=local_state.value['seed'].set,
169
+ thumb_label=True)
170
+ with solara.lab.Tab("FILTER"):
171
+ with solara.Card(title="Data Filter", margin=1, elevation=10,
172
+ subtitle="""In addition to the input/output attributes, you can also
173
+ select a subset of rows for training. Filtered dataframe displayed on the
174
+ right will be used in the training."""):
175
+ solara.CrossFilterReport(df)
176
+ for col in ['replica','cpu','expected_tps','previous_tps']:
177
+ if col in df.columns:
178
+ solara.CrossFilterSelect(df, configurable=False, column=col)
179
 
 
180
 
181
  @solara.component
182
  def Page():
183
  df = state.value['data']
184
+ attributes = list(df.columns)
185
  dff = df
186
  filtered_cols = []
187
  if len(local_state.value['input_cols'].value) > 0:
 
190
  filtered_cols += local_state.value['output_cols'].value
191
  if len(filtered_cols) > 0:
192
  dff = df[filtered_cols]
193
+ with solara.Sidebar():
194
+ ParameterSelection(dff, attributes)
195
+ with solara.ColumnsResponsive():
196
+ ExecutePanel(dff)
197
+ with solara.Card(title="Training/Testing Data", margin=1, elevation=10,
198
+ subtitle="""Based on the selected nput/output attributes and the cross-filters,
199
+ this is the final data used in training/validation. Right before using
200
+ this data in the training/validation, normalization is applied. For more
201
+ information please check backend.data.ExplorationDataset"""):
202
+ solara.CrossFilterDataFrame(dff, items_per_page=10)
203
 
204
 
agent/public/training.drawio ADDED
@@ -0,0 +1 @@
 
 
1
+ <mxfile host="Electron" modified="2024-04-24T09:20:44.239Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.7.4 Chrome/106.0.5249.199 Electron/21.3.3 Safari/537.36" version="20.7.4" etag="chSOnRKB6Z1sgUmyfTrz" type="device"><diagram id="4Ei_wvUUD_S_ACNlq_Ix" name="Page-1">7Vnbcto6FP0aHpvxBdvwyDWlA4EGOuexI2zZ1olseWQRQr++ki1fRU6ghdIzA5kJ0tLWlqy1vKUtOuYoenukIAkXxIO4Y2jeW8ccdwxDt/Ue/xLIIUesXj8HAoo8aVQBa/QDSlCT6A55MG0YMkIwQ0kTdEkcQ5c1MEAp2TfNfIKboyYggAqwdgFW0X+Qx8Ic7VlahX+GKAiLkXVNtkSgMJZAGgKP7GuQOemYI0oIy0vR2whisXjFuuT9pu+0lhOjMGandPi6wxN3M58Pv2ub749P9Ml1g0+WZOMV4J184tXzZDwbbWbLp45hY+56uKW8FIjSYjmezOXjsEOxRpTsYg+KYTRusw8Rg+sEuKJ1z1XBsZBFmNd0XvRJzKYgQlgI4gtkQwpQnHKHCxIT3l4uU2G8lgNldYTxiGBCs4FN3xJ/0q6G5x/hjFHyAmstdvbhLfKxIWXw7d0F1UuauL4hiSCjB24iO3zqFlxLbdtdWd/XlCKhsCaSwgxIbQal64o+XpAMnsGmrSlsPk9W89lo8Pdw5lmw53WPcdMztubFuLHsFjfmadwYV+PGULgZrb5xYD5bzDZ3fqxb82Mq/MyXg/GdGOfWxHTfeXG+rQePk7+HH9+Htuse48dz+ltNuxA/5e5RBjbrxvxYCj+LyeLOTxnYbs2PrfCzWa3vvDg35sVxFA6gx3MPWSWUhSQgMcCTCh02Waps5oQkcnn/hYwdZCIFdoycxxyMvYFIm3jrFhP3JYemSDzbuOJCzPRcJijEgKHXZr9jyyq7rgjiHisGS8Ykg47WoiYlO+pC2a2eCbU9WUZTC47e8sQADSBTPPGVAYeaWSIM0nOm3NXOnFmzAy/kc6hkVy7wbyhR3WE/z9ab5TNPHOZqEjgebNR8gr/xiSi6B4y4Qqn5cRDZ5lqeb0sAuC9BpvDljnE3RcBIczHr1gn6bR+aAOz5R4OL7fbg1r9QcHFatNmGGlz6R4KLc7Xgom7KarRRX/UaO81Ic0LYuEiMqK2XdWS9Cux3Q0nXafFl/2oo6eofeHonlFzs3VV39zvRFT3mR/ScTHQ5pVsR3bsfF86i3tL7D5p5dDf9Bfa1P3RiUAb6IwcA9RZ4zQCDYuJicuoZgKFItDJFk3wTZU0JNXfemIhtvbFNSwhgFMTiBMGFATk+FFsycgEeyIYIeV6m6mPniv+IYoNXGCPaSkSMop4pgAMhYwknxjL52cbiyy3+CYP0ISAkwBAkKH1wSZQ1uGlmOvXzMXixGuUS54n2JYxVHB5udbPcU28vF9wxctNTNDLU7zq5ik7aSa3VPy2pvZ5O1FvUhJLX7Dc83jVOdlwOU7JjWUHzAANXkAaGPvv/CiPzKlOeS91+2K0Db5mw1ISiX+j6g1erXzXzLar6bdic/AQ=</diagram></mxfile>
agent/public/training.png ADDED