m7mdal7aj commited on
Commit
d6824cb
1 Parent(s): 062b387

Update my_model/tabs/results.py

Browse files
Files changed (1) hide show
  1. my_model/tabs/results.py +43 -287
my_model/tabs/results.py CHANGED
@@ -1,292 +1,48 @@
1
- import os
2
- import altair as alt
3
- import evaluation_config as config
4
  import streamlit as st
5
- from PIL import Image
6
- import pandas as pd
7
- import random
8
 
9
-
10
- class ResultDemonstrator:
11
  """
12
- A class to demonstrate the results of the Knowledge-Based Visual Question Answering (KB-VQA) model.
13
-
14
- Attributes:
15
- main_data (pd.DataFrame): Data loaded from an Excel file containing evaluation results.
16
- sample_img_pool (list[str]): List of image file names available for demonstration.
17
- model_names (list[str]): List of model names as defined in the configuration.
18
- model_configs (list[str]): List of model configurations as defined in the configuration.
19
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
- def __init__(self) -> None:
22
- """
23
- Initializes the ResultDemonstrator class by loading the data from an Excel file.
24
- """
25
- # Load data
26
- self.main_data = pd.read_excel('evaluation_results.xlsx', sheet_name="Main Data")
27
- self.sample_img_pool = list(os.listdir("demo"))
28
- self.model_names = config.MODEL_NAMES
29
- self.model_configs = config.MODEL_CONFIGURATIONS
30
-
31
- @staticmethod
32
- def display_table(data: pd.DataFrame) -> None:
33
- """
34
- Displays a DataFrame using Streamlit's dataframe display function.
35
-
36
- Args:
37
- data (pd.DataFrame): The data to display.
38
- """
39
- st.dataframe(data)
40
-
41
- def calculate_and_append_data(self, data_list: list, score_column: str, model_config: str) -> None:
42
- """
43
- Calculates mean scores by category and appends them to the data list.
44
-
45
- Args:
46
- data_list (list): List to append new data rows.
47
- score_column (str): Name of the column to calculate mean scores for.
48
- model_config (str): Configuration of the model.
49
- """
50
- if score_column in self.main_data.columns:
51
- category_means = self.main_data.groupby('question_category')[score_column].mean()
52
- for category, mean_value in category_means.items():
53
- data_list.append({
54
- "Category": category,
55
- "Configuration": model_config,
56
- "Mean Value": round(mean_value * 100, 2)
57
- })
58
-
59
- def display_ablation_results_per_question_category(self) -> None:
60
- """Displays ablation results per question category for each model configuration."""
61
-
62
- score_types = ['vqa', 'vqa_gpt4', 'em', 'em_gpt4']
63
- data_lists = {key: [] for key in score_types}
64
- column_names = {
65
- 'vqa': 'vqa_score_{config}',
66
- 'vqa_gpt4': 'gpt4_vqa_score_{config}',
67
- 'em': 'exact_match_score_{config}',
68
- 'em_gpt4': 'gpt4_em_score_{config}'
69
- }
70
-
71
- for model_name in config.MODEL_NAMES:
72
- for conf in config.MODEL_CONFIGURATIONS:
73
- model_config = f"{model_name}_{conf}"
74
- for score_type, col_template in column_names.items():
75
- self.calculate_and_append_data(data_lists[score_type],
76
- col_template.format(config=model_config),
77
- model_config)
78
-
79
- # Process and display results for each score type
80
- for score_type, data_list in data_lists.items():
81
- df = pd.DataFrame(data_list)
82
- results_df = df.pivot(index='Category', columns='Configuration', values='Mean Value').applymap(
83
- lambda x: f"{x:.2f}%")
84
-
85
- with st.expander(f"{score_type.upper()} Scores per Question Category and Model Configuration"):
86
- self.display_table(results_df)
87
-
88
- def display_main_results(self) -> None:
89
- """Displays the main model results from the Scores sheet, these are displayed from the file directly."""
90
- main_scores = pd.read_excel('evaluation_results.xlsx', sheet_name="Scores", index_col=0)
91
- st.markdown("### Main Model Results (Inclusive of Ablation Experiments)")
92
- main_scores.reset_index()
93
- self.display_table(main_scores)
94
-
95
- def plot_token_count_vs_scores(self, conf: str, model_name: str, score_name: str = 'VQA Score') -> None:
96
- """
97
- Plots an interactive scatter plot comparing token counts to VQA or EM scores using Altair.
98
-
99
- Args:
100
- conf (str): The configuration name.
101
- model_name (str): The name of the model.
102
- score_name (str): The type of score to plot.
103
- """
104
-
105
- # Construct the full model configuration name
106
- model_configuration = f"{model_name}_{conf}"
107
-
108
- # Determine the score column name and legend mapping based on the score type
109
- if score_name == 'VQA Score':
110
-
111
- score_column_name = f"vqa_score_{model_configuration}"
112
- scores = self.main_data[score_column_name]
113
- # Map scores to categories for the legend
114
- legend_map = ['Correct' if score == 1 else 'Partially Correct' if round(score, 2) == 0.67 else 'Incorrect' for score in scores]
115
- color_scale = alt.Scale(domain=['Correct', 'Partially Correct', 'Incorrect'], range=['green', 'orange', 'red'])
116
- else:
117
- score_column_name = f"exact_match_score_{model_configuration}"
118
- scores = self.main_data[score_column_name]
119
- # Map scores to categories for the legend
120
- legend_map = ['Correct' if score == 1 else 'Incorrect' for score in scores]
121
- color_scale = alt.Scale(domain=['Correct', 'Incorrect'], range=['green', 'red'])
122
-
123
- # Retrieve token counts from the data
124
- token_counts = self.main_data[f'tokens_count_{conf}']
125
-
126
- # Create a DataFrame for the scatter plot
127
- scatter_data = pd.DataFrame({
128
- 'Index': range(len(token_counts)),
129
- 'Token Counts': token_counts,
130
- score_name: legend_map
131
- })
132
-
133
- # Create an interactive scatter plot using Altair
134
- chart = alt.Chart(scatter_data).mark_circle(
135
- size=60,
136
- fillOpacity=1, # Sets the fill opacity to maximum
137
- strokeWidth=1, # Adjusts the border width making the circles bolder
138
- stroke='black' # Sets the border color to black
139
- ).encode(
140
- x=alt.X('Index', scale=alt.Scale(domain=[0, 1020])),
141
- y=alt.Y('Token Counts', scale=alt.Scale(domain=[token_counts.min()-200, token_counts.max()+200])),
142
- color=alt.Color(score_name, scale=color_scale, legend=alt.Legend(title=score_name)),
143
- tooltip=['Index', 'Token Counts', score_name]
144
- ).interactive() # Enables zoom & pan
145
-
146
- chart = chart.properties(
147
- title={
148
- "text": f"Token Counts vs {score_name} + Score + ({model_configuration})",
149
- "color": "black", # Optional color
150
- "fontSize": 20, # Optional font size
151
- "anchor": "middle", # Optional anchor position
152
- "offset": 0 # Optional offset
153
- },
154
- width=700,
155
- height=500
156
- )
157
-
158
- # Display the interactive plot in Streamlit
159
- st.altair_chart(chart, use_container_width=True)
160
-
161
- @staticmethod
162
- def color_scores(value: float) -> str:
163
- """
164
- Applies color coding based on the score value.
165
-
166
- Args:
167
- value (float): The score value.
168
-
169
- Returns:
170
- str: CSS color style based on score value.
171
- """
172
-
173
- try:
174
- value = float(value) # Convert to float to handle numerical comparisons
175
- except ValueError:
176
- return 'color: black;' # Return black if value is not a number
177
-
178
- if value == 1.0:
179
- return 'color: green;'
180
- elif value == 0.0:
181
- return 'color: red;'
182
- elif value == 0.67:
183
- return 'color: orange;'
184
- return 'color: black;'
185
-
186
- def show_samples(self, num_samples: int = 3) -> None:
187
- """
188
- Displays random sample images and their associated models answers and evaluations.
189
-
190
- Args:
191
- num_samples (int): Number of sample images to display.
192
- """
193
-
194
- # Sample images from the pool
195
- target_imgs = random.sample(self.sample_img_pool, num_samples)
196
- # Generate model configurations
197
- model_configs = [f"{model_name}_{conf}" for model_name in self.model_names for conf in self.model_configs]
198
- # Define column names for scores dynamically
199
- column_names = {
200
- 'vqa': 'vqa_score_{config}',
201
- 'vqa_gpt4': 'gpt4_vqa_score_{config}',
202
- 'em': 'exact_match_score_{config}',
203
- 'em_gpt4': 'gpt4_em_score_{config}'
204
- }
205
-
206
- for img_filename in target_imgs:
207
- image_data = self.main_data[self.main_data['image_filename'] == img_filename]
208
- im = Image.open(f"demo/{img_filename}")
209
- col1, col2 = st.columns([1, 2]) # to display images side by side with their data.
210
- # Create a container for each image
211
- with st.container():
212
- st.write("-------------------------------")
213
- with col1:
214
- st.image(im, use_column_width=True)
215
- with st.expander('Show Caption'):
216
- st.text(image_data.iloc[0]['caption'])
217
- with st.expander('Show DETIC Objects'):
218
- st.text(image_data.iloc[0]['objects_detic_trimmed'])
219
- with st.expander('Show YOLOv5 Objects'):
220
- st.text(image_data.iloc[0]['objects_yolov5'])
221
- with col2:
222
- if not image_data.empty:
223
- st.write(f"**Question: {image_data.iloc[0]['question']}**")
224
- st.write(f"**Ground Truth Answers:** {image_data.iloc[0]['raw_answers']}")
225
-
226
- # Initialize an empty DataFrame for summary data
227
- summary_data = pd.DataFrame(
228
- columns=['Model Configuration', 'Answer', 'VQA Score', 'VQA Score (GPT-4)', 'EM Score',
229
- 'EM Score (GPT-4)'])
230
-
231
- for config in model_configs:
232
- # Collect data for each model configuration
233
- row_data = {
234
- 'Model Configuration': config,
235
- 'Answer': image_data.iloc[0].get(f'{config}', '-')
236
- }
237
- for score_type, score_template in column_names.items():
238
- score_col = score_template.format(config=config)
239
- score_value = image_data.iloc[0].get(score_col, '-')
240
- if pd.notna(score_value) and not isinstance(score_value, str):
241
- # Format score to two decimals if it's a valid number
242
- score_value = f"{float(score_value):.2f}"
243
- row_data[score_type.replace('_', ' ').title()] = score_value
244
-
245
- # Convert row data to a DataFrame and concatenate it
246
- rd = pd.DataFrame([row_data])
247
- rd.columns = summary_data.columns
248
- summary_data = pd.concat([summary_data, rd], axis=0, ignore_index=True)
249
-
250
- # Apply styling to DataFrame for score coloring
251
- styled_summary = summary_data.style.applymap(self.color_scores,
252
- subset=['VQA Score', 'VQA Score (GPT-4)',
253
- 'EM Score',
254
- 'EM Score (GPT-4)'])
255
- st.markdown(styled_summary.to_html(escape=False, index=False), unsafe_allow_html=True)
256
- else:
257
- st.write("No data available for this image.")
258
-
259
- def run_demo(self):
260
- """
261
- Run the interactive Streamlit demo for visualizing model evaluation results and analysis.
262
- """
263
-
264
- col1, col2 = st.columns([1, 4])
265
- with col1:
266
- # User selects the evaluation analysis aspect
267
- section_type = st.radio("Select Evaluation Aspect", ["Evaluation Results & Analysis", 'Evaluation Samples'])
268
-
269
- # Only show analysis type if the section type is "Evaluation Results & Analysis"
270
- if section_type == "Evaluation Results & Analysis":
271
- analysis_type = st.radio("Select Type", ["Main & Ablation Results", "Results per Question Category",
272
- "Prompt Length (token count) Impact on Performance"], index=2)
273
- if analysis_type == "Prompt Length (token count) Impact on Performance":
274
- # Based on the selection, other options appear
275
- model_name = st.radio("Select Model Size", self.model_names)
276
- score_name = st.radio("Select Score Type", ["VQA Score", "Exact Match"])
277
-
278
- elif section_type == 'Evaluation Samples':
279
- samples_button = st.button("Generate Random Samples")
280
- with col2:
281
- if section_type == "Evaluation Results & Analysis":
282
- if analysis_type == "Prompt Length (token count) Impact on Performance":
283
- for conf in self.model_configs:
284
- with st.expander(conf):
285
- self.plot_token_count_vs_scores(conf, model_name, score_name)
286
- elif analysis_type == "Main & Ablation Results":
287
- self.display_main_results()
288
- elif analysis_type == "Results per Question Category":
289
- self.display_ablation_results_per_question_category()
290
- elif section_type == 'Evaluation Samples':
291
- if samples_button:
292
- self.show_samples(3)
 
 
 
 
1
  import streamlit as st
2
+ from my_model.results.demo import ResultDemonstrator
3
+ from my_model.config import evaluation_config as config
 
4
 
5
+ def run_demo():
 
6
  """
