Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct indexing bugs due to incorrect refactor in robustIteration() #109

Closed

Conversation

AlexHarker
Copy link
Contributor

Fixes the indexing bug discussed today with @weefuzzy.

It could probably do with a quick check over to see that this looks similar to the code here:

https://github.com/flucoma/flucoma-core/blob/2011fc0b21d4ec597d973bc64657542768269452/include/algorithms/ARModel.hpp

Which I think is the last good version.

James Bradbury and others added 2 commits February 16, 2022 15:15
* batchsize was not capped down, leading to hilarious crashes (flucoma#63)

* updating credits with the new team

* Include SHAs for flucoma-core and current project in version string

* Conform version string with SHAs to semantic versioning spec

* add chroma feature to NoveltySlice

* Toggle BLAS settings for compiling on APPLE (flucoma#67)

* disable blas for compiling on macos

* remove line according to O's suggestion

* error in the client of (buf)noveltyslice since introducing chroma as feature

* Enhance/versioning (flucoma#75)

* Remove old header template

* Add in TU template and declaration header

* update CMake to new version scheme

* Get SHA from top level source folder

* ensure git is found

* fix issue flucoma#23 - zeroing the output vector in the mTracker loop (flucoma#82)

* fix issue flucoma#23 - zeroing the output vector in the mTracker loop

* now really corrected thanks to @weefuzzy

* Initial unit tests for `include/data` (flucoma#83)

* initial FluidTensor tests

* add assert death test to cmake

* more assert death

* fix compile tests

* Working assertion tests, it seems

* Add first FluidTensorView tests

* tidy up cmake a bit

* factor out EqualRange matcher to own header

* Add FluidTensorSupport tests

* rollback to Catch2 

for compatability with approvaltests.cpp

* add tests for FluidDataSet

bubba's first approval test ✨

* test print for bigger range as well

* tidy cmake

* make building tests optional

* remove spurious files from tracking

* add workflow for CI

* make workflow manually triggerable

* correct workflow file extention

* pleading and bargaining with github

* getting event name right

* FluidTensorSlice: fix terrible and aged typename mistake

* workflow: try and cache whole build folder

* wotkflow: unbreak yaml

* workflow: disable fail-fast

* Amend upper frequency limit of mel bands in NoveltySlice to 20kHz

* [Enhance] FluCoMa-wide DataSets as a resource (flucoma#88)

* treat wav files as binary

* move audio files to resources folder

* add datasets

* add pre-trained neural networks

* add flucoma corpus

* move datasets to data

* BufAudioTransport now has A-B based arguments

* fix mistakenly fixed type signature in FluidSink

* Tests for framing and overlap add bits

* remove build folder caching as a bad job 

(failing forever once cache goes bad)

* Test/sc ports/slicers (flucoma#91)

* Working port of SC NoveltySlice tests

* formatting and constifying

* use generated path for test signal loading

* update testsignals header and cmake

* Add TestOnsetSegmention, update TestNoveltySeg for new resource loading

* Add Onsets and update novelty in CMake

* Add EnvelopeSeg tests and some missing headers

* Add EnvelopeGate tests

* Add TransientSlice tests

* update location of audio files

* add missing function to signals.cpp.in

* Fix test signal for AmpSlice test

* try and speed up test run

* FluidSource test blackholed on MSVC

It doesn't like GENERATE_REF nested in GENERATE. Nosir.

* ignore all build folders for a quieter life

* bump Eigen version (flucoma#93)

* bump Eigen version

* note new Eigen version in readme

* add mammoth dataset

* OnsetSlice and NoveltySlice clients: fix block size dependency (flucoma#96)

Makes tracking of `frameOffset` stateful across calls to `process` so that odd hop sizes are handled correctly

* `SliceIterator::end()` fix (flucoma#97)

* fix problem with 0-size slices and end() sentinels

* adds basic test for slice ietrator fix

* annotate datasets

* add mfcc for fluid_corpus

* update mfcc dataset

* bump version to beta5 (flucoma#101)

Co-authored-by: tremblap <info@pierrealexandretremblay.com>
Co-authored-by: weefuzzy <gungwho@gmail.com>
Co-authored-by: g-roma <gerard.roma@gmail.com>
Co-authored-by: Ted Moore <ted@tedmooremusic.com>
@AlexHarker
Copy link
Contributor Author

Impossible for me to tell if the tests should fail given the change or not. The tests that fail are all to do with checking the output of transient processes, but if they are based on old results then it would make sense for them to now be different.

@weefuzzy
Copy link
Member

weefuzzy commented Mar 1, 2022

Yes, those are all unsurprising test failures – we'll have to quite literally play it by ear.

@weefuzzy
Copy link
Member

weefuzzy commented Mar 1, 2022

This feels qualitatively easier to use with the real-time slicer and extractor.

@AlexHarker
Copy link
Contributor Author

Thanks - I had no doubt it would be better as all my original audio testing was done on code that was functional. The question for me is how far the improvements go. Is it still missing obvious transients (as per your tests sent separately last month with graphical accompaniment)?

@weefuzzy
Copy link
Member

weefuzzy commented Mar 1, 2022

Here's the windowed forward and backward error, plotted against their source material

forward windowed error, with fix

backward windowed error, with fix

@AlexHarker
Copy link
Contributor Author

To my mind that's vastly improved from the previous plots and for good reason as most of the previous ARModel would have been almost entirely based on the raw data, which means that it is likely that if there's enough transient in the window, or it's a bit softer that it likely won't detect (as it did not before).

Levels of noisiness are about what I'd expect - I presume they are about the same on both (it's just that the spikes are higher for backwards), but it's a bit hard to tell due to the scaling differences on display. but it seems to be mostly just under 1, which for a normalised error (assuming the factor is around 3) would be correct/expected.

I see nothing here that points to anything other than merging this and then considering other improvements either to the variance estimate or possibly the manner of prediction (although I still have reservations about whether that route should be taken, or at least how to validate that it is really an improvement from either an empirical or theoretical standpoint) as future enhancements. As far as I can tell this represents what I intended the code to do and performs better so I would vote merge and then we can look at the block edge effects discussed and then leave you to make whatever further changes you wish after that.

It might be a good time to update the tests and pull in the updated autocorrelation code and possibly way of calculating the AR parameters here as there would then be a good basis for checking those changes. That can also be done without me, but I'd be happy to be involved in reviewing that as it removes some other non-optimal aspects of the code to date. Likewise the safety changes to ARModel.hpp

@weefuzzy
Copy link
Member

weefuzzy commented Mar 1, 2022

I've adjusted the slicer tests and will run them by @tremblap in supercollider form before fixing up here.

Bafflingly, however, the transients decomposition objects no longer null sum when using the reported latency. I'm going to go and sit in a dark cave to try and figure out why this single change should / could do that (yes, I've been back to the dev branch and rebuilt / rechecked 😉 )

(less sure of this now...)

Well, it 'nulls' to about -100dB and a mean around -200 dB, whereas the existing test in SC has a threshold of -120 dB. Personally, I'm not hugely inclined to lose sleep over that, if it cancels to better than 16-bits.

@AlexHarker
Copy link
Contributor Author

AlexHarker commented Mar 1, 2022

Hmmmm. If this were an FFT process I'd agree and consider that acceptable because there are loads of points of accuracy to consider. However, given that the output is literally formed from time domain subtraction then the question is what bit depth is the null sum test performed at - I'm guessing given that it's SC we are down to 32 bit? (my thinking is that even if the interpolated output was formed of generated noise, it should still null sum with the input given how the transient output is formed). On the other hand, floating point dB limits are complex to reason about (because floating and also potential catastrophic subtraction relative error). -100dB seems a bit high for me, even for a single sample, but I'd have to look at the whole of the processing chain in the test to have any decent thoughts about what acceptable performance would be. It would also be worth having a relative error test to indicate what that -100dB equates to (more like how many ULP is that?).

In theory 32 bit is obviously 24bits of precision, so you'd expect a worst case 1ULP error in relation to the loudest value to be -144dB - however, this assumes that all signals are under 0dB - if that assumption is not the case then things change, but you'd have to be quite a few dB up and I see no reason that would be the case in the test unless there's some funky gain somewhere.

@weefuzzy
Copy link
Member

weefuzzy commented Mar 2, 2022

Well, yes, being SC there's quite a lot of gubbins in the the way between language, server buffers, process, and back again.

Probably worth checking this as close to source as possible before getting too excited.


ULPs are new things for me, but with some hasty googling, the answer would be appear to be 'many ULPs':

The peak difference between the sum of the transients + residual and the source (done in sclang) is
-0.015426635742188 - -0.015437006950378 = 1.0371208e-05

Now, SC doesn't have the facilities for working out the ULP (as far as can see), but with numpy

(np.float32(-0.015426635742188) - np.float32(-0.015437006950378)) / np.spacing(np.float32(-0.015426635742188))

comes out at a chunky 11136. Did I do that right though?

@AlexHarker
Copy link
Contributor Author

AlexHarker commented Mar 2, 2022

Well - we don't need to get as technical as ULP probably, although over a small number of simple calculations you are looking for a few ULP at most lost accuracy, unless there is some significant reason that accuracy is lost somewhere.

If the numbers above are correct that is at the 4th significant figures or around the 10th significant bit. That seems far too much - something funky is going on, but it is hard to see how it could be in the transient separator given the way it forms it output.

I suspect this might be an investigation of the testing system, rather than the algo - but I would need to see the whole of the test process to really understand it. For now the next step is to see what the two components are for the step that has that "large" error.

@weefuzzy
Copy link
Member

weefuzzy commented Mar 2, 2022

So, for the afflicted area, it seems like something goes batshit. Here is the source waveform over 1000 samples around the glitch
crazy_source
Looks innocent enough. But here is the transient channel output. -250 seems excessive as a value.
crazy_trans
Here is the residual
crazy_res
Source and residual together, on a sensible scale,

crazy_source_res

and some detritus when we do (trans + residual) - source

crazy_mess

@AlexHarker
Copy link
Contributor Author

Well - that explains the null summing error perfectly - so this is definitely something to do with what is coming out of the transient separator and the lack of null summing accuracy is the fact that one component has gone well about 0dB and we are losing accuracy in the bit we care about (so the -250 is cancelled but not perfectly because it obliterates some of the low bits in sum).

Next thing to investigate is why this is the output and what this means for the transient separator. I'd very much hope that that section is a detected transient (not that it necessarily should be) and thus the interpolator is going a bit haywire - then we need to figure out why.

@weefuzzy
Copy link
Member

weefuzzy commented Mar 2, 2022

Source is Tremblay-AaS-SynthTwoVoices-M.wav

Params are default:

order 20
blockSize 256
padSize 128
threshFwd 2
threshBack 1.1
windowSize 14
clumpLength 25

@AlexHarker
Copy link
Contributor Author

OK. See (original code from 2018):

for (int i = 0; i < mOrder + size; i++)

And now see (code now):

for (index i = mParameters.size(); i < mParameters.size() + size; i++)

Which are not the same loop size/points.

I see why that's been done (to avoid reading from input that is prior to the pointer), but as far as I can see the first part of the vector isn't explicitly initialised (it may default to zeros - not sure) and in fact this pre-reading was intentional (it's another example of the sort of issue already discussed about the prediction methods and should probably be addressed similarly). This may be unrelated to the issues of accuracy, but it should be addressed.

I didn't make that change.

@weefuzzy
Copy link
Member

weefuzzy commented Mar 2, 2022

Good find. That fixes it, thanks. I can see you didn't make the change 😉

@AlexHarker
Copy link
Contributor Author

AlexHarker commented Mar 2, 2022

Good. I hoped it might, but I wasn't sure. Happy to discuss why I do this, but it relates to the vagueness in the Kleiner/Martin/Thomson paper about how to deal with the start of time series (they don't tell you if I recall).

It's also important in the context of the transient code (if I recall correctly) that the input that gets passed in at the beginning of the blocks as you move through time is the residual (in other words because the beginning of the estimates array never updates, it's important that we feed it something that has a high probility of already being "correct" - which in this case means that the transients/outliers have already been removed).

That's what happens here (might be worth correcting the comment that should say "into" but has been messed up by an "int"->"index" find replace situation:

// Copy the residual indexo the correct place

It's all coming back to me now...

@weefuzzy weefuzzy changed the base branch from main to dev March 2, 2022 17:10
@weefuzzy weefuzzy mentioned this pull request Mar 16, 2022
@weefuzzy
Copy link
Member

superseded by #117

@weefuzzy weefuzzy closed this Mar 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants