-
Notifications
You must be signed in to change notification settings - Fork 4
/
get_classes.py
144 lines (117 loc) · 5.53 KB
/
get_classes.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""
This script parses through all classes available in Google's AudioSet dataset
collection. Using the available meta data for the set such as quality estimated
for each class and whether or not they have child classes, designated
'suitable_classes' are found and saved for later use in downloading and sorting.
REQUIRES:
- 'MetaData' folder that holds the following files(Should contain others for later):
- labels.xlsx : mID to name conversion table for classes
- ontology.json : AudioSet ontology which includes all meta dta about classes
- qa_true_counts.csv : Estimated quality of classes from Google's testing
OUTPUTS:
- A numpy loadable file which contains a 2D array with the classes from
AudioSet that meet requirements, the first dimension is the mID and
second dimension is the readable name of class
- option for a PNG plot of how number of available classes scale with quality threshold
- Just uncomment graphing() call in main
- Printed number of classes found
"""
###############################################################################
#IMPORTS
###############################################################################
import os
import json
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
###############################################################################
#FUNCTIONS
###############################################################################
def suitable_class_extractor(quality, path_to_meta, leaf=True):
"""
Function to extract suitable classes from the AudioSet ontology based on
some requirements
:param qual: float
Minimum quality threshold for considered classes, between 0 and 1
:param leafs: Boolean
Whether or not to only consider leaf nodes of AudioSet hierarchy
:return len(suitabe): int
Number of suitable classes found from ontology
:return suitable: array
2D array with mIDs along with legible class names (suitable_classes.npy)
"""
# Read in mid to label conversion table
label_convert = pd.read_excel(path_to_meta + '\labels.xlsx', index_col=0)
# Read in ontology stored in json file
with open(path_to_meta + '/ontology.json') as f:
ontology = json.load(f)
# Read in quality estimates for classes
quality_estimates = pd.read_csv(path_to_meta + '/qa_true_counts.csv')
quality_estimates['rate'] = quality_estimates['num_true'] / quality_estimates['num_rated']
# Stores the suitable classes to extract in 2D, [mid, label_name]
suitable = []
for i, val in enumerate(ontology):
example = ontology[i]
# Checks if leaf node or not
if leaf:
if len(example['child_ids']) > 0:
continue
if example['restrictions'] == ['blacklist']:
continue
mid = example['id']
sub_df = quality_estimates.loc[quality_estimates['label_id'] == mid]
# Some classes do not seem to exist outside of the ontology and so skip
if sub_df.empty:
continue
# Make sure that quality threshold is reached
if (sub_df['rate'].item() >= quality):
sub_label = label_convert.loc[label_convert['mid'] == mid]
mid_name = sub_label['display_name'].item()
# If both requirements satisfied we save class by name and MID
suitable.append([mid, mid_name])
return len(suitable), suitable
def graphing(path_to_meta):
"""
Determines number of available classes(leaf nodes) that are available
at various quality thresholds
:save: PNG
Graph of how number of suitbale classes scale with estimated
quality threshold
"""
# Deals with data collection
numbers_of_classes = []
thresholds = np.arange(0, 1.05, 0.05)
for i in thresholds:
nums, classes = suitable_class_extractor(i, path_to_meta, True)
numbers_of_classes.append(nums)
# Takes data and plots/saves
plt.figure(figsize=(15, 10))
plt.plot(thresholds, numbers_of_classes)
plt.xlabel('Quality Threshold')
plt.ylabel('Number of Leaf Classes Available')
plt.savefig('audioset_leafs_per_threshold_quality.png')
plt.show()
###############################################################################
# MAIN FUNCTION WITH CALL
###############################################################################
def main_get_classes(leafs, qual, path_to_meta):
"""
Main file function which calls everything required
:param qual: float
Minimum quality threshold for considered classes, between 0 and 1
:param leafs: Boolean
Whether or not to only consider leaf nodes of AudioSet hierarchy
:print: int
Number of suitable classes found from ontology
:save: array
2D array with mIDs along with legible class names (suitable_classes.npy)
"""
if leafs == 'n':
num_classes, classes = suitable_class_extractor(qual, path_to_meta, False)
print(f'{num_classes} suitable classes found in AudioSet using passed parameters')
else:
num_classes, classes = suitable_class_extractor(qual, path_to_meta, True)
print(f'{num_classes} suitable classes found in AudioSet using passed parameters')
# Saves the 2D class array to a npy file for later loading
np.save('suitable_classes', classes)
#graphing(path_to_meta)