-
Notifications
You must be signed in to change notification settings - Fork 34
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
RSVP Copy Phrase Simulator #315
Conversation
…ype being a DataFrame rather than a List[Series]
…ided DataEngine with a query interface to allow the engine to abstract out the details about how the data is stored. Added a mechanism to the Copy Phrase simulation Task to match SignalModels to Samplers and used this in the compute_device_evidence method to support gathering evidence from multiple sources.
Multimodal simulator
Simulator Cleanup
"""Query the data.""" | ||
|
||
|
||
def convert_trials(data_source: ExtractedExperimentData) -> List[Trial]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this method also provide a list of Inquiries? Or, can it leave the structure as-is if the data is extracted by inquiries already? (Inquiries would later be useful for gaze simulation)
trials = self.sample(state) | ||
return self.reshaped(trials) | ||
|
||
def sample_with_context(self, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the context here include the information about where the sample is taken from (e.g. experiment #, trigger #) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's the idea. I expect some of this will require refinement when we implement the specifics for Gaze.
return model.metadata.evidence_type or DEFAULT_EVIDENCE_TYPE | ||
|
||
|
||
class SimulatorCopyPhraseTask(RSVPCopyPhraseTask): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like the clear method names here.
|
||
for model in self.signal_models: | ||
sampler = self.samplers[model] | ||
# This assumes that sampling is independent. Changes to the sampler API are needed if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does that mean we assume a uniform LM throughout the simulation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The language model evidence gets added in a different method (in the copy phrase wrapper initialize_series
). This method specifically gets evidence from devices. So any language model can be configured for simulation.
def exit_display(self) -> None: | ||
"""Close the UI and cleanup.""" | ||
|
||
def elapsed_seconds(self) -> float: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to estimate the just the computation time per symbol selection / next symbol querying? I think it would be more realistic if the formula here becomes something like: elapsed_time = inquiry_length + computation_time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The computation of time is surprisingly complicated. There is an estimate in the acquisition helper for how much time an inquiry will take (for acquisition buffering purposes), but there are some confounding factors. I will create a followup ticket because I want to give this more thought and perhaps provide a way for this to be configured.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! The class names and methods are much more clear after cleanup/refactoring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a considerable feature addition! Thank you for carrying this over for us. It seems beneficial enough to add some documentation to the main README and potentially to the install script itself for top-level client use.
entry_points={
'console_scripts': ['bcipy = bcipy.main:bcipy_main', 'bcipy-sim = bcipy.simulator'],
}
# OR if removing __main__
entry_points={
'console_scripts': ['bcipy = bcipy.main:bcipy_main', 'bcipy-sim = bcipy.simulator.task.task_runner:main'],
},
Then one could use,
bcipy-sim <args>
@@ -401,12 +401,11 @@ def __call__(self, | |||
return np.stack(reshaped_trials, 1), targetness_labels | |||
|
|||
|
|||
def update_inquiry_timing(timing: List[List[float]], downsample: int) -> List[List[float]]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would want to update the expected return from our reshapers to make this compatible. I think this is still correct, given we expect a sample instead of a time at this stage?
bcipy/simulator/README.md
Outdated
|
||
* Only provides EEG support | ||
* Only one sampler maybe provided for all devices. Ideally we should support a different sampling strategy for each device. | ||
* Only the RSVP Copy Phrase may be simulated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You list Matrix CopyPhrase in the documentation, and if this is true, we should update the example above to avoid confusion. It seems like we could do MatrixCopyPhrase?
@@ -0,0 +1,6 @@ | |||
""" Entry point to run Simulator """ | |||
|
|||
from bcipy.simulator.task import task_runner |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this behavior needed? I try to avoid putting functionality in init or main as much as possible since it can be harder to trace and understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allows you to run the module. It's not necessary, but if not here I would change the usage instructions. I don't have a preference here so I'm fine changing it.
bcipy/simulator/data/data_engine.py
Outdated
eeg - EEG data associated with this trial | ||
""" | ||
source: str | ||
# series_n: int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove?
for querying the processed data.""" | ||
|
||
def load(self): | ||
"""Load data from sources.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not necessary, but often we use the ...
when no return is set.
'feedback_stim_height': self.parameters['info_height'], | ||
'feedback_duration': self.parameters['feedback_duration']}, | ||
self.experiment_clock) | ||
self.feedback = self.init_feedback() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this too!
if save: | ||
self.write_session_data() | ||
if decision_made: | ||
self.session.add_series() | ||
|
||
def elapsed_seconds(self) -> float: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏼
DEFAULT_DEVICE_SPEC_FILENAME, | ||
) | ||
from bcipy.helpers.acquisition import analysis_channels | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that we can still use this script, but I do worry about its long-term survival. Could we add a replay feature to the simulator? It would permit slightly different questions and add a sampling strategy. The visualization was also beneficial (and the most used to communicate outwardly) and, I think, could be used more generally in the simulator output.
I'd be okay with deprecating this script (and most others) before the 2.0 release, even if it can't be rolled in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't actually make any changes to this script, but saving it organized the imports in my editor. Replicating this behavior should be fairly easy to do in the simulator. I think it's just a matter of having a stateful sampler.
|
||
bcipy/simulator/tests/resource/ | ||
!bcipy/simulator/data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have /data
earlier in the file, but this was too general and ignoring the data module in the simulator directory. The !
indicates not, so don't ignore this one.
`main.py` is the entry point for program. After following `BciPy` readme steps for setup, run the module from terminal: | ||
|
||
``` | ||
(venv) $ python bcipy/simulator -h |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would want to document other clients here or in a linked README (ex. helpers/state). Otherwise, we could move those clients to a demo if they will not be used often.
Overview
BciPy Simulator infrastructure.
Issues
https://www.pivotaltracker.com/story/show/185958637
Discussion
See the README for usage information, key components, and current limitations.