Difference between revisions of "MIR workshop 2011 day5 lab"

From CCRMA Wiki
Jump to: navigation, search
(Created page with 'Lab code is found in /usr/ccrma/courses/mir20110/cal500_new. A previous version was uploaded at /usr/ccrma/courses/mir2011/cal500 but it was using filenames from my University of…')
 
 
(5 intermediate revisions by the same user not shown)
Line 1: Line 1:
 +
MIR Workshop 2011 Day 5 Lab on Music Recommendation<br>
 +
Douglas Eck, Google
 +
 +
 +
<h2>Overview</h2>
 +
This lab covers the construction of parts of a music recommender. Focus is placed on building a similarity matrix from data and querying that matrix based on cosine distance.
 +
Fast programmers should be able to accomplish considerably more. 
 +
 +
 +
* The basics (some Python code available to help).
 +
** Calculate acoustic features on CAL500 dataset (students should have already done this.)
 +
** Read in user tag annotations for the same dataset provided by UCSD.
 +
** Build similarity matrix based on word vectors derived from these annotations. In my implementation the matrix is stored as a dictionary of vectors, but this is python-specific.
 +
** Query similarity matrix with a track to get top hits based on cosine distance.
 +
** Build second similarity matrix using acoustic features.
 +
** Query this similarity matrix with track to get top hits based on cosine distance.
 +
 +
