example 11. make the standardisation systematic and more in line with literature.

nix
Pierre Alexandre Tremblay 5 years ago
parent bb53874d83
commit 6aed1ba3dd

@ -1,3 +1,4 @@
// here we will define a process that creates and populates a series of parallel dataset, one of each 'feature-space' that we can then eventually manipulate more easily than individual dimensions.
// define a few datasets // define a few datasets
( (
@ -6,7 +7,6 @@
~mfccDS = FluidDataSet(s,\mfcc11); ~mfccDS = FluidDataSet(s,\mfcc11);
~durDS = FluidDataSet(s,\dur11); ~durDS = FluidDataSet(s,\dur11);
//define as many buffers as we have parallel voices/threads in the extractor processing (default is 4) //define as many buffers as we have parallel voices/threads in the extractor processing (default is 4)
~pitchbuf = 4.collect{Buffer.new}; ~pitchbuf = 4.collect{Buffer.new};
~statsPitchbuf = 4.collect{Buffer.new}; ~statsPitchbuf = 4.collect{Buffer.new};
@ -102,7 +102,7 @@ t = Main.elapsedTime;
~durDS.print; ~durDS.print;
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
//reduce the MFCC timbral space stats (many potential ways to explore here... just 2 provided for fun) //reduce the MFCC timbral space stats (many potential ways to explore here... - 2 are provided to compare, with and without the derivatives before running a dimension reduction)
~tempDS = FluidDataSet(s,\temp11); ~tempDS = FluidDataSet(s,\temp11);
~query = FluidDataSetQuery(s); ~query = FluidDataSetQuery(s);
@ -110,48 +110,57 @@ t = Main.elapsedTime;
~query.addRange((7*12),24);// and the same stats of the first derivative (moving 7 stats x 12 mfccs to the right) ~query.addRange((7*12),24);// and the same stats of the first derivative (moving 7 stats x 12 mfccs to the right)
~query.transform(~mfccDS, ~tempDS); ~query.transform(~mfccDS, ~tempDS);
//check //check that you end up with the expected 48 dimensions
~tempDS.print; ~tempDS.print;
//shrinking A: PCA then standardize // standardizing before the PCA
~pca = FluidPCA(s,4);//shrink to 4 dimensions
~timbreDSp = FluidDataSet(s,\timbreDSp11);
~pca.fitTransform(~tempDS,~timbreDSp,{|x|x.postln;})//accuracy
// shrinking B: standardize then PCA
// https://scikit-learn.org/stable/auto_examples/preprocessing/plot_scaling_importance.html // https://scikit-learn.org/stable/auto_examples/preprocessing/plot_scaling_importance.html
~pca2 = FluidPCA(s,4);//shrink to 4 dimensions
~stan = FluidStandardize(s); ~stan = FluidStandardize(s);
~stanDS = FluidDataSet(s,\stan11); ~stanDS = FluidDataSet(s,\stan11);
~stan.fitTransform(~tempDS,~stanDS) ~stan.fitTransform(~tempDS,~stanDS)
~timbreDSsp = FluidDataSet(s,\timbreDSsp11);
~pca2.fitTransform(~stanDS,~timbreDSsp,{|x|x.postln;})//accuracy //shrinking A: using 2 stats on the values, and 2 stats on the redivative (12 x 2 x 2 = 48 dim)
~pca = FluidPCA(s,4);//shrink to 4 dimensions
~timbreDSd = FluidDataSet(s,\timbreDSd11);
~pca.fitTransform(~stanDS,~timbreDSd,{|x|x.postln;})//accuracy
//shrinking B: using only the 2 stats on the values
~query.clear;
~query.addRange(0,24);//add only means and stddev of the 12 coeffs...
~query.transform(~stanDS, ~tempDS);//retrieve the values from the already standardized dataset
//check you have the expected 24 dimensions
~tempDS.print;
//keep its own PCA so we can keep the various states for later transforms
~pca2 = FluidPCA(s,4);//shrink to 4 dimensions
~timbreDS = FluidDataSet(s,\timbreDS11);
~pca2.fitTransform(~tempDS,~timbreDS,{|x|x.postln;})//accuracy
// comparing NN for fun // comparing NN for fun
~targetDSp = Buffer(s) ~targetDSd = Buffer(s)
~targetDSsp = Buffer(s) ~targetDS = Buffer(s)
~tree = FluidKDTree(s,5) ~tree = FluidKDTree(s,5)
// you can run this a few times to have fun // you can run this a few times to have fun
( (
~target = ~slicer.index.keys.asArray.scramble.[0].asSymbol; ~target = ~slicer.index.keys.asArray.scramble.[0].asSymbol;
~timbreDSp.getPoint(~target, ~targetDSp); ~timbreDSd.getPoint(~target, ~targetDSd);
~timbreDSsp.getPoint(~target, ~targetDSsp); ~timbreDS.getPoint(~target, ~targetDS);
) )
~tree.fit(~timbreDSp,{~tree.kNearest(~targetDSp,{|x|~nearestDSp = x.postln;})}) ~tree.fit(~timbreDSd,{~tree.kNearest(~targetDSd,{|x|~nearestDSd = x.postln;})})
~tree.fit(~timbreDSsp,{~tree.kNearest(~targetDSsp,{|x|~nearestDSsp = x.postln;})}) ~tree.fit(~timbreDS,{~tree.kNearest(~targetDS,{|x|~nearestDS = x.postln;})})
// play them in a row // play them in a row
( (
Routine{ Routine{
5.do{|i| 5.do{|i|
var dur; var dur;
v = ~slicer.index[~nearestDSp[i].asSymbol]; v = ~slicer.index[~nearestDSd[i].asSymbol];
dur = (v[\bounds][1] - v[\bounds][0]) / s.sampleRate; dur = (v[\bounds][1] - v[\bounds][0]) / s.sampleRate;
{BufRd.ar(v[\numchans],~loader.buffer,Line.ar(v[\bounds][0],v[\bounds][1],dur, doneAction: 2))}.play; {BufRd.ar(v[\numchans],~loader.buffer,Line.ar(v[\bounds][0],v[\bounds][1],dur, doneAction: 2))}.play;
~nearestDSp[i].postln; ~nearestDSd[i].postln;
dur.wait; dur.wait;
}; };
}.play; }.play;
@ -161,10 +170,10 @@ Routine{
Routine{ Routine{
5.do{|i| 5.do{|i|
var dur; var dur;
v = ~slicer.index[~nearestDSsp[i].asSymbol]; v = ~slicer.index[~nearestDS[i].asSymbol];
dur = (v[\bounds][1] - v[\bounds][0]) / s.sampleRate; dur = (v[\bounds][1] - v[\bounds][0]) / s.sampleRate;
{BufRd.ar(v[\numchans],~loader.buffer,Line.ar(v[\bounds][0],v[\bounds][1],dur, doneAction: 2))}.play; {BufRd.ar(v[\numchans],~loader.buffer,Line.ar(v[\bounds][0],v[\bounds][1],dur, doneAction: 2))}.play;
~nearestDSsp[i].postln; ~nearestDS[i].postln;
dur.wait; dur.wait;
}; };
}.play; }.play;
@ -204,7 +213,7 @@ Routine{
~query.and(0,">", 11025)//also larger than a quarter of second ~query.and(0,">", 11025)//also larger than a quarter of second
~query.transformJoin(~durDS, ~pitchDS, ~tempDS); //this passes to ~tempDS only the points that have the same label than those in ~durDS that satisfy the condition. No column were added so nothing from ~durDS is copied ~query.transformJoin(~durDS, ~pitchDS, ~tempDS); //this passes to ~tempDS only the points that have the same label than those in ~durDS that satisfy the condition. No column were added so nothing from ~durDS is copied
// print to see // print to see how many slices (rows) we have
~tempDS.print ~tempDS.print
// further conditions to assemble the query // further conditions to assemble the query
@ -213,7 +222,7 @@ Routine{
~query.addRange(0,4) //copy only mean and stddev of pitch and confidence ~query.addRange(0,4) //copy only mean and stddev of pitch and confidence
~query.transform(~tempDS, ~globalDS); // pass it to the final search ~query.transform(~tempDS, ~globalDS); // pass it to the final search
// print to see // print to see that we have less items, with only their pitch
~globalDS.print ~globalDS.print
// compare knearest on both globalDS and tempDS // compare knearest on both globalDS and tempDS
@ -268,7 +277,7 @@ Routine{
~normL.fitTransform(~loudDS, ~loudDSn); ~normL.fitTransform(~loudDS, ~loudDSn);
~normP.fitTransform(~pitchDS, ~pitchDSn); ~normP.fitTransform(~pitchDS, ~pitchDSn);
~normT.fitTransform(~timbreDSp, ~timbreDSn); ~normT.fitTransform(~timbreDSd, ~timbreDSn);
// let's assemble these datasets // let's assemble these datasets
~query.clear ~query.clear

Loading…
Cancel
Save