---
title: "DementiaBank Acoustics Project"
source: https://www.jemoka.com/posts/kbhdementiabank_acoustics_project/
---

The DementiaBank Acoustics Project is a working title for an acoustic-only challenge for AD detection. This document serves as the lab notebook for this project.
This project will attempt to replicate some of the results of Wang 2019 and Martinc 2021, but focusing on minimizing human involvement; we will first work on raw transcript classification with ERNIE (cutting all CHAT annotations), then introduce pause-encoding in a manner similar to Yuan 2021 which is automated by MFA. Goal is to replicate the results of Yuan 2021/or even Martinc 2021 in a completely automated manner.
Background Reading I first began by doing a literature survey on the ADReSS Challenge results published in the Frontiers AD special interest group issue.
Proposal And then, we wrote a proposal: DementiaBank Acoustics Project Proposal
Brainstoming More notes from the meeting: DementiaBank Acoustics Brainstoming
Protocol Notes July 1st Began by moving a subsample of Pitt&rsquo;s Cookie Theft to pitt-7-1 in the raw data folder Ran flo on all collected samples. Arguments used are the same as that for batchalign, except we filter out the INV tier as we are detecting AD on patient and not investigator: so flo +d +ca +t* -tINV Moved all collected samples (and changed extension to .txt) to the same sub-folder, but in transcripts_nodisfluency July 2nd Created a dataprep script dataprep.py which dumps a pickled copy of cleaned data to transcripts_nodisfluency/pitt-7-1.dat. Created sliding windows of 5 pieces of dialogue concatenated, stored it in transcripts_nodisfluency/pitt-7-1-windowed.dat Used tencent/HuYong&rsquo;s nghuyong/ernie-2.0-en Ernie 2.0 model, the continuous language model from Baidu (Layer:12, Hidden:768, Heads:12) July 4th Finalized training code. Selected base hyperparameters {bs: 8, epochs: 2, lr: 3e-3, length: 60}. Again, we are using Baidu&rsquo;s nghuyong/ernie-2.0-en. Started training fastcalculator on 24bc812 train: faithful-frog-3 {bs: 8, epochs: 2, lr: 3e-3, length: 60, pitt-7-1-windowed.dat }
Commentary: LR could be too high, looking at the divergent loss behavior. Decision: dropping bs to 4 and lr to 1e-5, similar to previous transformers. Also training for 3 epochs. train: revived-disco-5 {bs: 4, epochs: 3, lr: 1e-5, length: 60, pitt-7-1-windowed.dat }
Commentary: quintessential overfitting Decision: Made the corpus bigger cleaned the entire Pitt corpus (pitt-7-4 in the raw folder) to become training data. Similar to pitt-7-1, ran flo on all collected samples; arguments used are the same as that for batchalign, except we filter out the INV tier as we are detecting AD on patient and not investigator: so flo +d +ca +t* -tINV; the flo&rsquo;d results are in transcripts_nodisfluency. the notable difference between the previous dataset 7-1 and the current one 7-4 is that the 7-4 are prepended numbered by the task (cookie/100-01.cha &gt; =cookie-100-01.txt) New (full) Pitt data as prepared above is ran though the dataprep script as of b325514cfad79da82d7a519ed29ea19ed87b2be4 (difference is that empty/dummy files are ignored), and pickled at transcripts_nodisfluency/pitt-7-4.dat and transcripts_nodisfluency/pitt-7-4-windowed.dat respectively. For new data, window size is still 5, splitting 10 cases out for testing now instead of 5. train: vocal-oath-6 {bs: 4, epochs: 3, lr: 1e-5, length: 60, pitt-7-4-windowed.dat}
Commentary: high recall, low precision. Perhaps classes aren&rsquo;t balanced? Spoiler alert: they are not. An inspection of data reveals that there is 3211 rows of dementia, 2397 rows of control Decision: Created pitt-7-4-bal and pitt-7-4-windowed-bal series of data based on dataprep.py on 703f79248a20fd7a13a5033ca2bf7f691f42c941. This version force-crops to make sure that the dementia and control indicies have the exact same length for each class. train: helpful-leaf-7 {bs: 4, epochs: 3, lr: 1e-5, length: 60, pitt-7-4-windowed-bal.dat}
Beautiful. Question now is whether or not there is data leakage/external heuristics. It is a good time to do some LOOCV. Getting this result without any disfluency calculations seems unlikely.
But anyways, going to discuss these results as they seem to meet results we see in Yuan 2021, even without top-N ensemble; though this is one trial, LOOCV may still show that we actually need it.
July 5th Began the day with creating the script k-fold validation; I originally hoped to exactly replicate the procedure of Yuan 2021 for comparability, but, not sure how they got the actual result of a min/max range with LOOCV on binary; therefore, we will instead create a 95% confidence interval analysis via a single-variable t test on standard k-fold validation. K=50 During one-off testing, another set of hyperparameters seems to work too: {bs: 72, epochs: 3, lr: 1e-5, length: 60, pitt-7-4-windowed-bal.dat}. As we have not begun tuning for hyperparameters, we are just going to use this set, K=50, for the first k-fold trial. k-fold: F4ZVbGfdBAQvtvXemWZCZD code: 55f77ff1dea03c3ed66967864dc52fd2c0062f23
{bs: 72, epochs: 3, lr: 1e-5, length: 60, pitt-7-4-windowed-bal.dat} K = 50
It seems like the results we got is consistent and validates in a manner which we expect.
July 7th Yesterday was a day filled with working on batchalign, but we are back now. Today, I aim to look into the heuristic that I identified yesterday by playing with the model, which is that it seems like the model prefers the use of long-focused sentences about cookies, so the heruistic its picking up is probably on-topicness.
I am going to first leverage the lovely cdpierse/transformers-interpret tool to help build some explainability by adding it to validate.py. Upon some human validation with random sampling, the model seem to do less well than I&rsquo;d hoped. Running a train cycle with the new results/params seen above to see if it does better.
train: brisk-oath-10 {bs: 72, epochs: 3, lr: 1e-5, length: 60, pitt-7-4-windowed-bal.dat}
Commentary: It seems like the model is doing overall worse from validation data, but it does fairly well during test data. Decision: I can fairly confidently claim that the model is just fitting on topic. As in, if the topic is about cookies (theft/taking/cookie/mother/etc.), it will be classified as control. One thing that we can do is to claim this task as directly task-controlled: that is, include no data except cookie and control for that difference Then, the model would&rsquo;t be able to predict the result b/c the variation in topic won&rsquo;t have influence. This is going to be prepared in the cookiepitt-7-7-bal* based on dataprep.py in commit 518dec82bb961c0a8ad02e3080289b56102aa1a2 train: super-durian-11 {bs: 72, epochs: 3, lr: 1e-5, length: 60, cookiepitt-7-7-windowed-bal.dat}
Commentary: the model is no where near convergence Decision: multiplying the LR by 10 train: floral-sunset-12 {bs: 72, epochs: 3, lr: 1e-4, length: 60, cookiepitt-7-7-windowed-bal.dat}
Commentary: There we go. This seem to be more in line with what we see in Yuan 2021 Decision: ok, let&rsquo;s elongate the actual content. Perhaps we can try a 7-element search instead? This is written as cookiepitt-7-7-*-long. Code based on 9e31f4bc13c4bfe193dcc049059c3d9bda46c8d0 train: sweet-plasma-13 {bs: 72, epochs: 3, lr: 1e-4, length: 60, cookiepitt-7-7-windowed-long-bal.dat}
Commentary: underfitting Dropping batch size down to 64 to add more steps train: smart-river-14 {bs: 64, epochs: 3, lr: 1e-4, length: 60, cookiepitt-7-7-windowed-long-bal.dat}
Commentary: this finally fits to the specifications which Yuan 2021 have revealed Decision: running k-fold on this architecture k-fold: XgsP4FVS6ScFxCZKFJoVQ5. Code: 3870651ba71da8ddb3f481a7c3e046397a09d8b2
July 8th Began the day with aligning the entirety of cookie for both control and dementia, named the dataset alignedpitt-7-8 in the RAW folder
Per what we discussed, will add [pause] as a token to the model. Then, transcript the text such that it would contain normalized values to the pauses for pauses &gt; 0.250 seconds. Therefore, the data would look like
&ldquo;hello my name is [pause] 262 [pause] bob&rdquo;
July 9th Created transcript.py, which coverts the data in raw to transcripts_pauses, which contains pause values &gt; 250 msc and prepends them with [pause] tokens The code from above is taken from check.py in batchalign, used transcript.py from 7e19a4912cf0ad5d269c139da5ce018615495ebb to clean out the dataset; placed it in similar txt format to alignedpitt-7-8 Ran dataprep with window size of 5, created alignedpitt-7-8.bat and alignedpitt-7-8-windowed.bat as the dataprep file starting a new training run, with [pause] added as a new token, code 06846c6c95e6b1ccf17f0660c5da76aa50231567 train: golden-tree-16 {bs: 64, epochs: 3, lr: 1e-4, length: 60, alignedpitt-7-8-windowed.dat}
So realistically, we have the same F1 between the two, but pause encoding increased the accuracy of prediction yet dropped recall dramatically.
As a random check, let&rsquo;s find out if simple fine-tuning (only training on classifier) would work, so:
train: jumping-blaze-17 {bs: 64, epochs: 3, lr: 1e-4, length: 60, alignedpitt-7-8-windowed.dat}. This time with only training classifier.
Commentary: we did not like. start coverging Bumping LR by a factor of 10 train: vital-water-18 {bs: 64, epochs: 3, lr: 1e-3, length: 60, alignedpitt-7-8-windowed.dat}. This time with only training classifier.
Commentary: barely started converging, seem to be a local Training for 2 more epochs train: fiery-smoke-19 {bs: 64, epochs: 5, lr: 1e-3, length: 60, alignedpitt-7-8-windowed.dat}. This time with only training classifier.
Commentary: classic overfitting At this point, unlocking the model would probably be a good bet
train: leafy-deluge-20 {bs: 64, epochs: 5, lr: 1e-4, length: 60, alignedpitt-7-8-windowed.dat}.
Training once again with code without locking, and bump LR down
Commentary: classic the recall is slowly creeping up Decision: let&rsquo;s go for 8 epochs train: royal-pond-21 {bs: 64, epochs: 8, lr: 1e-4, length: 60, alignedpitt-7-8-windowed.dat}.
Commentary: let&rsquo;s run k-fold now, with these settings.
k-fold: QskZWfEsML52ofcQgGujE2. {bs: 64, epochs: 8, lr: 1e-4, length: 60, alignedpitt-7-8-windowed.dat}.
Ok, the base hypothesis from Yuan 2021 is very much confirmed here. The same training, same content, but pause encoding is very beneficial to the quality of the results. The results that they reported contained an ensemble data, which is in the high 80s; we can now continue doing something new as Yuan 2021&rsquo;s conclusion is fairly achieved.
We can probably call the replication stage done, with no dramatically better effect.
July 10th FluCalc! Leonid&rsquo;s lovely new program can be an uberuseful feature extraction tool Let&rsquo;s try using to build a new dataset, and network. FluCalc + Pause Encoding + Textual Data late fusion This is becoming alignedpitt-7-8-flucalc. As the program is currently under heavy development to include results from batchalign, we will specify version V 09-Jul-2022 11:00 for now. Done, the new data has the same i/o shape, but then has a bunch of features filtered for nulls which contains outputs from flucalc. Again, alignedpitt-7-8-flucalc from 4346fc07c4707343c507e32786b6769b6bd6fb49 does not take into account results from the %wor tier! July 11th ab19abd6486884141c9ab4e4e185255a77ae833e is the final-ish version of the late fusion model We are going to use alignedpitt-7-8-flucalc to start training train: royal-pond-21 {bs: 64, epochs: 8, lr: 1e-4, length: 60, alignedpitt-7-8-flucalc-windowed.dat}.
Commentary: overfitting Decision, droping lr by a factor of 10, also increasing length to 70 train: fallen-dust-25 {bs: 64, epochs: 8, lr: 1e-5, length: 70, alignedpitt-7-8-flucalc-windowed.dat}.
Commentary: overfitting Decision, droping lr by a factor of 10, dropping batch size to 32, training more to 10 train: dainty-meadow-26 {bs: 32, epochs: 10, lr: 1e-6, length: 70, alignedpitt-7-8-flucalc-windowed.dat}.
ah
At this point, I think it&rsquo;d be good to do some feature selection Let&rsquo;s do a chi^2 correlation, and select 3 best features import pandas as pd DATA = &#34;/Users/houliu/Documents/Projects/DBC/data/transcripts_pauses/alignedpitt-7-8-flucalc-windowed.bat&#34; # read pickle df = pd.read_pickle(DATA) # test test_data = df[df.split==&#34;test&#34;] # also, get only train data df = df[df.split==&#34;train&#34;] df target mor_Utts ... split utterance trial sample ... 120-2 1049 1 -0.179084 ... train well the boy is getting some cookies handing o... 336-1 2492 0 -0.481740 ... train +oh okay, the the little girl askin(g) for the... 076-4 786 1 -0.179084 ... train well the little boy was looking at that cookie... 279-0 2250 1 1.980274 ... train kid&#39;s stool turnin(g) [pause]540[pause] over s... 014-2 151 1 0.746355 ... train he&#39;s fallin(g) off the chair down here or try... ... ... ... ... ... ... 208-0 1655 0 -0.481740 ... train the boy [pause]920[pause] is going after [paus... 492-0 2696 1 -0.179084 ... train oh yes quite a_lot the kid&#39;s tryin(g) to get t... 497-1 2727 1 0.129396 ... train what else ? &amp;uh the see the [pause]2400[pause]... 175-2 1535 0 0.863668 ... train the window is open you can see out the curtain... 279-0 2261 1 1.980274 ... train the other kid with [pause]610[pause] the stool... [2848 rows x 44 columns] Let&rsquo;s slice out the bits which is labels, etc.
in_data = df.drop(columns=[&#34;utterance&#34;, &#34;target&#34;, &#34;split&#34;]) in_data.columns Index([&#39;mor_Utts&#39;, &#39;mor_Words&#39;, &#39;mor_syllables&#39;, &#39;#_Prolongation&#39;, &#39;%_Prolongation&#39;, &#39;#_Broken_word&#39;, &#39;%_Broken_word&#39;, &#39;#_Block&#39;, &#39;%_Block&#39;, &#39;#_PWR&#39;, &#39;%_PWR&#39;, &#39;#_PWR-RU&#39;, &#39;%_PWR-RU&#39;, &#39;#_WWR&#39;, &#39;%_WWR&#39;, &#39;#_mono-WWR&#39;, &#39;%_mono-WWR&#39;, &#39;#_WWR-RU&#39;, &#39;%_WWR-RU&#39;, &#39;#_mono-WWR-RU&#39;, &#39;%_mono-WWR-RU&#39;, &#39;Mean_RU&#39;, &#39;#_Phonological_fragment&#39;, &#39;%_Phonological_fragment&#39;, &#39;#_Phrase_repetitions&#39;, &#39;%_Phrase_repetitions&#39;, &#39;#_Word_revisions&#39;, &#39;%_Word_revisions&#39;, &#39;#_Phrase_revisions&#39;, &#39;%_Phrase_revisions&#39;, &#39;#_Pauses&#39;, &#39;%_Pauses&#39;, &#39;#_Filled_pauses&#39;, &#39;%_Filled_pauses&#39;, &#39;#_TD&#39;, &#39;%_TD&#39;, &#39;#_SLD&#39;, &#39;%_SLD&#39;, &#39;#_Total_(SLD+TD)&#39;, &#39;%_Total_(SLD+TD)&#39;, &#39;Weighted_SLD&#39;], dtype=&#39;object&#39;) And the labels:
out_data = df[&#34;target&#34;] out_data trial sample 120-2 1049 1 336-1 2492 0 076-4 786 1 279-0 2250 1 014-2 151 1 .. 208-0 1655 0 492-0 2696 1 497-1 2727 1 175-2 1535 0 279-0 2261 1 Name: target, Length: 2848, dtype: int64 And now, let&rsquo;s select 3 best features.
from sklearn.feature_selection import SelectKBest, f_classif k_best_tool = SelectKBest(f_classif, k=3) k_best_tool.fit(in_data, out_data) best_features = k_best_tool.get_feature_names_out() best_features %_WWR %_mono-WWR %Total(SLD+TD) OD = other disfluencies; SLD = stuttering-like disfluencies; TD = total disfluencies; WWR = whole-word-repetition
ok, let&rsquo;s select those features
train: visionary-plasma-27 {bs: 32, epochs: 10, lr: 1e-6, length: 70, alignedpitt-7-8-flucalc-windowed.dat}. Also with feature selection.
hmmm.
I am curious if we just ran something like a decision tree, what happens.
in_features = df.drop(columns=[&#34;utterance&#34;, &#34;target&#34;, &#34;split&#34;]) test_features = test_data.drop(columns=[&#34;utterance&#34;, &#34;target&#34;, &#34;split&#34;]) in_targets = df[&#34;target&#34;] test_targets = test_data[&#34;target&#34;] seed the classifier, and fit.
from sklearn.ensemble import RandomForestClassifier clsf = RandomForestClassifier() clsf.fit(in_features, in_targets) clsf.score(test_features, test_targets) 0.5932203389830508 OK nevermind. What about SVC?
from sklearn.svm import SVC clsf = SVC() clsf.fit(in_features, in_targets) clsf.score(test_features, test_targets) 0.5932203389830508 Turns out, deep learning still does better. I&rsquo;m thinking maybe the output is being faulty, say, for something like the loss function.
Decision: switching activation to sigmoid.
train: sunny-bush-31 {bs: 32, epochs: 10, lr: 1e-6, length: 70, alignedpitt-7-8-flucalc-windowed.dat}, selected features
Ok let&rsquo;s think about this. Decision: added batch normalization.
train: autumn-jazz-32 {bs: 32, epochs: 10, lr: 1e-6, length: 70, alignedpitt-7-8-flucalc-windowed.dat}, selected features
The model maybe overfitting on some simple heuristic; some basic statistics revealed that these variables are actually quite differently distributed.
Perhaps we should increase the complexity of the model?
train: fallen-microwave-33 {bs: 32, epochs: 10, lr: 1e-6, length: 70, alignedpitt-7-8-flucalc-windowed.dat}, selected features
Just to test, I am bumping the LR to 1e-5, just to see what happens. I am very confused.
train: upbeat-flower-35 {bs: 32, epochs: 10, lr: 1e-5, length: 70, alignedpitt-7-8-flucalc-windowed.dat}, selected features
The more we work on this, the more overfit it gets. (I FORGOT A RELUCTIFIER)
a note {bs: 32, epochs: 10, lr: 1e-5, length: 70, alignedpitt-7-11-flucalc-windowed.dat}, selected features
Pauses, no meta:
Pauses, meta:
so effectively cointoss
Concerns and Questions July 2nd pitt7-1/dementia/493-0 PAR tier &ldquo;tell me everything you see going on in that picture&rdquo; doesn&rsquo;t seem to be labeled correctly; I am guessing that&rsquo;s supposed to be INV? Has anyone tried to include investigator/participant cross-dialogue? July 4th Is the model overfitting on antiquated language? Is the model overfitting on cooke-theft on-topic-ness? July 11th LSTM only on pauses?
