UlysseCoteAllard / MyoArmbandDataset

GNU General Public License v3.0
84 stars 40 forks source link

What does the shift_electrodes function do? #14

Open Openyoureyes-Li opened 1 year ago

Openyoureyes-Li commented 1 year ago

Hello, the shift_electrodes function are defined in load_pre_training_dataset.py and load_evaluation_dataset.py files, What does this function do?

def shift_electrodes(examples, labels): index_normal_class = [1, 2, 6, 2] # The normal activation of the electrodes. class_mean = []

For the classes that are relatively invariant to the highest canals activation, we get on average for a

# subject the most active cannals for those classes
for classe in range(3, 7):
    X_example = []
    Y_example = []
    for k in range(len(examples)):
        X_example.extend(examples[k])
        Y_example.extend(labels[k])

    cwt_add = []
    for j in range(len(X_example)):
        if Y_example[j] == classe:
            if cwt_add == []:
                cwt_add = np.array(X_example[j][0])
            else:
                cwt_add += np.array(X_example[j][0])
    class_mean.append(np.argmax(np.sum(np.array(cwt_add), axis=0)))

# We check how many we have to shift for each channels to get back to the normal activation
new_cwt_emplacement_left = ((np.array(class_mean) - np.array(index_normal_class)) % 10)
new_cwt_emplacement_right = ((np.array(index_normal_class) - np.array(class_mean)) % 10)

shifts_array = []
for valueA, valueB in zip(new_cwt_emplacement_left, new_cwt_emplacement_right):
    if valueA < valueB:
        # We want to shift toward the left (the start of the array)
        orientation = -1
        shifts_array.append(orientation*valueA)
    else:
        # We want to shift toward the right (the end of the array)
        orientation = 1
        shifts_array.append(orientation*valueB)

# We get the mean amount of shift and round it up to get a discrete number representing how much we have to shift
# if we consider all the canals
# Do the shifting only if the absolute mean is greater or equal to 0.75
final_shifting = np.mean(np.array(shifts_array))
if abs(final_shifting) >= 0.5:
    final_shifting = int(np.round(final_shifting))
else:
    final_shifting = 0

# Build the dataset of the candiate with the circular shift taken into account.
X_example = []
Y_example = []
for k in range(len(examples)):
    sub_ensemble_example = []
    for example in examples[k]:
        sub_ensemble_example.append(np.roll(np.array(example), final_shifting))
    X_example.append(sub_ensemble_example)
    Y_example.append(labels[k])
return X_example, Y_example
MaginaDai commented 1 year ago

Hi, do you solve your problem? I don't understand this step as well.

UlysseCoteAllard commented 1 year ago

Hi,

The shift function is simply because participants could wear the EMG cuff in different orientations. This this function was a way to virtually align the cuffs of all participants based on some features that were most prevalent in a given channel (i.e. if the signal was most prevalent in channel 3 for participant and given a reference gesture while it was more prevalent in channel 5 for another participant, we virtually shift them so that the signal end up being at approximately the same orientation.)

Honestly, you don't need to use this function, the network during the pre-training should be able to learn a meaningful feature space to have good inference over the different participants and the fine-tuning step with the participant you are interested to do control with should also take care of any shift.

tl;dr, I don't use that type of functions anymore because I did not find it to really impact anything in practice.

MaginaDai commented 1 year ago

Hi, now I understand your motivation for this function, and I agree with you that the neural networks might have the ability to align them without this function. But back on this function (just for discussion), np.roll would shift the data along the time axis. That means the data at one timestamp will be rolled to another timestamp. However, I think the alignment wants to roll the data from one channel to another channel. Thus I guess the axis is selected wrongly. What's your idea?

Best Gaole Dai

UlysseCoteAllard commented 1 year ago

Hi,

Yes indeed, the np.roll is supposed to affect the channel axis and not the time axis. From memory, I had the shape of the matrix correctly to affect the channel axis and not the temporal one, but I of course can be wrong (I unfortunately do not have the code setup on my computer to be able to rapidly check). So thank you for raising this flag :)

All the best, Ulysse