diff --git a/admin/sql/create_models.sql b/admin/sql/create_models.sql index 7961ca31c..88c7e6de0 100644 --- a/admin/sql/create_models.sql +++ b/admin/sql/create_models.sql @@ -19,4 +19,96 @@ INSERT INTO model (model, model_version, date, status) VALUES ('timbre', 'v2.1_b INSERT INTO model (model, model_version, date, status) VALUES ('tonal_atonal', 'v2.1_beta1', now(), 'show'); INSERT INTO model (model, model_version, date, status) VALUES ('voice_instrumental', 'v2.1_beta1', now(), 'show'); +UPDATE model SET class_mapping = '{ + "danceable": "Danceable", + "not_danceable": "Not danceable" + }'::jsonb WHERE model.model = 'danceability'; + +UPDATE model SET class_mapping = '{ + "acoustic": "Acoustic", + "not_acoustic": "Not acoustic" + }'::jsonb WHERE model.model = 'mood_acoustic'; + +UPDATE model SET class_mapping = '{ + "aggressive": "Aggressive", + "not_aggressive": "Not aggressive" + }'::jsonb WHERE model.model = 'mood_aggressive'; + +UPDATE model SET class_mapping = '{ + "electronic": "Electronic", + "not_electronic": "Not electronic" + }'::jsonb WHERE model.model = 'mood_electronic'; + +UPDATE model SET class_mapping = '{ + "happy": "Happy", + "not_happy": "Not happy" + }'::jsonb WHERE model.model = 'mood_happy'; + +UPDATE model SET class_mapping = '{ + "party": "Party", + "not_party": "Not party" + }'::jsonb WHERE model.model = 'mood_party'; + +UPDATE model SET class_mapping = '{ + "relaxed": "Relaxed", + "not_relaxed": "Not relaxed" + }'::jsonb WHERE model.model = 'mood_relaxed'; + +UPDATE model SET class_mapping = '{ + "sad": "Sad", + "not_sad": "Not sad" + }'::jsonb WHERE model.model = 'mood_sad'; + +UPDATE model SET class_mapping = '{ + "Cluster1": "passionate, rousing, confident, boisterous, rowdy", + "Cluster2": "rollicking, cheerful, fun, sweet, amiable/good natured", + "Cluster3": "literate, poignant, wistful, bittersweet, autumnal, brooding", + "Cluster4": "humorous, silly, campy, quirky, whimsical, witty, wry", + "Cluster5": "aggressive, fiery, tense/anxious, intense, volatile, visceral" + }'::jsonb WHERE model.model = 'moods_mirex'; + +UPDATE model SET class_mapping = '{ + "alternative": "Alternative", + "blues": "Blues", + "electronic": "Electronic", + "folkcountry": "Folk/Country", + "funksoulrnb": "Funk/Soul/RnB", + "jazz": "Jazz", + "pop": "Pop", + "raphiphop": "Rap/Hiphop", + "rock": "Rock" + }'::jsonb WHERE model.model = 'genre_dortmund'; + +UPDATE model SET class_mapping = '{ + "ambient": "Ambient", + "dnb": "Drum and Bass", + "house": "House", + "techno": "Techno", + "trance": "Trance" + }'::jsonb WHERE model.model = 'genre_electronic'; + +UPDATE model SET class_mapping = '{ + "cla": "Classical", + "dan": "Dance", + "hip": "Hiphop", + "jaz": "Jazz", + "pop": "Pop", + "rhy": "Rhythm and Blues", + "roc": "Rock", + "spe": "Speech" + }'::jsonb WHERE model.model = 'genre_rosamerica'; + +UPDATE model SET class_mapping = '{ + "blu": "Blues", + "cla": "Classical", + "cou": "Country", + "dis": "Disco", + "hip": "Hiphop", + "jaz": "Jazz", + "met": "Metal", + "pop": "Pop", + "reg": "Reggae", + "roc": "Rock" + }'::jsonb WHERE model.model = 'genre_tzanetakis'; + COMMIT; diff --git a/admin/sql/create_tables.sql b/admin/sql/create_tables.sql index d58bcb4b3..e347a1ddc 100644 --- a/admin/sql/create_tables.sql +++ b/admin/sql/create_tables.sql @@ -53,7 +53,8 @@ CREATE TABLE model ( model TEXT NOT NULL, model_version TEXT NOT NULL, date TIMESTAMP WITH TIME ZONE DEFAULT NOW(), - status model_status NOT NULL DEFAULT 'hidden' + status model_status NOT NULL DEFAULT 'hidden', + class_mapping JSONB ); CREATE TABLE statistics ( diff --git a/admin/updates/20190606-highlevel-model-mappings.sql b/admin/updates/20190606-highlevel-model-mappings.sql new file mode 100644 index 000000000..b84d1578c --- /dev/null +++ b/admin/updates/20190606-highlevel-model-mappings.sql @@ -0,0 +1,97 @@ +BEGIN; + +ALTER TABLE model ADD COLUMN class_mapping JSONB; + +UPDATE model SET class_mapping = '{ + "danceable": "Danceable", + "not_danceable": "Not danceable" + }'::jsonb WHERE model.model = 'danceability'; + +UPDATE model SET class_mapping = '{ + "acoustic": "Acoustic", + "not_acoustic": "Not acoustic" + }'::jsonb WHERE model.model = 'mood_acoustic'; + +UPDATE model SET class_mapping = '{ + "aggressive": "Aggressive", + "not_aggressive": "Not aggressive" + }'::jsonb WHERE model.model = 'mood_aggressive'; + +UPDATE model SET class_mapping = '{ + "electronic": "Electronic", + "not_electronic": "Not electronic" + }'::jsonb WHERE model.model = 'mood_electronic'; + +UPDATE model SET class_mapping = '{ + "happy": "Happy", + "not_happy": "Not happy" + }'::jsonb WHERE model.model = 'mood_happy'; + +UPDATE model SET class_mapping = '{ + "party": "Party", + "not_party": "Not party" + }'::jsonb WHERE model.model = 'mood_party'; + +UPDATE model SET class_mapping = '{ + "relaxed": "Relaxed", + "not_relaxed": "Not relaxed" + }'::jsonb WHERE model.model = 'mood_relaxed'; + +UPDATE model SET class_mapping = '{ + "sad": "Sad", + "not_sad": "Not sad" + }'::jsonb WHERE model.model = 'mood_sad'; + +UPDATE model SET class_mapping = '{ + "Cluster1": "passionate, rousing, confident, boisterous, rowdy", + "Cluster2": "rollicking, cheerful, fun, sweet, amiable/good natured", + "Cluster3": "literate, poignant, wistful, bittersweet, autumnal, brooding", + "Cluster4": "humorous, silly, campy, quirky, whimsical, witty, wry", + "Cluster5": "aggressive, fiery, tense/anxious, intense, volatile, visceral" + }'::jsonb WHERE model.model = 'moods_mirex'; + +UPDATE model SET class_mapping = '{ + "alternative": "Alternative", + "blues": "Blues", + "electronic": "Electronic", + "folkcountry": "Folk/Country", + "funksoulrnb": "Funk/Soul/RnB", + "jazz": "Jazz", + "pop": "Pop", + "raphiphop": "Rap/Hiphop", + "rock": "Rock" + }'::jsonb WHERE model.model = 'genre_dortmund'; + +UPDATE model SET class_mapping = '{ + "ambient": "Ambient", + "dnb": "Drum and Bass", + "house": "House", + "techno": "Techno", + "trance": "Trance" + }'::jsonb WHERE model.model = 'genre_electronic'; + +UPDATE model SET class_mapping = '{ + "cla": "Classical", + "dan": "Dance", + "hip": "Hiphop", + "jaz": "Jazz", + "pop": "Pop", + "rhy": "Rhythm and Blues", + "roc": "Rock", + "spe": "Speech" + }'::jsonb WHERE model.model = 'genre_rosamerica'; + +UPDATE model SET class_mapping = '{ + "blu": "Blues", + "cla": "Classical", + "cou": "Country", + "dis": "Disco", + "hip": "Hiphop", + "jaz": "Jazz", + "met": "Metal", + "pop": "Pop", + "reg": "Reggae", + "roc": "Rock" + }'::jsonb WHERE model.model = 'genre_tzanetakis'; + +COMMIT; diff --git a/db/data.py b/db/data.py index f110958b4..c9e756448 100644 --- a/db/data.py +++ b/db/data.py @@ -312,17 +312,15 @@ def set_model_status(model_name, model_version, model_status): "model_status": model_status}) -def get_model(model_name, model_version): +def get_active_models(): with db.engine.begin() as connection: query = text( """SELECT * FROM model - WHERE model = :model_name - AND model_version = :model_version""") + WHERE status = :model_status""") result = connection.execute(query, - {"model_name": model_name, - "model_version": model_version}) - return result.fetchone() + {"model_status": STATUS_SHOW}) + return [dict(row) for row in result.fetchall()] def _get_model_id(model_name, version): @@ -471,12 +469,34 @@ def load_many_low_level(recordings): return dict(recordings_info) -def load_high_level(mbid, offset=0): +def map_highlevel_class_names(highlevel, mapping): + """Convert class names from the classifier output to human readable names. + + Arguments: + highlevel (dict): highlevel data dict containing shortened keys + mapping (dict): a mapping from class names -> human readable names + + Returns: + the highlevel input with the keys of the `all` item, and the `value` item + changed to the values from the provided mapping + """ + + new_all = {} + for cl, val in highlevel["all"].items(): + new_all[mapping[cl]] = val + highlevel["all"] = new_all + highlevel["value"] = mapping[highlevel["value"]] + + return highlevel + + +def load_high_level(mbid, offset=0, map_classes=False): """Load high-level data for a given MBID. Arguments: mbid (str): MBID to load offset (int): submission offset for this MBID, starting from 0 + map_classes (bool): if True, map class names to human readable values in the returned data Raises: NoDataFoundException: if this mbid doesn't exist or the offset is too high @@ -484,18 +504,19 @@ def load_high_level(mbid, offset=0): # in case it's a uuid mbid = str(mbid).lower() - result = load_many_high_level([(mbid, offset)]) + result = load_many_high_level([(mbid, offset)], map_classes) if not result: raise db.exceptions.NoDataFoundException return result[mbid][str(offset)] -def load_many_high_level(recordings): +def load_many_high_level(recordings, map_classes=False): """Collect high-level data for multiple recordings. Args: recordings: A list of tuples (mbid, offset). + map_classes (bool): if True, map class names to human readable values in the returned data Returns: {"mbid-1": {"offset-1": {"metadata-1": metadata, "highlevel-1": highlevel}, @@ -543,6 +564,7 @@ def load_many_high_level(recordings): , version.data as version , ll.gid::text , ll.submission_offset::text + , m.class_mapping FROM highlevel_model hlmo JOIN model m ON m.id = hlmo.model @@ -558,6 +580,10 @@ def load_many_high_level(recordings): for row in model_result.fetchall(): model = row['model'] data = row['data'] + mapping = row['class_mapping'] + if map_classes and mapping: + data = map_highlevel_class_names(data, mapping) + data['version'] = row['version'] gid = row['gid'] @@ -647,6 +673,7 @@ def get_summary_data(mbid, offset=0): """Fetches the low-level and high-level features from for the specified MBID. Args: + mbid: musicbrainz id to get data for offset: Offset can be specified if you need to get summary for a different submission. They are ordered by creation time. @@ -674,6 +701,8 @@ def get_summary_data(mbid, offset=0): try: highlevel = load_high_level(mbid, offset) summary['highlevel'] = highlevel + models = get_active_models() + summary['models'] = models except db.exceptions.NoDataFoundException: pass diff --git a/db/test/test_data.py b/db/test/test_data.py index a7675a61d..7b53edd32 100644 --- a/db/test/test_data.py +++ b/db/test/test_data.py @@ -3,6 +3,7 @@ import os.path import mock +import sqlalchemy import db.data import db.exceptions @@ -553,6 +554,50 @@ def test_load_many_high_level_offset(self): } self.assertEqual(expected, db.data.load_many_high_level(list(recordings))) + def test_load_high_level_map_class_names(self): + recordings = [(self.test_mbid, 0)] + + # If an offset doesn't exist or recording doesn't exist, it is skipped. + db.data.write_low_level(self.test_mbid, self.test_lowlevel_data, gid_types.GID_TYPE_MBID) + ll_id1 = self._get_ll_id_from_mbid(self.test_mbid)[0] + + db.data.add_model("model1", "v1", "show") + + build_sha = "sha" + ver = {"hlversion": "123", "models_essentia_git_sha": "v1"} + hl1 = {"highlevel": {"model1": {"all": {"one": 0.4, "two": 0.6}, "probability": 0.6, "value": "two"}}, + "metadata": {"meta": "here", + "version": {"highlevel": ver} + } + } + db.data.write_high_level(self.test_mbid, ll_id1, hl1, build_sha) + + hl1_expected = copy.deepcopy(hl1) + hl1_expected["highlevel"]["model1"]["version"] = ver + + expected = { + self.test_mbid: {'0': hl1_expected}, + } + # If we set map_classes, but there is no mapping, the results are the same as the original version + self.assertEqual(expected, db.data.load_many_high_level(list(recordings), map_classes=True)) + + # We have only one model, so for testing we just unconditionally set the mapping + with db.engine.connect() as connection: + connection.execute( + sqlalchemy.text("""UPDATE model set class_mapping = '{"one": "Class One", "two": "Class Two"}'::jsonb""") + ) + + # Now with the mapping, the values in the expected values have been changed + hl1_expected = copy.deepcopy(hl1) + hl1_expected["highlevel"]["model1"]["version"] = ver + hl1_expected["highlevel"]["model1"]["value"] = "Class Two" + hl1_expected["highlevel"]["model1"]["all"] = {"Class One": 0.4, "Class Two": 0.6} + + expected = { + self.test_mbid: {'0': hl1_expected}, + } + self.assertEqual(expected, db.data.load_many_high_level(list(recordings), map_classes=True)) + def test_count_lowlevel(self): db.data.submit_low_level_data(self.test_mbid, self.test_lowlevel_data, gid_types.GID_TYPE_MBID) self.assertEqual(1, db.data.count_lowlevel(self.test_mbid)) @@ -587,6 +632,19 @@ def test_get_failed_highlevel_submissions(self): self.assertEqual(len(rows), 1) self.assertEqual(rows[0]["gid"], self.test_mbid) + def test_get_active_models(self): + models = db.data.get_active_models() + self.assertEqual(len(models), 0) + db.data.add_model("new_model", "v1", db.data.STATUS_SHOW) + + models = db.data.get_active_models() + self.assertEqual(len(models), 1) + + # Adding a hidden model doesn't affect the result + db.data.add_model("hidden_test", "v1", db.data.STATUS_HIDDEN) + models = db.data.get_active_models() + self.assertEqual(len(models), 1) + def test_get_summary_data(self): pass @@ -653,3 +711,48 @@ def test_clean_metadata(self): db.data.clean_metadata(d) self.assertFalse('unknown_tag' in d['metadata']['tags']) self.assertTrue('file_name' in d['metadata']['tags']) + + def test_map_highlevel_class_names(self): + highlevel = { + "all": { + "blu": 0.0626613423228, + "cla": 0.0348169617355, + "cou": 0.104475811124, + "dis": 0.0784321576357, + "hip": 0.15692435205, + "jaz": 0.313974827528, + "met": 0.0448166541755, + "pop": 0.0627359300852, + "reg": 0.0627360641956, + "roc": 0.0784258767962 + }, + "probability": 0.313974827528, + "value": "jaz", + "version": { + "essentia": "2.1-beta1", + "essentia_build_sha": "8e24b98b71ad84f3024c7541412f02124a26d327", + "essentia_git_sha": "v2.1_beta1-228-g260734a", + "extractor": "music 1.0", + "gaia": "2.4-dev", + "gaia_git_sha": "857329b", + "models_essentia_git_sha": "v2.1_beta1" + } + } + mapping = { + "blu": "Blues", + "cla": "Classical", + "cou": "Country", + "dis": "Disco", + "hip": "Hiphop", + "jaz": "Jazz", + "met": "Metal", + "pop": "Pop", + "reg": "Reggae", + "roc": "Rock" + } + + mapped = db.data.map_highlevel_class_names(highlevel, mapping) + + self.assertEqual(mapped["value"], "Jazz") + self.assertItemsEqual(mapped["all"], ["Blues", "Classical", "Country", "Disco", "Hiphop", + "Jazz", "Metal", "Pop", "Reggae", "Rock"]) diff --git a/webserver/templates/data/summary.html b/webserver/templates/data/summary.html index b40ea8104..07fff3694 100644 --- a/webserver/templates/data/summary.html +++ b/webserver/templates/data/summary.html @@ -57,11 +57,14 @@

Low-level information Summary

High-level information

{% macro print_row(row) %} - {# Prints table row. #} - {{ row[0] }} {# Name #} - {{ row[1] }} {# Value #} - {{ row[2]|float * 100 }}% + {{ row.name }} + + {% if row.original %}{% endif %} + {{ row.value }} + {% if row.original %}{% endif %} + + {{ row.percent }}% {% endmacro %} diff --git a/webserver/templates/datasets/accuracy.html b/webserver/templates/datasets/accuracy.html index d4f41625a..e8e6c49f1 100644 --- a/webserver/templates/datasets/accuracy.html +++ b/webserver/templates/datasets/accuracy.html @@ -2,42 +2,42 @@ {%- block content -%}
-

Accuracies and confusion matrices for default models

+

Accuracies and confusion matrices for default models

Read more about the model training process on the essentia website.

- +

danceability

In-house MTG collection

Use: classification of music by danceability

Size: 306 full tracks, 124/182 per class

-
Accuracy: 92.410714%
+
Accuracy: 92.41%
@@ -74,7 +74,7 @@

gender

In-house MTG collection

Use: classification of vocal music by gender (male/female)

Size: 3311 full tracks, 1508/1803 per class

-
Accuracy: 87.213915%
+
Accuracy: 87.21%

Predicted (%)

@@ -115,9 +115,9 @@

genre_dortmund

Music Audio Benchmark Data Set by TU Dortmund University (Homburg et al., 2005)

Use: classification of music by genre

Size: 1820 track excerpts, 46-490 per genre

-

Homburg, H., Mierswa, I., Möller, B., Morik, K., & Wurst, M. (2005). A Benchmark Dataset for Audio Classification and Clustering. In 6th International Conference on Music Information Retrieval (ISMIR'05), pp. 528-31.

+

Homburg, H., Mierswa, I., Möller, B., Morik, K., & Wurst, M. (2005). A Benchmark Dataset for Audio Classification and Clustering. In 6th International Conference on Music Information Retrieval (ISMIR'05), pp. 528-31.

-
Accuracy: 60.254372%
+
Accuracy: 60.25%

Predicted (%)

@@ -277,14 +277,14 @@

genre_electronic

In-house MTG collection

Use: classification of electronic music by subgenres

Size: 250 track excerpts, 50 per genre

-
Accuracy: 91.699605%
+
Accuracy: 91.70%

Predicted (%)

- - + + -

Predicted (%)

Predicted (%)

+ @@ -359,14 +359,14 @@

genre_rosamerica

Size: 400 tracks, 50 per genre

Classes: classical, dance, hip-hop, jazz, pop, rhythm'n'blues, rock, speech

Guaus, E. (2009). Audio content processing for automatic music genre classification: descriptors, databases, and classifiers (Doctoral dissertation, Universitat Pompeu Fabra, Barcelona). -

Accuracy: 87.557604%
+
Accuracy: 87.56%
- - + + -

Predicted (%)

Predicted (%)

+ @@ -497,183 +497,183 @@

genre_tzanetakis

Size: 1000 track excerpts, 100 per genre

Tzanetakis, G., & Cook, P. (2002). Musical genre classification of audio signals. IEEE transactions on Speech and Audio Processing, 10(5), 293-302.

Sturm, B. L. (2012). An analysis of the GTZAN music genre dataset. In 2nd International ACM Workshop on Music Information Retrieval with User-centered and Multimodal Strategies (pp. 7-12).

-
Accuracy: 75.528701%
+
Accuracy: 75.53%
- - + + - - + +

Predicted (%)

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - < - th>pop - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bluclacoudishipjazmetpopregrocProportion
blu78.00 78 blu (out of 100) classified as blu1.00 1 blu (out of 100) classified as cla8.00 8 blu (out of 100) classified as cou3.00 3 blu (out of 100) classified as dis1.00 1 blu (out of 100) classified as hip1.00 1 blu (out of 100) classified as jaz3.00 3 blu (out of 100) classified as met0.00 0 blu (out of 100) classified as pop2.00 2 blu (out of 100) classified as reg3.00 3 blu (out of 100) classified as rocblu10.07 %
cla2.15 2 cla (out of 93) classified as blu92.47 86 cla (out of 93) classified as cla1.08 1 cla (out of 93) classified as cou2.15 2 cla (out of 93) classified as dis0.00 0 cla (out of 93) classified as hip0.00 0 cla (out of 93) classified as jaz0.00 0 cla (out of 93) classified as met1.08 1 cla (out of 93) classified as pop0.00 0 cla (out of 93) classified as reg1.08 1 cla (out of 93) classified as roccla9.37 %
cou1.00 1 cou (out of 100) classified as blu1.00 1 cou (out of 100) classified as cla78.00 78 cou (out of 100) classified as cou7.00 7 cou (out of 100) classified as dis0.00 0 cou (out of 100) classified as hip2.00 2 cou (out of 100) classified as jaz0.00 0 cou (out of 100) classified as met4.00 4 cou (out of 100) classified as pop3.00 3 cou (out of 100) classified as reg4.00 4 cou (out of 100) classified as roccou10.07 %
dis0.00 0 dis (out of 100) classified as blu1.00 1 dis (out of 100) classified as cla5.00 5 dis (out of 100) classified as cou71.00 71 dis (out of 100) classified as dis3.00 3 dis (out of 100) classified as hip1.00 1 dis (out of 100) classified as jaz2.00 2 dis (out of 100) classified as met7.00 7 dis (out of 100) classified as pop5.00 5 dis (out of 100) classified as reg5.00 5 dis (out of 100) classified as rocdis10.07 %
hip2.00 2 hip (out of 100) classified as blu1.00 1 hip (out of 100) classified as cla0.00 0 hip (out of 100) classified as cou6.00 6 hip (out of 100) classified as dis73.00 73 hip (out of 100) classified as hip0.00 0 hip (out of 100) classified as jaz3.00 3 hip (out of 100) classified as met3.00 3 hip (out of 100) classified as pop11.00 11 hip (out of 100) classified as reg1.00 1 hip (out of 100) classified as rochip10.07 %
jaz7.00 7 jaz (out of 100) classified as blu4.00 4 jaz (out of 100) classified as cla4.00 4 jaz (out of 100) classified as cou3.00 3 jaz (out of 100) classified as dis1.00 1 jaz (out of 100) classified as hip79.00 79 jaz (out of 100) classified as jaz0.00 0 jaz (out of 100) classified as met1.00 1 jaz (out of 100) classified as pop1.00 1 jaz (out of 100) classified as reg0.00 0 jaz (out of 100) classified as rocjaz10.07 %
met2.00 2 met (out of 100) classified as blu0.00 0 met (out of 100) classified as cla0.00 0 met (out of 100) classified as cou1.00 1 met (out of 100) classified as dis3.00 3 met (out of 100) classified as hip2.00 2 met (out of 100) classified as jaz86.00 86 met (out of 100) classified as met1.00 1 met (out of 100) classified as pop0.00 0 met (out of 100) classified as reg5.00 5 met (out of 100) classified as rocmet10.07 %
pop0.00 0 pop (out of 100) classified as blu1.00 1 pop (out of 100) classified as cla6.00 6 pop (out of 100) classified as cou6.00 6 pop (out of 100) classified as dis5.00 5 pop (out of 100) classified as hip0.00 0 pop (out of 100) classified as jaz0.00 0 pop (out of 100) classified as met75.00 75 pop (out of 100) classified as pop4.00 4 pop (out of 100) classified as reg3.00 3 pop (out of 100) classified as roc10.07 %
reg3.00 3 reg (out of 100) classified as blu2.00 2 reg (out of 100) classified as cla4.00 4 reg (out of 100) classified as cou4.00 4 reg (out of 100) classified as dis11.00 11 reg (out of 100) classified as hip2.00 2 reg (out of 100) classified as jaz0.00 0 reg (out of 100) classified as met5.00 5 reg (out of 100) classified as pop64.00 64 reg (out of 100) classified as reg5.00 5 reg (out of 100) classified as rocreg10.07 %
roc7.00 7 roc (out of 100) classified as blu2.00 2 roc (out of 100) classified as cla6.00 6 roc (out of 100) classified as cou10.00 10 roc (out of 100) classified as dis3.00 3 roc (out of 100) classified as hip2.00 2 roc (out of 100) classified as jaz4.00 4 roc (out of 100) classified as met2.00 2 roc (out of 100) classified as pop4.00 4 roc (out of 100) classified as reg60.00 60 roc (out of 100) classified as rocroc10.07 %
-

Actual (%)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bluclacoudishipjazmetpopregrocProportion
blu78.00 78 blu (out of 100) classified as blu1.00 1 blu (out of 100) classified as cla8.00 8 blu (out of 100) classified as cou3.00 3 blu (out of 100) classified as dis1.00 1 blu (out of 100) classified as hip1.00 1 blu (out of 100) classified as jaz3.00 3 blu (out of 100) classified as met0.00 0 blu (out of 100) classified as pop2.00 2 blu (out of 100) classified as reg3.00 3 blu (out of 100) classified as rocblu10.07 %
cla2.15 2 cla (out of 93) classified as blu92.47 86 cla (out of 93) classified as cla1.08 1 cla (out of 93) classified as cou2.15 2 cla (out of 93) classified as dis0.00 0 cla (out of 93) classified as hip0.00 0 cla (out of 93) classified as jaz0.00 0 cla (out of 93) classified as met1.08 1 cla (out of 93) classified as pop0.00 0 cla (out of 93) classified as reg1.08 1 cla (out of 93) classified as roccla9.37 %
cou1.00 1 cou (out of 100) classified as blu1.00 1 cou (out of 100) classified as cla78.00 78 cou (out of 100) classified as cou7.00 7 cou (out of 100) classified as dis0.00 0 cou (out of 100) classified as hip2.00 2 cou (out of 100) classified as jaz0.00 0 cou (out of 100) classified as met4.00 4 cou (out of 100) classified as pop3.00 3 cou (out of 100) classified as reg4.00 4 cou (out of 100) classified as roccou10.07 %
dis0.00 0 dis (out of 100) classified as blu1.00 1 dis (out of 100) classified as cla5.00 5 dis (out of 100) classified as cou71.00 71 dis (out of 100) classified as dis3.00 3 dis (out of 100) classified as hip1.00 1 dis (out of 100) classified as jaz2.00 2 dis (out of 100) classified as met7.00 7 dis (out of 100) classified as pop5.00 5 dis (out of 100) classified as reg5.00 5 dis (out of 100) classified as rocdis10.07 %
hip2.00 2 hip (out of 100) classified as blu1.00 1 hip (out of 100) classified as cla0.00 0 hip (out of 100) classified as cou6.00 6 hip (out of 100) classified as dis73.00 73 hip (out of 100) classified as hip0.00 0 hip (out of 100) classified as jaz3.00 3 hip (out of 100) classified as met3.00 3 hip (out of 100) classified as pop11.00 11 hip (out of 100) classified as reg1.00 1 hip (out of 100) classified as rochip10.07 %
jaz7.00 7 jaz (out of 100) classified as blu4.00 4 jaz (out of 100) classified as cla4.00 4 jaz (out of 100) classified as cou3.00 3 jaz (out of 100) classified as dis1.00 1 jaz (out of 100) classified as hip79.00 79 jaz (out of 100) classified as jaz0.00 0 jaz (out of 100) classified as met1.00 1 jaz (out of 100) classified as pop1.00 1 jaz (out of 100) classified as reg0.00 0 jaz (out of 100) classified as rocjaz10.07 %
met2.00 2 met (out of 100) classified as blu0.00 0 met (out of 100) classified as cla0.00 0 met (out of 100) classified as cou1.00 1 met (out of 100) classified as dis3.00 3 met (out of 100) classified as hip2.00 2 met (out of 100) classified as jaz86.00 86 met (out of 100) classified as met1.00 1 met (out of 100) classified as pop0.00 0 met (out of 100) classified as reg5.00 5 met (out of 100) classified as rocmet10.07 %
pop0.00 0 pop (out of 100) classified as blu1.00 1 pop (out of 100) classified as cla6.00 6 pop (out of 100) classified as cou6.00 6 pop (out of 100) classified as dis5.00 5 pop (out of 100) classified as hip0.00 0 pop (out of 100) classified as jaz0.00 0 pop (out of 100) classified as met75.00 75 pop (out of 100) classified as pop4.00 4 pop (out of 100) classified as reg3.00 3 pop (out of 100) classified as rocpop10.07 %
reg3.00 3 reg (out of 100) classified as blu2.00 2 reg (out of 100) classified as cla4.00 4 reg (out of 100) classified as cou4.00 4 reg (out of 100) classified as dis11.00 11 reg (out of 100) classified as hip2.00 2 reg (out of 100) classified as jaz0.00 0 reg (out of 100) classified as met5.00 5 reg (out of 100) classified as pop64.00 64 reg (out of 100) classified as reg5.00 5 reg (out of 100) classified as rocreg10.07 %
roc7.00 7 roc (out of 100) classified as blu2.00 2 roc (out of 100) classified as cla6.00 6 roc (out of 100) classified as cou10.00 10 roc (out of 100) classified as dis3.00 3 roc (out of 100) classified as hip2.00 2 roc (out of 100) classified as jaz4.00 4 roc (out of 100) classified as met2.00 2 roc (out of 100) classified as pop4.00 4 roc (out of 100) classified as reg60.00 60 roc (out of 100) classified as rocroc10.07 %
+

Actual (%)

@@ -683,177 +683,177 @@

ismir04_rhythm

Use: classification of ballroom music by dance styles

Size: 683 track excerpts, 60-110 per class

Cano, P., Gómez, E., Gouyon, F., Herrera, P., Koppenberger, M., Ong, B., ... & Wack, N. (2006). ISMIR 2004 audio description contest. Music Technology Group, Universitat Pompeu Fabra, Tech. Rep.

-
Accuracy: 73.209169%
+
Accuracy: 73.21%
- - + + - @@ -865,38 +865,38 @@

mood_acoustic

Use: classification of music by type of sound (acoustic/non-acoustic)

Size: 321 full tracks + excerpts, 193/128 per class

Laurier, C., Meyers, O., Serra, J., Blech, M., & Herrera, P. (2009). Music mood annotator design and integration. In 7th International Workshop on Content-Based Multimedia Indexing (CBMI'09), pp. 156-161.

-
Accuracy: 92.982456%
+
Accuracy: 92.98%

Predicted (%)

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ChaChaChaJiveQuickstepRumba-AmericanRumba-InternationalRumba-MiscSambaTangoVienneseWaltzWaltzProportion
ChaChaCha83.78 93 ChaChaCha (out of 111) classified as ChaChaCha5.41 6 ChaChaCha (out of 111) classified as Jive1.80 2 ChaChaCha (out of 111) classified as Quickstep0.00 0 ChaChaCha (out of 111) classified as Rumba-American3.60 4 ChaChaCha (out of 111) classified as Rumba-International0.00 0 ChaChaCha (out of 111) classified as Rumba-Misc3.60 4 ChaChaCha (out of 111) classified as Samba1.80 2 ChaChaCha (out of 111) classified as Tango0.00 0 ChaChaCha (out of 111) classified as VienneseWaltz0.00 0 ChaChaCha (out of 111) classified as WaltzChaChaCha15.90 %
Jive15.00 9 Jive (out of 60) classified as ChaChaCha68.33 41 Jive (out of 60) classified as Jive3.33 2 Jive (out of 60) classified as Quickstep0.00 0 Jive (out of 60) classified as Rumba-American3.33 2 Jive (out of 60) classified as Rumba-International1.67 1 Jive (out of 60) classified as Rumba-Misc5.00 3 Jive (out of 60) classified as Samba0.00 0 Jive (out of 60) classified as Tango3.33 2 Jive (out of 60) classified as VienneseWaltz0.00 0 Jive (out of 60) classified as WaltzJive8.60 %
Quickstep6.10 5 Quickstep (out of 82) classified as ChaChaCha3.66 3 Quickstep (out of 82) classified as Jive74.39 61 Quickstep (out of 82) classified as Quickstep1.22 1 Quickstep (out of 82) classified as Rumba-American2.44 2 Quickstep (out of 82) classified as Rumba-International0.00 0 Quickstep (out of 82) classified as Rumba-Misc10.98 9 Quickstep (out of 82) classified as Samba0.00 0 Quickstep (out of 82) classified as Tango0.00 0 Quickstep (out of 82) classified as VienneseWaltz1.22 1 Quickstep (out of 82) classified as WaltzQuickstep11.75 %
Rumba-American0.00 0 Rumba-American (out of 7) classified as ChaChaCha0.00 0 Rumba-American (out of 7) classified as Jive14.29 1 Rumba-American (out of 7) classified as Quickstep28.57 2 Rumba-American (out of 7) classified as Rumba-American42.86 3 Rumba-American (out of 7) classified as Rumba-International0.00 0 Rumba-American (out of 7) classified as Rumba-Misc0.00 0 Rumba-American (out of 7) classified as Samba14.29 1 Rumba-American (out of 7) classified as Tango0.00 0 Rumba-American (out of 7) classified as VienneseWaltz0.00 0 Rumba-American (out of 7) classified as WaltzRumba-American1.00 %
Rumba-International1.96 1 Rumba-International (out of 51) classified as ChaChaCha0.00 0 Rumba-International (out of 51) classified as Jive3.92 2 Rumba-International (out of 51) classified as Quickstep1.96 1 Rumba-International (out of 51) classified as Rumba-American74.51 38 Rumba-International (out of 51) classified as Rumba-International0.00 0 Rumba-International (out of 51) classified as Rumba-Misc1.96 1 Rumba-International (out of 51) classified as Samba1.96 1 Rumba-International (out of 51) classified as Tango7.84 4 Rumba-International (out of 51) classified as VienneseWaltz5.88 3 Rumba-International (out of 51) classified as WaltzRumba-International7.31 %
Rumba-Misc5.00 2 Rumba-Misc (out of 40) classified as ChaChaCha7.50 3 Rumba-Misc (out of 40) classified as Jive7.50 3 Rumba-Misc (out of 40) classified as Quickstep0.00 0 Rumba-Misc (out of 40) classified as Rumba-American2.50 1 Rumba-Misc (out of 40) classified as Rumba-International52.50 21 Rumba-Misc (out of 40) classified as Rumba-Misc5.00 2 Rumba-Misc (out of 40) classified as Samba5.00 2 Rumba-Misc (out of 40) classified as Tango2.50 1 Rumba-Misc (out of 40) classified as VienneseWaltz12.50 5 Rumba-Misc (out of 40) classified as WaltzRumba-Misc5.73 %
Samba6.98 6 Samba (out of 86) classified as ChaChaCha6.98 6 Samba (out of 86) classified as Jive13.95 12 Samba (out of 86) classified as Quickstep0.00 0 Samba (out of 86) classified as Rumba-American2.33 2 Samba (out of 86) classified as Rumba-International1.16 1 Samba (out of 86) classified as Rumba-Misc66.28 57 Samba (out of 86) classified as Samba2.33 2 Samba (out of 86) classified as Tango0.00 0 Samba (out of 86) classified as VienneseWaltz0.00 0 Samba (out of 86) classified as WaltzSamba12.32 %
Tango4.65 4 Tango (out of 86) classified as ChaChaCha0.00 0 Tango (out of 86) classified as Jive0.00 0 Tango (out of 86) classified as Quickstep2.33 2 Tango (out of 86) classified as Rumba-American0.00 0 Tango (out of 86) classified as Rumba-International5.81 5 Tango (out of 86) classified as Rumba-Misc0.00 0 Tango (out of 86) classified as Samba83.72 72 Tango (out of 86) classified as Tango1.16 1 Tango (out of 86) classified as VienneseWaltz2.33 2 Tango (out of 86) classified as WaltzTango12.32 %
VienneseWaltz0.00 0 VienneseWaltz (out of 65) classified as ChaChaCha1.54 1 VienneseWaltz (out of 65) classified as Jive1.54 1 VienneseWaltz (out of 65) classified as Quickstep0.00 0 VienneseWaltz (out of 65) classified as Rumba-American4.62 3 VienneseWaltz (out of 65) classified as Rumba-International3.08 2 VienneseWaltz (out of 65) classified as Rumba-Misc0.00 0 VienneseWaltz (out of 65) classified as Samba0.00 0 VienneseWaltz (out of 65) classified as Tango67.69 44 VienneseWaltz (out of 65) classified as VienneseWaltz21.54 14 VienneseWaltz (out of 65) classified as WaltzVienneseWaltz9.31 %
Waltz0.00 0 Waltz (out of 110) classified as ChaChaCha0.00 0 Waltz (out of 110) classified as Jive0.91 1 Waltz (out of 110) classified as Quickstep0.00 0 Waltz (out of 110) classified as Rumba-American4.55 5 Waltz (out of 110) classified as Rumba-International6.36 7 Waltz (out of 110) classified as Rumba-Misc0.00 0 Waltz (out of 110) classified as Samba2.73 3 Waltz (out of 110) classified as Tango10.91 12 Waltz (out of 110) classified as VienneseWaltz74.55 82 Waltz (out of 110) classified as WaltzWaltz15.76 %
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ChaChaChaJiveQuickstepRumba-AmericanRumba-InternationalRumba-MiscSambaTangoVienneseWaltzWaltzProportion
ChaChaCha83.78 93 ChaChaCha (out of 111) classified as ChaChaCha5.41 6 ChaChaCha (out of 111) classified as Jive1.80 2 ChaChaCha (out of 111) classified as Quickstep0.00 0 ChaChaCha (out of 111) classified as Rumba-American3.60 4 ChaChaCha (out of 111) classified as Rumba-International0.00 0 ChaChaCha (out of 111) classified as Rumba-Misc3.60 4 ChaChaCha (out of 111) classified as Samba1.80 2 ChaChaCha (out of 111) classified as Tango0.00 0 ChaChaCha (out of 111) classified as VienneseWaltz0.00 0 ChaChaCha (out of 111) classified as WaltzChaChaCha15.90 %
Jive15.00 9 Jive (out of 60) classified as ChaChaCha68.33 41 Jive (out of 60) classified as Jive3.33 2 Jive (out of 60) classified as Quickstep0.00 0 Jive (out of 60) classified as Rumba-American3.33 2 Jive (out of 60) classified as Rumba-International1.67 1 Jive (out of 60) classified as Rumba-Misc5.00 3 Jive (out of 60) classified as Samba0.00 0 Jive (out of 60) classified as Tango3.33 2 Jive (out of 60) classified as VienneseWaltz0.00 0 Jive (out of 60) classified as WaltzJive8.60 %
Quickstep6.10 5 Quickstep (out of 82) classified as ChaChaCha3.66 3 Quickstep (out of 82) classified as Jive74.39 61 Quickstep (out of 82) classified as Quickstep1.22 1 Quickstep (out of 82) classified as Rumba-American2.44 2 Quickstep (out of 82) classified as Rumba-International0.00 0 Quickstep (out of 82) classified as Rumba-Misc10.98 9 Quickstep (out of 82) classified as Samba0.00 0 Quickstep (out of 82) classified as Tango0.00 0 Quickstep (out of 82) classified as VienneseWaltz1.22 1 Quickstep (out of 82) classified as WaltzQuickstep11.75 %
Rumba-American0.00 0 Rumba-American (out of 7) classified as ChaChaCha0.00 0 Rumba-American (out of 7) classified as Jive14.29 1 Rumba-American (out of 7) classified as Quickstep28.57 2 Rumba-American (out of 7) classified as Rumba-American42.86 3 Rumba-American (out of 7) classified as Rumba-International0.00 0 Rumba-American (out of 7) classified as Rumba-Misc0.00 0 Rumba-American (out of 7) classified as Samba14.29 1 Rumba-American (out of 7) classified as Tango0.00 0 Rumba-American (out of 7) classified as VienneseWaltz0.00 0 Rumba-American (out of 7) classified as WaltzRumba-American1.00 %
Rumba-International1.96 1 Rumba-International (out of 51) classified as ChaChaCha0.00 0 Rumba-International (out of 51) classified as Jive3.92 2 Rumba-International (out of 51) classified as Quickstep1.96 1 Rumba-International (out of 51) classified as Rumba-American74.51 38 Rumba-International (out of 51) classified as Rumba-International0.00 0 Rumba-International (out of 51) classified as Rumba-Misc1.96 1 Rumba-International (out of 51) classified as Samba1.96 1 Rumba-International (out of 51) classified as Tango7.84 4 Rumba-International (out of 51) classified as VienneseWaltz5.88 3 Rumba-International (out of 51) classified as WaltzRumba-International7.31 %
Rumba-Misc5.00 2 Rumba-Misc (out of 40) classified as ChaChaCha7.50 3 Rumba-Misc (out of 40) classified as Jive7.50 3 Rumba-Misc (out of 40) classified as Quickstep0.00 0 Rumba-Misc (out of 40) classified as Rumba-American2.50 1 Rumba-Misc (out of 40) classified as Rumba-International52.50 21 Rumba-Misc (out of 40) classified as Rumba-Misc5.00 2 Rumba-Misc (out of 40) classified as Samba5.00 2 Rumba-Misc (out of 40) classified as Tango2.50 1 Rumba-Misc (out of 40) classified as VienneseWaltz12.50 5 Rumba-Misc (out of 40) classified as WaltzRumba-Misc5.73 %
Samba6.98 6 Samba (out of 86) classified as ChaChaCha6.98 6 Samba (out of 86) classified as Jive13.95 12 Samba (out of 86) classified as Quickstep0.00 0 Samba (out of 86) classified as Rumba-American2.33 2 Samba (out of 86) classified as Rumba-International1.16 1 Samba (out of 86) classified as Rumba-Misc66.28 57 Samba (out of 86) classified as Samba2.33 2 Samba (out of 86) classified as Tango0.00 0 Samba (out of 86) classified as VienneseWaltz0.00 0 Samba (out of 86) classified as WaltzSamba12.32 %
Tango4.65 4 Tango (out of 86) classified as ChaChaCha0.00 0 Tango (out of 86) classified as Jive0.00 0 Tango (out of 86) classified as Quickstep2.33 2 Tango (out of 86) classified as Rumba-American0.00 0 Tango (out of 86) classified as Rumba-International5.81 5 Tango (out of 86) classified as Rumba-Misc0.00 0 Tango (out of 86) classified as Samba83.72 72 Tango (out of 86) classified as Tango1.16 1 Tango (out of 86) classified as VienneseWaltz2.33 2 Tango (out of 86) classified as WaltzTango12.32 %
VienneseWaltz0.00 0 VienneseWaltz (out of 65) classified as ChaChaCha1.54 1 VienneseWaltz (out of 65) classified as Jive1.54 1 VienneseWaltz (out of 65) classified as Quickstep0.00 0 VienneseWaltz (out of 65) classified as Rumba-American4.62 3 VienneseWaltz (out of 65) classified as Rumba-International3.08 2 VienneseWaltz (out of 65) classified as Rumba-Misc0.00 0 VienneseWaltz (out of 65) classified as Samba0.00 0 VienneseWaltz (out of 65) classified as Tango67.69 44 VienneseWaltz (out of 65) classified as VienneseWaltz21.54 14 VienneseWaltz (out of 65) classified as WaltzVienneseWaltz9.31 %
Waltz0.00 0 Waltz (out of 110) classified as ChaChaCha0.00 0 Waltz (out of 110) classified as Jive0.91 1 Waltz (out of 110) classified as Quickstep0.00 0 Waltz (out of 110) classified as Rumba-American4.55 5 Waltz (out of 110) classified as Rumba-International6.36 7 Waltz (out of 110) classified as Rumba-Misc0.00 0 Waltz (out of 110) classified as Samba2.73 3 Waltz (out of 110) classified as Tango10.91 12 Waltz (out of 110) classified as VienneseWaltz74.55 82 Waltz (out of 110) classified as WaltzWaltz15.76 %

Actual (%)

- - + + - - + +

Predicted (%)

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - -
acousticnot_acousticProportion
acoustic95.04 115 acoustic (out of 121) classified as acoustic4.96 6 acoustic (out of 121) classified as not_acousticacoustic53.07 %
not_acoustic9.35 10 not_acoustic (out of 107) classified as acoustic90.65 97 not_acoustic (out of 107) classified as not_acousticnot_acoustic46.93 %
-

Actual (%)

+ + + + + + + + + + + + + + + + + + + + + +
acousticnot_acousticProportion
acoustic95.04 115 acoustic (out of 121) classified as acoustic4.96 6 acoustic (out of 121) classified as not_acousticacoustic53.07 %
not_acoustic9.35 10 not_acoustic (out of 107) classified as acoustic90.65 97 not_acoustic (out of 107) classified as not_acousticnot_acoustic46.93 %
+

Actual (%)

@@ -907,38 +907,38 @@

mood_aggressive

Size: 280 full tracks + excerpts, 133/147 per class

Laurier, C., Meyers, O., Serra, J., Blech, M., & Herrera, P. (2009). Music mood annotator design and integration. In 7th International Workshop on Content-Based Multimedia Indexing (CBMI'09), pp. 156-161.

-
Accuracy: 97.500000%
+
Accuracy: 97.50%
- - + + - +

Predicted (%)

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - - -
aggressivenot_aggressiveProportion
aggressive95.49 127 aggressive (out of 133) classified as aggressive4.51 6 aggressive (out of 133) classified as not_aggressiveaggressive47.50 %
not_aggressive0.68 1 not_aggressive (out of 147) classified as aggressive99.32 146 not_aggressive (out of 147) classified as not_aggressivenot_aggressive52.50 %
-

Actual (%)

+ + + + + + + + + + + + + + + + + + + + + + +
aggressivenot_aggressiveProportion
aggressive95.49 127 aggressive (out of 133) classified as aggressive4.51 6 aggressive (out of 133) classified as not_aggressiveaggressive47.50 %
not_aggressive0.68 1 not_aggressive (out of 147) classified as aggressive99.32 146 not_aggressive (out of 147) classified as not_aggressivenot_aggressive52.50 %
+

Actual (%)

@@ -949,39 +949,39 @@

mood_electronic

Size: 332 full tracks + excerpts, 164/168 per class

Laurier, C., Meyers, O., Serra, J., Blech, M., & Herrera, P. (2009). Music mood annotator design and integration. In 7th International Workshop on Content-Based Multimedia Indexing (CBMI'09), pp. 156-161.

-
Accuracy: 86.379928%
+
Accuracy: 86.38%
- - + +

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - - -
electronicnot_electronicProportion
electronic82.84 111 electronic (out of 134) classified as electronic17.16 23 electronic (out of 134) classified as not_electronicelectronic48.03 %
not_electronic10.34 15 not_electronic (out of 145) classified as electronic89.66 130 not_electronic (out of 145) classified as not_electronicnot_electronic51.97 %
-

Actual (%)

+ + + + + + + + + + + + + + + + + + + + + + +
electronicnot_electronicProportion
electronic82.84 111 electronic (out of 134) classified as electronic17.16 23 electronic (out of 134) classified as not_electronicelectronic48.03 %
not_electronic10.34 15 not_electronic (out of 145) classified as electronic89.66 130 not_electronic (out of 145) classified as not_electronicnot_electronic51.97 %
+

Actual (%)

@@ -992,37 +992,37 @@

mood_happy

Size: 302 full tracks + excerpts, 139/163 per class

Laurier, C., Meyers, O., Serra, J., Blech, M., & Herrera, P. (2009). Music mood annotator design and integration. In 7th International Workshop on Content-Based Multimedia Indexing (CBMI'09), pp. 156-161.

-
Accuracy: 83.265306%
+
Accuracy: 83.27%
- - - - - - + + + + + +

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - -
happynot_happyProportion
happy82.14 92 happy (out of 112) classified as happy17.86 20 happy (out of 112) classified as not_happyhappy45.71 %
not_happy15.79 21 not_happy (out of 133) classified as happy84.21 112 not_happy (out of 133) classified as not_happynot_happy54.29 %
-

Actual (%)

Predicted (%)

+ + + + + + + + + + + + + + + + + + + + + +
happynot_happyProportion
happy82.14 92 happy (out of 112) classified as happy17.86 20 happy (out of 112) classified as not_happyhappy45.71 %
not_happy15.79 21 not_happy (out of 133) classified as happy84.21 112 not_happy (out of 133) classified as not_happynot_happy54.29 %
+

Actual (%)


@@ -1032,38 +1032,38 @@

mood_party

Size: 349 full tracks + excerpts, 198/151 per class

Laurier, C., Meyers, O., Serra, J., Blech, M., & Herrera, P. (2009). Music mood annotator design and integration. In 7th International Workshop on Content-Based Multimedia Indexing (CBMI'09), pp. 156-161.

-
Accuracy: 88.381743%
+
Accuracy: 88.38%
- - + + - - + +

Predicted (%)

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - -
not_partypartyProportion
not_party85.07 114 not_party (out of 134) classified as not_party14.93 20 not_party (out of 134) classified as partynot_party55.60 %
party7.48 8 party (out of 107) classified as not_party92.52 99 party (out of 107) classified as partyparty44.40 %
-

Actual (%)

+ + + + + + + + + + + + + + + + + + + + + +
not_partypartyProportion
not_party85.07 114 not_party (out of 134) classified as not_party14.93 20 not_party (out of 134) classified as partynot_party55.60 %
party7.48 8 party (out of 107) classified as not_party92.52 99 party (out of 107) classified as partyparty44.40 %
+

Actual (%)

@@ -1074,39 +1074,39 @@

mood_relaxed

Size: 446 full tracks + excerpts, 145/301 per class

Laurier, C., Meyers, O., Serra, J., Blech, M., & Herrera, P. (2009). Music mood annotator design and integration. In 7th International Workshop on Content-Based Multimedia Indexing (CBMI'09), pp. 156-161.

-
Accuracy: 93.201133%
+
Accuracy: 93.20%
- - + + - - + +

Predicted (%)

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - - -
not_relaxedrelaxedProportion
not_relaxed85.48 106 not_relaxed (out of 124) classified as not_relaxed14.52 18 not_relaxed (out of 124) classified as relaxednot_relaxed35.13 %
relaxed2.62 6 relaxed (out of 229) classified as not_relaxed97.38 223 relaxed (out of 229) classified as relaxedrelaxed64.87 %
-

Actual (%)

+ + + + + + + + + + + + + + + + + + + + + + +
not_relaxedrelaxedProportion
not_relaxed85.48 106 not_relaxed (out of 124) classified as not_relaxed14.52 18 not_relaxed (out of 124) classified as relaxednot_relaxed35.13 %
relaxed2.62 6 relaxed (out of 229) classified as not_relaxed97.38 223 relaxed (out of 229) classified as relaxedrelaxed64.87 %
+

Actual (%)

@@ -1117,14 +1117,14 @@

mood_sad

Size: 230 full tracks + excerpts, 96/134 per class

Laurier, C., Meyers, O., Serra, J., Blech, M., & Herrera, P. (2009). Music mood annotator design and integration. In 7th International Workshop on Content-Based Multimedia Indexing (CBMI'09), pp. 156-161.

-
Accuracy: 87.826087%
+
Accuracy: 87.83%
-

Predicted (%)

+ @@ -1158,167 +1158,167 @@

moods_mirex

MIREX Audio Mood Classification Dataset (Hu and Downie, 2007)

Use: classification of music into 5 mood clusters

    -
  • Cluster1: passionate, rousing, confident,boisterous, rowdy
  • +
  • Cluster1: passionate, rousing, confident, boisterous, rowdy
  • Cluster2: rollicking, cheerful, fun, sweet, amiable/good natured
  • Cluster3: literate, poignant, wistful, bittersweet, autumnal, brooding
  • Cluster4: humorous, silly, campy, quirky, whimsical, witty, wry
  • -
  • Cluster5: aggressive, fiery,tense/anxious, intense, volatile,visceral
  • +
  • Cluster5: aggressive, fiery, tense/anxious, intense, volatile, visceral

Size: 269 track excerpts, 60-110 per class

Hu, X., & Downie, J. S. (2007). Exploring Mood Metadata: Relationships with Genre, Artist and Usage Metadata. In 8th International Conference on Music Information Retrieval (ISMIR'07), pp. 67-72.

-
Accuracy: 57.089552%
+
Accuracy: 57.09%
- - - - - - - - + + + + + + + +

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cluster1Cluster2Cluster3Cluster4Cluster5Proportion
Cluster156.90 33 Cluster1 (out of 58) classified as Cluster115.52 9 Cluster1 (out of 58) classified as Cluster28.62 5 Cluster1 (out of 58) classified as Cluster35.17 3 Cluster1 (out of 58) classified as Cluster413.79 8 Cluster1 (out of 58) classified as Cluster5Cluster121.64 %
Cluster222.22 12 Cluster2 (out of 54) classified as Cluster153.70 29 Cluster2 (out of 54) classified as Cluster216.67 9 Cluster2 (out of 54) classified as Cluster35.56 3 Cluster2 (out of 54) classified as Cluster41.85 1 Cluster2 (out of 54) classified as Cluster5Cluster220.15 %
Cluster35.48 4 Cluster3 (out of 73) classified as Cluster119.18 14 Cluster3 (out of 73) classified as Cluster268.49 50 Cluster3 (out of 73) classified as Cluster35.48 4 Cluster3 (out of 73) classified as Cluster41.37 1 Cluster3 (out of 73) classified as Cluster5Cluster327.24 %
Cluster415.62 5 Cluster4 (out of 32) classified as Cluster137.50 12 Cluster4 (out of 32) classified as Cluster215.62 5 Cluster4 (out of 32) classified as Cluster325.00 8 Cluster4 (out of 32) classified as Cluster46.25 2 Cluster4 (out of 32) classified as Cluster5Cluster411.94 %
Cluster527.45 14 Cluster5 (out of 51) classified as Cluster17.84 4 Cluster5 (out of 51) classified as Cluster20.00 0 Cluster5 (out of 51) classified as Cluster30.00 0 Cluster5 (out of 51) classified as Cluster464.71 33 Cluster5 (out of 51) classified as Cluster5Cluster519.03 %
-

Actual (%)

Predicted (%)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Cluster1Cluster2Cluster3Cluster4Cluster5Proportion
Cluster156.90 33 Cluster1 (out of 58) classified as Cluster115.52 9 Cluster1 (out of 58) classified as Cluster28.62 5 Cluster1 (out of 58) classified as Cluster35.17 3 Cluster1 (out of 58) classified as Cluster413.79 8 Cluster1 (out of 58) classified as Cluster5Cluster121.64 %
Cluster222.22 12 Cluster2 (out of 54) classified as Cluster153.70 29 Cluster2 (out of 54) classified as Cluster216.67 9 Cluster2 (out of 54) classified as Cluster35.56 3 Cluster2 (out of 54) classified as Cluster41.85 1 Cluster2 (out of 54) classified as Cluster5Cluster220.15 %
Cluster35.48 4 Cluster3 (out of 73) classified as Cluster119.18 14 Cluster3 (out of 73) classified as Cluster268.49 50 Cluster3 (out of 73) classified as Cluster35.48 4 Cluster3 (out of 73) classified as Cluster41.37 1 Cluster3 (out of 73) classified as Cluster5Cluster327.24 %
Cluster415.62 5 Cluster4 (out of 32) classified as Cluster137.50 12 Cluster4 (out of 32) classified as Cluster215.62 5 Cluster4 (out of 32) classified as Cluster325.00 8 Cluster4 (out of 32) classified as Cluster46.25 2 Cluster4 (out of 32) classified as Cluster5Cluster411.94 %
Cluster527.45 14 Cluster5 (out of 51) classified as Cluster17.84 4 Cluster5 (out of 51) classified as Cluster20.00 0 Cluster5 (out of 51) classified as Cluster30.00 0 Cluster5 (out of 51) classified as Cluster464.71 33 Cluster5 (out of 51) classified as Cluster5Cluster519.03 %
+

Actual (%)


timbre

-

In-house MTG collection

+

In-house MTG collection

Use: classification of music by timbre colour (dark/bright timbre)

Size: 3000 track excerpts, 1500 per class

-
Accuracy: 94.317418%
+
Accuracy: 94.32%
- - + + - - + +

Predicted (%)

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - -
brightdarkProportion
bright93.76 1383 bright (out of 1475) classified as bright6.24 92 bright (out of 1475) classified as darkbright49.60 %
dark5.14 77 dark (out of 1499) classified as bright94.86 1422 dark (out of 1499) classified as darkdark50.40 %
-

Actual (%)

+ + + + + + + + + + + + + + + + + + + + + +
brightdarkProportion
bright93.76 1383 bright (out of 1475) classified as bright6.24 92 bright (out of 1475) classified as darkbright49.60 %
dark5.14 77 dark (out of 1499) classified as bright94.86 1422 dark (out of 1499) classified as darkdark50.40 %
+

Actual (%)


tonal_atonal

-

In-house MTG collection

+

In-house MTG collection

Use: classification of music by tonality (tonal/atonal)

Size: 345 track excerpts, 200/145

-
Accuracy: 97.667638%
+
Accuracy: 97.67%
- - - - - - - - + + + + + + + +

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - - -
atonaltonalProportion
atonal96.53 139 atonal (out of 144) classified as atonal3.47 5 atonal (out of 144) classified as tonalatonal41.98 %
tonal1.51 3 tonal (out of 199) classified as atonal98.49 196 tonal (out of 199) classified as tonaltonal58.02 %
-

Actual (%)

Predicted (%)

+ + + + + + + + + + + + + + + + + + + + + + +
atonaltonalProportion
atonal96.53 139 atonal (out of 144) classified as atonal3.47 5 atonal (out of 144) classified as tonalatonal41.98 %
tonal1.51 3 tonal (out of 199) classified as atonal98.49 196 tonal (out of 199) classified as tonaltonal58.02 %
+

Actual (%)


@@ -1326,37 +1326,37 @@

voice_instrumental

In-house MTG collection

Use: classification into music with voice/instrumental

Size: 1000 track excerpts, 500 per class

-
Accuracy: 93.800000%
+
Accuracy: 93.80%
- - + + - +

Predicted (%)

Predicted (%)

- - - - - - - - - - - - - - - - - - - - - -
instrumentalvoiceProportion
instrumental94.20 471 instrumental (out of 500) classified as instrumental5.80 29 instrumental (out of 500) classified as voiceinstrumental50.00 %
voice6.60 33 voice (out of 500) classified as instrumental93.40 467 voice (out of 500) classified as voicevoice50.00 %
-
+ + + + + + + + + + + + + + + + + + + + + +
instrumentalvoiceProportion
instrumental94.20 471 instrumental (out of 500) classified as instrumental5.80 29 instrumental (out of 500) classified as voiceinstrumental50.00 %
voice6.60 33 voice (out of 500) classified as instrumental93.40 467 voice (out of 500) classified as voicevoice50.00 %
+

Actual (%)

diff --git a/webserver/views/api/v1/core.py b/webserver/views/api/v1/core.py index 2b7ae2ac5..486eb90cc 100644 --- a/webserver/views/api/v1/core.py +++ b/webserver/views/api/v1/core.py @@ -86,12 +86,14 @@ def get_high_level(mbid): endpoint. :query n: *Optional.* Integer specifying an offset for a document. + :query map_classes: *Optional.* If set to 'true', map class names to human-readable values :resheader Content-Type: *application/json* """ offset = _validate_offset(request.args.get("n")) + map_classes = _validate_map_classes(request.args.get("map_classes")) try: - return jsonify(db.data.load_high_level(str(mbid), offset)) + return jsonify(db.data.load_high_level(str(mbid), offset, map_classes)) except NoDataFoundException: raise webserver.views.api.exceptions.APINotFound("Not found") @@ -117,6 +119,18 @@ def submit_low_level(mbid): return jsonify({"message": "ok"}) +def _validate_map_classes(map_classes): + """Validate the map_classes parameter + + Arguments: + map_classes (Optional[str]): the value of the query parameter + + Returns: + (bool): True if the map_classes parameter is 'true', False otherwise""" + + return map_classes is not None and map_classes.lower() == 'true' + + def _validate_offset(offset): """Validate the offset. @@ -272,10 +286,13 @@ def get_many_highlevel(): You can specify up to :py:const:`~webserver.views.api.v1.core.MAX_ITEMS_PER_BULK_REQUEST` MBIDs in a request. + :query map_classes: *Optional.* If set to 'true', map class names to human-readable values + :resheader Content-Type: *application/json* """ + map_classes = _validate_map_classes(request.args.get("map_classes")) recordings = check_bad_request_for_multiple_recordings() - recording_details = db.data.load_many_high_level(recordings) + recording_details = db.data.load_many_high_level(recordings, map_classes) return jsonify(recording_details) diff --git a/webserver/views/api/v1/test/test_core.py b/webserver/views/api/v1/test/test_core.py index f119c5c71..a7902f033 100644 --- a/webserver/views/api/v1/test/test_core.py +++ b/webserver/views/api/v1/test/test_core.py @@ -124,19 +124,19 @@ def test_get_high_level(self, hl): hl.return_value = {} resp = self.client.get("/api/v1/%s/high-level" % self.uuid) self.assertEqual(200, resp.status_code) - hl.assert_called_with(self.uuid, 0) + hl.assert_called_with(self.uuid, 0, False) # upper-case resp = self.client.get("/api/v1/%s/high-level" % self.uuid.upper()) self.assertEqual(200, resp.status_code) - hl.assert_called_with(self.uuid, 0) + hl.assert_called_with(self.uuid, 0, False) @mock.patch("db.data.load_high_level") def test_hl_numerical_offset(self, hl): hl.return_value = {} resp = self.client.get("/api/v1/%s/high-level?n=3" % self.uuid) self.assertEqual(200, resp.status_code) - hl.assert_called_with(self.uuid, 3) + hl.assert_called_with(self.uuid, 3, False) @mock.patch('db.data.load_many_low_level') def test_get_bulk_ll_no_param(self, load_many_low_level): @@ -274,7 +274,31 @@ def test_get_bulk_hl(self, load_many_high_level): ("7f27d7a9-27f0-4663-9d20-2c9c40200e6d", 3), ("405a5ff4-7ee2-436b-95c1-90ce8a83b359", 2), ("405a5ff4-7ee2-436b-95c1-90ce8a83b359", 3)] - load_many_high_level.assert_called_with(recordings) + load_many_high_level.assert_called_with(recordings, False) + + @mock.patch('db.data.load_many_high_level') + def test_get_bulk_hl_map_classes(self, load_many_high_level): + # Check that many items are returned, including two offsets of the + # same mbid + + params = "c5f4909e-1d7b-4f15-a6f6-1af376bc01c9" + + rec_c5 = {"recording": "c5f4909e-1d7b-4f15-a6f6-1af376bc01c9"} + + load_many_high_level.return_value = { + "c5f4909e-1d7b-4f15-a6f6-1af376bc01c9": {"0": rec_c5}, + } + + resp = self.client.get('api/v1/high-level?map_classes=true&recording_ids=' + params) + self.assert200(resp) + + expected_result = { + "c5f4909e-1d7b-4f15-a6f6-1af376bc01c9": {"0": rec_c5}, + } + self.assertDictEqual(resp.json, expected_result) + + recordings = [("c5f4909e-1d7b-4f15-a6f6-1af376bc01c9", 0)] + load_many_high_level.assert_called_with(recordings, True) # upper-case params = "c5f4909e-1d7b-4f15-a6f6-1AF376BC01C9" @@ -289,7 +313,7 @@ def test_get_bulk_hl(self, load_many_high_level): # to load_many_high_level is always lower-case regardless of what we pass in self.assertDictEqual(resp.json, expected_result) recordings = [("c5f4909e-1d7b-4f15-a6f6-1af376bc01c9", 0)] - load_many_high_level.assert_called_with(recordings) + load_many_high_level.assert_called_with(recordings, False) @mock.patch('db.data.load_many_high_level') def test_get_bulk_hl_absent_mbid(self, load_many_high_level): @@ -318,9 +342,9 @@ def test_get_bulk_hl_absent_mbid(self, load_many_high_level): recordings = [("c5f4909e-1d7b-4f15-a6f6-1af376bc01c9", 0), ("7f27d7a9-27f0-4663-9d20-2c9c40200e6d", 3), ("405a5ff4-7ee2-436b-95c1-90ce8a83b359", 2)] - load_many_high_level.assert_called_with(recordings) + load_many_high_level.assert_called_with(recordings, False) - def test_get_bulk_hl_more_than_200(self): + def test_get_bulk_hl_more_than_25(self): # Create many random uuids, because of parameter deduplication manyids = [str(uuid.uuid4()) for i in range(26)] limit_exceed_url = ";".join(manyids) @@ -381,7 +405,7 @@ def test_get_bulk_count(self): self.assertEqual(resp.status_code, 200) self.assertDictEqual(resp.json, expected_result) - def test_get_bulk_count_more_than_200(self): + def test_get_bulk_count_more_than_25(self): # Create many random uuids, because of parameter deduplication manyids = [str(uuid.uuid4()) for i in range(26)] limit_exceed_url = ";".join(manyids) diff --git a/webserver/views/data.py b/webserver/views/data.py index daa8360f7..89178a175 100644 --- a/webserver/views/data.py +++ b/webserver/views/data.py @@ -94,7 +94,7 @@ def summary(mbid): summary_data = {} if summary_data.get("highlevel"): - genres, moods, other = _interpret_high_level(summary_data["highlevel"]) + genres, moods, other = _interpret_high_level(summary_data["highlevel"], summary_data["models"]) if genres or moods or other: summary_data["highlevel"] = { "genres": genres, @@ -195,72 +195,85 @@ def get_tag(name): return {} -def _interpret_high_level(hl): +def _interpret_high_level(hl, models): - def interpret(text, data, threshold=.6): - if data['probability'] >= threshold: - return text, data['value'].replace("_", " "), "%.3f" % data['probability'] - else: - return text, "unsure", "%.3f" % data['probability'] + model_map = {} + for m in models: + model_map[m["model"]] = m + + def interpret(text, model_name, data): + """used by the print_row macro in data/summary.html""" + value = data["value"] + original = None + class_map = model_map.get(model_name, {}).get("class_mapping") + if class_map and value in class_map: + original = value + value = class_map[value] + + return {"name": text, + "model_href": "%s#%s" % (url_for("datasets.accuracy"), model_name), + "value": value.title(), + "original": original, + "percent": round(data['probability']*100, 1)} genres = [] - tzan = hl['highlevel'].get('genre_tzanetakis') + tzan = hl["highlevel"].get("genre_tzanetakis") if tzan: - genres.append(interpret("Tzanetakis model", tzan)) - elec = hl['highlevel'].get('genre_electronic') + genres.append(interpret("GTZAN model", "genre_tzanetakis", tzan)) + elec = hl["highlevel"].get("genre_electronic") if elec: - genres.append(interpret("Electronic classification", elec)) - dort = hl['highlevel'].get('genre_dortmund') + genres.append(interpret("Electronic classification", "genre_electronic", elec)) + dort = hl["highlevel"].get("genre_dortmund") if dort: - genres.append(interpret("Dortmund model", dort)) - ros = hl['highlevel'].get('genre_rosamerica') + genres.append(interpret("Dortmund model", "genre_dortmund", dort)) + ros = hl["highlevel"].get("genre_rosamerica") if ros: - genres.append(interpret("Rosamerica model", ros)) + genres.append(interpret("Rosamerica model", "genre_rosamerica", ros)) moods = [] - elec = hl['highlevel'].get('mood_electronic') + elec = hl["highlevel"].get("mood_electronic") if elec: - moods.append(interpret("Electronic", elec)) - party = hl['highlevel'].get('mood_party') + moods.append(interpret("Electronic", "mood_electronic", elec)) + party = hl["highlevel"].get("mood_party") if party: - moods.append(interpret("Party", party)) - aggressive = hl['highlevel'].get('mood_aggressive') + moods.append(interpret("Party", "mood_party", party)) + aggressive = hl["highlevel"].get("mood_aggressive") if aggressive: - moods.append(interpret("Aggressive", aggressive)) - acoustic = hl['highlevel'].get('mood_acoustic') + moods.append(interpret("Aggressive", "mood_aggressive", aggressive)) + acoustic = hl["highlevel"].get("mood_acoustic") if acoustic: - moods.append(interpret("Acoustic", acoustic)) - happy = hl['highlevel'].get('mood_happy') + moods.append(interpret("Acoustic", "mood_acoustic", acoustic)) + happy = hl["highlevel"].get("mood_happy") if happy: - moods.append(interpret("Happy", happy)) - sad = hl['highlevel'].get('mood_sad') + moods.append(interpret("Happy", "mood_happy", happy)) + sad = hl["highlevel"].get("mood_sad") if sad: - moods.append(interpret("Sad", sad)) - relaxed = hl['highlevel'].get('mood_relaxed') + moods.append(interpret("Sad", "mood_sad", sad)) + relaxed = hl["highlevel"].get("mood_relaxed") if relaxed: - moods.append(interpret("Relaxed", relaxed)) - mirex = hl['highlevel'].get('mood_mirex') + moods.append(interpret("Relaxed", "mood_relaxed", relaxed)) + mirex = hl["highlevel"].get("moods_mirex") if mirex: - moods.append(interpret("Mirex method", mirex)) + moods.append(interpret("Mirex method", "moods_mirex", mirex)) other = [] - voice = hl['highlevel'].get('voice_instrumental') + voice = hl["highlevel"].get("voice_instrumental") if voice: - other.append(interpret("Voice", voice)) - gender = hl['highlevel'].get('gender') + other.append(interpret("Voice", "voice_instrumental", voice)) + gender = hl["highlevel"].get("gender") if gender: - other.append(interpret("Gender", gender)) - dance = hl['highlevel'].get('danceability') + other.append(interpret("Gender", "gender", gender)) + dance = hl["highlevel"].get("danceability") if dance: - other.append(interpret("Danceability", dance)) - tonal = hl['highlevel'].get('tonal_atonal') + other.append(interpret("Danceability", "danceability", dance)) + tonal = hl["highlevel"].get("tonal_atonal") if tonal: - other.append(interpret("Tonal", tonal)) - timbre = hl['highlevel'].get('timbre') + other.append(interpret("Tonal", "tonal_atonal", tonal)) + timbre = hl["highlevel"].get("timbre") if timbre: - other.append(interpret("Timbre", timbre)) - rhythm = hl['highlevel'].get('ismir04_rhythm') + other.append(interpret("Timbre", "timbre", timbre)) + rhythm = hl["highlevel"].get("ismir04_rhythm") if rhythm: - other.append(interpret("ISMIR04 Rhythm", rhythm)) + other.append(interpret("ISMIR04 Rhythm", "ismir04_rhythm", rhythm)) return genres, moods, other