7
+ Run the interactive Streamlit demo for visualizing model evaluation results and analysis.
 
 
 
 
 
 
8
  """
9
+ st.set_page_config(page_title="Model Evaluation Results and Analyses",
10
+ layout="wide",
11
+ initial_sidebar_state="expanded")
12
+ demo = ResultDemonstrator() # Instantiate the ResultDemonstrator class
13
+
14
+ col1, col2 = st.columns([1, 4])
15
+
16
+ with col1:
17
+ # User selects the evaluation analysis aspect
18
+ section_type = st.radio("Select Evaluation Aspect", ["Evaluation Results & Analysis", 'Evaluation Samples'])
19
+
20
+ # Only show analysis type if the section type is "Evaluation Results & Analysis"
21
+ if section_type == "Evaluation Results & Analysis":
22
+ analysis_type = st.radio("Select Type", ["Main & Ablation Results", "Results per Question Category",
23
+ "Prompt Length (token count) Impact on Performance"], index=2)
24
+ if analysis_type == "Prompt Length (token count) Impact on Performance":
25
+ # Based on the selection, other options appear
26
+ model_name = st.radio("Select Model Size", config.MODEL_NAMES)
27
+ score_name = st.radio("Select Score Type", ["VQA Score", "Exact Match"])
28
+
29
+ elif section_type == 'Evaluation Samples':
30
+ samples_button = st.button("Generate Random Samples")
31
+
32
+ with col2:
33
+ if section_type == "Evaluation Results & Analysis":
34
+ if analysis_type == "Prompt Length (token count) Impact on Performance":
35
+ for conf in config.MODEL_CONFIGURATIONS:
36
+ with st.expander(conf):
37
+ demo.plot_token_count_vs_scores(conf, model_name, score_name)
38
+
39
+ elif analysis_type == "Main & Ablation Results":
40
+ demo.display_main_results()
41
+
42
+ elif analysis_type == "Results per Question Category":
43
+ demo.display_ablation_results_per_question_category()
44
+
45
+ elif section_type == 'Evaluation Samples':
46
+ if samples_button:
47
+ demo.show_samples(3)
48