* Extra (I didn't write code for this, but can help students find examples).
 +
** Query the EchoNest for additional acoustic features and compare to yours.
 +
** Use the CAL500 user annotations as ground truth and evaluate your audio features (ROC curve or some precision measure).
 +
** Compare a 2D visualization of acoustic features versus UCSD user annotations.
 +
** Train a classifier on CAL500.  Train / test splits will be generated this afternoon.
 +
 
Lab code is found in /usr/ccrma/courses/mir20110/cal500_new.
 
Lab code is found in /usr/ccrma/courses/mir20110/cal500_new.
 
A previous version was uploaded at /usr/ccrma/courses/mir2011/cal500 but it was using filenames from my University of Montreal lab.  I renamed audio files to match those of UCSD Cal500
 
A previous version was uploaded at /usr/ccrma/courses/mir2011/cal500 but it was using filenames from my University of Montreal lab.  I renamed audio files to match those of UCSD Cal500
 +
 +
An example call for the code provided by me:
 +
 +
<pre>
 +
%python cal500_example.py norah_jones-dont_know_why
 +
1 Cosine distance=0.0000 Track=norah_jones-dont_know_why
 +
2 Cosine distance=0.1111 Track=carole_king-youve_got_a_friend
 +
3 Cosine distance=0.1365 Track=alicia_keys-fallin
 +
4 Cosine distance=0.1387 Track=dido-here_with_me
 +
5 Cosine distance=0.1610 Track=fiona_apple-love_ridden
 +
6 Cosine distance=0.1646 Track=barry_manilow-mandy
 +
7 Cosine distance=0.1661 Track=stan_getz-corcovado_quiet_nights_of_quiet_stars
 +
8 Cosine distance=0.1696 Track=aimee_mann-wise_up
 +
9 Cosine distance=0.1758 Track=marvelettes-please_mr._postman
 +
10 Cosine distance=0.1772 Track=ben_folds_five-brick
 +
11 Cosine distance=0.1795 Track=cranberries-linger
 +
12 Cosine distance=0.1833 Track=sade-smooth_operator
 +
13 Cosine distance=0.1860 Track=john_lennon-imagine
 +
14 Cosine distance=0.1864 Track=dionne_warwick-walk_on_by
 +
15 Cosine distance=0.1918 Track=5th_dimension-one_less_bell_to_answer
 +
16 Cosine distance=0.1923 Track=carpenters-rainy_days_and_mondays
 +
17 Cosine distance=0.1932 Track=diana_ross_and_the_supremes-where_did_our_love_go
 +
18 Cosine distance=0.1939 Track=smokey_robinson_and_the_miracles-ooo_baby_baby
 +
19 Cosine distance=0.1939 Track=fleetwood_mac-say_you_love_me
 +
20 Cosine distance=0.1970 Track=rufus_wainwright-cigarettes_and_chocolate_milk
 +
</pre>
 +
 +
 +
Functions provided by me in cal500_example.py.  Students can recode as they please in any language. They are free to use as much of my code as they want.
 +
 +
<pre>
 +
def RemapFilename(infile):
 +
  """Maps a filename from Doug name to real cal500 name."""
 +
 +
 +
def RenameCal500(dest_directory='high_bitrate'):
 +
  """Renames cal500 files from Doug naming scheme to standard one
 +
  and places them in dest_directory."""
 +
 +
 +
def MakeFilenameMap(infile = 'cal500_doug_filenames.txt',
 +
                      outfile = 'cal500_filename_map.txt'):
 +
  """Create text file mapping old (Doug) filenames to standard
 +
  Cal500 filenames."""
 +
 +
 +
def GetKeyFromAnnotationPath(annotation_path):
 +
  """Gets key from annnotation file path, stripping off
 +
  the number.
 +
  # Ex: norine_braun-spanish_banks_02.txt yields
 +
  # norine_braun-spanish_banks
 +
 +
 +
# Mapping from text values in CAL500 annotation files to (somewhat arbitrary) numeric values.
 +
ANNOTATION_MAP = {
 +
    'yes': 1.0,
 +
    'prominent': 1.0,
 +
    'present': 0.75,
 +
    'uncertain': 0.5,
 +
    'no': 0.0,
 +
    'none': 0.0,
 +
    '5': 5/5.0,
 +
    '4': 4/5.0,
 +
    '3': 3/5.0,
 +
    '2': 2/5.0,
 +
    '1': 1/5.0,
 +
    '0': 0.0
 +
    }
 +
 +
 +
def AddTagWeightsToDictFromAnnotationFile(annotation_path, tag_weights):
 +
  """Reads tag weights into a dictionary keyed by tag name
 +
  and adds them to the defaultdict tag_weights. Use key 'counter'
 +
  to track number of annotations."""
 +
 +
 +
def BuildTagDictionary(tag_directory='annotations'):
 +
  """Builds dictionary mapping cal500 key to a weighted tag vector.
 +
  Returns dictionary and our vocabulary of tags."""
 +
 +
 +
def BuildVectorDictionaryFromTagDictionary(tag_dict, vocabulary):
 +
  """Transforms tag dictionaries int tag vectors using vocabulary."""
 +
 +
 +
def CosineDistance(v1, v2):
 +
  """Calculates cosine distance using numpy."""
 +
 +
 +
def ScoreQuery(vector_dict, query):
 +
  """Finds nearest neigbors for query in vector_dict."""
 +
 +
 +
def PrintScoreDict(score_dict, query, k=20):
 +
  """Print score dictionary for a query."""
 +
 +
 +
# Here is the main function as called above.
 +
if __name__=='__main__':
 +
  if len(sys.argv)>1:
 +
    query = sys.argv[1]
 +
  else:
 +
    query = 'norah_jones-dont_know_why'
 +
 +
  # Build vectors from words.
 +
  tag_dict, vocabulary = BuildTagDictionary()
 +
  vector_dict = BuildVectorDictionaryFromTagDictionary(tag_dict, vocabulary)
 +
 +
  # Score a query.
 +
  score_dict = ScoreQuery(vector_dict, query)
 +
  PrintScoreDict(score_dict, query)
 +
 +
</pre>

Latest revision as of 09:04, 1 July 2011

MIR Workshop 2011 Day 5 Lab on Music Recommendation
Douglas Eck, Google


Overview

This lab covers the construction of parts of a music recommender. Focus is placed on building a similarity matrix from data and querying that matrix based on cosine distance. Fast programmers should be able to accomplish considerably more.


  • The basics (some Python code available to help).
    • Calculate acoustic features on CAL500 dataset (students should have already done this.)
    • Read in user tag annotations for the same dataset provided by UCSD.
    • Build similarity matrix based on word vectors derived from these annotations. In my implementation the matrix is stored as a dictionary of vectors, but this is python-specific.
    • Query similarity matrix with a track to get top hits based on cosine distance.
    • Build second similarity matrix using acoustic features.
    • Query this similarity matrix with track to get top hits based on cosine distance.
  • Extra (I didn't write code for this, but can help students find examples).
    • Query the EchoNest for additional acoustic features and compare to yours.
    • Use the CAL500 user annotations as ground truth and evaluate your audio features (ROC curve or some precision measure).
    • Compare a 2D visualization of acoustic features versus UCSD user annotations.
    • Train a classifier on CAL500. Train / test splits will be generated this afternoon.

Lab code is found in /usr/ccrma/courses/mir20110/cal500_new. A previous version was uploaded at /usr/ccrma/courses/mir2011/cal500 but it was using filenames from my University of Montreal lab. I renamed audio files to match those of UCSD Cal500

An example call for the code provided by me:

%python cal500_example.py norah_jones-dont_know_why
1 Cosine distance=0.0000 Track=norah_jones-dont_know_why
2 Cosine distance=0.1111 Track=carole_king-youve_got_a_friend
3 Cosine distance=0.1365 Track=alicia_keys-fallin
4 Cosine distance=0.1387 Track=dido-here_with_me
5 Cosine distance=0.1610 Track=fiona_apple-love_ridden
6 Cosine distance=0.1646 Track=barry_manilow-mandy
7 Cosine distance=0.1661 Track=stan_getz-corcovado_quiet_nights_of_quiet_stars
8 Cosine distance=0.1696 Track=aimee_mann-wise_up
9 Cosine distance=0.1758 Track=marvelettes-please_mr._postman
10 Cosine distance=0.1772 Track=ben_folds_five-brick
11 Cosine distance=0.1795 Track=cranberries-linger
12 Cosine distance=0.1833 Track=sade-smooth_operator
13 Cosine distance=0.1860 Track=john_lennon-imagine
14 Cosine distance=0.1864 Track=dionne_warwick-walk_on_by
15 Cosine distance=0.1918 Track=5th_dimension-one_less_bell_to_answer
16 Cosine distance=0.1923 Track=carpenters-rainy_days_and_mondays
17 Cosine distance=0.1932 Track=diana_ross_and_the_supremes-where_did_our_love_go
18 Cosine distance=0.1939 Track=smokey_robinson_and_the_miracles-ooo_baby_baby
19 Cosine distance=0.1939 Track=fleetwood_mac-say_you_love_me
20 Cosine distance=0.1970 Track=rufus_wainwright-cigarettes_and_chocolate_milk


Functions provided by me in cal500_example.py. Students can recode as they please in any language. They are free to use as much of my code as they want.

def RemapFilename(infile):
  """Maps a filename from Doug name to real cal500 name."""


def RenameCal500(dest_directory='high_bitrate'):
  """Renames cal500 files from Doug naming scheme to standard one
  and places them in dest_directory."""


def MakeFilenameMap(infile = 'cal500_doug_filenames.txt',
                      outfile = 'cal500_filename_map.txt'):
  """Create text file mapping old (Doug) filenames to standard
  Cal500 filenames."""


def GetKeyFromAnnotationPath(annotation_path):
  """Gets key from annnotation file path, stripping off
  the number.
  # Ex: norine_braun-spanish_banks_02.txt yields
  # norine_braun-spanish_banks


# Mapping from text values in CAL500 annotation files to (somewhat arbitrary) numeric values.
ANNOTATION_MAP = {
    'yes': 1.0,
    'prominent': 1.0,
    'present': 0.75,
    'uncertain': 0.5,
    'no': 0.0,
    'none': 0.0,
    '5': 5/5.0,
    '4': 4/5.0,
    '3': 3/5.0,
    '2': 2/5.0,
    '1': 1/5.0,
    '0': 0.0
    }


def AddTagWeightsToDictFromAnnotationFile(annotation_path, tag_weights):
  """Reads tag weights into a dictionary keyed by tag name
  and adds them to the defaultdict tag_weights. Use key 'counter'
  to track number of annotations."""


def BuildTagDictionary(tag_directory='annotations'):
  """Builds dictionary mapping cal500 key to a weighted tag vector.
  Returns dictionary and our vocabulary of tags."""


def BuildVectorDictionaryFromTagDictionary(tag_dict, vocabulary):
  """Transforms tag dictionaries int tag vectors using vocabulary."""


def CosineDistance(v1, v2):
  """Calculates cosine distance using numpy."""


def ScoreQuery(vector_dict, query):
  """Finds nearest neigbors for query in vector_dict."""


def PrintScoreDict(score_dict, query, k=20):
  """Print score dictionary for a query."""


# Here is the main function as called above.
if __name__=='__main__':
  if len(sys.argv)>1:
    query = sys.argv[1]
  else:
    query = 'norah_jones-dont_know_why'

  # Build vectors from words.
  tag_dict, vocabulary = BuildTagDictionary()
  vector_dict = BuildVectorDictionaryFromTagDictionary(tag_dict, vocabulary)

  # Score a query.
  score_dict = ScoreQuery(vector_dict, query)
  PrintScoreDict(score_dict, query)