Пример #1
0
def test_run():
    trial = lambda logger: None
    blocks = [[trial], [trial, trial]]
    info = {'id': 'test'}

    session = Session(info, blocks)
    session.run()
Пример #2
0
def test_hide_trial():
    blocks = [[lambda logger: logger.hide_trial()],
              [
                  lambda logger: logger.log({2: 2}, save_to_file=False),
                  lambda logger: logger.log({3: 3}, save_to_file=False)
              ]]
    info = {'id': 'test'}

    session = Session(info, blocks)
    session.run()

    assert session.log_history[0][0] == dict()
    assert session.log_history[1][0] == {'2': 2}
    assert session.log_history[1][1] == {'3': 3}
Пример #3
0
def test_save_hidden():
    blocks = [[lambda logger: logger.hide_trial()],
              [
                  lambda logger: logger.log({2: 2}),
                  lambda logger: logger.log({3: 3})
              ]]
    info = {'id': 'test'}

    session = Session(info, blocks)
    session.run()

    with open('idtest.csv') as f:
        with open('tests/test_data/hidref.csv') as ref:
            assert f.read() == ref.read()

    os.remove('idtest.csv')
Пример #4
0
def TrainingSession(win, iterations: int, trials_per_iteration: int, clf=WrappedCSPLDAClassifier(), trial_duration=4, sampling_rate=500, data_channels=list(range(20)), window_size=500, step_size=100, eeg_source_id='myuid323457', eeg_stream_no=0, resolution=6):
    
    def kill(logger):
        logger.hide_trial()
        info = logger.info
        # save data
        # save data, labels to file
        np.save('data.npy', info['data'])
        np.save('labels.npy', np.array(info['labels']))

        # kill old classifier (if there is one)
        if 'cproc' in info and info['cproc']:
            info['cproc'].kill()
            info['cproc'].join()
            info['cproc'].close()
            
            
    def collect(logger):
        print('starting collect trial')
        info = logger.info

        # ask to start
        text_stim.text = 'Press any key to start.'
        text_stim.draw()
        window.flip()
        event.waitKeys()
        window.flip()
        # 2 sec delay
        core.wait(2)
        # loop for 4 seconds neurofeedback, start recording eeg data
        trial_data = []
        predict_probas = []
        clock = core.Clock()
        print('starting trial loop')
        # wait until classifier process is ready to start classifying
        info['cinlet'].pull_sample()
        # clear eeg lsl buffer
        info['eeg_inlet'].pull_chunk(max_samples=int(1e6))
        while clock.getTime() < info['trial_duration'] or len(trial_data) < info['samples_per_trial']:
            # neurofeedback
            prob = info['cinlet'].pull_sample()[0][0] # sample = [[prob], timestamp]
            # print('pulled sample:', prob)
            nf_stim.draw(prob)
            window.flip()
            trial_data = trial_data + info['eeg_inlet'].pull_chunk()[0]
            predict_probas.append(prob)


        # ask for label
        text_stim.text = 'Which side were you imagining? press 1 for left and 0 for right'
        text_stim.draw()
        window.flip()
        key = event.waitKeys(keyList=['0', '1'])
        label = int('0' in key)

        # append label and data to info
        # change trial data to mne's CSP input format
        print('untrimmed trial_data shape:', np.array(trial_data).shape)

        trial_data = np.transpose(np.array(trial_data)[:info['samples_per_trial'],info['data_channels']])
        print('trial_data shape:', trial_data.shape)
        info['data'] = np.vstack((info['data'], [trial_data]))
        info['labels'].append(label)
        print('[collect]: data shape:', np.array(info['data']).shape)
        # log true label and list of predict proba
        logger.log({'label': label, 'predict_probas': predict_probas})

    def train(logger):
        logger.hide_trial()
        info = logger.info
        # kill old classifier (if there is one)
        if 'cproc' in info and info['cproc']:
            info['cproc'].kill()
            info['cproc'].join()
            info['cproc'].close()
        # split data into the right size chunks for clf input
        print('[train]: data shape:', np.array(info['data']).shape)
        gc.collect()
        data, labels = get_windows(np.array(info['data']), np.array(info['labels']), info['window_size'], step_size=100)
        print('windowed data shape:', data.shape)
        # re-train model
        info['clf'].fit(data, labels)
        # re-start classifier process
        info['cproc'] = ClassifierProcess(info['clf'], info['eeg_source_id'], window_size=info['window_size'], stream_no=info['eeg_stream_no'])
        info['cproc'].start()

        # make new classifier inlet in case the previos timed out
        info['cinlet'] = ClassifierInlet()
        gc.collect()
        
        # save data, labels to file
        np.save('data.npy', info['data'])
        np.save('labels.npy', np.array(info['labels']))
    
    
    
    
    
    
    window = win
    text_stim = visual.TextStim(window)
    nf_stim = NeuroFeedbackStim(window, resolution)

    samples_per_trial = trial_duration*sampling_rate
    info = {
        'clf': clf,
        'trial_duration': trial_duration,
        'window_size': window_size,
        'eeg_source_id': eeg_source_id,
        'eeg_stream_no': eeg_stream_no,
        'sampling_rate': sampling_rate,
        'samples_per_trial': samples_per_trial,
        'data_channels': data_channels,
        'data': np.empty((0,len(data_channels), samples_per_trial)), # [NOTE]: parameterize or somehow integrate this
        'labels': []
    }

    
    # initialise eeg inlet
    print('looking for eeg stream...')
    streams = resolve_stream('source_id', eeg_source_id)
    info['eeg_inlet'] = StreamInlet(streams[eeg_stream_no])
    print('found')

    ########## INITIALIZE CLASSIFIER ##########
    # train initial classifier on noise
    print('collecting noise...')
    trial_data = []
    clock = core.Clock()
    while clock.getTime() < info['trial_duration']*2 or len(trial_data) < samples_per_trial*2:
        chunk = info['eeg_inlet'].pull_chunk()[0]
        # print('chunk shape:', np.array(chunk).shape)
        trial_data = trial_data + chunk

    # crop noise
    trial_data = np.array(trial_data)
    print('trail data shape:', trial_data.shape)
    trial_data = trial_data[:,data_channels]
    trial_data = trial_data[:samples_per_trial*2]
    # split, transpose and label noise arbitrarily
    data = np.array([ np.transpose(trial_data[:samples_per_trial]), np.transpose(trial_data[-samples_per_trial:]) ])
    labels = np.array([1,0])
    # just partitioning this won't give enough data to run csp, so we'll run a sliding window over it
    data, labels = get_windows(data, labels, window_size, step_size)
    # train classifier on noise
    print('training initial classifier on noise...')
    print('data shape:', data.shape)
    print('labels shape:', labels.shape)
    clf.fit(data, labels)
    ########## INITIALIZE CLASSIFIER ##########


    # start running the classifier process
    print('starting classifier process')
    info['cproc'] = ClassifierProcess(info['clf'], info['eeg_source_id'], window_size=info['window_size'], stream_no=info['eeg_stream_no'])
    info['cproc'].start()

    # initialise classifier inlet
    print('initialising cinlet')
    info['cinlet'] = ClassifierInlet()


    # make and return session
    blocks = [[collect]*trials_per_iteration] + [ [train], [collect]*trials_per_iteration ]*(iterations-1) + [[kill]]
    return Session(info, blocks, use_json=True, hide_info=True)
