gcds / src /data /dataset.py
Alexandre D'Hooge
push my stuff
2c6366f
Raw History Blame Contribute Delete
8.33 kB
import pandas as pd
import torch
from src.data.shape_to_manyhot import shape_to_manyhot
from src.data.chord_label_translator import get_vector_representation, get_chord_label_notes, get_chord_label
from src.config import NUM_FRETS, NUM_STRINGS, PITCH_CLASSES
import src.data.chord_functions as F
from src.data.open_chords import shape_is_open_chord
from tqdm import tqdm
import src.exceptions as E
class SimpleDataset():
def __init__(self, df_path: str | None, df: pd.DataFrame | None) -> None:
self.df_path: str | None
self.df: pd.DataFrame
self.unique_df: pd.DataFrame
self.df_path = df_path
self.df = pd.read_csv(df_path, index_col=0) if df_path is not None else df
if 'filename' in self.df.columns:
self.df = self.df.drop_duplicates(
subset=['filename', 'current_chord', 'next_chord',
'current_position', 'next_position'])
def previous_chord(self):
return self.df['current_chord']
def previous_position(self):
return self.df['current_position']
def current_chord(self):
return self.df['next_chord']
def current_position(self):
return self.df['next_position']
def target(self):
return self.current_position()
def source(self):
return (self.previous_chord(), self.previous_position(),
self.current_chord())
def __len__(self):
return len(self.df)
class TorchDataset(torch.utils.data.Dataset):
@staticmethod
def fingering_from_source_tensor(tensor: torch.Tensor,
with_mute: bool = False) -> str:
t = tensor[:-2*PITCH_CLASSES]
num_frets = NUM_FRETS + 1 if with_mute else NUM_FRETS
t = torch.reshape(t, (NUM_STRINGS, num_frets))
out = ""
for row in t:
if with_mute and torch.argmax(row) == (num_frets-1):
out += "x."
continue
l = torch.argwhere(row>0.5)
if len(l) == 0:
out += "x"
elif len(l) == 1:
out += str(l[0].item())
else:
for v in l:
out += str(v.item())
out += "|"
out += '.'
return out
@staticmethod
def fingering_from_target_tensor(tensor: torch.Tensor,
with_mute: bool = False) -> str:
num_frets = NUM_FRETS + 1 if with_mute else NUM_FRETS
t = torch.reshape(tensor, (NUM_STRINGS, num_frets))
out = ""
for row in t:
if with_mute and torch.argmax(row) == (num_frets-1):
out += "x."
continue
l = torch.argwhere(row == 1)
if len(l) == 0:
out += "x"
elif len(l) == 1:
out += str(l[0].item())
else:
for v in l:
out += str(v.item())
out += "|"
out += '.'
return out
@staticmethod
def chordlabel_from_source_tensor(tensor: torch.Tensor) -> str:
t = tensor[-2*PITCH_CLASSES:]
return get_chord_label(t)
def __init__(self, df_path: str | None, df: pd.DataFrame | None,
with_mute: bool = False, drop_duplicates_strict: bool = False,
drop_duplicates_stricter: bool = False,
drop_duplicates_strictest: bool = False,
augment: bool = False) -> None:
self.df_path: str | None
self.df: pd.DataFrame
self.unique_df: pd.DataFrame
self.df_path = df_path
self.df = pd.read_csv(df_path, index_col=0) if df_path is not None else df
self.df = self.df.reset_index(drop=True)
self._clean_df()
if augment:
self.data_augment()
self._clean_df()
if 'filename' in self.df.columns:
if drop_duplicates_strictest:
self.df = self.df.drop_duplicates(
subset=['next_chord'])
elif drop_duplicates_stricter:
self.df = self.df.drop_duplicates(
subset=['next_chord','next_position'])
elif drop_duplicates_strict:
self.df = self.df.drop_duplicates(
subset=['filename', 'next_chord','next_position'])
else:
self.df = self.df.drop_duplicates(
subset=['filename', 'current_chord', 'next_chord',
'current_position', 'next_position'])
self.df = self.df.reset_index()
if augment:
self.df.to_csv('cleaned_df_with_augmentation.csv')
self.with_mute = with_mute
super().__init__()
def _clean_df(self):
"""
Some chord labels are not known yet. Remove them from the df until they're
dealt with.
"""
to_drop = []
for i in range(len(self.df)):
if get_chord_label_notes(self.df.iloc[i]['next_chord']) is None:
to_drop.append(i)
self.df = self.df.drop(index=to_drop)
print(f"Dropped {len(to_drop)} unknown chords.")
def _current_fingering_from_idx(self, index):
return shape_to_manyhot(self.df.iloc[index]['current_position'],
with_mute=self.with_mute).type(torch.float)
def _next_fingering_from_idx(self, index):
return shape_to_manyhot(self.df.iloc[index]['next_position'],
with_mute=self.with_mute).type(torch.float)
def _next_chord_from_idx(self, index):
return get_vector_representation(self.df.iloc[index]['next_chord'], tensor=True)
def __getitem__(self, index):
current_fingering = self._current_fingering_from_idx(index)
next_fingering = self._next_fingering_from_idx(index)
next_chord = self._next_chord_from_idx(index)
return torch.cat((torch.flatten(current_fingering), next_chord)), torch.flatten(next_fingering)
def __len__(self):
return len(self.df)
def data_augment(self):
to_add = []
for i, row in tqdm(self.df.iterrows()):
if '0' in row['current_position'] or '0' in row['next_position']:
continue
else:
new_df = self.augment_from_row(row)
if new_df is None:
continue
to_add.append(new_df)
augmented_df = pd.concat(to_add, ignore_index=True)
self.df = pd.concat([self.df, augmented_df], ignore_index=True)
self.df.to_csv(self.df_path + 'with_augmentation')
def augment_from_row(self, row):
df = pd.DataFrame(columns=self.df.columns)
filename = row['filename'] + '-augmented'
measure = row['measure']
current_chord = row['current_chord']
next_chord = row['next_chord']
current_pos = row['current_position']
next_pos = row['next_position']
new_current_chord = current_chord
new_next_chord = next_chord
new_current_pos = current_pos
new_next_pos = next_pos
#print(filename, current_chord, next_chord)
while not shape_is_open_chord(new_current_pos) and not shape_is_open_chord(new_next_pos):
try:
new_current_chord, new_current_pos = F.transpose(new_current_chord, new_current_pos, -1)
except E.RootError:
return None
new_next_chord, new_next_pos = F.transpose(new_next_chord, new_next_pos, -1)
df.loc[-1] = [filename, measure, new_current_chord, new_next_chord,
new_current_pos, new_next_pos]
df.index += 1
df = df.sort_index()
new_current_chord = current_chord
new_next_chord = next_chord
new_current_pos = current_pos
new_next_pos = next_pos
while not F.reach_twelfth_fret(new_current_pos) and not F.reach_twelfth_fret(new_next_pos):
new_current_chord, new_current_pos = F.transpose(new_current_chord, new_current_pos, 1)
new_next_chord, new_next_pos = F.transpose(new_next_chord, new_next_pos, 1)
df.loc[-1] = [filename, measure, new_current_chord, new_next_chord,
new_current_pos, new_next_pos]
df.index += 1
df = df.sort_index()
return df