Пример #5
0
def TrainingSession(win,
                    iterations: int,
                    trials_per_iteration: int,
                    clf=WrappedCSPLDAClassifier(),
                    trial_duration=4,
                    sampling_rate=500,
                    data_channels=list(range(20)),
                    window_size=500,
                    step_size=100,
                    eeg_source_id='myuid323457',
                    eeg_stream_no=0,
                    resolution=6):
    """Returns a Session object that runs an iterative training session.

    The returned Session performs a block of neurofeedback trials, then re-trains the classifier on the newly collected data and runs a new block of neurofeedback trials. The EEG data, classifier predictions and true labels are saved to files. The defaults of this function are suitable for dry EEG
    
    Parameters
    ----------
    win : psychopy.visual.Window()
        window in which the session will occur
    iterations : int
        number of blocks/ number of times the classifier is re-trained on new data
    trials_per_iteration : int
        number of trials per block
    clf : classifier object compatible with BIpy.bci.ClassifierProcess()
        the classifier used to predict left/right motor imagery
    trial_duration : int, default 4
        duration in seconds of each trial
    sampling_rate : int, default 500
        sampling rate of data sent to the EEG lsl stream
    data_channels : list, default 0 through 19
        indeces of the electrode channels the classifier should use as input
    window_size: int, default 500
        number of samples the given classifier should take as input at once
    step_size : int, default 100
        the given classifier is trained on multiple windows spanning the data collected in one trial. step_size is the gap (in samples) between the start of each window.
        if one trial contains 800 samples of eeg data, the window size is 400 and the step size is 200, then the classifier will be trained using 3 windows for each trial: samples 0-400, 200-600, and 400-800
        the window size, step size and samples per trial need not line up perfectly, all data will be used for training regardless (but the last step size will differ from the rest)
    eeg_source_id : str, default 'myuid323457'
        Pylsl stream source_id of incoming eeg data to be fed to the classifier
        Default myuid323457 - dry EEG, for ActiChamp use 17010768
    eeg_stream_no : int, default 0
        Index of the stream. Should be 0 or 1, ask Tian for help on this
    resolution : int, default 6
        number of segments in on each side of the BIpy.bci.stims.NeuroFeedbackStim displayed on screen


    Output
    ------
    BIpy.Session Object
    
    """
    def kill(logger):
        logger.hide_trial()
        info = logger.info
        # save data
        # save data, labels to file
        np.save('data.npy', info['data'])
        np.save('labels.npy', np.array(info['labels']))

        # kill old classifier (if there is one)
        if 'cproc' in info and info['cproc']:
            info['cproc'].kill()
            info['cproc'].join()
            info['cproc'].close()

    def collect(logger):
        # print('starting collect trial')
        info = logger.info

        # ask to start
        text_stim.text = 'Press any key to start.'
        text_stim.draw()
        window.flip()
        event.waitKeys()
        text_stim.text = 'Buffering...'
        text_stim.draw()
        window.flip()
        # 2 sec delay
        core.wait(2)
        # loop for 4 seconds neurofeedback, start recording eeg data
        trial_data = []
        predict_probas = []
        clock = core.Clock()
        # print('starting trial loop')
        # wait until classifier process is ready to start classifying
        info['cinlet'].pull_sample()
        # clear eeg lsl buffer
        info['eeg_inlet'].pull_chunk(max_samples=int(1e6))
        while clock.getTime() < info['trial_duration'] or len(
                trial_data) < info['samples_per_trial']:
            # neurofeedback
            prob = info['cinlet'].pull_sample()[0][
                0]  # sample = [[prob], timestamp]
            # print('pulled sample:', prob)
            nf_stim.draw(prob)
            window.flip()
            trial_data = trial_data + info['eeg_inlet'].pull_chunk()[0]
            predict_probas.append(prob)

        # ask for label
        text_stim.text = 'Which side were you imagining? press 1 for left and 0 for right'
        text_stim.draw()
        window.flip()
        key = event.waitKeys(keyList=['0', '1'])
        label = int('0' in key)

        # append label and data to info
        # change trial data to mne's CSP input format
        # print('untrimmed trial_data shape:', np.array(trial_data).shape)

        trial_data = np.transpose(
            np.array(trial_data)[:info['samples_per_trial'],
                                 info['data_channels']])
        # print('trial_data shape:', trial_data.shape)
        info['data'] = np.vstack((info['data'], [trial_data]))
        info['labels'].append(label)
        # print('[collect]: data shape:', np.array(info['data']).shape)
        # log true label and list of predict proba
        logger.log({'label': label, 'predict_probas': predict_probas})

    def train(logger):
        logger.hide_trial()
        info = logger.info

        text_stim.text = 'Training classifier...'
        text_stim.draw()
        window.flip()

        # kill old classifier (if there is one)
        if 'cproc' in info and info['cproc']:
            info['cproc'].kill()
            info['cproc'].join()
            info['cproc'].close()
        # split data into the right size chunks for clf input
        # print('[train]: data shape:', np.array(info['data']).shape)
        gc.collect()
        data, labels = get_windows(np.array(info['data']),
                                   np.array(info['labels']),
                                   info['window_size'],
                                   step_size=100)
        # print('windowed data shape:', data.shape)
        # re-train model
        info['clf'].fit(data, labels)
        # re-start classifier process
        info['cproc'] = ClassifierProcess(info['clf'],
                                          info['eeg_source_id'],
                                          window_size=info['window_size'],
                                          stream_no=info['eeg_stream_no'])
        info['cproc'].start()

        # make new classifier inlet in case the previos timed out
        info['cinlet'] = ClassifierInlet()
        gc.collect()

        # save data, labels to file
        np.save('data.npy', info['data'])
        np.save('labels.npy', np.array(info['labels']))

    window = win
    text_stim = visual.TextStim(window)
    nf_stim = NeuroFeedbackStim(window, resolution)

    samples_per_trial = trial_duration * sampling_rate
    info = {
        'clf': clf,
        'trial_duration': trial_duration,
        'window_size': window_size,
        'eeg_source_id': eeg_source_id,
        'eeg_stream_no': eeg_stream_no,
        'sampling_rate': sampling_rate,
        'samples_per_trial': samples_per_trial,
        'data_channels': data_channels,
        'data': np.empty((0, len(data_channels), samples_per_trial)),
        'labels': []
    }

    # initialise eeg inlet
    print('looking for eeg stream...')
    streams = resolve_stream('source_id', eeg_source_id)
    info['eeg_inlet'] = StreamInlet(streams[eeg_stream_no])
    print('found')

    ########## INITIALIZE CLASSIFIER ##########
    # train initial classifier on noise
    print('collecting noise...')
    trial_data = []
    clock = core.Clock()
    while clock.getTime() < info['trial_duration'] * 2 or len(
            trial_data) < samples_per_trial * 2:
        chunk = info['eeg_inlet'].pull_chunk()[0]
        # print('chunk shape:', np.array(chunk).shape)
        trial_data = trial_data + chunk

    # crop noise
    trial_data = np.array(trial_data)
    print('trail data shape:', trial_data.shape)
    trial_data = trial_data[:, data_channels]
    trial_data = trial_data[:samples_per_trial * 2]
    # split, transpose and label noise arbitrarily
    data = np.array([
        np.transpose(trial_data[:samples_per_trial]),
        np.transpose(trial_data[-samples_per_trial:])
    ])
    labels = np.array([1, 0])
    # just partitioning this won't give enough data to run csp, so we'll run a sliding window over it
    data, labels = get_windows(data, labels, window_size, step_size)
    # train classifier on noise
    print('training initial classifier on noise...')
    print('data shape:', data.shape)
    print('labels shape:', labels.shape)
    clf.fit(data, labels)
    ########## INITIALIZE CLASSIFIER ##########

    # start running the classifier process
    print('starting classifier process')
    info['cproc'] = ClassifierProcess(info['clf'],
                                      info['eeg_source_id'],
                                      window_size=info['window_size'],
                                      stream_no=info['eeg_stream_no'])
    info['cproc'].start()

    # initialise classifier inlet
    print('initialising cinlet')
    info['cinlet'] = ClassifierInlet()

    # make and return session
    blocks = [[collect] * trials_per_iteration
              ] + [[train], [collect] * trials_per_iteration
                   ] * (iterations - 1) + [[kill]]
    return Session(info, blocks, use_json=True, hide_info=True)