Repository: torcheeg/torcheeg (language: python)

Issue:
Refactor datasets



Discussion / hints:

Fix patch:
diff --git a/docs/source/torcheeg.datasets.rst b/docs/source/torcheeg.datasets.rst
index 3d644dd..883ec70 100644
--- a/docs/source/torcheeg.datasets.rst
+++ b/docs/source/torcheeg.datasets.rst
@@ -57,6 +57,7 @@ Customized Datasets
 
     NumpyDataset
     MNEDataset
+    FolderDataset
 
 Hooks
 ---------------------------------------------------------
diff --git a/torcheeg/datasets/functional/__init__.py b/torcheeg/datasets/functional/__init__.py
index 6a8dfd5..717e4a6 100644
--- a/torcheeg/datasets/functional/__init__.py
+++ b/torcheeg/datasets/functional/__init__.py
@@ -1,6 +1,2 @@
-from .emotion_recognition import *
-from .mne import mne_constructor
-from .numpy import numpy_constructor
-from .personal_identification import *
-from .ssvep import *
-from .hooks import *
\ No newline at end of file
+from .hooks import *
+from .operators import *
diff --git a/torcheeg/datasets/functional/emotion_recognition/__init__.py b/torcheeg/datasets/functional/emotion_recognition/__init__.py
deleted file mode 100644
index ed4312b..0000000
--- a/torcheeg/datasets/functional/emotion_recognition/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from .amigos import amigos_constructor
-from .deap import deap_constructor
-from .dreamer import dreamer_constructor
-from .mahnob import mahnob_constructor
-from .seed import seed_constructor
-from .seed_feature import seed_feature_constructor
-from .seed_iv import seed_iv_constructor
-from .seed_iv_feature import seed_iv_feature_constructor
-from .mped_feature import mped_feature_constructor
\ No newline at end of file
diff --git a/torcheeg/datasets/functional/emotion_recognition/amigos.py b/torcheeg/datasets/functional/emotion_recognition/amigos.py
deleted file mode 100644
index def6d19..0000000
--- a/torcheeg/datasets/functional/emotion_recognition/amigos.py
+++ /dev/null
@@ -1,259 +0,0 @@
-import os
-import re
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, List, Union
-
-import scipy.io as scio
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(file_name: str, root_path: str, chunk_size: int,
-                       overlap: int, num_channel: int, num_trial: int,
-                       skipped_subjects: List, num_baseline: int,
-                       baseline_chunk_size: int, before_trial: Union[Callable,
-                                                                     None],
-                       transform: Union[Callable, None],
-                       after_trial: Union[Callable, None], queue: Queue):
-    subject = int(re.findall(r'Data_Preprocessed_P(\d*).mat',
-                             file_name)[0])  # subject (40)
-
-    if subject in skipped_subjects:
-        return
-
-    data = scio.loadmat(os.path.join(root_path, file_name),
-                        verify_compressed_data_integrity=False)
-    samples = data['joined_data'][
-        0]  # trial (20), timestep(n*128), channel(17) (14 channels are EEGs)
-    # label file
-    labels = data['labels_selfassessment'][
-        0]  # trial (20), label of different dimensions ((1, 12))
-
-    write_pointer = 0
-
-    max_len = len(samples)
-    if not (num_trial <= 0):
-        max_len = min(len(samples), num_trial)
-
-    # loop for each trial
-    for trial_id in range(max_len):
-        # extract baseline signals
-        trial_samples = samples[trial_id]
-
-        # record the common meta info
-        trial_meta_info = {'subject_id': subject, 'trial_id': trial_id}
-        trial_rating = labels[trial_id][0]  # label of different dimensions (12)
-
-        # missing values
-        if (not sum(trial_samples.shape)) or (not sum(trial_rating.shape)):
-            # 3 of the participants (08,24,28<->32) of the previous experiment did not watch a set of 4 long affective
-            if sum(trial_samples.shape) != sum(trial_rating.shape):
-                print(
-                    f'[WARNING] Find EEG signals without labels, or labels without EEG signals. Please check the {trial_id + 1}-th experiment of the {subject}-th subject in the file {file_name}. TorchEEG currently skipped the mismatched data.'
-                )
-            continue
-
-        trial_samples = trial_samples.swapaxes(
-            1, 0)  # channel(17), timestep(n*128)
-        if before_trial:
-            trial_samples = before_trial(trial_samples)
-
-        for label_index, label_name in enumerate([
-                'arousal', 'valence', 'dominance', 'liking', 'familiarity',
-                'neutral', 'disgust', 'happiness', 'surprise', 'anger', 'fear',
-                'sadness'
-        ]):
-            trial_meta_info[label_name] = trial_rating[label_index]
-
-        # extract baseline signals
-        trial_baseline_sample = trial_samples[:num_channel, :
-                                              baseline_chunk_size *
-                                              num_baseline]  # channel(14), timestep(5*128)
-        trial_baseline_sample = trial_baseline_sample.reshape(
-            num_channel, num_baseline,
-            baseline_chunk_size).mean(axis=1)  # channel(14), timestep(128)
-
-        trial_queue = []
-
-        start_at = baseline_chunk_size * num_baseline
-        if chunk_size <= 0:
-            chunk_size = trial_samples.shape[1] - start_at
-
-        # chunk with chunk size
-        end_at = start_at + chunk_size
-        # calculate moving step
-        step = chunk_size - overlap
-
-        while end_at <= trial_samples.shape[1]:
-            clip_sample = trial_samples[:num_channel, start_at:end_at]
-
-            t_eeg = clip_sample
-            t_baseline = trial_baseline_sample
-            if not transform is None:
-                t = transform(eeg=clip_sample, baseline=trial_baseline_sample)
-                t_eeg = t['eeg']
-                t_baseline = t['baseline']
-
-            # put baseline signal into IO
-            if not 'baseline_id' in trial_meta_info:
-                trial_base_id = f'{file_name}_{write_pointer}'
-                queue.put({'eeg': t_baseline, 'key': trial_base_id})
-                write_pointer += 1
-                trial_meta_info['baseline_id'] = trial_base_id
-
-            clip_id = f'{file_name}_{write_pointer}'
-            write_pointer += 1
-
-            # record meta info for each signal
-            record_info = {
-                'start_at': start_at,
-                'end_at': end_at,
-                'clip_id': clip_id
-            }
-            record_info.update(trial_meta_info)
-            if after_trial:
-                trial_queue.append({
-                    'eeg': t_eeg,
-                    'key': clip_id,
-                    'info': record_info
-                })
-            else:
-                queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-            start_at = start_at + step
-            end_at = start_at + chunk_size
-
-        if len(trial_queue) and after_trial:
-            trial_queue = after_trial(trial_queue)
-            for obj in trial_queue:
-                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def amigos_constructor(root_path: str = './data_preprocessed',
-                       chunk_size: int = 128,
-                       overlap: int = 0,
-                       num_channel: int = 14,
-                       num_trial: int = 16,
-                       skipped_subjects: List[int] = [
-                           9, 12, 21, 22, 23, 24, 33
-                       ],
-                       num_baseline: int = 5,
-                       baseline_chunk_size: int = 128,
-                       before_trial: Union[None, Callable] = None,
-                       transform: Union[None, Callable] = None,
-                       after_trial: Union[Callable, None] = None,
-                       io_path: str = './io/amigos',
-                       io_size: int = 10485760,
-                       io_mode: str = 'lmdb',
-                       num_worker: int = 0,
-                       verbose: bool = True) -> None:
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # loop to access the dataset files
-    file_list = os.listdir(root_path)
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(file_list))
-        pbar.set_description("[AMIGOS]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-
-        partial_mp_fn = partial(transform_producer,
-                                root_path=root_path,
-                                chunk_size=chunk_size,
-                                overlap=overlap,
-                                num_channel=num_channel,
-                                num_trial=num_trial,
-                                skipped_subjects=skipped_subjects,
-                                num_baseline=num_baseline,
-                                baseline_chunk_size=baseline_chunk_size,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, file_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-
-    else:
-        for file_name in file_list:
-            transform_producer(file_name=file_name,
-                               root_path=root_path,
-                               chunk_size=chunk_size,
-                               overlap=overlap,
-                               num_channel=num_channel,
-                               num_trial=num_trial,
-                               skipped_subjects=skipped_subjects,
-                               num_baseline=num_baseline,
-                               baseline_chunk_size=baseline_chunk_size,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/emotion_recognition/bci2022.py b/torcheeg/datasets/functional/emotion_recognition/bci2022.py
deleted file mode 100644
index 7fa538b..0000000
--- a/torcheeg/datasets/functional/emotion_recognition/bci2022.py
+++ /dev/null
@@ -1,310 +0,0 @@
-import os
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, List, Union
-
-import joblib
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-FIRST_BATCH_CHANNEL = [
-    'FP1', 'FP2', 'FZ', 'F3', 'F4', 'F7', 'F8', 'FC1', 'FC2', 'FC5', 'FC6',
-    'CZ', 'C3', 'C4', 'T7', 'T8', 'A1', 'A2', 'CP1', 'CP2', 'CP5', 'CP6', 'PZ',
-    'P3', 'P4', 'P7', 'P8', 'PO3', 'PO4', 'OZ', 'O1', 'O2'
-]
-
-SECOND_BATCH_CHANNEL = [
-    'FP1', 'FP2', 'FZ', 'F3', 'F4', 'F7', 'F8', 'FC1', 'FC2', 'FC5', 'FC6',
-    'CZ', 'C3', 'C4', 'T7', 'T8', 'CP1', 'CP2', 'CP5', 'CP6', 'PZ', 'P3', 'P4',
-    'P7', 'P8', 'PO3', 'PO4', 'OZ', 'O1', 'O2', 'A2', 'A1'
-]
-
-FIRST_TO_SECOND_ORDER = [
-    FIRST_BATCH_CHANNEL.index(c) for c in SECOND_BATCH_CHANNEL
-]
-
-VALENCE_DICT = {
-    1: -1,  # negative
-    2: -1,
-    3: -1,
-    4: -1,
-    5: -1,
-    6: -1,
-    7: -1,
-    8: -1,
-    9: -1,
-    10: -1,
-    11: -1,
-    12: -1,
-    13: 0,  # neutral
-    14: 0,
-    15: 0,
-    16: 0,
-    17: 1,  # positive
-    18: 1,
-    19: 1,
-    20: 1,
-    21: 1,
-    22: 1,
-    23: 1,
-    24: 1,
-    25: 1,
-    26: 1,
-    27: 1,
-    28: 1
-}
-
-EMOTION_DICT = {
-    1: 0,  # anger	
-    2: 0,
-    3: 0,
-    4: 1,  # disgust
-    5: 1,
-    6: 1,
-    7: 2,  # fear
-    8: 2,
-    9: 2,
-    10: 3,  # sadness
-    11: 3,
-    12: 3,
-    13: 4,  # neutral
-    14: 4,
-    15: 4,
-    16: 4,
-    17: 5,  # amusement
-    18: 5,
-    19: 5,
-    20: 6,  # excitation
-    21: 6,
-    22: 6,
-    23: 7,  # happy
-    24: 7,
-    25: 7,
-    26: 8,  # warmth
-    27: 8,
-    28: 8
-}
-
-
-def transform_producer(file_name: str, root_path: str, chunk_size: int,
-                       overlap: int, channel_num: int,
-                       before_trial: Union[Callable, None],
-                       transform: Union[List[Callable], Callable, None],
-                       after_trial: Union[Callable,
-                                          None], reorder: bool, queue: Queue):
-
-    subject = file_name  # subject (54)
-    samples = joblib.load(
-        os.path.join(root_path, file_name,
-                     f'{file_name}.pkl'))  # channel(33), timestep(n*250)
-
-    events = samples[-1]
-    if reorder:
-        samples = samples.take(FIRST_TO_SECOND_ORDER, axis=0)
-
-    # initial pointers
-    trial_id = 0
-    write_pointer = 0
-
-    video_id = None
-    start_at = None
-    end_at = None
-
-    # loop for each trial
-    for i, event in enumerate(events):
-
-        if event in list(range(1, 29)):
-            # Video events 1-28: Different events correspond to different experimental video materials
-            video_id = event
-        elif event == 240:
-            # Current trial video start event 240: This event appears 0.1s after the video event, indicating that the video starts to play.
-            start_at = i
-        elif event == 241:
-            # Current trial video end event 241: This event indicates that the video ends playing. Block end event 243: This event indicates the end of the block.
-            end_at = i
-            assert (not video_id is None) and (
-                not start_at is None
-            ), f'Parse event fail for trial {trial_id} with video_id={video_id}, start_at={start_at}, end_at={end_at}!'
-
-            trial_meta_info = {
-                'trial_id': trial_id,
-                'video_id': video_id,
-                'subject_id': subject,
-                'valence': VALENCE_DICT[video_id],
-                'emotion': EMOTION_DICT[video_id],
-            }
-
-            cur_start_at = start_at
-            if chunk_size <= 0:
-                chunk_size = end_at - start_at
-            cur_end_at = cur_start_at + chunk_size
-            step = chunk_size - overlap
-
-            trial_queue = []
-
-            if before_trial:
-                samples[:channel_num, cur_start_at:end_at] = before_trial(
-                    samples[:channel_num, cur_start_at:end_at])
-
-            while cur_end_at <= end_at:
-                t_eeg = samples[:channel_num, cur_start_at:cur_end_at]
-                if not transform is None:
-                    t_eeg = transform(eeg=t_eeg)['eeg']
-
-                clip_id = f'{subject}_{write_pointer}'
-                write_pointer += 1
-
-                record_info = {
-                    'start_at': cur_start_at,
-                    'end_at': cur_end_at,
-                    'clip_id': clip_id
-                }
-                record_info.update(trial_meta_info)
-                if after_trial:
-                    trial_queue.append({
-                        'eeg': t_eeg,
-                        'key': clip_id,
-                        'info': record_info
-                    })
-                else:
-                    queue.put({
-                        'eeg': t_eeg,
-                        'key': clip_id,
-                        'info': record_info
-                    })
-
-                cur_start_at = cur_start_at + step
-                cur_end_at = cur_start_at + chunk_size
-
-            if len(trial_queue) and after_trial:
-                trial_queue = after_trial(trial_queue)
-                for obj in trial_queue:
-                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                    queue.put(obj)
-
-            # prepare for the next trial
-            trial_id += 1
-            video_id = None
-            start_at = None
-            end_at = None
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def bci2022_constructor(root_path: str = './2022EmotionPublic/TrainSet/',
-                        chunk_size: int = 250,
-                        overlap: int = 0,
-                        channel_num: int = 30,
-                        before_trial: Union[None, Callable] = None,
-                        transform: Union[None, Callable] = None,
-                        after_trial: Union[Callable, None] = None,
-                        io_path: str = './io/bci2022',
-                        io_size: int = 10485760,
-                        io_mode: str = 'lmdb',
-                        num_worker: int = 0,
-                        verbose: bool = True) -> None:
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-    os.makedirs(io_path, exist_ok=True)
-
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    for train_set_batch_index, train_set_batch in enumerate(
-        ['TrainSet_first_batch', 'TrainSet_second_batch']):
-        # loop to access the first batch files
-        file_list = os.listdir(os.path.join(root_path, train_set_batch))
-
-        if verbose:
-            # show process bar
-            pbar = tqdm(total=len(file_list))
-            pbar.set_description(f"[BCI2022 BATCH {train_set_batch_index+1}/2]")
-
-        if num_worker > 1:
-            manager = Manager()
-            queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-            io_consumer_process = Process(target=io_consumer,
-                                          args=(eeg_io.write_eeg,
-                                                info_io.write_info, queue),
-                                          daemon=True)
-            io_consumer_process.start()
-
-            partial_mp_fn = partial(
-                transform_producer,
-                root_path=os.path.join(root_path, train_set_batch),
-                chunk_size=chunk_size,
-                overlap=overlap,
-                channel_num=channel_num,
-                before_trial=before_trial,
-                transform=transform,
-                after_trial=after_trial,
-                reorder=train_set_batch == 'TrainSet_first_batch',
-                queue=queue)
-
-            for _ in Pool(num_worker).imap(partial_mp_fn, file_list):
-                if verbose:
-                    pbar.update(1)
-
-            queue.put(None)
-
-            io_consumer_process.join()
-            io_consumer_process.close()
-
-        else:
-            for file_name in file_list:
-                transform_producer(
-                    file_name=file_name,
-                    root_path=os.path.join(root_path, train_set_batch),
-                    chunk_size=chunk_size,
-                    overlap=overlap,
-                    channel_num=channel_num,
-                    before_trial=before_trial,
-                    transform=transform,
-                    after_trial=after_trial,
-                    reorder=train_set_batch == 'TrainSet_first_batch',
-                    queue=SingleProcessingQueue(eeg_io.write_eeg,
-                                                info_io.write_info))
-                if verbose:
-                    pbar.update(1)
-
-        if verbose:
-            pbar.close()
-            print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/emotion_recognition/deap.py b/torcheeg/datasets/functional/emotion_recognition/deap.py
deleted file mode 100644
index 174a700..0000000
--- a/torcheeg/datasets/functional/emotion_recognition/deap.py
+++ /dev/null
@@ -1,220 +0,0 @@
-import os
-import pickle as pkl
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, Union
-
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(file_name: str, root_path: str, chunk_size: int,
-                       overlap: int, num_channel: int, num_baseline: int,
-                       baseline_chunk_size: int, before_trial: Union[Callable,
-                                                                     None],
-                       transform: Union[Callable, None],
-                       after_trial: Union[Callable, None], queue: Queue):
-    with open(os.path.join(root_path, file_name), 'rb') as f:
-        pkl_data = pkl.load(f, encoding='iso-8859-1')
-
-    samples = pkl_data['data']  # trial(40), channel(32), timestep(63*128)
-    labels = pkl_data['labels']
-    subject_id = file_name
-
-    write_pointer = 0
-    # loop for each trial
-    for trial_id in range(len(samples)):
-        # extract baseline signals
-
-        trial_samples = samples[trial_id, :
-                                num_channel]  # channel(32), timestep(63*128)
-        if before_trial:
-            trial_samples = before_trial(trial_samples)
-
-        trial_baseline_sample = trial_samples[:, :baseline_chunk_size *
-                                              num_baseline]  # channel(32), timestep(3*128)
-        trial_baseline_sample = trial_baseline_sample.reshape(
-            num_channel, num_baseline,
-            baseline_chunk_size).mean(axis=1)  # channel(32), timestep(128)
-
-        # record the common meta info
-        trial_meta_info = {'subject_id': subject_id, 'trial_id': trial_id}
-        trial_rating = labels[trial_id]
-
-        for label_index, label_name in enumerate(
-            ['valence', 'arousal', 'dominance', 'liking']):
-            trial_meta_info[label_name] = trial_rating[label_index]
-
-        start_at = baseline_chunk_size * num_baseline
-        if chunk_size <= 0:
-            chunk_size = trial_samples.shape[1] - start_at
-
-        # chunk with chunk size
-        end_at = start_at + chunk_size
-        # calculate moving step
-        step = chunk_size - overlap
-
-        trial_queue = []
-        while end_at <= trial_samples.shape[1]:
-            clip_sample = trial_samples[:, start_at:end_at]
-
-            t_eeg = clip_sample
-            t_baseline = trial_baseline_sample
-
-            if not transform is None:
-                t = transform(eeg=clip_sample, baseline=trial_baseline_sample)
-                t_eeg = t['eeg']
-                t_baseline = t['baseline']
-
-            # put baseline signal into IO
-            if not 'baseline_id' in trial_meta_info:
-                trial_base_id = f'{file_name}_{write_pointer}'
-                queue.put({'eeg': t_baseline, 'key': trial_base_id})
-                write_pointer += 1
-                trial_meta_info['baseline_id'] = trial_base_id
-
-            clip_id = f'{file_name}_{write_pointer}'
-            write_pointer += 1
-
-            # record meta info for each signal
-            record_info = {
-                'start_at': start_at,
-                'end_at': end_at,
-                'clip_id': clip_id
-            }
-            record_info.update(trial_meta_info)
-            if after_trial:
-                trial_queue.append({
-                    'eeg': t_eeg,
-                    'key': clip_id,
-                    'info': record_info
-                })
-            else:
-                queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-            start_at = start_at + step
-            end_at = start_at + chunk_size
-
-        if len(trial_queue) and after_trial:
-            trial_queue = after_trial(trial_queue)
-            for obj in trial_queue:
-                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def deap_constructor(root_path: str = './data_preprocessed_python',
-                     chunk_size: int = 128,
-                     overlap: int = 0,
-                     num_channel: int = 32,
-                     num_baseline: int = 3,
-                     baseline_chunk_size: int = 128,
-                     before_trial: Union[None, Callable] = None,
-                     transform: Union[None, Callable] = None,
-                     after_trial: Union[Callable, None] = None,
-                     io_path: str = './io/deap',
-                     io_size: int = 10485760,
-                     io_mode: str = 'lmdb',
-                     num_worker: int = 0,
-                     verbose: bool = True) -> None:
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # loop to access the dataset files
-    file_list = os.listdir(root_path)
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(file_list))
-        pbar.set_description("[DEAP]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                root_path=root_path,
-                                chunk_size=chunk_size,
-                                overlap=overlap,
-                                num_channel=num_channel,
-                                num_baseline=num_baseline,
-                                baseline_chunk_size=baseline_chunk_size,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, file_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-    else:
-        for file_name in file_list:
-            transform_producer(file_name=file_name,
-                               root_path=root_path,
-                               chunk_size=chunk_size,
-                               overlap=overlap,
-                               num_channel=num_channel,
-                               num_baseline=num_baseline,
-                               baseline_chunk_size=baseline_chunk_size,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
\ No newline at end of file
diff --git a/torcheeg/datasets/functional/emotion_recognition/dreamer.py b/torcheeg/datasets/functional/emotion_recognition/dreamer.py
deleted file mode 100644
index dade3ba..0000000
--- a/torcheeg/datasets/functional/emotion_recognition/dreamer.py
+++ /dev/null
@@ -1,236 +0,0 @@
-import os
-from typing import Callable, Union
-from functools import partial
-import scipy.io as scio
-from multiprocessing import Manager, Pool, Process, Queue
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(subject: int, trial_len: int, mat_data: any,
-                       chunk_size: int, overlap: int, num_channel: int,
-                       num_baseline: int, baseline_chunk_size: int,
-                       before_trial: Union[Callable,
-                                           None], transform: Union[Callable,
-                                                                   None],
-                       after_trial: Union[Callable, None], queue: Queue):
-
-    write_pointer = 0
-    # loop for each trial
-    for trial_id in range(trial_len):
-        # extract baseline signals
-        trial_baseline_sample = mat_data['DREAMER'][0, 0]['Data'][
-            0, subject]['EEG'][0, 0]['baseline'][0, 0][trial_id, 0]
-        trial_baseline_sample = trial_baseline_sample[:, :num_channel].swapaxes(
-            1, 0)  # channel(14), timestep(61*128)
-        trial_baseline_sample = trial_baseline_sample[:, :num_baseline *
-                                                      baseline_chunk_size].reshape(
-                                                          num_channel,
-                                                          num_baseline,
-                                                          baseline_chunk_size
-                                                      ).mean(
-                                                          axis=1
-                                                      )  # channel(14), timestep(128)
-
-        # record the common meta info
-        trial_meta_info = {'subject_id': subject, 'trial_id': trial_id}
-
-        trial_meta_info['valence'] = mat_data['DREAMER'][0, 0]['Data'][
-            0, subject]['ScoreValence'][0, 0][trial_id, 0]
-        trial_meta_info['arousal'] = mat_data['DREAMER'][0, 0]['Data'][
-            0, subject]['ScoreArousal'][0, 0][trial_id, 0]
-        trial_meta_info['dominance'] = mat_data['DREAMER'][0, 0]['Data'][
-            0, subject]['ScoreDominance'][0, 0][trial_id, 0]
-
-        trial_samples = mat_data['DREAMER'][0, 0]['Data'][0, subject]['EEG'][
-            0, 0]['stimuli'][0, 0][trial_id, 0]
-        trial_samples = trial_samples[:, :num_channel].swapaxes(
-            1, 0)  # channel(14), timestep(n*128)
-
-        if before_trial:
-            trial_samples = before_trial(trial_samples)
-
-        start_at = 0
-        if chunk_size <= 0:
-            chunk_size = trial_samples.shape[1] - start_at
-
-        # chunk with chunk size
-        end_at = chunk_size
-        # calculate moving step
-        step = chunk_size - overlap
-
-        trial_queue = []
-        while end_at <= trial_samples.shape[1]:
-            clip_sample = trial_samples[:, start_at:end_at]
-
-            t_eeg = clip_sample
-            t_baseline = trial_baseline_sample
-
-            if not transform is None:
-                t = transform(eeg=clip_sample, baseline=trial_baseline_sample)
-                t_eeg = t['eeg']
-                t_baseline = t['baseline']
-
-            # put baseline signal into IO
-            if not 'baseline_id' in trial_meta_info:
-                trial_base_id = f'{subject}_{write_pointer}'
-                queue.put({'eeg': t_baseline, 'key': trial_base_id})
-                write_pointer += 1
-                trial_meta_info['baseline_id'] = trial_base_id
-
-            clip_id = f'{subject}_{write_pointer}'
-            write_pointer += 1
-
-            # record meta info for each signal
-            record_info = {
-                'start_at': start_at,
-                'end_at': end_at,
-                'clip_id': clip_id
-            }
-            record_info.update(trial_meta_info)
-            if after_trial:
-                trial_queue.append({
-                    'eeg': t_eeg,
-                    'key': clip_id,
-                    'info': record_info
-                })
-            else:
-                queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-            start_at = start_at + step
-            end_at = start_at + chunk_size
-
-        if len(trial_queue) and after_trial:
-            trial_queue = after_trial(trial_queue)
-            for obj in trial_queue:
-                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def dreamer_constructor(
-    mat_path: str = './DREAMER.mat',
-    chunk_size: int = 128,
-    overlap: int = 0,
-    num_channel: int = 14,
-    num_baseline: int = 61,
-    baseline_chunk_size: int = 128,
-    before_trial: Union[None, Callable] = None,
-    transform: Union[None, Callable] = None,
-    after_trial: Union[Callable, None] = None,
-    io_path: str = './io/dreamer',
-    io_size: int = 10485760,
-    io_mode: str = 'lmdb',
-    num_worker: int = 0,
-    verbose: bool = True,
-) -> None:
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # access the dataset files
-    mat_data = scio.loadmat(mat_path, verify_compressed_data_integrity=False)
-
-    subject_len = len(mat_data['DREAMER'][0, 0]['Data'][0])  # 23
-    trial_len = len(
-        mat_data['DREAMER'][0, 0]['Data'][0, 0]['EEG'][0,
-                                                       0]['stimuli'][0,
-                                                                     0])  # 18
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=subject_len)
-        pbar.set_description("[DREAMER]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                trial_len=trial_len,
-                                mat_data=mat_data,
-                                chunk_size=chunk_size,
-                                overlap=overlap,
-                                num_channel=num_channel,
-                                num_baseline=num_baseline,
-                                baseline_chunk_size=baseline_chunk_size,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, list(range(subject_len))):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-
-    else:
-        for subject in list(range(subject_len)):
-            transform_producer(subject=subject,
-                               trial_len=trial_len,
-                               mat_data=mat_data,
-                               chunk_size=chunk_size,
-                               overlap=overlap,
-                               num_channel=num_channel,
-                               num_baseline=num_baseline,
-                               baseline_chunk_size=baseline_chunk_size,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/emotion_recognition/mahnob.py b/torcheeg/datasets/functional/emotion_recognition/mahnob.py
deleted file mode 100644
index ee2ab1f..0000000
--- a/torcheeg/datasets/functional/emotion_recognition/mahnob.py
+++ /dev/null
@@ -1,264 +0,0 @@
-import glob
-import json
-import os
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue, set_start_method
-from typing import Callable, List, Union
-
-import mne
-import xmltodict
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(file_name: str, root_path: str, chunk_size: int,
-                       sampling_rate: int, overlap: int, num_channel: int,
-                       num_baseline: int, baseline_chunk_size: int,
-                       num_trial_sample: int, before_trial: Union[Callable,
-                                                                  None],
-                       transform: Union[Callable, None],
-                       after_trial: Union[Callable, None], queue: Queue):
-    trial_dir = os.path.join(root_path, file_name)
-
-    mne.set_log_level('CRITICAL')
-    # record the common meta info for the trial
-    label_file = os.path.join(trial_dir, 'session.xml')
-    emodims = [
-        '@feltArsl', '@feltCtrl', '@feltEmo', '@feltPred', '@feltVlnc',
-        '@isStim'
-    ]
-    with open(label_file) as f:
-        label_info = xmltodict.parse('\n'.join(f.readlines()))
-    label_info = json.loads(json.dumps(label_info))['session']
-
-    if not '@feltArsl' in label_info:
-        # skip label_info['@isStim'] == '0' and other exception
-        return
-
-    trial_meta_info = {
-        'subject_id': label_info['subject']['@id'],
-        'trial_id': label_info['@mediaFile'],
-        'duration': float(label_info['@cutLenSec'])
-    }
-    # feltArsl, feltCtrl, feltEmo, feltPred, feltVlnc, isStim
-    trial_meta_info.update({k[1:]: int(label_info[k]) for k in emodims})
-
-    write_pointer = 0
-
-    # extract signals
-    sample_file = glob.glob(str(os.path.join(trial_dir, '*.bdf')))[0]
-
-    raw = mne.io.read_raw_bdf(sample_file, preload=True, stim_channel='Status')
-    events = mne.find_events(raw, stim_channel='Status')
-
-    montage = mne.channels.make_standard_montage(kind='biosemi32')
-    raw.set_montage(montage, on_missing='ignore')
-
-    # pick channels
-    raw.pick_channels(raw.ch_names[:num_channel])
-
-    start_samp, end_samp = events[0][0] + 1, events[1][0] - 1
-
-    # extract baseline signals
-    trial_baseline_raw = raw.copy().crop(raw.times[0], raw.times[end_samp])
-    trial_baseline_raw = trial_baseline_raw.resample(sampling_rate)
-
-    trial_baseline_sample = trial_baseline_raw.to_data_frame().to_numpy(
-    )[:, 1:].swapaxes(1, 0)  # channel(32), timestep(30 * 128)
-    trial_baseline_sample = trial_baseline_sample[:, :num_baseline *
-                                                  baseline_chunk_size]
-    trial_baseline_sample = trial_baseline_sample.reshape(
-        num_channel, num_baseline,
-        baseline_chunk_size).mean(axis=1)  # channel(32), timestep(128)
-
-    # extract experimental signals
-    trial_raw = raw.copy().crop(raw.times[start_samp], raw.times[end_samp])
-    trial_raw = trial_raw.resample(sampling_rate)
-    trial_samples = trial_raw.to_data_frame().to_numpy()[:, 1:].swapaxes(1, 0)
-    if before_trial:
-        trial_samples = before_trial(trial_samples)
-
-    start_at = 0
-    if chunk_size <= 0:
-        chunk_size = trial_samples.shape[1] - start_at
-
-    # chunk with chunk size
-    end_at = chunk_size
-    # calculate moving step
-    step = chunk_size - overlap
-
-    max_len = trial_samples.shape[1]
-    if not (num_trial_sample <= 0):
-        max_len = min(num_trial_sample * chunk_size, trial_samples.shape[1])
-
-    trial_queue = []
-    while end_at <= max_len:
-        clip_sample = trial_samples[:, start_at:end_at]
-
-        t_eeg = clip_sample
-        t_baseline = trial_baseline_sample
-        if not transform is None:
-            t = transform(eeg=clip_sample, baseline=trial_baseline_sample)
-            t_eeg = t['eeg']
-            t_baseline = t['baseline']
-
-        # put baseline signal into IO
-        if not 'baseline_id' in trial_meta_info:
-            trial_base_id = f'{file_name}_{write_pointer}'
-
-            queue.put({'eeg': t_baseline, 'key': trial_base_id})
-            write_pointer += 1
-            trial_meta_info['baseline_id'] = trial_base_id
-
-        clip_id = f'{file_name}_{write_pointer}'
-        write_pointer += 1
-
-        # record meta info for each signal
-        record_info = {
-            'start_at': start_at,
-            'end_at': end_at,
-            'clip_id': clip_id
-        }
-        record_info.update(trial_meta_info)
-        if after_trial:
-            trial_queue.append({
-                'eeg': t_eeg,
-                'key': clip_id,
-                'info': record_info
-            })
-        else:
-            queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-        start_at = start_at + step
-        end_at = start_at + chunk_size
-
-    if len(trial_queue) and after_trial:
-        trial_queue = after_trial(trial_queue)
-        for obj in trial_queue:
-            assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-            queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def mahnob_constructor(root_path: str = './Sessions',
-                       chunk_size: int = 128,
-                       sampling_rate: int = 128,
-                       overlap: int = 0,
-                       num_channel: int = 32,
-                       num_baseline: int = 30,
-                       baseline_chunk_size: int = 128,
-                       num_trial_sample: int = 30,
-                       before_trial: Union[None, Callable] = None,
-                       transform: Union[None, Callable] = None,
-                       after_trial: Union[Callable, None] = None,
-                       io_path: str = './io/mahnob',
-                       io_size: int = 10485760,
-                       io_mode: str = 'lmdb',
-                       num_worker: int = 0,
-                       verbose: bool = True) -> None:
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # loop to access the dataset files
-    file_list = os.listdir(root_path)
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(file_list))
-        pbar.set_description("[MAHNOB]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                root_path=root_path,
-                                chunk_size=chunk_size,
-                                sampling_rate=sampling_rate,
-                                overlap=overlap,
-                                num_channel=num_channel,
-                                num_baseline=num_baseline,
-                                baseline_chunk_size=baseline_chunk_size,
-                                num_trial_sample=num_trial_sample,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, file_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-
-    else:
-        for file_name in file_list:
-            transform_producer(file_name=file_name,
-                               root_path=root_path,
-                               chunk_size=chunk_size,
-                               sampling_rate=sampling_rate,
-                               overlap=overlap,
-                               num_channel=num_channel,
-                               num_baseline=num_baseline,
-                               baseline_chunk_size=baseline_chunk_size,
-                               num_trial_sample=num_trial_sample,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/emotion_recognition/mped_feature.py b/torcheeg/datasets/functional/emotion_recognition/mped_feature.py
deleted file mode 100644
index e2d80c6..0000000
--- a/torcheeg/datasets/functional/emotion_recognition/mped_feature.py
+++ /dev/null
@@ -1,214 +0,0 @@
-import os
-import re
-import numpy as np
-
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, Union
-
-import scipy.io as scio
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(file_name: str, root_path: str, feature: list,
-                       num_channel: int, before_trial: Union[None, Callable],
-                       transform: Union[None, Callable],
-                       after_trial: Union[Callable, None], queue: Queue):
-    labels = [
-        0, 2, 1, 4, 3, 5, 6, 7, 1, 2, 3, 6, 7, 4, 5, 0, 1, 5, 6, 2, 2, 1, 7, 6,
-        4, 4, 3, 5, 3, 7
-    ]  # 0-resting status, 1-neutral, 2-joy, 3-funny, 4-angry, 5-fear, 6-disgust, 7-sadness
-
-    subject = os.path.basename(file_name).split('.')[0].split('_')[0]
-
-    samples_dict = {}
-    for cur_feature in feature:
-        samples_dict[cur_feature] = scio.loadmat(
-            os.path.join(root_path, cur_feature, file_name),
-            verify_compressed_data_integrity=False)  # (1, 30)
-    write_pointer = 0
-
-    for trial_id in range(30):
-        trial_samples = []
-        for cur_feature, samples in samples_dict.items():
-            for sub_band in samples.keys():
-                # HHS: hhs_A, hhs_E
-                # Hjorth/HOC: alpha, beta, delta, gamma, theta, whole
-                # STFT: STFT
-                # PSD: PSD
-                if not str.startswith(sub_band, '__'):
-                    # not '__header__', '__version__', '__globals__'
-                    trial_samples += [
-                        samples[sub_band][0][trial_id][:num_channel],
-                    ]
-                    # PSD: (62, 120, 5)
-                    # Hjorth: (62, 120, 3)
-                    # HOC: (62, 120, 20)
-                    # HHS: (62, 120, 5)
-                    # STFT: (62, 120, 5)
-        trial_samples = np.concatenate(trial_samples,
-                                       axis=-1)  # (62, 120, num_features)
-        if before_trial:
-            trial_samples = before_trial(trial_samples)
-
-        # record the common meta info
-        trial_meta_info = {
-            'subject_id': subject,
-            'trial_id': trial_id,
-            'emotion': labels[trial_id]
-        }
-        num_clips = trial_samples.shape[1]
-
-        trial_queue = []
-        for clip_id in range(num_clips):
-            # PSD: (62, 5)
-            # Hjorth: (62, 3 * 6)
-            # HOC: (62, 20 * 6)
-            # STFT: (62, 5)
-            # HHS: (62, 5 * 2)
-            clip_sample = trial_samples[:, clip_id]
-
-            t_eeg = clip_sample
-            if not transform is None:
-                t_eeg = transform(eeg=clip_sample)['eeg']
-
-            clip_id = f'{file_name}_{write_pointer}'
-            write_pointer += 1
-
-            # record meta info for each signal
-            record_info = {'clip_id': clip_id}
-            record_info.update(trial_meta_info)
-            if after_trial:
-                trial_queue.append({
-                    'eeg': t_eeg,
-                    'key': clip_id,
-                    'info': record_info
-                })
-            else:
-                queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-        if len(trial_queue) and after_trial:
-            trial_queue = after_trial(trial_queue)
-            for obj in trial_queue:
-                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def mped_feature_constructor(root_path: str = './EEG_feature',
-                             feature: list = ['PSD'],
-                             num_channel: int = 62,
-                             before_trial: Union[None, Callable] = None,
-                             transform: Union[None, Callable] = None,
-                             after_trial: Union[Callable, None] = None,
-                             io_path: str = './io/mped_feature',
-                             io_size: int = 10485760,
-                             io_mode: str = 'lmdb',
-                             num_worker: int = 0,
-                             verbose: bool = True) -> None:
-    avaliable_features = os.listdir(
-        root_path)  # ['HHS', 'Hjorth', 'PSD', 'STFT', 'HOC']
-    assert set(feature).issubset(
-        set(avaliable_features)
-    ), 'The features supported by the MPEDFeature dataset are HHS, Hjorth, PSD, STFT, HOC. The input features are not a subset of the list of supported features.'
-
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # loop to access the dataset files
-    file_list = os.listdir(os.path.join(root_path, avaliable_features[0]))
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(file_list))
-        pbar.set_description("[MPED FEATURE]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                root_path=root_path,
-                                feature=feature,
-                                num_channel=num_channel,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, file_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-
-    else:
-        for file_name in file_list:
-            transform_producer(file_name=file_name,
-                               root_path=root_path,
-                               feature=feature,
-                               num_channel=num_channel,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/emotion_recognition/seed.py b/torcheeg/datasets/functional/emotion_recognition/seed.py
deleted file mode 100644
index 959b387..0000000
--- a/torcheeg/datasets/functional/emotion_recognition/seed.py
+++ /dev/null
@@ -1,208 +0,0 @@
-import os
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, Union
-
-import scipy.io as scio
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(file_name: str, root_path: str, chunk_size: int,
-                       overlap: int, num_channel: int,
-                       before_trial: Union[None, Callable],
-                       transform: Union[None, Callable],
-                       after_trial: Union[Callable, None], queue: Queue):
-    subject = int(
-        os.path.basename(file_name).split('.')[0].split('_')[0])  # subject (15)
-    date = int(
-        os.path.basename(file_name).split('.')[0].split('_')[1])  # period (3)
-
-    samples = scio.loadmat(os.path.join(root_path, file_name),
-                           verify_compressed_data_integrity=False
-                           )  # trial (15), channel(62), timestep(n*200)
-    # label file
-    labels = scio.loadmat(os.path.join(root_path, 'label.mat'),
-                          verify_compressed_data_integrity=False)['label'][0]
-
-    trial_ids = [key for key in samples.keys() if 'eeg' in key]
-
-    write_pointer = 0
-    # loop for each trial
-    for trial_id in trial_ids:
-        # extract baseline signals
-        trial_samples = samples[trial_id]  # channel(62), timestep(n*200)
-        if before_trial:
-            trial_samples = before_trial(trial_samples)
-
-        # record the common meta info
-        trial_meta_info = {
-            'subject_id': subject,
-            'trial_id': trial_id,
-            'emotion': int(labels[int(trial_id.split('_')[-1][3:]) - 1]),
-            'date': date
-        }
-
-        # extract experimental signals
-        start_at = 0
-        if chunk_size <= 0:
-            chunk_size = trial_samples.shape[1] - start_at
-
-        # chunk with chunk size
-        end_at = chunk_size
-        # calculate moving step
-        step = chunk_size - overlap
-
-        trial_queue = []
-        while end_at <= trial_samples.shape[1]:
-            clip_sample = trial_samples[:num_channel, start_at:end_at]
-
-            t_eeg = clip_sample
-            if not transform is None:
-                t_eeg = transform(eeg=clip_sample)['eeg']
-
-            clip_id = f'{file_name}_{write_pointer}'
-            write_pointer += 1
-
-            # record meta info for each signal
-            record_info = {
-                'start_at': start_at,
-                'end_at': end_at,
-                'clip_id': clip_id
-            }
-            record_info.update(trial_meta_info)
-            if after_trial:
-                trial_queue.append({
-                    'eeg': t_eeg,
-                    'key': clip_id,
-                    'info': record_info
-                })
-            else:
-                queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-            start_at = start_at + step
-            end_at = start_at + chunk_size
-
-        if len(trial_queue) and after_trial:
-            trial_queue = after_trial(trial_queue)
-            for obj in trial_queue:
-                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def seed_constructor(root_path: str = './Preprocessed_EEG',
-                     chunk_size: int = 200,
-                     overlap: int = 0,
-                     num_channel: int = 62,
-                     before_trial: Union[None, Callable] = None,
-                     transform: Union[None, Callable] = None,
-                     after_trial: Union[Callable, None] = None,
-                     io_path: str = './io/seed',
-                     io_size: int = 10485760,
-                     io_mode: str = 'lmdb',
-                     num_worker: int = 0,
-                     verbose: bool = True) -> None:
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # loop to access the dataset files
-    file_list = os.listdir(root_path)
-    skip_set = ['label.mat', 'readme.txt']
-    file_list = [f for f in file_list if f not in skip_set]
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(file_list))
-        pbar.set_description("[SEED]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                root_path=root_path,
-                                chunk_size=chunk_size,
-                                overlap=overlap,
-                                num_channel=num_channel,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, file_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-
-    else:
-        for file_name in file_list:
-            transform_producer(file_name=file_name,
-                               root_path=root_path,
-                               chunk_size=chunk_size,
-                               overlap=overlap,
-                               num_channel=num_channel,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/emotion_recognition/seed_feature.py b/torcheeg/datasets/functional/emotion_recognition/seed_feature.py
deleted file mode 100644
index f9e7e89..0000000
--- a/torcheeg/datasets/functional/emotion_recognition/seed_feature.py
+++ /dev/null
@@ -1,206 +0,0 @@
-import os
-import re
-import numpy as np
-
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, Union
-
-import scipy.io as scio
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(file_name: str, root_path: str, feature: list,
-                       num_channel: int, before_trial: Union[None, Callable],
-                       transform: Union[None, Callable],
-                       after_trial: Union[Callable, None], queue: Queue):
-    subject = int(
-        os.path.basename(file_name).split('.')[0].split('_')[0])  # subject (15)
-    date = int(
-        os.path.basename(file_name).split('.')[0].split('_')[1])  # period (3)
-
-    samples = scio.loadmat(os.path.join(root_path, file_name),
-                           verify_compressed_data_integrity=False
-                           )  # trial (15), channel(62), timestep(n*200)
-    # label file
-    labels = scio.loadmat(os.path.join(root_path, 'label.mat'),
-                          verify_compressed_data_integrity=False)['label'][0]
-
-    trial_ids = [
-        int(re.findall(r"de_movingAve(\d+)", key)[0]) for key in samples.keys()
-        if 'de_movingAve' in key
-    ]
-
-    write_pointer = 0
-    # loop for each trial
-    for trial_id in trial_ids:
-        # extract baseline signals
-        trial_samples = []
-        for cur_feature in feature:
-            trial_samples.append(
-                samples[cur_feature +
-                        str(trial_id)])  # channel(62), timestep(n), bands(5)
-        trial_samples = np.concatenate(
-            trial_samples,
-            axis=-1)[:num_channel]  # channel(62), timestep(n), features(5*k)
-        trial_samples = trial_samples.transpose((1, 0, 2))
-
-        if before_trial:
-            trial_samples = before_trial(trial_samples)
-
-        # record the common meta info
-        trial_meta_info = {
-            'subject_id': subject,
-            'trial_id': trial_id,
-            'emotion': int(labels[trial_id - 1]),
-            'date': date
-        }
-
-        trial_queue = []
-        for i, clip_sample in enumerate(trial_samples):
-            t_eeg = clip_sample
-            if not transform is None:
-                t_eeg = transform(eeg=clip_sample)['eeg']
-
-            clip_id = f'{file_name}_{write_pointer}'
-            write_pointer += 1
-
-            # record meta info for each signal
-            record_info = {
-                'start_at': i * 200,
-                'end_at': (i + 1) * 200,
-                'clip_id': clip_id
-            }
-            record_info.update(trial_meta_info)
-            if after_trial:
-                trial_queue.append({
-                    'eeg': t_eeg,
-                    'key': clip_id,
-                    'info': record_info
-                })
-            else:
-                queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-        if len(trial_queue) and after_trial:
-            trial_queue = after_trial(trial_queue)
-            for obj in trial_queue:
-                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def seed_feature_constructor(
-    root_path: str = './ExtractedFeatures',
-    feature: list = ['de_movingAve'],
-    num_channel: int = 62,
-    before_trial: Union[None, Callable] = None,
-    transform: Union[None, Callable] = None,
-    after_trial: Union[Callable, None] = None,
-    io_path: str = './io/seed_feature',
-    io_size: int = 10485760,
-    io_mode: str = 'lmdb',
-    num_worker: int = 0,
-    verbose: bool = True,
-) -> None:
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # loop to access the dataset files
-    file_list = os.listdir(root_path)
-    skip_set = ['label.mat', 'readme.txt']
-    file_list = [f for f in file_list if f not in skip_set]
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(file_list))
-        pbar.set_description("[SEED FEATURE]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                root_path=root_path,
-                                feature=feature,
-                                num_channel=num_channel,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, file_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-
-    else:
-        for file_name in file_list:
-            transform_producer(file_name=file_name,
-                               root_path=root_path,
-                               feature=feature,
-                               num_channel=num_channel,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/emotion_recognition/seed_iv.py b/torcheeg/datasets/functional/emotion_recognition/seed_iv.py
deleted file mode 100644
index 2193a66..0000000
--- a/torcheeg/datasets/functional/emotion_recognition/seed_iv.py
+++ /dev/null
@@ -1,221 +0,0 @@
-import os
-import re
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, Union
-
-import scipy.io as scio
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(file_path: str, chunk_size: int, overlap: int,
-                       num_channel: int, before_trial: Union[None, Callable],
-                       transform: Union[None, Callable],
-                       after_trial: Union[Callable, None], queue: Queue):
-    session_id = os.path.basename(os.path.dirname(file_path))
-    _, file_name = os.path.split(file_path)
-
-    subject = int(
-        os.path.basename(file_name).split('.')[0].split('_')[0])  # subject (15)
-    date = int(
-        os.path.basename(file_name).split('.')[0].split('_')[1])  # period (3)
-
-    samples = scio.loadmat(file_path, verify_compressed_data_integrity=False
-                           )  # trial (15), channel(62), timestep(n*200)
-    # label file
-    labels = [[
-        1, 2, 3, 0, 2, 0, 0, 1, 0, 1, 2, 1, 1, 1, 2, 3, 2, 2, 3, 3, 0, 3, 0, 3
-    ], [
-        2, 1, 3, 0, 0, 2, 0, 2, 3, 3, 2, 3, 2, 0, 1, 1, 2, 1, 0, 3, 0, 1, 3, 1
-    ], [
-        1, 2, 2, 1, 3, 3, 3, 1, 1, 2, 1, 0, 2, 3, 3, 0, 2, 3, 0, 0, 2, 0, 1, 0
-    ]]  # The labels with 0, 1, 2, and 3 denote the ground truth, neutral, sad, fear, and happy emotions, respectively.
-    session_labels = labels[int(session_id) - 1]
-
-    trial_name_ids = [(trial_name,
-                       int(re.findall(r".*_eeg(\d+)", trial_name)[0]))
-                      for trial_name in samples.keys() if 'eeg' in trial_name]
-
-    write_pointer = 0
-    # loop for each trial
-    for trial_name, trial_id in trial_name_ids:
-        trial_samples = samples[trial_name]  # channel(62), timestep(n*200)
-        if before_trial:
-            trial_samples = before_trial(trial_samples)
-
-        # record the common meta info
-        trial_meta_info = {
-            'subject_id': subject,
-            'trial_id': trial_id,
-            'session_id': session_id,
-            'emotion': int(session_labels[trial_id - 1]),
-            'date': date
-        }
-
-        # extract experimental signals
-        start_at = 0
-        if chunk_size <= 0:
-            chunk_size = trial_samples.shape[1] - start_at
-
-        # chunk with chunk size
-        end_at = chunk_size
-        # calculate moving step
-        step = chunk_size - overlap
-
-        trial_queue = []
-        while end_at <= trial_samples.shape[1]:
-            clip_sample = trial_samples[:num_channel, start_at:end_at]
-
-            t_eeg = clip_sample
-            if not transform is None:
-                t_eeg = transform(eeg=clip_sample)['eeg']
-
-            clip_id = f'{file_name}_{write_pointer}'
-            write_pointer += 1
-
-            # record meta info for each signal
-            record_info = {
-                'start_at': start_at,
-                'end_at': end_at,
-                'clip_id': clip_id
-            }
-            record_info.update(trial_meta_info)
-            if after_trial:
-                trial_queue.append({
-                    'eeg': t_eeg,
-                    'key': clip_id,
-                    'info': record_info
-                })
-            else:
-                queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-            start_at = start_at + step
-            end_at = start_at + chunk_size
-
-        if len(trial_queue) and after_trial:
-            trial_queue = after_trial(trial_queue)
-            for obj in trial_queue:
-                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def seed_iv_constructor(
-    root_path: str = './eeg_raw_data',
-    chunk_size: int = 800,
-    overlap: int = 0,
-    num_channel: int = 62,
-    before_trial: Union[None, Callable] = None,
-    transform: Union[None, Callable] = None,
-    after_trial: Union[Callable, None] = None,
-    io_path: str = './io/seed_iv',
-    io_size: int = 10485760,
-    io_mode: str = 'lmdb',
-    num_worker: int = 0,
-    verbose: bool = True,
-) -> None:
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # loop to access the dataset files
-    session_list = ['1', '2', '3']
-    file_path_list = []
-    for session in session_list:
-        session_root_path = os.path.join(root_path, session)
-        for file_name in os.listdir(session_root_path):
-            file_path_list.append(os.path.join(session_root_path, file_name))
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(file_path_list))
-        pbar.set_description("[SEED-IV]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                chunk_size=chunk_size,
-                                overlap=overlap,
-                                num_channel=num_channel,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, file_path_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-
-    else:
-        for file_path in file_path_list:
-            transform_producer(file_path=file_path,
-                               chunk_size=chunk_size,
-                               overlap=overlap,
-                               num_channel=num_channel,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/emotion_recognition/seed_iv_feature.py b/torcheeg/datasets/functional/emotion_recognition/seed_iv_feature.py
deleted file mode 100644
index 6cd53b8..0000000
--- a/torcheeg/datasets/functional/emotion_recognition/seed_iv_feature.py
+++ /dev/null
@@ -1,216 +0,0 @@
-import os
-import re
-import numpy as np
-
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, Union
-
-import scipy.io as scio
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(file_path: str, feature: list, num_channel: int,
-                       before_trial: Union[None, Callable],
-                       transform: Union[None, Callable],
-                       after_trial: Union[Callable, None], queue: Queue):
-    session_id = os.path.basename(os.path.dirname(file_path))
-    _, file_name = os.path.split(file_path)
-
-    subject = int(
-        os.path.basename(file_name).split('.')[0].split('_')[0])  # subject (15)
-    date = int(
-        os.path.basename(file_name).split('.')[0].split('_')[1])  # period (3)
-
-    samples = scio.loadmat(file_path, verify_compressed_data_integrity=False
-                           )  # trial (15), channel(62), timestep(n*200)
-    # label file
-    labels = [[
-        1, 2, 3, 0, 2, 0, 0, 1, 0, 1, 2, 1, 1, 1, 2, 3, 2, 2, 3, 3, 0, 3, 0, 3
-    ], [
-        2, 1, 3, 0, 0, 2, 0, 2, 3, 3, 2, 3, 2, 0, 1, 1, 2, 1, 0, 3, 0, 1, 3, 1
-    ], [
-        1, 2, 2, 1, 3, 3, 3, 1, 1, 2, 1, 0, 2, 3, 3, 0, 2, 3, 0, 0, 2, 0, 1, 0
-    ]]  # The labels with 0, 1, 2, and 3 denote the ground truth, neutral, sad, fear, and happy emotions, respectively.
-    session_labels = labels[int(session_id) - 1]
-
-    trial_ids = [
-        int(re.findall(r"de_movingAve(\d+)", key)[0]) for key in samples.keys()
-        if 'de_movingAve' in key
-    ]
-
-    write_pointer = 0
-    # loop for each trial
-    for trial_id in trial_ids:
-        # extract baseline signals
-        trial_samples = []
-        for cur_feature in feature:
-            trial_samples.append(
-                samples[cur_feature +
-                        str(trial_id)])  # channel(61), timestep(n), bands(5)
-        trial_samples = np.concatenate(
-            trial_samples,
-            axis=-1)[:num_channel]  # channel(61), timestep(n), features(5*k)
-        trial_samples = trial_samples.transpose((1, 0, 2))
-        # timestep(n), channel(61), features(5*k)
-
-        if before_trial:
-            trial_samples = before_trial(trial_samples)
-
-        # record the common meta info
-        trial_meta_info = {
-            'subject_id': subject,
-            'trial_id': trial_id,
-            'session_id': session_id,
-            'emotion': int(session_labels[trial_id - 1]),
-            'date': date
-        }
-
-        trial_queue = []
-        for i, clip_sample in enumerate(trial_samples):
-            t_eeg = clip_sample
-            if not transform is None:
-                t_eeg = transform(eeg=clip_sample)['eeg']
-
-            clip_id = f'{file_name}_{write_pointer}'
-            write_pointer += 1
-
-            # record meta info for each signal
-            record_info = {
-                'start_at': i * 400,
-                'end_at': (i + 1) *
-                400,  # The size of the sliding time windows for feature extraction is 4 seconds.
-                'clip_id': clip_id
-            }
-            record_info.update(trial_meta_info)
-            if after_trial:
-                trial_queue.append({
-                    'eeg': t_eeg,
-                    'key': clip_id,
-                    'info': record_info
-                })
-            else:
-                queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-        if len(trial_queue) and after_trial:
-            trial_queue = after_trial(trial_queue)
-            for obj in trial_queue:
-                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def seed_iv_feature_constructor(root_path: str = './eeg_feature_smooth',
-                                feature: list = ['de_movingAve'],
-                                num_channel: int = 61,
-                                before_trial: Union[None, Callable] = None,
-                                transform: Union[None, Callable] = None,
-                                after_trial: Union[Callable, None] = None,
-                                io_path: str = './io/seed_iv_feature',
-                                io_size: int = 10485760,
-                                io_mode: str = 'lmdb',
-                                num_worker: int = 0,
-                                verbose: bool = True) -> None:
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # loop to access the dataset files
-    session_list = ['1', '2', '3']
-    file_path_list = []
-    for session in session_list:
-        session_root_path = os.path.join(root_path, session)
-        for file_name in os.listdir(session_root_path):
-            file_path_list.append(os.path.join(session_root_path, file_name))
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(file_path_list))
-        pbar.set_description("[SEED-IV FEATURE]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                feature=feature,
-                                num_channel=num_channel,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, file_path_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-
-    else:
-        for file_path in file_path_list:
-            transform_producer(file_path=file_path,
-                               feature=feature,
-                               num_channel=num_channel,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/mne.py b/torcheeg/datasets/functional/mne.py
deleted file mode 100644
index 0c48261..0000000
--- a/torcheeg/datasets/functional/mne.py
+++ /dev/null
@@ -1,215 +0,0 @@
-import os
-import mne
-import numpy as np
-
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, Dict, Tuple, Union, List
-
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(epochs_metadata_rank: Tuple[mne.Epochs, Dict, int],
-                       chunk_size: int, overlap: int, num_channel: int,
-                       before_trial: Union[Callable,
-                                           None], transform: Union[Callable,
-                                                                   None],
-                       after_trial: Union[Callable, None], queue: Queue):
-
-    epochs, metadata, rank = epochs_metadata_rank
-
-    if chunk_size <= 0:
-        chunk_size = len(epochs.times)
-
-    if num_channel == -1:
-        num_channel = len(epochs.info['chs'])
-
-    trial_event_index = epochs.events[:, 2]
-    trial_start_at_list = epochs.events[:, 0]
-
-    trial_end_at = len(epochs.times) - chunk_size
-
-    clip_sample_start_at_list = np.arange(0, trial_end_at + 1,
-                                          chunk_size - overlap)
-
-    sample_events = [[clip_sample_start_at, chunk_size, -1]
-                     for clip_sample_start_at in clip_sample_start_at_list]
-
-    epoch_meta_info = metadata
-
-    write_pointer = 0
-
-    # for loop of trials
-    for trial_id, trial in enumerate(epochs):
-        # split sample from epochs
-        start_at_list = clip_sample_start_at_list + trial_start_at_list[trial_id]
-        end_at_list = clip_sample_start_at_list + trial_start_at_list[
-            trial_id] + chunk_size
-        event_index_list = len(sample_events) * [trial_event_index[trial_id]]
-
-        trial_samples = mne.Epochs(mne.io.RawArray(trial, epochs.info),
-                                   sample_events,
-                                   baseline=None,
-                                   tmin=0,
-                                   tmax=(chunk_size - 1) / epochs.info["sfreq"])
-        trial_samples.drop_bad(reject=None, flat=None)
-        if before_trial:
-            trial_samples = before_trial(trial_samples)
-
-        # for loop of samples
-        trial_queue = []
-        for i, trial_signal in enumerate(trial_samples.get_data()):
-            t_eeg = trial_signal[:num_channel, :]
-            if not transform is None:
-                t = transform(eeg=trial_signal[:num_channel, :])
-                t_eeg = t['eeg']
-
-            clip_id = f'{rank}_{write_pointer}'
-            write_pointer += 1
-
-            record_info = {
-                'trial_id': trial_id,
-                'start_at': start_at_list[i],
-                'end_at': end_at_list[i],
-                'event': event_index_list[i],
-                'clip_id': clip_id
-            }
-            record_info.update(epoch_meta_info)
-            if after_trial:
-                trial_queue.append({
-                    'eeg': t_eeg,
-                    'key': clip_id,
-                    'info': record_info
-                })
-            else:
-                queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-        if len(trial_queue) and after_trial:
-            trial_queue = after_trial(trial_queue)
-            for obj in trial_queue:
-                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def mne_constructor(epochs_list: List[mne.Epochs],
-                    metadata_list: List[Dict],
-                    chunk_size: int = -1,
-                    overlap: int = 0,
-                    num_channel: int = -1,
-                    before_trial: Union[None, Callable] = None,
-                    transform: Union[None, Callable] = None,
-                    after_trial: Union[Callable, None] = None,
-                    io_path: str = './io/mne',
-                    io_size: int = 10485760,
-                    io_mode: str = 'lmdb',
-                    num_worker: int = 0,
-                    verbose: bool = True) -> None:
-
-    mne.set_log_level('CRITICAL')
-
-    assert len(epochs_list) == len(
-        metadata_list
-    ), f'The number of mne.Epochs {len(epochs_list)} does not match the number of metadata {len(metadata_list)}.'
-
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    epochs_metadata_rank_list = []
-    for rank, (epochs, metadata) in enumerate(zip(epochs_list, metadata_list)):
-        assert (epochs.tmax - epochs.tmin) * epochs.info[
-            "sfreq"] >= chunk_size, f'chunk_size cannot be larger than (tmax - tmin) * sfreq. Here, tmax is set to {epochs.tmax}, tmin is set to {epochs.tmin}, and sfreq is {epochs.info["sfreq"]}. In the current configuration, chunk_size {chunk_size} is greater than {(epochs.tmax - epochs.tmin) * epochs.info["sfreq"]}!'
-        epochs_metadata_rank_list.append((epochs, metadata, rank))
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(epochs_metadata_rank_list))
-        pbar.set_description("[MNE]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                chunk_size=chunk_size,
-                                overlap=overlap,
-                                num_channel=num_channel,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn,
-                                       epochs_metadata_rank_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-
-    else:
-        for epochs_metadata_rank in epochs_metadata_rank_list:
-            transform_producer(epochs_metadata_rank=epochs_metadata_rank,
-                               chunk_size=chunk_size,
-                               overlap=overlap,
-                               num_channel=num_channel,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/numpy.py b/torcheeg/datasets/functional/numpy.py
deleted file mode 100644
index 0f6f301..0000000
--- a/torcheeg/datasets/functional/numpy.py
+++ /dev/null
@@ -1,168 +0,0 @@
-import os
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, Dict, Tuple, Union
-
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-import numpy as np
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(X_y_rank: Tuple[np.ndarray, Dict, int],
-                       before_trial: Union[Callable,
-                                           None], transform: Union[Callable,
-                                                                   None],
-                       after_trial: Union[Callable, None], queue: Queue):
-    X, y, worker_rank = X_y_rank
-    if before_trial:
-        X = before_trial(X)
-
-    trial_queue = []
-    for write_pointer, clip_sample in enumerate(X):
-
-        t_eeg = clip_sample
-
-        if not transform is None:
-            t = transform(eeg=clip_sample)
-            t_eeg = t['eeg']
-
-        clip_id = f'{worker_rank}_{write_pointer}'
-
-        # record meta info for each signal
-        record_info = {'clip_id': clip_id}
-        record_info.update({k: v[write_pointer] for k, v in y.items()})
-        if after_trial:
-            trial_queue.append({
-                'eeg': t_eeg,
-                'key': clip_id,
-                'info': record_info
-            })
-        else:
-            queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-    if len(trial_queue) and after_trial:
-        trial_queue = after_trial(trial_queue)
-        for obj in trial_queue:
-            assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-            queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def numpy_constructor(
-    X: np.ndarray,
-    y: Dict,
-    before_trial: Union[None, Callable] = None,
-    transform: Union[None, Callable] = None,
-    after_trial: Union[Callable, None] = None,
-    num_samples_per_worker: int = 100,
-    io_path: str = './io/numpy',
-    io_size: int = 10485760,
-    io_mode: str = 'lmdb',
-    num_worker: int = 0,
-    verbose: bool = True,
-) -> None:
-
-    for k, v in y.items():
-        assert len(X) == len(
-            v
-        ), f'The number of labels {len(v)} does not match the number of samples {len(X)} for labels {k}.'
-
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # access the data
-    indices = np.arange(len(X))
-    worker_indices_list = np.array_split(indices,
-                                         len(X) // num_samples_per_worker)
-
-    X_y_rank_list = []
-    for worker_rank, worker_indices in enumerate(worker_indices_list):
-        X_worker = X[worker_indices]
-        y_worker = {k: v[worker_indices] for k, v in y.items()}
-        X_y_rank_list.append((X_worker, y_worker, worker_rank))
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(X_y_rank_list))
-        pbar.set_description("[NUMPY]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, X_y_rank_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-
-    else:
-        for X_y_rank in X_y_rank_list:
-            transform_producer(X_y_rank=X_y_rank,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/operators.py b/torcheeg/datasets/functional/operators.py
new file mode 100644
index 0000000..9938e03
--- /dev/null
+++ b/torcheeg/datasets/functional/operators.py
@@ -0,0 +1,188 @@
+import math
+import os
+import shutil
+from multiprocessing import Manager
+from typing import Any, Callable, Union
+
+from joblib import Parallel, delayed
+from tqdm import tqdm
+
+from torcheeg.io import EEGSignalIO, MetaInfoIO
+from torcheeg.datasets import BaseDataset
+
+
+def __block__(**kwargs):
+    root_path = kwargs.pop('root_path', '.')  # str
+    num_samples_per_worker = kwargs.pop('num_samples_per_worker', '.')  # str
+
+    existing_meta_info_io_path = os.path.join(root_path, 'info.csv')
+    existing_info_io = MetaInfoIO(existing_meta_info_io_path)
+    df = existing_info_io.read_all()
+
+    block_list = list()
+    num_block_list = math.ceil(len(df) / num_samples_per_worker)
+    for i in range(num_block_list):
+        block_list.append(
+            [i * num_samples_per_worker, (i + 1) * num_samples_per_worker])
+    return block_list
+
+
+def __io__(block,
+           io_path: str = None,
+           io_size: int = 10485760,
+           io_mode: str = 'lmdb',
+           lock: Any = None,
+           **kwargs):
+    start_id, end_id = block
+
+    transform = kwargs.pop('transform', None)
+    root_path = kwargs.pop('root_path', '.')
+
+    eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+    existing_meta_info_io_path = os.path.join(io_path, 'info.csv')
+    existing_eeg_signal_io_path = os.path.join(root_path, 'eeg')
+
+    existing_info_io = MetaInfoIO(existing_meta_info_io_path)
+    existing_eeg_io = EEGSignalIO(existing_eeg_signal_io_path,
+                                  io_size=io_size,
+                                  io_mode=io_mode)
+
+    df = existing_info_io.read_all()
+    chunk = df[start_id:end_id]
+
+    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
+
+    last_baseline_id = None
+    last_baseline_sample = None
+
+    for i, row in chunk.iterrows():
+        clip_id = row['clip_id']
+        clip_sample = existing_eeg_io.read_eeg(clip_id)
+
+        if 'baseline_id' in row:
+            baseline_id = row['baseline_id']
+
+            if last_baseline_id == baseline_id:
+                trial_baseline_sample = last_baseline_sample
+            else:
+                trial_baseline_sample = existing_eeg_io.read_eeg(baseline_id)
+
+            if transform is not None:
+                t = transform(eeg=clip_sample, baseline=trial_baseline_sample)
+            else:
+                t = dict(eeg=clip_sample, baseline=trial_baseline_sample)
+
+            t_eeg = t['eeg']
+            t_baseline = t['baseline']
+
+            if not last_baseline_id == baseline_id:
+                with lock:
+                    eeg_io.write_eeg(t_baseline, baseline_id)
+
+                last_baseline_id = baseline_id
+                last_baseline_sample = trial_baseline_sample
+
+            with lock:
+                eeg_io.write_eeg(t_eeg, clip_id)
+
+        else:
+            if transform is not None:
+                t = transform(eeg=clip_sample)
+            else:
+                t = dict(eeg=clip_sample)
+            t_eeg = t['eeg']
+
+            with lock:
+                eeg_io.write_eeg(t_eeg, clip_id)
+
+
+class MockLock():
+    def __enter__(self):
+        pass
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        pass
+
+
+def from_existing(dataset: Any,
+                  io_path: str,
+                  transform: Union[None, Callable] = None,
+                  num_worker: int = 0,
+                  verbose: bool = True,
+                  io_size: int = 10485760,
+                  io_mode: str = 'lmdb',
+                  num_samples_per_worker: int = 100,
+                  in_memory: bool = False,
+                  **kwargs):
+    '''
+    To create new datasets from existing databases, which is often used where new transformations are expected to be applied to already processed datasets. 
+
+    Args:
+        dataset (Basedataset): The existing database, which can be obtained through :obj:`DEAPDataset`, :obj:`SEEDDataset`, and so on.
+        io_path (str): The path to generated unified data IO, cached as an intermediate result. (default: :obj:`./io/deap`)
+        transform (Callable, optional): The transformation of the EEG signals and baseline EEG signals. The input is a :obj:`np.ndarray`, and the ouput is used as the first and second value of each element in the dataset. It is executed before generating IO intermediate results. (default: :obj:`None`)
+        num_worker (str): How many subprocesses to use for data processing. (default: :obj:`0`)
+        verbose (bool): Whether to display logs during processing, such as progress bars, etc. (default: :obj:`True`)
+        verbose (bool): Whether to display logs during processing, such as progress bars, etc. (default: :obj:`True`)
+        io_size (int): Maximum size database may grow to; used to size the memory mapping. If database grows larger than ``map_size``, an exception will be raised and the user must close and reopen. (default: :obj:`10485760`)
+        io_mode (str): Storage mode of EEG signal. When io_mode is set to :obj:`lmdb`, TorchEEG provides an efficient database (LMDB) for storing EEG signals. LMDB may not perform well on limited operating systems, where a file system based EEG signal storage is also provided. When io_mode is set to :obj:`pickle`, pickle-based persistence files are used. (default: :obj:`lmdb`)
+        num_samples_per_worker (int): The number of samples processed by each process. Once the specified number of samples are processed, the process will be destroyed and new processes will be created to perform new tasks. (default: :obj:`100`)
+        in_memory (bool): Whether to load the entire dataset into memory. If :obj:`in_memory` is set to True, then the first time an EEG sample is read, the entire dataset is loaded into memory for subsequent retrieval. Otherwise, the dataset is stored on disk to avoid the out-of-memory problem. (default: :obj:`False`)    
+    '''
+    root_path = dataset.io_path
+    params = {
+        'root_path': root_path,
+        'io_path': io_path,
+        'transform': transform,
+        'num_worker': num_worker,
+        'verbose': verbose,
+        'io_size': io_size,
+        'io_mode': io_mode,
+        'num_samples_per_worker': num_samples_per_worker,
+        'in_memory': in_memory,
+    }
+    params.update(kwargs)
+
+    meta_info_io_path = os.path.join(io_path, 'info.csv')
+    eeg_signal_io_path = eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+    exist_io = os.path.exists(meta_info_io_path) and os.path.exists(
+        eeg_signal_io_path)
+
+    if not exist_io:
+        print(
+            f'dataset does not exist at path {io_path}, generating files to path...'
+        )
+        os.makedirs(io_path, exist_ok=True)
+
+        # # init sub-folders
+        shutil.copy(os.path.join(root_path, 'info.csv'),
+                    os.path.join(io_path, 'info.csv'))
+        EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
+
+        if num_worker == 0:
+            lock = MockLock()  # do nothing, just for compatibility
+            for block in tqdm(__block__(**params),
+                              disable=not verbose,
+                              desc="[PROCESS]"):
+                __io__(block=block, lock=lock, **params)
+        else:
+            # lock for lmdb writter, LMDB only allows single-process writes
+            manager = Manager()
+            lock = manager.Lock()
+
+            Parallel(n_jobs=num_worker)(
+                delayed(__io__)(block=block, lock=lock, **params)
+                for block in tqdm(
+                    __block__(**params), disable=not verbose, desc="[PROCESS]"))
+    else:
+        print(f'dataset already exists at path {io_path}, reading from path...')
+
+    return type(dataset)(io_path=io_path,
+                         offline_transform=transform,
+                         num_worker=num_worker,
+                         verbose=verbose,
+                         io_size=io_size,
+                         in_memory=in_memory,
+                         **kwargs)
diff --git a/torcheeg/datasets/functional/personal_identification/__init__.py b/torcheeg/datasets/functional/personal_identification/__init__.py
deleted file mode 100644
index 1f7246e..0000000
--- a/torcheeg/datasets/functional/personal_identification/__init__.py
+++ /dev/null
@@ -1,1 +0,0 @@
-from .m3cv import m3cv_constructor
\ No newline at end of file
diff --git a/torcheeg/datasets/functional/personal_identification/m3cv.py b/torcheeg/datasets/functional/personal_identification/m3cv.py
deleted file mode 100644
index 0bae54e..0000000
--- a/torcheeg/datasets/functional/personal_identification/m3cv.py
+++ /dev/null
@@ -1,204 +0,0 @@
-import os
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, List, Union
-
-import numpy as np
-import pandas as pd
-import scipy.io as scio
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(df: pd.DataFrame, root_path: str, chunk_size: int,
-                       overlap: int, num_channel: int,
-                       before_trial: Union[Callable,
-                                           None], transform: Union[Callable,
-                                                                   None],
-                       after_trial: Union[Callable, None], queue: Queue):
-
-    # calculate moving step
-    write_pointer = 0
-
-    start_epoch = None
-
-    for _, epoch_info in df.iterrows():
-        epoch_meta_info = {
-            'epoch_id': epoch_info['EpochID'],
-            'subject_id': epoch_info['SubjectID'],
-            'session': epoch_info['Session'],
-            'task': epoch_info['Task'],
-            'usage': epoch_info['Usage'],
-        }
-
-        epoch_id = epoch_meta_info['epoch_id']
-
-        if start_epoch is None:
-            start_epoch = epoch_id
-
-        trial_samples = scio.loadmat(os.path.join(root_path,
-                                                  epoch_id))['epoch_data']
-        if before_trial:
-            trial_samples = before_trial(trial_samples)
-
-        start_at = 0
-        if chunk_size <= 0:
-            chunk_size = trial_samples.shape[1] - start_at
-
-        # chunk with chunk size
-        end_at = chunk_size
-        # calculate moving step
-        step = chunk_size - overlap
-
-        trial_queue = []
-        while end_at <= trial_samples.shape[1]:
-            clip_sample = trial_samples[:num_channel, start_at:end_at]
-            t_eeg = clip_sample
-
-            if not transform is None:
-                t_eeg = transform(eeg=clip_sample)['eeg']
-
-            clip_id = f'after{start_epoch}_{write_pointer}'
-            write_pointer += 1
-
-            # record meta info for each signal
-            record_info = {
-                'start_at': start_at,
-                'end_at': end_at,
-                'clip_id': clip_id
-            }
-            record_info.update(epoch_meta_info)
-            if after_trial:
-                trial_queue.append({
-                    'eeg': t_eeg,
-                    'key': clip_id,
-                    'info': record_info
-                })
-            else:
-                queue.put({'eeg': t_eeg, 'key': clip_id, 'info': record_info})
-
-            start_at = start_at + step
-            end_at = start_at + chunk_size
-
-        if len(trial_queue) and after_trial:
-            trial_queue = after_trial(trial_queue)
-            for obj in trial_queue:
-                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def m3cv_constructor(
-    root_path: str = './aistudio',
-    subset: str = 'Enrollment',
-    chunk_size: int = 1000,
-    overlap: int = 0,
-    num_channel: int = 65,
-    before_trial: Union[None, Callable] = None,
-    transform: Union[None, Callable] = None,
-    after_trial: Union[Callable, None] = None,
-    io_path: str = './io/m3cv',
-    io_size: int = 10485760,
-    io_mode: str = 'lmdb',
-    num_worker: int = 0,
-    verbose: bool = True,
-) -> None:
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # loop to access the dataset files
-    df = pd.read_csv(os.path.join(root_path, f'{subset}_Info.csv'))
-    df_list_num = len(df) // 60
-    df_list = np.array_split(df, df_list_num)
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(df_list))
-        pbar.set_description("[M3CV]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                root_path=os.path.join(root_path, subset),
-                                chunk_size=chunk_size,
-                                overlap=overlap,
-                                num_channel=num_channel,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, df_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-    else:
-        for df in df_list:
-            transform_producer(df=df,
-                               root_path=os.path.join(root_path, subset),
-                               chunk_size=chunk_size,
-                               overlap=overlap,
-                               num_channel=num_channel,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/functional/ssvep/__init__.py b/torcheeg/datasets/functional/ssvep/__init__.py
deleted file mode 100644
index 2ce8511..0000000
--- a/torcheeg/datasets/functional/ssvep/__init__.py
+++ /dev/null
@@ -1,1 +0,0 @@
-from .tsu_benchmark import tsu_benchmark_constructor
\ No newline at end of file
diff --git a/torcheeg/datasets/functional/ssvep/tsu_benchmark.py b/torcheeg/datasets/functional/ssvep/tsu_benchmark.py
deleted file mode 100644
index 2735544..0000000
--- a/torcheeg/datasets/functional/ssvep/tsu_benchmark.py
+++ /dev/null
@@ -1,218 +0,0 @@
-import os
-import re
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue, set_start_method
-from typing import Callable, List, Union
-
-import scipy.io as scio
-from torcheeg.io import EEGSignalIO, MetaInfoIO
-from tqdm import tqdm
-
-MAX_QUEUE_SIZE = 1024
-
-
-def transform_producer(file_name: str, root_path: str, chunk_size: int,
-                       overlap: int, num_channel: int,
-                       before_trial: Union[Callable,
-                                           None], transform: Union[Callable,
-                                                                   None],
-                       after_trial: Union[Callable, None], queue: Queue):
-    subject = int(re.findall(r'S(\d*).mat', file_name)[0])  # subject (35)
-    freq_phase = scio.loadmat(os.path.join(root_path, 'Freq_Phase.mat'))
-    freqs = freq_phase['freqs'][0]
-    phases = freq_phase['phases'][0]
-
-    samples = scio.loadmat(os.path.join(root_path,
-                                        file_name))['data'].transpose(
-                                            2, 3, 0, 1)
-    # 40, 6, 64, 1500
-    # Target number: 40
-    # Block number: 6
-    # Electrode number: 64
-    # Time points: 1500
-
-    write_pointer = 0
-
-    for trial_id in range(samples.shape[0]):
-        trial_meta_info = {
-            'subject_id': subject,
-            'trial_id': trial_id,
-            'phases': phases[trial_id],
-            'freqs': freqs[trial_id]
-        }
-        trial_samples = samples[trial_id]
-
-        for block_id in range(trial_samples.shape[0]):
-            block_meta_info = {'block_id': block_id}
-            block_meta_info.update(trial_meta_info)
-            block_samples = trial_samples[block_id]
-            if before_trial:
-                block_samples = before_trial(block_samples)
-
-            start_at = 0
-            if chunk_size <= 0:
-                chunk_size = block_samples.shape[1] - start_at
-
-            # chunk with chunk size
-            end_at = chunk_size
-            # calculate moving step
-            step = chunk_size - overlap
-
-            block_queue = []
-            while end_at <= block_samples.shape[1]:
-                clip_sample = block_samples[:num_channel, start_at:end_at]
-
-                t_eeg = clip_sample
-                if not transform is None:
-                    t_eeg = transform(eeg=clip_sample)['eeg']
-
-                clip_id = f'{file_name}_{write_pointer}'
-                write_pointer += 1
-
-                # record meta info for each signal
-                record_info = {
-                    'start_at': start_at,
-                    'end_at': end_at,
-                    'clip_id': clip_id
-                }
-                record_info.update(block_meta_info)
-                if after_trial:
-                    block_queue.append({
-                        'eeg': t_eeg,
-                        'key': clip_id,
-                        'info': record_info
-                    })
-                else:
-                    queue.put({
-                        'eeg': t_eeg,
-                        'key': clip_id,
-                        'info': record_info
-                    })
-
-                start_at = start_at + step
-                end_at = start_at + chunk_size
-
-            if len(block_queue) and after_trial:
-                block_queue = after_trial(block_queue)
-                for obj in block_queue:
-                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
-                    queue.put(obj)
-
-
-def io_consumer(write_eeg_fn: Callable, write_info_fn: Callable, queue: Queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-            if 'info' in item:
-                info = item['info']
-                write_info_fn(info)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn: Callable, write_info_fn: Callable):
-        self.write_eeg_fn = write_eeg_fn
-        self.write_info_fn = write_info_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-        if 'info' in item:
-            info = item['info']
-            self.write_info_fn(info)
-
-
-def tsu_benchmark_constructor(root_path: str = './TSUBenchmark',
-                              chunk_size: int = 200,
-                              overlap: int = 0,
-                              num_channel: int = 64,
-                              before_trial: Union[None, Callable] = None,
-                              transform: Union[None, Callable] = None,
-                              after_trial: Union[Callable, None] = None,
-                              io_path: str = './io/tsu_benchmark',
-                              io_size: int = 10485760,
-                              io_mode: str = 'lmdb',
-                              num_worker: int = 0,
-                              verbose: bool = True) -> None:
-    # init IO
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    if os.path.exists(io_path) and not os.path.getsize(meta_info_io_path) == 0:
-        print(
-            f'The target folder already exists, if you need to regenerate the database IO, please delete the path {io_path}.'
-        )
-        return
-
-    os.makedirs(io_path, exist_ok=True)
-
-    meta_info_io_path = os.path.join(io_path, 'info.csv')
-    eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-    info_io = MetaInfoIO(meta_info_io_path)
-    eeg_io = EEGSignalIO(eeg_signal_io_path, io_size=io_size, io_mode=io_mode)
-
-    # loop to access the dataset files
-    file_list = os.listdir(root_path)
-    skip_set = [
-        'Readme.txt', 'Sub_info.txt', '64-channels.loc', '64-channels.loc',
-        'Freq_Phase.mat'
-    ]
-    file_list = [f for f in file_list if f not in skip_set]
-
-    if verbose:
-        # show process bar
-        pbar = tqdm(total=len(file_list))
-        pbar.set_description("[TSU Benchmark]")
-
-    if num_worker > 1:
-        manager = Manager()
-        queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-        io_consumer_process = Process(target=io_consumer,
-                                      args=(eeg_io.write_eeg,
-                                            info_io.write_info, queue),
-                                      daemon=True)
-        io_consumer_process.start()
-
-        partial_mp_fn = partial(transform_producer,
-                                root_path=root_path,
-                                chunk_size=chunk_size,
-                                overlap=overlap,
-                                num_channel=num_channel,
-                                before_trial=before_trial,
-                                transform=transform,
-                                after_trial=after_trial,
-                                queue=queue)
-
-        for _ in Pool(num_worker).imap(partial_mp_fn, file_list):
-            if verbose:
-                pbar.update(1)
-
-        queue.put(None)
-
-        io_consumer_process.join()
-        io_consumer_process.close()
-
-    else:
-        for file_name in file_list:
-            transform_producer(file_name=file_name,
-                               root_path=root_path,
-                               chunk_size=chunk_size,
-                               overlap=overlap,
-                               num_channel=num_channel,
-                               before_trial=before_trial,
-                               transform=transform,
-                               after_trial=after_trial,
-                               queue=SingleProcessingQueue(
-                                   eeg_io.write_eeg, info_io.write_info))
-            if verbose:
-                pbar.update(1)
-
-    if verbose:
-        pbar.close()
-        print('Please wait for the writing process to complete...')
diff --git a/torcheeg/datasets/module/__init__.py b/torcheeg/datasets/module/__init__.py
index ab8c3df..ef5d8a3 100644
--- a/torcheeg/datasets/module/__init__.py
+++ b/torcheeg/datasets/module/__init__.py
@@ -1,5 +1,6 @@
 from .base_dataset import BaseDataset
 from .emotion_recognition import *
+from .folder_dataset import FolderDataset
 from .mne_dataset import MNEDataset
 from .numpy_dataset import NumpyDataset
 from .personal_identification import *
diff --git a/torcheeg/datasets/module/base_dataset.py b/torcheeg/datasets/module/base_dataset.py
index e61561d..f1711ab 100644
--- a/torcheeg/datasets/module/base_dataset.py
+++ b/torcheeg/datasets/module/base_dataset.py
@@ -1,165 +1,23 @@
-import math
 import os
-import shutil
-import pandas as pd
-from functools import partial
-from multiprocessing import Manager, Pool, Process, Queue
-from typing import Callable, Dict, List, Union, Any
+from typing import Any, Dict
 
 from torch.utils.data import Dataset
+from multiprocessing import Manager
 from torcheeg.io import EEGSignalIO, MetaInfoIO
+from joblib import Parallel, delayed
+
 from tqdm import tqdm
 
 MAX_QUEUE_SIZE = 1024
 
 
-def copyfile(src, dst, *, follow_symlinks=True):
-    if shutil._samefile(src, dst):
-        raise shutil.SameFileError("{!r} and {!r} are the same file".format(
-            src, dst))
-
-    for fn in [src, dst]:
-        try:
-            st = os.stat(fn)
-        except OSError:
-            pass
-        else:
-            if shutil.stat.S_ISFIFO(st.st_mode):
-                raise shutil.SpecialFileError("`%s` is a named pipe" % fn)
-
-    if not follow_symlinks and os.path.islink(src):
-        os.symlink(os.readlink(src), dst)
-    else:
-        size = os.stat(src).st_size
-        with open(src, 'rb') as fsrc:
-            with open(dst, 'wb') as fdst:
-                copyfileobj(fsrc, fdst, total=size)
-    return dst
-
-
-def copyfileobj(fsrc, fdst, total, length=16 * 1024):
-    pbar = tqdm(total=total)
-    pbar.set_description("[FROM EXISTING]")
-    while True:
-        buf = fsrc.read(length)
-        if not buf:
-            break
-        fdst.write(buf)
-        pbar.update(len(buf))
-
-
-def copy_with_progress(src, dst, *, follow_symlinks=True):
-    if os.path.isdir(dst):
-        dst = os.path.join(dst, os.path.basename(src))
-    copyfile(src, dst, follow_symlinks=follow_symlinks)
-    shutil.copymode(src, dst)
-    return dst
-
-
-def split_df_by_size(df, chunk_size=100):
-    chunks = list()
-    num_chunks = math.ceil(len(df) / chunk_size)
-    for i in range(num_chunks):
-        chunks.append(df[i * chunk_size:(i + 1) * chunk_size])
-    return chunks
-
-
-def split_df_by_column(df, column_name='baseline_id'):
-    chunks = list()
-    column_uniques = df[column_name].unique()
-    for column in column_uniques:
-        chunks.append(df[df[column_name].isin([column])])
-    return chunks
-
-
-def io_consumer(write_eeg_fn, queue):
-    while True:
-        item = queue.get()
-        if not item is None:
-            eeg = item['eeg']
-            key = item['key']
-            write_eeg_fn(eeg, key)
-        else:
-            break
-
-
-class SingleProcessingQueue:
-    def __init__(self, write_eeg_fn):
-        self.write_eeg_fn = write_eeg_fn
-
-    def put(self, item):
-        eeg = item['eeg']
-        key = item['key']
-        self.write_eeg_fn(eeg, key)
-
-
-def basic_producer(chunk: pd.DataFrame, transform: Callable,
-                   read_eeg_fn: Callable, queue: Queue):
-
-    last_baseline_id = None
-    last_baseline_sample = None
-
-    for i, row in chunk.iterrows():
-        clip_id = row['clip_id']
-        clip_sample = read_eeg_fn(clip_id)
-
-        if 'baseline_id' in row:
-            baseline_id = row['baseline_id']
-
-            if last_baseline_id == baseline_id:
-                trial_baseline_sample = last_baseline_sample
-            else:
-                trial_baseline_sample = read_eeg_fn(baseline_id)
-
-            t = transform(eeg=clip_sample, baseline=trial_baseline_sample)
-            t_eeg = t['eeg']
-            t_baseline = t['baseline']
-
-            if not last_baseline_id == baseline_id:
-                queue.put({'eeg': t_baseline, 'key': baseline_id})
-
-                last_baseline_id = baseline_id
-                last_baseline_sample = trial_baseline_sample
-
-            queue.put({'eeg': t_eeg, 'key': clip_id})
-
-        else:
-            t = transform(eeg=clip_sample)
-            t_eeg = t['eeg']
-            queue.put({'eeg': t_eeg, 'key': clip_id})
-
-
-def reduce_producer(chunk: List[pd.DataFrame], transform: Callable,
-                    read_eeg_fn: Callable, write_info_fn: Callable,
-                    queue: Queue):
+class MockLock():
 
-    for reduce_list in chunk:
+    def __enter__(self):
+        pass
 
-        reduce_info = None
-
-        reduce_clip_list = []
-        reduce_baseline_list = []
-
-        reduce_list = reduce_list.sort_values("clip_id", inplace=False)
-
-        for i, row in reduce_list.iterrows():
-            if reduce_info is None:
-                reduce_info = row.to_dict()
-            reduce_clip_list.append(read_eeg_fn(row['clip_id']))
-            if 'baseline_id' in row:
-                reduce_baseline_list.append(read_eeg_fn(row['baseline_id']))
-
-        reduce_clip = transform(reduce_clip_list)
-        queue.put({'eeg': reduce_clip, 'key': reduce_info['clip_id']})
-
-        if len(reduce_baseline_list):
-            reduce_baseline = transform(reduce_baseline_list)
-            queue.put({
-                'eeg': reduce_baseline,
-                'key': reduce_info['baseline_id']
-            })
-
-        write_info_fn(reduce_info)
+    def __exit__(self, exc_type, exc_value, traceback):
+        pass
 
 
 class BaseDataset(Dataset):
@@ -167,28 +25,150 @@ class BaseDataset(Dataset):
     adjacency_matrix = []
 
     def __init__(self,
-                 io_path: str,
+                 io_path: str = None,
                  io_size: int = 10485760,
                  io_mode: str = 'lmdb',
-                 in_memory: bool = False):
-        if not self.exist(io_path):
-            raise RuntimeError(
-                'Database IO does not exist, please regenerate database IO.')
+                 in_memory: bool = False,
+                 num_worker: int = 0,
+                 verbose: bool = True,
+                 **kwargs):
+
         self.io_path = io_path
         self.io_size = io_size
         self.io_mode = io_mode
         self.in_memory = in_memory
+        self.num_worker = num_worker
+        self.verbose = verbose
+
+        # new IO
+        if not self.exist(self.io_path):
+            print(
+                f'dataset does not exist at path {self.io_path}, generating files to path...'
+            )
+            # make the root dictionary
+            os.makedirs(self.io_path, exist_ok=True)
+
+            # init sub-folders
+            meta_info_io_path = os.path.join(self.io_path, 'info.csv')
+            eeg_signal_io_path = os.path.join(self.io_path, 'eeg')
+
+            MetaInfoIO(meta_info_io_path)
+            EEGSignalIO(eeg_signal_io_path,
+                        io_size=self.io_size,
+                        io_mode=self.io_mode)
+
+            if self.num_worker == 0:
+                lock = MockLock()  # do nothing, just for compatibility
+                for block in tqdm(self.__block__(io_path=self.io_path,
+                                                 io_size=self.io_size,
+                                                 io_mode=self.io_mode,
+                                                 **kwargs),
+                                  disable=not self.verbose,
+                                  desc="[PROCESS]"):
+                    self.__io__(io_path=self.io_path,
+                                io_size=self.io_size,
+                                io_mode=self.io_mode,
+                                block=block,
+                                lock=lock,
+                                **kwargs)
+            else:
+                # lock for lmdb writter, LMDB only allows single-process writes
+                manager = Manager()
+                lock = manager.Lock()
+
+                Parallel(n_jobs=self.num_worker)(
+                    delayed(self.__io__)(io_path=io_path,
+                                         io_size=io_size,
+                                         io_mode=io_mode,
+                                         block=block,
+                                         lock=lock,
+                                         **kwargs)
+                    for block in tqdm(self.__block__(io_path=self.io_path,
+                                                     io_size=self.io_size,
+                                                     io_mode=self.io_mode,
+                                                     **kwargs),
+                                      disable=not self.verbose,
+                                      desc="[PROCESS]"))
+
+        print(
+            f'dataset already exists at path {self.io_path}, reading from path...'
+        )
 
         meta_info_io_path = os.path.join(self.io_path, 'info.csv')
         eeg_signal_io_path = os.path.join(self.io_path, 'eeg')
 
         info_io = MetaInfoIO(meta_info_io_path)
         self.eeg_io = EEGSignalIO(eeg_signal_io_path,
-                                  io_size=io_size,
-                                  io_mode=io_mode)
+                                  io_size=self.io_size,
+                                  io_mode=self.io_mode)
 
         self.info = info_io.read_all()
 
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        '''
+        The IO method for generating the database. It is used to describe how data blocks are processed to generate the database. It is called in parallel by :obj:`joblib.Parallel` in :obj:`__init__` of the class.
+
+        Args:
+            io_path (str): The path to generated unified data IO, cached as an intermediate result. (default: :obj:`None`)
+            io_size (int): Maximum size database may grow to; used to size the memory mapping. If database grows larger than ``map_size``, an exception will be raised and the user must close and reopen. (default: :obj:`10485760`)
+            io_mode (str): Storage mode of EEG signal. When io_mode is set to :obj:`lmdb`, TorchEEG provides an efficient database (LMDB) for storing EEG signals. LMDB may not perform well on limited operating systems, where a file system based EEG signal storage is also provided. When io_mode is set to :obj:`pickle`, pickle-based persistence files are used. (default: :obj:`lmdb`)
+            block (Any): The block to be processed. It is an element in the list returned by __block__. (default: :obj:`Any`)
+            lock (joblib.parallel.Lock): The lock for IO writter. (default: :obj:`None`)
+            **kwargs: The arguments derived from __init__ of the class.
+
+        .. code-block:: python
+
+            meta_info_io_path = os.path.join(io_path, 'info.csv')
+            eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+            info_io = MetaInfoIO(meta_info_io_path)
+            eeg_io = EEGSignalIO(eeg_signal_io_path,
+                                io_size=io_size,
+                                io_mode=io_mode)
+
+            # derive the given arguments (kwargs)
+            chunk_size = kwargs.pop('chunk_size', 128)  # int
+            offline_transforms = kwargs.pop('offline_transforms', lambda x: x)  # Callable
+            # process block
+            eeg = None
+            key = None
+            info = None
+
+            # can be used in a for loop
+            with lock:
+                info_io.write_eeg(eeg, key)
+                eeg_io.write_info(info)
+
+        '''
+
+        raise NotImplementedError(
+            "Method __io__ is not implemented in class BaseDataset")
+
+    @staticmethod
+    def __block__(**kwargs):
+        '''
+        The block method for generating the database. It is used to describe which data blocks need to be processed to generate the database. It is called in parallel by :obj:`joblib.Parallel` in :obj:`__init__` of the class.
+
+        Args:
+            lock (joblib.parallel.Lock): The lock for IO writter. (default: :obj:`None`)
+            **kwargs: The arguments derived from __init__ of the class.
+
+        .. code-block:: python
+
+            # e.g., return file name list for __io__ to process
+            root_path = kwargs.pop('root_path', None)  # str
+            return os.listdir(root_path)
+
+        '''
+        raise NotImplementedError(
+            "Method __block__ is not implemented in class BaseDataset")
+
     def read_eeg(self, key: str) -> Any:
         r'''
         Query the corresponding EEG signal in the EEGSignalIO according to the the given :obj:`key`. If :obj:`self.in_memory` is set to :obj:`True`, then EEGSignalIO will be read into memory and directly index the specified EEG signal in memory with the given :obj:`key` on subsequent reads.
@@ -285,175 +265,3 @@ def __repr__(self) -> str:
                 format_string += ', '
             format_string += f'{k}={v}'
         return format_string
-
-    @staticmethod
-    def from_existing(dataset,
-                      io_path: str,
-                      offline_transform: Union[None, Callable] = None,
-                      num_worker: int = 0,
-                      verbose: bool = True,
-                      io_size: int = 10485760,
-                      io_mode: str = 'lmdb',
-                      chunk_size_for_worker: int = 100,
-                      chunk_column_for_worker: str = 'baseline_id',
-                      **args):
-        meta_info_io_path = os.path.join(io_path, 'info.csv')
-        eeg_signal_io_path = eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-        exist_io = os.path.exists(meta_info_io_path) and os.path.exists(
-            eeg_signal_io_path)
-
-        if not exist_io:
-            os.makedirs(io_path, exist_ok=True)
-
-            # copy info file
-            shutil.copy(os.path.join(dataset.io_path, 'info.csv'),
-                        os.path.join(io_path, 'info.csv'))
-            # copy dataset
-            if not offline_transform is None:
-                eeg_io = EEGSignalIO(eeg_signal_io_path,
-                                     io_size=io_size,
-                                     io_mode=io_mode)
-                if chunk_column_for_worker in dataset.info.columns:
-                    chunk_for_worker = split_df_by_column(
-                        dataset.info, chunk_column_for_worker)
-                else:
-                    chunk_for_worker = split_df_by_size(dataset.info,
-                                                        chunk_size_for_worker)
-
-                if verbose:
-                    # show process bar
-                    pbar = tqdm(total=len(chunk_for_worker))
-                    pbar.set_description("[FROM EXISTING]")
-                if num_worker > 1:
-                    manager = Manager()
-                    queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-
-                    partial_mp_fn = partial(basic_producer,
-                                            transform=offline_transform,
-                                            read_eeg_fn=dataset.eeg_io.read_eeg,
-                                            queue=queue)
-
-                    io_consumer_process = Process(target=io_consumer,
-                                                  args=(eeg_io.write_eeg,
-                                                        queue),
-                                                  daemon=True)
-                    io_consumer_process.start()
-
-                    for _ in Pool(num_worker).imap(partial_mp_fn,
-                                                   chunk_for_worker):
-                        if verbose:
-                            pbar.update(1)
-
-                    queue.put(None)
-
-                    io_consumer_process.join()
-                    io_consumer_process.close()
-
-                else:
-                    for chunk in chunk_for_worker:
-                        basic_producer(chunk=chunk,
-                                       transform=offline_transform,
-                                       read_eeg_fn=dataset.eeg_io.read_eeg,
-                                       queue=SingleProcessingQueue(
-                                           eeg_io.write_eeg))
-                        if verbose:
-                            pbar.update(1)
-
-                if verbose:
-                    pbar.close()
-                    print('Please wait for the writing process to complete...')
-            else:
-                if verbose:
-                    os.makedirs(os.path.join(io_path, 'eeg'), exist_ok=True)
-                    copy_with_progress(
-                        os.path.join(dataset.io_path, 'eeg', 'data.mdb'),
-                        os.path.join(io_path, 'eeg', 'data.mdb'))
-                else:
-                    shutil.copytree(os.path.join(dataset.io_path, 'eeg'),
-                                    os.path.join(io_path, 'eeg'))
-
-        return type(dataset)(io_path=io_path,
-                             offline_transform=offline_transform,
-                             num_worker=num_worker,
-                             verbose=verbose,
-                             io_size=io_size,
-                             **args)
-
-    @staticmethod
-    def reduce_from_existing(dataset,
-                             io_path: str,
-                             reduce_fn: Callable,
-                             reduce_by: str = 'epoch_id',
-                             verbose: bool = True,
-                             io_size: int = 10485760,
-                             io_mode: str = 'lmdb',
-                             num_worker: int = 0,
-                             chunk_size_for_worker: int = 100,
-                             **args):
-        meta_info_io_path = os.path.join(io_path, 'info.csv')
-        eeg_signal_io_path = eeg_signal_io_path = os.path.join(io_path, 'eeg')
-
-        exist_io = os.path.exists(meta_info_io_path) and os.path.exists(
-            eeg_signal_io_path)
-
-        if not exist_io:
-            os.makedirs(io_path, exist_ok=True)
-
-            info_io = MetaInfoIO(meta_info_io_path)
-            eeg_io = EEGSignalIO(eeg_signal_io_path,
-                                 io_size=io_size,
-                                 io_mode=io_mode)
-
-            reduce_list = split_df_by_column(dataset.info, reduce_by)
-            chunk_for_worker = [
-                reduce_list[i:i + chunk_size_for_worker]
-                for i in range(0, len(reduce_list), chunk_size_for_worker)
-            ]
-
-            if verbose:
-                # show process bar
-                pbar = tqdm(total=len(chunk_for_worker))
-                pbar.set_description("[REDUCE]")
-
-            if num_worker > 1:
-                manager = Manager()
-                queue = manager.Queue(maxsize=MAX_QUEUE_SIZE)
-                io_consumer_process = Process(target=io_consumer,
-                                              args=(eeg_io.write_eeg, queue),
-                                              daemon=True)
-                io_consumer_process.start()
-
-                partial_mp_fn = partial(reduce_producer,
-                                        transform=reduce_fn,
-                                        read_eeg_fn=dataset.eeg_io.read_eeg,
-                                        write_info_fn=info_io.write_info,
-                                        queue=queue)
-
-                for _ in Pool(num_worker).imap(partial_mp_fn, chunk_for_worker):
-                    if verbose:
-                        pbar.update(1)
-
-                queue.put(None)
-
-                io_consumer_process.join()
-                io_consumer_process.close()
-            else:
-                for chunk in chunk_for_worker:
-                    reduce_producer(chunk=chunk,
-                                    transform=reduce_fn,
-                                    read_eeg_fn=dataset.eeg_io.read_eeg,
-                                    write_info_fn=info_io.write_info,
-                                    queue=SingleProcessingQueue(
-                                        eeg_io.write_eeg))
-                    if verbose:
-                        pbar.update(1)
-
-            if verbose:
-                pbar.close()
-
-        return type(dataset)(io_path=io_path,
-                             verbose=verbose,
-                             io_size=io_size,
-                             num_worker=num_worker,
-                             **args)
diff --git a/torcheeg/datasets/module/emotion_recognition/amigos.py b/torcheeg/datasets/module/emotion_recognition/amigos.py
index 54abb6f..c382238 100644
--- a/torcheeg/datasets/module/emotion_recognition/amigos.py
+++ b/torcheeg/datasets/module/emotion_recognition/amigos.py
@@ -1,8 +1,13 @@
-from typing import Callable, Dict, List, Tuple, Union
+import os
+import re
+from typing import Any, Callable, Dict, List, Tuple, Union
+
+import scipy.io as scio
+
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 
 from ...constants.emotion_recognition.amigos import (
     AMIGOS_ADJACENCY_MATRIX, AMIGOS_CHANNEL_LOCATION_DICT)
-from ...functional.emotion_recognition.amigos import amigos_constructor
 from ..base_dataset import BaseDataset
 
 
@@ -147,44 +152,187 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        amigos_constructor(
-            root_path=root_path,
-            chunk_size=chunk_size,
-            overlap=overlap,
-            num_channel=num_channel,
-            num_trial=num_trial,
-            skipped_subjects=skipped_subjects,
-            num_baseline=num_baseline,
-            baseline_chunk_size=baseline_chunk_size,
-            before_trial=before_trial,
-            transform=offline_transform,
-            after_trial=after_trial,
-            io_path=io_path,
-            io_size=io_size,
-            io_mode=io_mode,
-            num_worker=num_worker,
-            verbose=verbose,
-        )
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.root_path = root_path
-        self.chunk_size = chunk_size
-        self.overlap = overlap
-        self.num_channel = num_channel
-        self.num_trial = num_trial
-        self.skipped_subjects = skipped_subjects
-        self.num_baseline = num_baseline
-        self.baseline_chunk_size = baseline_chunk_size
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'chunk_size': chunk_size,
+            'overlap': overlap,
+            'num_channel': num_channel,
+            'num_trial': num_trial,
+            'skipped_subjects': skipped_subjects,
+            'num_baseline': num_baseline,
+            'baseline_chunk_size': baseline_chunk_size,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        file_name = block  # an element from file name list
+        root_path = kwargs.pop('root_path', './data_preprocessed')  # str
+        chunk_size = kwargs.pop('chunk_size', 128)  # int
+        overlap = kwargs.pop('overlap', 0)  # int
+        num_channel = kwargs.pop('num_channel', 14)  # int
+        num_trial = kwargs.pop('num_trial', 16)  # int
+        skipped_subjects = kwargs.pop('skipped_subjects',
+                                      [9, 12, 21, 22, 23, 24, 33])  # list
+        num_baseline = kwargs.pop('num_baseline', 5)  # int
+        baseline_chunk_size = kwargs.pop('baseline_chunk_size', 128)  # int
+        before_trial = kwargs.pop('before_trial', None)  # callable
+        transform = kwargs.pop('offline_transform', None)  # callable
+        after_trial = kwargs.pop('after_trial', None)  # callable
+
+        subject = int(
+            re.findall(r'Data_Preprocessed_P(\d*).mat',
+                       file_name)[0])  # subject (40)
+
+        if subject in skipped_subjects:
+            return
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        data = scio.loadmat(os.path.join(root_path, file_name),
+                            verify_compressed_data_integrity=False)
+        samples = data['joined_data'][
+            0]  # trial (20), timestep(n*128), channel(17) (14 channels are EEGs)
+        # label file
+        labels = data['labels_selfassessment'][
+            0]  # trial (20), label of different dimensions ((1, 12))
+
+        write_pointer = 0
+
+        max_len = len(samples)
+        if not (num_trial <= 0):
+            max_len = min(len(samples), num_trial)
+
+        # loop for each trial
+        for trial_id in range(max_len):
+            # extract baseline signals
+            trial_samples = samples[trial_id]
+
+            # record the common meta info
+            trial_meta_info = {'subject_id': subject, 'trial_id': trial_id}
+            trial_rating = labels[trial_id][
+                0]  # label of different dimensions (12)
+
+            # missing values
+            if (not sum(trial_samples.shape)) or (not sum(trial_rating.shape)):
+                # 3 of the participants (08,24,28<->32) of the previous experiment did not watch a set of 4 long affective
+                if sum(trial_samples.shape) != sum(trial_rating.shape):
+                    print(
+                        f'[WARNING] Find EEG signals without labels, or labels without EEG signals. Please check the {trial_id + 1}-th experiment of the {subject}-th subject in the file {file_name}. TorchEEG currently skipped the mismatched data.'
+                    )
+                continue
+
+            trial_samples = trial_samples.swapaxes(
+                1, 0)  # channel(17), timestep(n*128)
+            if before_trial:
+                trial_samples = before_trial(trial_samples)
+
+            for label_index, label_name in enumerate([
+                    'arousal', 'valence', 'dominance', 'liking', 'familiarity',
+                    'neutral', 'disgust', 'happiness', 'surprise', 'anger',
+                    'fear', 'sadness'
+            ]):
+                trial_meta_info[label_name] = trial_rating[label_index]
+
+            # extract baseline signals
+            trial_baseline_sample = trial_samples[:num_channel, :
+                                                  baseline_chunk_size *
+                                                  num_baseline]  # channel(14), timestep(5*128)
+            trial_baseline_sample = trial_baseline_sample.reshape(
+                num_channel, num_baseline,
+                baseline_chunk_size).mean(axis=1)  # channel(14), timestep(128)
+
+            trial_queue = []
+
+            start_at = baseline_chunk_size * num_baseline
+            if chunk_size <= 0:
+                chunk_size = trial_samples.shape[1] - start_at
+
+            # chunk with chunk size
+            end_at = start_at + chunk_size
+            # calculate moving step
+            step = chunk_size - overlap
+
+            while end_at <= trial_samples.shape[1]:
+                clip_sample = trial_samples[:num_channel, start_at:end_at]
+
+                t_eeg = clip_sample
+                t_baseline = trial_baseline_sample
+                if not transform is None:
+                    t = transform(eeg=clip_sample,
+                                  baseline=trial_baseline_sample)
+                    t_eeg = t['eeg']
+                    t_baseline = t['baseline']
+
+                # put baseline signal into IO
+                if not 'baseline_id' in trial_meta_info:
+                    trial_base_id = f'{file_name}_{write_pointer}'
+                    with lock:
+                        eeg_io.write_eeg(t_baseline, trial_base_id)
+                    write_pointer += 1
+                    trial_meta_info['baseline_id'] = trial_base_id
+
+                clip_id = f'{file_name}_{write_pointer}'
+                write_pointer += 1
+
+                # record meta info for each signal
+                record_info = {
+                    'start_at': start_at,
+                    'end_at': end_at,
+                    'clip_id': clip_id
+                }
+                record_info.update(trial_meta_info)
+                if after_trial:
+                    trial_queue.append({
+                        'eeg': t_eeg,
+                        'key': clip_id,
+                        'info': record_info
+                    })
+                else:
+                    with lock:
+                        eeg_io.write_eeg(t_eeg, clip_id)
+                        info_io.write_info(record_info)
+
+                start_at = start_at + step
+                end_at = start_at + chunk_size
+
+            if len(trial_queue) and after_trial:
+                trial_queue = after_trial(trial_queue)
+                for obj in trial_queue:
+                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                    with lock:
+                        eeg_io.write_eeg(obj['eeg'], obj['key'])
+                        info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './data_preprocessed')  # str
+        return os.listdir(root_path)
 
     def __getitem__(self, index: int) -> Tuple[any, any, int, int, int]:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/emotion_recognition/bci2022.py b/torcheeg/datasets/module/emotion_recognition/bci2022.py
index e3ad4cd..e0e8a20 100644
--- a/torcheeg/datasets/module/emotion_recognition/bci2022.py
+++ b/torcheeg/datasets/module/emotion_recognition/bci2022.py
@@ -1,10 +1,92 @@
-from typing import Callable, Dict, Tuple, Union
+import os
+from typing import Any, Callable, Dict, Tuple, Union
+
+import joblib
+
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 
 from ...constants.emotion_recognition.bci2022 import (
     BCI2022_ADJACENCY_MATRIX, BCI2022_CHANNEL_LOCATION_DICT)
-from ...functional.emotion_recognition.bci2022 import bci2022_constructor
 from ..base_dataset import BaseDataset
 
+FIRST_BATCH_CHANNEL = [
+    'FP1', 'FP2', 'FZ', 'F3', 'F4', 'F7', 'F8', 'FC1', 'FC2', 'FC5', 'FC6',
+    'CZ', 'C3', 'C4', 'T7', 'T8', 'A1', 'A2', 'CP1', 'CP2', 'CP5', 'CP6', 'PZ',
+    'P3', 'P4', 'P7', 'P8', 'PO3', 'PO4', 'OZ', 'O1', 'O2'
+]
+
+SECOND_BATCH_CHANNEL = [
+    'FP1', 'FP2', 'FZ', 'F3', 'F4', 'F7', 'F8', 'FC1', 'FC2', 'FC5', 'FC6',
+    'CZ', 'C3', 'C4', 'T7', 'T8', 'CP1', 'CP2', 'CP5', 'CP6', 'PZ', 'P3', 'P4',
+    'P7', 'P8', 'PO3', 'PO4', 'OZ', 'O1', 'O2', 'A2', 'A1'
+]
+
+FIRST_TO_SECOND_ORDER = [
+    FIRST_BATCH_CHANNEL.index(c) for c in SECOND_BATCH_CHANNEL
+]
+
+VALENCE_DICT = {
+    1: -1,  # negative
+    2: -1,
+    3: -1,
+    4: -1,
+    5: -1,
+    6: -1,
+    7: -1,
+    8: -1,
+    9: -1,
+    10: -1,
+    11: -1,
+    12: -1,
+    13: 0,  # neutral
+    14: 0,
+    15: 0,
+    16: 0,
+    17: 1,  # positive
+    18: 1,
+    19: 1,
+    20: 1,
+    21: 1,
+    22: 1,
+    23: 1,
+    24: 1,
+    25: 1,
+    26: 1,
+    27: 1,
+    28: 1
+}
+
+EMOTION_DICT = {
+    1: 0,  # anger	
+    2: 0,
+    3: 0,
+    4: 1,  # disgust
+    5: 1,
+    6: 1,
+    7: 2,  # fear
+    8: 2,
+    9: 2,
+    10: 3,  # sadness
+    11: 3,
+    12: 3,
+    13: 4,  # neutral
+    14: 4,
+    15: 4,
+    16: 4,
+    17: 5,  # amusement
+    18: 5,
+    19: 5,
+    20: 6,  # excitation
+    21: 6,
+    22: 6,
+    23: 7,  # happy
+    24: 7,
+    25: 7,
+    26: 8,  # warmth
+    27: 8,
+    28: 8
+}
+
 
 class BCI2022Dataset(BaseDataset):
     r'''
@@ -135,34 +217,160 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        bci2022_constructor(root_path=root_path,
-                            chunk_size=chunk_size,
-                            overlap=overlap,
-                            channel_num=channel_num,
-                            before_trial=before_trial,
-                            transform=offline_transform,
-                            after_trial=after_trial,
-                            io_path=io_path,
-                            io_size=io_size,
-                            io_mode=io_mode,
-                            num_worker=num_worker,
-                            verbose=verbose)
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.root_path = root_path
-        self.chunk_size = chunk_size
-        self.overlap = overlap
-        self.channel_num = channel_num
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'chunk_size': chunk_size,
+            'overlap': overlap,
+            'channel_num': channel_num,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        file_name = os.path.basename(block)  # an element from file name list
+        chunk_size = kwargs.pop('chunk_size', 250)  # int
+        overlap = kwargs.pop('overlap', 0)  # int
+        channel_num = kwargs.pop('channel_num', 30)  # int
+        before_trial = kwargs.pop('before_trial', None)  # Callable
+        transform = kwargs.pop('transform', None)  # Callable
+        after_trial = kwargs.pop('after_trial', None)  # Callable
+        reorder = 'TrainSet_first_batch' in file_name  # bool, the first batch needs to be reordered
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        subject = file_name  # subject (54)
+        samples = joblib.load(os.path.join(
+            block, f'{file_name}.pkl'))  # channel(33), timestep(n*250)
+
+        events = samples[-1]
+        if reorder:
+            samples = samples.take(FIRST_TO_SECOND_ORDER, axis=0)
+
+        # initial pointers
+        trial_id = 0
+        write_pointer = 0
+
+        video_id = None
+        start_at = None
+        end_at = None
+
+        # loop for each trial
+        for i, event in enumerate(events):
+
+            if event in list(range(1, 29)):
+                # Video events 1-28: Different events correspond to different experimental video materials
+                video_id = event
+            elif event == 240:
+                # Current trial video start event 240: This event appears 0.1s after the video event, indicating that the video starts to play.
+                start_at = i
+            elif event == 241:
+                # Current trial video end event 241: This event indicates that the video ends playing. Block end event 243: This event indicates the end of the block.
+                end_at = i
+                assert (not video_id is None) and (
+                    not start_at is None
+                ), f'Parse event fail for trial {trial_id} with video_id={video_id}, start_at={start_at}, end_at={end_at}!'
+
+                trial_meta_info = {
+                    'trial_id': trial_id,
+                    'video_id': video_id,
+                    'subject_id': subject,
+                    'valence': VALENCE_DICT[video_id],
+                    'emotion': EMOTION_DICT[video_id],
+                }
+
+                cur_start_at = start_at
+                if chunk_size <= 0:
+                    chunk_size = end_at - start_at
+                cur_end_at = cur_start_at + chunk_size
+                step = chunk_size - overlap
+
+                trial_queue = []
+
+                if before_trial:
+                    samples[:channel_num, cur_start_at:end_at] = before_trial(
+                        samples[:channel_num, cur_start_at:end_at])
+
+                while cur_end_at <= end_at:
+                    t_eeg = samples[:channel_num, cur_start_at:cur_end_at]
+                    if not transform is None:
+                        t_eeg = transform(eeg=t_eeg)['eeg']
+
+                    clip_id = f'{subject}_{write_pointer}'
+                    write_pointer += 1
+
+                    record_info = {
+                        'start_at': cur_start_at,
+                        'end_at': cur_end_at,
+                        'clip_id': clip_id
+                    }
+                    record_info.update(trial_meta_info)
+                    if after_trial:
+                        trial_queue.append({
+                            'eeg': t_eeg,
+                            'key': clip_id,
+                            'info': record_info
+                        })
+                    else:
+                        with lock:
+                            eeg_io.write_eeg(t_eeg, clip_id)
+                            info_io.write_info(record_info)
+
+                    cur_start_at = cur_start_at + step
+                    cur_end_at = cur_start_at + chunk_size
+
+                if len(trial_queue) and after_trial:
+                    trial_queue = after_trial(trial_queue)
+                    for obj in trial_queue:
+                        assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                        with lock:
+                            eeg_io.write_eeg(t_eeg, clip_id)
+                            info_io.write_info(record_info)
+
+                # prepare for the next trial
+                trial_id += 1
+                video_id = None
+                start_at = None
+                end_at = None
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './data_preprocessed_python')  # str
+        outputs = []
+        for train_set_batch in [
+                'TrainSet_first_batch', 'TrainSet_second_batch'
+        ]:
+            # loop to access the first batch files
+            file_list = os.listdir(os.path.join(root_path, train_set_batch))
+            for file in file_list:
+                # loop to access the second batch files
+                file_path = os.path.join(root_path, train_set_batch, file)
+                outputs.append(file_path)
+        return outputs
 
     def __getitem__(self, index: int) -> Tuple[any, any, int, int, int]:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/emotion_recognition/deap.py b/torcheeg/datasets/module/emotion_recognition/deap.py
index 9b4d199..24d3bca 100644
--- a/torcheeg/datasets/module/emotion_recognition/deap.py
+++ b/torcheeg/datasets/module/emotion_recognition/deap.py
@@ -1,6 +1,9 @@
-from typing import Callable, Dict, Tuple, Union
+import os
+import pickle as pkl
+from typing import Any, Callable, Dict, Tuple, Union
+
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 
-from ...functional.emotion_recognition.deap import deap_constructor
 from ..base_dataset import BaseDataset
 
 
@@ -121,6 +124,7 @@ class DEAPDataset(BaseDataset):
         verbose (bool): Whether to display logs during processing, such as progress bars, etc. (default: :obj:`True`)
         in_memory (bool): Whether to load the entire dataset into memory. If :obj:`in_memory` is set to True, then the first time an EEG sample is read, the entire dataset is loaded into memory for subsequent retrieval. Otherwise, the dataset is stored on disk to avoid the out-of-memory problem. (default: :obj:`False`)
     '''
+
     def __init__(self,
                  root_path: str = './data_preprocessed_python',
                  chunk_size: int = 128,
@@ -139,38 +143,154 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        deap_constructor(root_path=root_path,
-                         chunk_size=chunk_size,
-                         overlap=overlap,
-                         num_channel=num_channel,
-                         num_baseline=num_baseline,
-                         baseline_chunk_size=baseline_chunk_size,
-                         before_trial=before_trial,
-                         transform=offline_transform,
-                         after_trial=after_trial,
-                         io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         num_worker=num_worker,
-                         verbose=verbose)
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.root_path = root_path
-        self.chunk_size = chunk_size
-        self.overlap = overlap
-        self.num_channel = num_channel
-        self.num_baseline = num_baseline
-        self.baseline_chunk_size = baseline_chunk_size
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'chunk_size': chunk_size,
+            'overlap': overlap,
+            'num_channel': num_channel,
+            'num_baseline': num_baseline,
+            'baseline_chunk_size': baseline_chunk_size,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        file_name = block  # an element from file name list
+        root_path = kwargs.pop('root_path', './data_preprocessed_python')
+        chunk_size = kwargs.pop('chunk_size', 128)
+        overlap = kwargs.pop('overlap', 0)
+        num_channel = kwargs.pop('num_channel', 32)
+        num_baseline = kwargs.pop('num_baseline', 3)
+        baseline_chunk_size = kwargs.pop('baseline_chunk_size', 128)
+        before_trial = kwargs.pop('before_trial', None)
+        transform = kwargs.pop('offline_transform', None)
+        after_trial = kwargs.pop('after_trial', None)
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        # derive the given arguments (kwargs)
+        with open(os.path.join(root_path, file_name), 'rb') as f:
+            pkl_data = pkl.load(f, encoding='iso-8859-1')
+
+        samples = pkl_data['data']  # trial(40), channel(32), timestep(63*128)
+        labels = pkl_data['labels']
+        subject_id = file_name
+
+        write_pointer = 0
+        # loop for each trial
+        for trial_id in range(len(samples)):
+            # extract baseline signals
+
+            trial_samples = samples[
+                trial_id, :num_channel]  # channel(32), timestep(63*128)
+            if before_trial:
+                trial_samples = before_trial(trial_samples)
+
+            trial_baseline_sample = trial_samples[:, :baseline_chunk_size *
+                                                  num_baseline]  # channel(32), timestep(3*128)
+            trial_baseline_sample = trial_baseline_sample.reshape(
+                num_channel, num_baseline,
+                baseline_chunk_size).mean(axis=1)  # channel(32), timestep(128)
+
+            # record the common meta info
+            trial_meta_info = {'subject_id': subject_id, 'trial_id': trial_id}
+            trial_rating = labels[trial_id]
+
+            for label_index, label_name in enumerate(
+                ['valence', 'arousal', 'dominance', 'liking']):
+                trial_meta_info[label_name] = trial_rating[label_index]
+
+            start_at = baseline_chunk_size * num_baseline
+            if chunk_size <= 0:
+                chunk_size = trial_samples.shape[1] - start_at
+
+            # chunk with chunk size
+            end_at = start_at + chunk_size
+            # calculate moving step
+            step = chunk_size - overlap
+
+            trial_queue = []
+            while end_at <= trial_samples.shape[1]:
+                clip_sample = trial_samples[:, start_at:end_at]
+
+                t_eeg = clip_sample
+                t_baseline = trial_baseline_sample
+
+                if not transform is None:
+                    t = transform(eeg=clip_sample,
+                                  baseline=trial_baseline_sample)
+                    t_eeg = t['eeg']
+                    t_baseline = t['baseline']
+
+                # put baseline signal into IO
+                if not 'baseline_id' in trial_meta_info:
+                    trial_base_id = f'{file_name}_{write_pointer}'
+                    with lock:
+                        eeg_io.write_eeg(t_baseline, trial_base_id)
+                    write_pointer += 1
+                    trial_meta_info['baseline_id'] = trial_base_id
+
+                clip_id = f'{file_name}_{write_pointer}'
+                write_pointer += 1
+
+                # record meta info for each signal
+                record_info = {
+                    'start_at': start_at,
+                    'end_at': end_at,
+                    'clip_id': clip_id
+                }
+                record_info.update(trial_meta_info)
+                if after_trial:
+                    trial_queue.append({
+                        'eeg': t_eeg,
+                        'key': clip_id,
+                        'info': record_info
+                    })
+                else:
+                    with lock:
+                        eeg_io.write_eeg(t_eeg, clip_id)
+                        info_io.write_info(record_info)
+
+                start_at = start_at + step
+                end_at = start_at + chunk_size
+
+            if len(trial_queue) and after_trial:
+                trial_queue = after_trial(trial_queue)
+                for obj in trial_queue:
+                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                    with lock:
+                        eeg_io.write_eeg(obj['eeg'], obj['key'])
+                        info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './data_preprocessed_python')  # str
+        return os.listdir(root_path)
 
     def __getitem__(self, index: int) -> Tuple:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/emotion_recognition/dreamer.py b/torcheeg/datasets/module/emotion_recognition/dreamer.py
index b423132..902a2aa 100644
--- a/torcheeg/datasets/module/emotion_recognition/dreamer.py
+++ b/torcheeg/datasets/module/emotion_recognition/dreamer.py
@@ -1,9 +1,10 @@
-from typing import Callable, Dict, Tuple, Union
-
+import os
+from typing import Callable, Dict, Tuple, Union, Any
+import scipy.io as scio
 from ...constants.emotion_recognition.dreamer import (
     DREAMER_ADJACENCY_MATRIX, DREAMER_CHANNEL_LOCATION_DICT)
-from ...functional.emotion_recognition.dreamer import dreamer_constructor
 from ..base_dataset import BaseDataset
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 
 
 class DREAMERDataset(BaseDataset):
@@ -138,38 +139,170 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        dreamer_constructor(mat_path=mat_path,
-                            chunk_size=chunk_size,
-                            overlap=overlap,
-                            num_channel=num_channel,
-                            num_baseline=num_baseline,
-                            baseline_chunk_size=baseline_chunk_size,
-                            before_trial=before_trial,
-                            transform=offline_transform,
-                            after_trial=after_trial,
-                            io_path=io_path,
-                            io_size=io_size,
-                            io_mode=io_mode,
-                            num_worker=num_worker,
-                            verbose=verbose)
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.mat_path = mat_path
-        self.chunk_size = chunk_size
-        self.overlap = overlap
-        self.num_channel = num_channel
-        self.num_baseline = num_baseline
-        self.baseline_chunk_size = baseline_chunk_size
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'mat_path': mat_path,
+            'chunk_size': chunk_size,
+            'overlap': overlap,
+            'num_channel': num_channel,
+            'num_baseline': num_baseline,
+            'baseline_chunk_size': baseline_chunk_size,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        subject = block
+        mat_path = kwargs.pop('mat_path', './DREAMER.mat')  # str
+        chunk_size = kwargs.pop('chunk_size', 128)  # int
+        overlap = kwargs.pop('overlap', 0)  # int
+        num_channel = kwargs.pop('num_channel', 14)  # int
+        num_baseline = kwargs.pop('num_baseline', 61)  # int
+        baseline_chunk_size = kwargs.pop('baseline_chunk_size', 128)  # int
+        before_trial = kwargs.pop('before_trial', None)  # Callable
+        transform = kwargs.pop('offline_transform', None)  # Callable
+        after_trial = kwargs.pop('after_trial', None)  # Callable
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        mat_data = scio.loadmat(mat_path,
+                                verify_compressed_data_integrity=False)
+
+        trial_len = len(
+            mat_data['DREAMER'][0, 0]['Data'][0,
+                                              0]['EEG'][0,
+                                                        0]['stimuli'][0,
+                                                                      0])  # 18
+
+        write_pointer = 0
+        # loop for each trial
+        for trial_id in range(trial_len):
+            # extract baseline signals
+            trial_baseline_sample = mat_data['DREAMER'][0, 0]['Data'][
+                0, subject]['EEG'][0, 0]['baseline'][0, 0][trial_id, 0]
+            trial_baseline_sample = trial_baseline_sample[:, :num_channel].swapaxes(
+                1, 0)  # channel(14), timestep(61*128)
+            trial_baseline_sample = trial_baseline_sample[:, :num_baseline *
+                                                          baseline_chunk_size].reshape(
+                                                              num_channel,
+                                                              num_baseline,
+                                                              baseline_chunk_size
+                                                          ).mean(
+                                                              axis=1
+                                                          )  # channel(14), timestep(128)
+
+            # record the common meta info
+            trial_meta_info = {'subject_id': subject, 'trial_id': trial_id}
+
+            trial_meta_info['valence'] = mat_data['DREAMER'][0, 0]['Data'][
+                0, subject]['ScoreValence'][0, 0][trial_id, 0]
+            trial_meta_info['arousal'] = mat_data['DREAMER'][0, 0]['Data'][
+                0, subject]['ScoreArousal'][0, 0][trial_id, 0]
+            trial_meta_info['dominance'] = mat_data['DREAMER'][0, 0]['Data'][
+                0, subject]['ScoreDominance'][0, 0][trial_id, 0]
+
+            trial_samples = mat_data['DREAMER'][0, 0]['Data'][
+                0, subject]['EEG'][0, 0]['stimuli'][0, 0][trial_id, 0]
+            trial_samples = trial_samples[:, :num_channel].swapaxes(
+                1, 0)  # channel(14), timestep(n*128)
+
+            if before_trial:
+                trial_samples = before_trial(trial_samples)
+
+            start_at = 0
+            if chunk_size <= 0:
+                chunk_size = trial_samples.shape[1] - start_at
+
+            # chunk with chunk size
+            end_at = chunk_size
+            # calculate moving step
+            step = chunk_size - overlap
+
+            trial_queue = []
+            while end_at <= trial_samples.shape[1]:
+                clip_sample = trial_samples[:, start_at:end_at]
+
+                t_eeg = clip_sample
+                t_baseline = trial_baseline_sample
+
+                if not transform is None:
+                    t = transform(eeg=clip_sample,
+                                  baseline=trial_baseline_sample)
+                    t_eeg = t['eeg']
+                    t_baseline = t['baseline']
+
+                # put baseline signal into IO
+                if not 'baseline_id' in trial_meta_info:
+                    trial_base_id = f'{subject}_{write_pointer}'
+                    with lock:
+                        eeg_io.write_eeg(t_baseline, trial_base_id)
+                    write_pointer += 1
+                    trial_meta_info['baseline_id'] = trial_base_id
+
+                clip_id = f'{subject}_{write_pointer}'
+                write_pointer += 1
+
+                # record meta info for each signal
+                record_info = {
+                    'start_at': start_at,
+                    'end_at': end_at,
+                    'clip_id': clip_id
+                }
+                record_info.update(trial_meta_info)
+                if after_trial:
+                    trial_queue.append({
+                        'eeg': t_eeg,
+                        'key': clip_id,
+                        'info': record_info
+                    })
+                else:
+                    with lock:
+                        eeg_io.write_eeg(t_eeg, clip_id)
+                        info_io.write_info(record_info)
+
+                start_at = start_at + step
+                end_at = start_at + chunk_size
+
+            if len(trial_queue) and after_trial:
+                trial_queue = after_trial(trial_queue)
+                for obj in trial_queue:
+                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                    with lock:
+                        eeg_io.write_eeg(obj['eeg'], obj['key'])
+                        info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        mat_path = kwargs.pop('mat_path', './DREAMER.mat')  # str
+        mat_data = scio.loadmat(mat_path,
+                                verify_compressed_data_integrity=False)
+
+        subject_len = len(mat_data['DREAMER'][0, 0]['Data'][0])  # 23
+        return list(range(subject_len))
 
     def __getitem__(self, index: int) -> Tuple:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/emotion_recognition/mahnob.py b/torcheeg/datasets/module/emotion_recognition/mahnob.py
index 74bcca1..6436fa1 100644
--- a/torcheeg/datasets/module/emotion_recognition/mahnob.py
+++ b/torcheeg/datasets/module/emotion_recognition/mahnob.py
@@ -1,8 +1,14 @@
-from typing import Callable, Dict, Tuple, Union
+import glob
+import json
+import os
+from typing import Any, Callable, Dict, Tuple, Union
+from torcheeg.io import EEGSignalIO, MetaInfoIO
+
+import mne
+import xmltodict
 
 from ...constants.emotion_recognition.mahnob import (
     MAHNOB_ADJACENCY_MATRIX, MAHNOB_CHANNEL_LOCATION_DICT)
-from ...functional.emotion_recognition.mahnob import mahnob_constructor
 from ..base_dataset import BaseDataset
 
 
@@ -153,42 +159,191 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        mahnob_constructor(root_path=root_path,
-                           chunk_size=chunk_size,
-                           sampling_rate=sampling_rate,
-                           overlap=overlap,
-                           num_channel=num_channel,
-                           num_baseline=num_baseline,
-                           baseline_chunk_size=baseline_chunk_size,
-                           num_trial_sample=num_trial_sample,
-                           before_trial=before_trial,
-                           transform=offline_transform,
-                           after_trial=after_trial,
-                           io_path=io_path,
-                           io_size=io_size,
-                           io_mode=io_mode,
-                           num_worker=num_worker,
-                           verbose=verbose)
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.root_path = root_path
-        self.chunk_size = chunk_size
-        self.sampling_rate = sampling_rate
-        self.overlap = overlap
-        self.num_channel = num_channel
-        self.num_baseline = num_baseline
-        self.baseline_chunk_size = baseline_chunk_size
-        self.num_trial_sample = num_trial_sample
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'chunk_size': chunk_size,
+            'sampling_rate': sampling_rate,
+            'overlap': overlap,
+            'num_channel': num_channel,
+            'num_baseline': num_baseline,
+            'baseline_chunk_size': baseline_chunk_size,
+            'num_trial_sample': num_trial_sample,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        file_name = block
+        root_path = kwargs.pop('root_path', './Sessions')  # str
+        chunk_size = kwargs.pop('chunk_size', 128)  # int
+        sampling_rate = kwargs.pop('sampling_rate', 128)  # int
+        overlap = kwargs.pop('overlap', 0)  # int
+        num_channel = kwargs.pop('num_channel', 32)  # int
+        num_baseline = kwargs.pop('num_baseline', 30)  # int
+        baseline_chunk_size = kwargs.pop('baseline_chunk_size', 128)  # int
+        num_trial_sample = kwargs.pop('num_trial_sample', 30)  # int
+        before_trial = kwargs.pop('before_trial', None)  # Callable
+        transform = kwargs.pop('offline_transform', None)  # Callable
+        after_trial = kwargs.pop('after_trial', None)  # Callable
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        trial_dir = os.path.join(root_path, file_name)
+
+        mne.set_log_level('CRITICAL')
+        # record the common meta info for the trial
+        label_file = os.path.join(trial_dir, 'session.xml')
+        emodims = [
+            '@feltArsl', '@feltCtrl', '@feltEmo', '@feltPred', '@feltVlnc',
+            '@isStim'
+        ]
+        with open(label_file) as f:
+            label_info = xmltodict.parse('\n'.join(f.readlines()))
+        label_info = json.loads(json.dumps(label_info))['session']
+
+        if not '@feltArsl' in label_info:
+            # skip label_info['@isStim'] == '0' and other exception
+            return
+
+        trial_meta_info = {
+            'subject_id': label_info['subject']['@id'],
+            'trial_id': label_info['@mediaFile'],
+            'duration': float(label_info['@cutLenSec'])
+        }
+        # feltArsl, feltCtrl, feltEmo, feltPred, feltVlnc, isStim
+        trial_meta_info.update({k[1:]: int(label_info[k]) for k in emodims})
+
+        write_pointer = 0
+
+        # extract signals
+        sample_file = glob.glob(str(os.path.join(trial_dir, '*.bdf')))[0]
+
+        raw = mne.io.read_raw_bdf(sample_file,
+                                  preload=True,
+                                  stim_channel='Status')
+        events = mne.find_events(raw, stim_channel='Status')
+
+        montage = mne.channels.make_standard_montage(kind='biosemi32')
+        raw.set_montage(montage, on_missing='ignore')
+
+        # pick channels
+        raw.pick_channels(raw.ch_names[:num_channel])
+
+        start_samp, end_samp = events[0][0] + 1, events[1][0] - 1
+
+        # extract baseline signals
+        trial_baseline_raw = raw.copy().crop(raw.times[0], raw.times[end_samp])
+        trial_baseline_raw = trial_baseline_raw.resample(sampling_rate)
+
+        trial_baseline_sample = trial_baseline_raw.to_data_frame().to_numpy(
+        )[:, 1:].swapaxes(1, 0)  # channel(32), timestep(30 * 128)
+        trial_baseline_sample = trial_baseline_sample[:, :num_baseline *
+                                                      baseline_chunk_size]
+        trial_baseline_sample = trial_baseline_sample.reshape(
+            num_channel, num_baseline,
+            baseline_chunk_size).mean(axis=1)  # channel(32), timestep(128)
+
+        # extract experimental signals
+        trial_raw = raw.copy().crop(raw.times[start_samp], raw.times[end_samp])
+        trial_raw = trial_raw.resample(sampling_rate)
+        trial_samples = trial_raw.to_data_frame().to_numpy()[:,
+                                                             1:].swapaxes(1, 0)
+        if before_trial:
+            trial_samples = before_trial(trial_samples)
+
+        start_at = 0
+        if chunk_size <= 0:
+            chunk_size = trial_samples.shape[1] - start_at
+
+        # chunk with chunk size
+        end_at = chunk_size
+        # calculate moving step
+        step = chunk_size - overlap
+
+        max_len = trial_samples.shape[1]
+        if not (num_trial_sample <= 0):
+            max_len = min(num_trial_sample * chunk_size, trial_samples.shape[1])
+
+        trial_queue = []
+        while end_at <= max_len:
+            clip_sample = trial_samples[:, start_at:end_at]
+
+            t_eeg = clip_sample
+            t_baseline = trial_baseline_sample
+            if not transform is None:
+                t = transform(eeg=clip_sample, baseline=trial_baseline_sample)
+                t_eeg = t['eeg']
+                t_baseline = t['baseline']
+
+            # put baseline signal into IO
+            if not 'baseline_id' in trial_meta_info:
+                trial_base_id = f'{file_name}_{write_pointer}'
+                with lock:
+                    eeg_io.write_eeg(t_baseline, trial_base_id)
+                write_pointer += 1
+                trial_meta_info['baseline_id'] = trial_base_id
+
+            clip_id = f'{file_name}_{write_pointer}'
+            write_pointer += 1
+
+            # record meta info for each signal
+            record_info = {
+                'start_at': start_at,
+                'end_at': end_at,
+                'clip_id': clip_id
+            }
+            record_info.update(trial_meta_info)
+            if after_trial:
+                trial_queue.append({
+                    'eeg': t_eeg,
+                    'key': clip_id,
+                    'info': record_info
+                })
+            else:
+                with lock:
+                    eeg_io.write_eeg(t_eeg, clip_id)
+                    info_io.write_info(record_info)
+
+            start_at = start_at + step
+            end_at = start_at + chunk_size
+
+        if len(trial_queue) and after_trial:
+            trial_queue = after_trial(trial_queue)
+            for obj in trial_queue:
+                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                with lock:
+                    eeg_io.write_eeg(obj['eeg'], obj['key'])
+                    info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './Sessions')  # str
+        return os.listdir(root_path)
 
     def __getitem__(self, index: int) -> Tuple:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/emotion_recognition/mped_feature.py b/torcheeg/datasets/module/emotion_recognition/mped_feature.py
index c735376..849e8ab 100644
--- a/torcheeg/datasets/module/emotion_recognition/mped_feature.py
+++ b/torcheeg/datasets/module/emotion_recognition/mped_feature.py
@@ -1,9 +1,13 @@
-from typing import Callable, Dict, Tuple, Union
+import os
+from typing import Any, Callable, Dict, Tuple, Union
+
+import numpy as np
+import scipy.io as scio
+
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 
 from ...constants.emotion_recognition.mped import (MPED_ADJACENCY_MATRIX,
                                                    MPED_CHANNEL_LOCATION_DICT)
-from ...functional.emotion_recognition.mped_feature import \
-    mped_feature_constructor
 from ..base_dataset import BaseDataset
 
 
@@ -114,33 +118,145 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        mped_feature_constructor(root_path=root_path,
-                                 feature=feature,
-                                 num_channel=num_channel,
-                                 before_trial=before_trial,
-                                 transform=offline_transform,
-                                 after_trial=after_trial,
-                                 io_path=io_path,
-                                 io_size=io_size,
-                                 io_mode=io_mode,
-                                 num_worker=num_worker,
-                                 verbose=verbose)
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.root_path = root_path
-        self.feature = feature
-        self.num_channel = num_channel
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.verbose = verbose
-        self.io_size = io_size
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'feature': feature,
+            'num_channel': num_channel,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        file_name = block
+        root_path = kwargs.pop('root_path', './EEG_feature')
+        feature = kwargs.pop('feature', ['PSD'])
+        num_channel = kwargs.pop('num_channel', 62)
+        before_trial = kwargs.pop('before_trial', None)
+        transform = kwargs.pop('offline_transform', None)
+        after_trial = kwargs.pop('after_trial', None)
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        labels = [
+            0, 2, 1, 4, 3, 5, 6, 7, 1, 2, 3, 6, 7, 4, 5, 0, 1, 5, 6, 2, 2, 1, 7,
+            6, 4, 4, 3, 5, 3, 7
+        ]  # 0-resting status, 1-neutral, 2-joy, 3-funny, 4-angry, 5-fear, 6-disgust, 7-sadness
+
+        subject = os.path.basename(file_name).split('.')[0].split('_')[0]
+
+        samples_dict = {}
+        for cur_feature in feature:
+            samples_dict[cur_feature] = scio.loadmat(
+                os.path.join(root_path, cur_feature, file_name),
+                verify_compressed_data_integrity=False)  # (1, 30)
+        write_pointer = 0
+
+        for trial_id in range(30):
+            trial_samples = []
+            for cur_feature, samples in samples_dict.items():
+                for sub_band in samples.keys():
+                    # HHS: hhs_A, hhs_E
+                    # Hjorth/HOC: alpha, beta, delta, gamma, theta, whole
+                    # STFT: STFT
+                    # PSD: PSD
+                    if not str.startswith(sub_band, '__'):
+                        # not '__header__', '__version__', '__globals__'
+                        trial_samples += [
+                            samples[sub_band][0][trial_id][:num_channel],
+                        ]
+                        # PSD: (62, 120, 5)
+                        # Hjorth: (62, 120, 3)
+                        # HOC: (62, 120, 20)
+                        # HHS: (62, 120, 5)
+                        # STFT: (62, 120, 5)
+            trial_samples = np.concatenate(trial_samples,
+                                           axis=-1)  # (62, 120, num_features)
+            if before_trial:
+                trial_samples = before_trial(trial_samples)
+
+            # record the common meta info
+            trial_meta_info = {
+                'subject_id': subject,
+                'trial_id': trial_id,
+                'emotion': labels[trial_id]
+            }
+            num_clips = trial_samples.shape[1]
+
+            trial_queue = []
+            for clip_id in range(num_clips):
+                # PSD: (62, 5)
+                # Hjorth: (62, 3 * 6)
+                # HOC: (62, 20 * 6)
+                # STFT: (62, 5)
+                # HHS: (62, 5 * 2)
+                clip_sample = trial_samples[:, clip_id]
+
+                t_eeg = clip_sample
+                if not transform is None:
+                    t_eeg = transform(eeg=clip_sample)['eeg']
+
+                clip_id = f'{file_name}_{write_pointer}'
+                write_pointer += 1
+
+                # record meta info for each signal
+                record_info = {'clip_id': clip_id}
+                record_info.update(trial_meta_info)
+                if after_trial:
+                    trial_queue.append({
+                        'eeg': t_eeg,
+                        'key': clip_id,
+                        'info': record_info
+                    })
+                else:
+                    with lock:
+                        eeg_io.write_eeg(t_eeg, clip_id)
+                        info_io.write_info(record_info)
+
+            if len(trial_queue) and after_trial:
+                trial_queue = after_trial(trial_queue)
+                for obj in trial_queue:
+                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                    with lock:
+                        eeg_io.write_eeg(obj['eeg'], obj['key'])
+                        info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './data_preprocessed_python')  # str
+        feature = kwargs.pop('feature', ['PSD'])  # list
+        avaliable_features = os.listdir(root_path)
+
+        assert set(feature).issubset(
+            set(avaliable_features)
+        ), 'The features supported by the MPEDFeature dataset are HHS, Hjorth, PSD, STFT, HOC. The input features are not a subset of the list of supported features.'
+
+        file_list = os.listdir(os.path.join(root_path, avaliable_features[0]))
+        return file_list
 
     def __getitem__(self, index: int) -> Tuple[any, any, int, int, int]:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/emotion_recognition/seed.py b/torcheeg/datasets/module/emotion_recognition/seed.py
index 659cd32..e0131d6 100644
--- a/torcheeg/datasets/module/emotion_recognition/seed.py
+++ b/torcheeg/datasets/module/emotion_recognition/seed.py
@@ -1,8 +1,11 @@
-from typing import Callable, Dict, Tuple, Union
+import os
+from torcheeg.io import EEGSignalIO, MetaInfoIO
+from typing import Any, Callable, Dict, Tuple, Union
+
+import scipy.io as scio
 
 from ...constants.emotion_recognition.seed import (SEED_ADJACENCY_MATRIX,
                                                    SEED_CHANNEL_LOCATION_DICT)
-from ...functional.emotion_recognition.seed import seed_constructor
 from ..base_dataset import BaseDataset
 
 
@@ -139,34 +142,140 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        seed_constructor(root_path=root_path,
-                         chunk_size=chunk_size,
-                         overlap=overlap,
-                         num_channel=num_channel,
-                         before_trial=before_trial,
-                         transform=offline_transform,
-                         after_trial=after_trial,
-                         io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         num_worker=num_worker,
-                         verbose=verbose)
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.root_path = root_path
-        self.chunk_size = chunk_size
-        self.overlap = overlap
-        self.num_channel = num_channel
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'chunk_size': chunk_size,
+            'overlap': overlap,
+            'num_channel': num_channel,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        file_name = block
+        root_path = kwargs.pop('root_path', './Preprocessed_EEG')  # str
+        chunk_size = kwargs.pop('chunk_size', 200)  # int
+        overlap = kwargs.pop('overlap', 0)  # int
+        num_channel = kwargs.pop('num_channel', 62)  # int
+        before_trial = kwargs.pop('before_trial', None)  # Callable
+        transform = kwargs.pop('offline_transform', None)  # Callable
+        after_trial = kwargs.pop('after_trial', None)  # Callable
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        subject = int(os.path.basename(file_name).split('.')[0].split('_')
+                      [0])  # subject (15)
+        date = int(os.path.basename(file_name).split('.')[0].split('_')
+                   [1])  # period (3)
+
+        samples = scio.loadmat(os.path.join(root_path, file_name),
+                               verify_compressed_data_integrity=False
+                               )  # trial (15), channel(62), timestep(n*200)
+        # label file
+        labels = scio.loadmat(
+            os.path.join(root_path, 'label.mat'),
+            verify_compressed_data_integrity=False)['label'][0]
+
+        trial_ids = [key for key in samples.keys() if 'eeg' in key]
+
+        write_pointer = 0
+        # loop for each trial
+        for trial_id in trial_ids:
+            # extract baseline signals
+            trial_samples = samples[trial_id]  # channel(62), timestep(n*200)
+            if before_trial:
+                trial_samples = before_trial(trial_samples)
+
+            # record the common meta info
+            trial_meta_info = {
+                'subject_id': subject,
+                'trial_id': trial_id,
+                'emotion': int(labels[int(trial_id.split('_')[-1][3:]) - 1]),
+                'date': date
+            }
+
+            # extract experimental signals
+            start_at = 0
+            if chunk_size <= 0:
+                chunk_size = trial_samples.shape[1] - start_at
+
+            # chunk with chunk size
+            end_at = chunk_size
+            # calculate moving step
+            step = chunk_size - overlap
+
+            trial_queue = []
+            while end_at <= trial_samples.shape[1]:
+                clip_sample = trial_samples[:num_channel, start_at:end_at]
+
+                t_eeg = clip_sample
+                if not transform is None:
+                    t_eeg = transform(eeg=clip_sample)['eeg']
+
+                clip_id = f'{file_name}_{write_pointer}'
+                write_pointer += 1
+
+                # record meta info for each signal
+                record_info = {
+                    'start_at': start_at,
+                    'end_at': end_at,
+                    'clip_id': clip_id
+                }
+                record_info.update(trial_meta_info)
+                if after_trial:
+                    trial_queue.append({
+                        'eeg': t_eeg,
+                        'key': clip_id,
+                        'info': record_info
+                    })
+                else:
+                    with lock:
+                        eeg_io.write_eeg(t_eeg, clip_id)
+                        info_io.write_info(record_info)
+
+                start_at = start_at + step
+                end_at = start_at + chunk_size
+
+            if len(trial_queue) and after_trial:
+                trial_queue = after_trial(trial_queue)
+                for obj in trial_queue:
+                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                    with lock:
+                        eeg_io.write_eeg(obj['eeg'], obj['key'])
+                        info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './Preprocessed_EEG')  # str
+        file_list = os.listdir(root_path)
+        skip_set = ['label.mat', 'readme.txt']
+        file_list = [f for f in file_list if f not in skip_set]
+        return file_list
 
     def __getitem__(self, index: int) -> Tuple[any, any, int, int, int]:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/emotion_recognition/seed_feature.py b/torcheeg/datasets/module/emotion_recognition/seed_feature.py
index ccee17c..a21987b 100644
--- a/torcheeg/datasets/module/emotion_recognition/seed_feature.py
+++ b/torcheeg/datasets/module/emotion_recognition/seed_feature.py
@@ -1,9 +1,14 @@
-from typing import Callable, Dict, Tuple, Union
+import os
+import re
+from typing import Any, Callable, Dict, Tuple, Union
+
+import numpy as np
+import scipy.io as scio
+
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 
 from ...constants.emotion_recognition.seed import (SEED_ADJACENCY_MATRIX,
                                                    SEED_CHANNEL_LOCATION_DICT)
-from ...functional.emotion_recognition.seed_feature import \
-    seed_feature_constructor
 from ..base_dataset import BaseDataset
 
 
@@ -117,33 +122,136 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        seed_feature_constructor(root_path=root_path,
-                                 feature=feature,
-                                 num_channel=num_channel,
-                                 before_trial=before_trial,
-                                 transform=offline_transform,
-                                 after_trial=after_trial,
-                                 io_path=io_path,
-                                 io_size=io_size,
-                                 io_mode=io_mode,
-                                 num_worker=num_worker,
-                                 verbose=verbose)
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.root_path = root_path
-        self.feature = feature
-        self.num_channel = num_channel
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.verbose = verbose
-        self.io_size = io_size
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'feature': feature,
+            'num_channel': num_channel,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        file_name = block
+        root_path = kwargs.pop('root_path', './ExtractedFeatures')  # str
+        feature = kwargs.pop('feature', ['de_movingAve'])  # list
+        num_channel = kwargs.pop('num_channel', 62)  # int
+        before_trial = kwargs.pop('before_trial', None)  # Callable
+        transform = kwargs.pop('offline_transform', None)  # Callable
+        after_trial = kwargs.pop('after_trial', None)  # Callable
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        subject = int(os.path.basename(file_name).split('.')[0].split('_')
+                      [0])  # subject (15)
+        date = int(os.path.basename(file_name).split('.')[0].split('_')
+                   [1])  # period (3)
+
+        samples = scio.loadmat(os.path.join(root_path, file_name),
+                               verify_compressed_data_integrity=False
+                               )  # trial (15), channel(62), timestep(n*200)
+        # label file
+        labels = scio.loadmat(
+            os.path.join(root_path, 'label.mat'),
+            verify_compressed_data_integrity=False)['label'][0]
+
+        trial_ids = [
+            int(re.findall(r"de_movingAve(\d+)", key)[0])
+            for key in samples.keys() if 'de_movingAve' in key
+        ]
+
+        write_pointer = 0
+        # loop for each trial
+        for trial_id in trial_ids:
+            # extract baseline signals
+            trial_samples = []
+            for cur_feature in feature:
+                trial_samples.append(samples[
+                    cur_feature +
+                    str(trial_id)])  # channel(62), timestep(n), bands(5)
+            trial_samples = np.concatenate(
+                trial_samples,
+                axis=-1)[:
+                         num_channel]  # channel(62), timestep(n), features(5*k)
+            trial_samples = trial_samples.transpose((1, 0, 2))
+
+            if before_trial:
+                trial_samples = before_trial(trial_samples)
+
+            # record the common meta info
+            trial_meta_info = {
+                'subject_id': subject,
+                'trial_id': trial_id,
+                'emotion': int(labels[trial_id - 1]),
+                'date': date
+            }
+
+            trial_queue = []
+            for i, clip_sample in enumerate(trial_samples):
+                t_eeg = clip_sample
+                if not transform is None:
+                    t_eeg = transform(eeg=clip_sample)['eeg']
+
+                clip_id = f'{file_name}_{write_pointer}'
+                write_pointer += 1
+
+                # record meta info for each signal
+                record_info = {
+                    'start_at': i * 200,
+                    'end_at': (i + 1) * 200,
+                    'clip_id': clip_id
+                }
+                record_info.update(trial_meta_info)
+                if after_trial:
+                    trial_queue.append({
+                        'eeg': t_eeg,
+                        'key': clip_id,
+                        'info': record_info
+                    })
+                else:
+                    with lock:
+                        eeg_io.write_eeg(t_eeg, clip_id)
+                        info_io.write_info(record_info)
+
+            if len(trial_queue) and after_trial:
+                trial_queue = after_trial(trial_queue)
+                for obj in trial_queue:
+                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                    with lock:
+                        eeg_io.write_eeg(obj['eeg'], obj['key'])
+                        info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './ExtractedFeatures')  # str
+        file_list = os.listdir(root_path)
+        skip_set = ['label.mat', 'readme.txt']
+        file_list = [f for f in file_list if f not in skip_set]
+        return file_list
 
     def __getitem__(self, index: int) -> Tuple[any, any, int, int, int]:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/emotion_recognition/seed_iv.py b/torcheeg/datasets/module/emotion_recognition/seed_iv.py
index 52f1220..e31a84b 100644
--- a/torcheeg/datasets/module/emotion_recognition/seed_iv.py
+++ b/torcheeg/datasets/module/emotion_recognition/seed_iv.py
@@ -1,8 +1,13 @@
-from typing import Callable, Dict, Tuple, Union
+import os
+import re
+from typing import Any, Callable, Dict, Tuple, Union
+
+import scipy.io as scio
+
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 
 from ...constants.emotion_recognition.seed_iv import (
     SEED_IV_ADJACENCY_MATRIX, SEED_IV_CHANNEL_LOCATION_DICT)
-from ...functional.emotion_recognition.seed_iv import seed_iv_constructor
 from ..base_dataset import BaseDataset
 
 
@@ -130,36 +135,171 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        seed_iv_constructor(
-            root_path=root_path,
-            chunk_size=chunk_size,
-            overlap=overlap,
-            num_channel=num_channel,
-            before_trial=before_trial,
-            transform=offline_transform,
-            after_trial=after_trial,
-            io_path=io_path,
-            io_size=io_size,
-            io_mode=io_mode,
-            num_worker=num_worker,
-            verbose=verbose,
-        )
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.root_path = root_path
-        self.chunk_size = chunk_size
-        self.overlap = overlap
-        self.num_channel = num_channel
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'chunk_size': chunk_size,
+            'overlap': overlap,
+            'num_channel': num_channel,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        file_path = block  # an element from file name list
+        chunk_size = kwargs.pop('chunk_size', 800)
+        overlap = kwargs.pop('overlap', 0)
+        num_channel = kwargs.pop('num_channel', 62)
+        before_trial = kwargs.pop('before_trial', None)
+        transform = kwargs.pop('transform', None)
+        after_trial = kwargs.pop('after_trial', None)
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        session_id = os.path.basename(os.path.dirname(file_path))
+        _, file_name = os.path.split(file_path)
+
+        subject = int(os.path.basename(file_name).split('.')[0].split('_')
+                      [0])  # subject (15)
+        date = int(os.path.basename(file_name).split('.')[0].split('_')
+                   [1])  # period (3)
+
+        samples = scio.loadmat(file_path,
+                               verify_compressed_data_integrity=False
+                               )  # trial (15), channel(62), timestep(n*200)
+        # label file
+        labels = [
+            [
+                1, 2, 3, 0, 2, 0, 0, 1, 0, 1, 2, 1, 1, 1, 2, 3, 2, 2, 3, 3, 0,
+                3, 0, 3
+            ],
+            [
+                2, 1, 3, 0, 0, 2, 0, 2, 3, 3, 2, 3, 2, 0, 1, 1, 2, 1, 0, 3, 0,
+                1, 3, 1
+            ],
+            [
+                1, 2,
+                2, 1,
+                3, 3,
+                3, 1,
+                1, 2,
+                1, 0,
+                2, 3,
+                3, 0,
+                2, 3,
+                0, 0,
+                2, 0,
+                1, 0
+            ]
+        ]  # The labels with 0, 1, 2, and 3 denote the ground truth, neutral, sad, fear, and happy emotions, respectively.
+        session_labels = labels[int(session_id) - 1]
+
+        trial_name_ids = [(trial_name,
+                           int(re.findall(r".*_eeg(\d+)", trial_name)[0]))
+                          for trial_name in samples.keys()
+                          if 'eeg' in trial_name]
+
+        write_pointer = 0
+        # loop for each trial
+        for trial_name, trial_id in trial_name_ids:
+            trial_samples = samples[trial_name]  # channel(62), timestep(n*200)
+            if before_trial:
+                trial_samples = before_trial(trial_samples)
+
+            # record the common meta info
+            trial_meta_info = {
+                'subject_id': subject,
+                'trial_id': trial_id,
+                'session_id': session_id,
+                'emotion': int(session_labels[trial_id - 1]),
+                'date': date
+            }
+
+            # extract experimental signals
+            start_at = 0
+            if chunk_size <= 0:
+                chunk_size = trial_samples.shape[1] - start_at
+
+            # chunk with chunk size
+            end_at = chunk_size
+            # calculate moving step
+            step = chunk_size - overlap
+
+            trial_queue = []
+            while end_at <= trial_samples.shape[1]:
+                clip_sample = trial_samples[:num_channel, start_at:end_at]
+
+                t_eeg = clip_sample
+                if not transform is None:
+                    t_eeg = transform(eeg=clip_sample)['eeg']
+
+                clip_id = f'{file_name}_{write_pointer}'
+                write_pointer += 1
+
+                # record meta info for each signal
+                record_info = {
+                    'start_at': start_at,
+                    'end_at': end_at,
+                    'clip_id': clip_id
+                }
+                record_info.update(trial_meta_info)
+                if after_trial:
+                    trial_queue.append({
+                        'eeg': t_eeg,
+                        'key': clip_id,
+                        'info': record_info
+                    })
+                else:
+                    with lock:
+                        eeg_io.write_eeg(t_eeg, clip_id)
+                        info_io.write_info(record_info)
+
+                start_at = start_at + step
+                end_at = start_at + chunk_size
+
+            if len(trial_queue) and after_trial:
+                trial_queue = after_trial(trial_queue)
+                for obj in trial_queue:
+                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                    with lock:
+                        eeg_io.write_eeg(obj['eeg'], obj['key'])
+                        info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './eeg_raw_data')  # str
+        session_list = ['1', '2', '3']
+        file_path_list = []
+        for session in session_list:
+            session_root_path = os.path.join(root_path, session)
+            for file_name in os.listdir(session_root_path):
+                file_path_list.append(os.path.join(session_root_path,
+                                                   file_name))
+        return file_path_list
 
     def __getitem__(self, index: int) -> Tuple[any, any, int, int, int]:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/emotion_recognition/seed_iv_feature.py b/torcheeg/datasets/module/emotion_recognition/seed_iv_feature.py
index 7a01f6c..c71e47f 100644
--- a/torcheeg/datasets/module/emotion_recognition/seed_iv_feature.py
+++ b/torcheeg/datasets/module/emotion_recognition/seed_iv_feature.py
@@ -1,9 +1,14 @@
-from typing import Callable, Dict, Tuple, Union
+import os
+import re
+from typing import Any, Callable, Dict, Tuple, Union
+
+import numpy as np
+import scipy.io as scio
+
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 
 from ...constants.emotion_recognition.seed_iv import (
     SEED_IV_ADJACENCY_MATRIX, SEED_IV_CHANNEL_LOCATION_DICT)
-from ...functional.emotion_recognition.seed_iv_feature import \
-    seed_iv_feature_constructor
 from ..base_dataset import BaseDataset
 
 
@@ -106,32 +111,169 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        seed_iv_feature_constructor(root_path=root_path,
-                                    feature=feature,
-                                    num_channel=num_channel,
-                                    before_trial=before_trial,
-                                    transform=offline_transform,
-                                    after_trial=after_trial,
-                                    io_path=io_path,
-                                    io_size=io_size,
-                                    io_mode=io_mode,
-                                    num_worker=num_worker,
-                                    verbose=verbose)
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.root_path = root_path
-        self.feature = feature
-        self.num_channel = num_channel
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'feature': feature,
+            'num_channel': num_channel,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        file_path = block  # an element from file name list
+        feature = kwargs.pop('feature', ['de_movingAve'])
+        num_channel = kwargs.pop('num_channel', 62)
+        before_trial = kwargs.pop('before_trial', None)
+        transform = kwargs.pop('offline_transform', None)
+        after_trial = kwargs.pop('after_trial', None)
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        session_id = os.path.basename(os.path.dirname(file_path))
+        _, file_name = os.path.split(file_path)
+
+        subject = int(os.path.basename(file_name).split('.')[0].split('_')
+                      [0])  # subject (15)
+        date = int(os.path.basename(file_name).split('.')[0].split('_')
+                   [1])  # period (3)
+
+        samples = scio.loadmat(file_path,
+                               verify_compressed_data_integrity=False
+                               )  # trial (15), channel(62), timestep(n*200)
+        # label file
+        labels = [
+            [
+                1, 2, 3, 0, 2, 0, 0, 1, 0, 1, 2, 1, 1, 1, 2, 3, 2, 2, 3, 3, 0,
+                3, 0, 3
+            ],
+            [
+                2, 1, 3, 0, 0, 2, 0, 2, 3, 3, 2, 3, 2, 0, 1, 1, 2, 1, 0, 3, 0,
+                1, 3, 1
+            ],
+            [
+                1, 2,
+                2, 1,
+                3, 3,
+                3, 1,
+                1, 2,
+                1, 0,
+                2, 3,
+                3, 0,
+                2, 3,
+                0, 0,
+                2, 0,
+                1, 0
+            ]
+        ]  # The labels with 0, 1, 2, and 3 denote the ground truth, neutral, sad, fear, and happy emotions, respectively.
+        session_labels = labels[int(session_id) - 1]
+
+        trial_ids = [
+            int(re.findall(r"de_movingAve(\d+)", key)[0])
+            for key in samples.keys() if 'de_movingAve' in key
+        ]
+
+        write_pointer = 0
+        # loop for each trial
+        for trial_id in trial_ids:
+            # extract baseline signals
+            trial_samples = []
+            for cur_feature in feature:
+                trial_samples.append(samples[
+                    cur_feature +
+                    str(trial_id)])  # channel(61), timestep(n), bands(5)
+            trial_samples = np.concatenate(
+                trial_samples,
+                axis=-1)[:
+                         num_channel]  # channel(61), timestep(n), features(5*k)
+            trial_samples = trial_samples.transpose((1, 0, 2))
+            # timestep(n), channel(61), features(5*k)
+
+            if before_trial:
+                trial_samples = before_trial(trial_samples)
+
+            # record the common meta info
+            trial_meta_info = {
+                'subject_id': subject,
+                'trial_id': trial_id,
+                'session_id': session_id,
+                'emotion': int(session_labels[trial_id - 1]),
+                'date': date
+            }
+
+            trial_queue = []
+            for i, clip_sample in enumerate(trial_samples):
+                t_eeg = clip_sample
+                if not transform is None:
+                    t_eeg = transform(eeg=clip_sample)['eeg']
+
+                clip_id = f'{file_name}_{write_pointer}'
+                write_pointer += 1
+
+                # record meta info for each signal
+                record_info = {
+                    'start_at': i * 400,
+                    'end_at': (i + 1) *
+                    400,  # The size of the sliding time windows for feature extraction is 4 seconds.
+                    'clip_id': clip_id
+                }
+                record_info.update(trial_meta_info)
+                if after_trial:
+                    trial_queue.append({
+                        'eeg': t_eeg,
+                        'key': clip_id,
+                        'info': record_info
+                    })
+                else:
+                    with lock:
+                        eeg_io.write_eeg(t_eeg, clip_id)
+                        info_io.write_info(record_info)
+
+            if len(trial_queue) and after_trial:
+                trial_queue = after_trial(trial_queue)
+                for obj in trial_queue:
+                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                    with lock:
+                        eeg_io.write_eeg(obj['eeg'], obj['key'])
+                        info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './eeg_feature_smooth')  # str
+
+        session_list = ['1', '2', '3']
+        file_path_list = []
+        for session in session_list:
+            session_root_path = os.path.join(root_path, session)
+            for file_name in os.listdir(session_root_path):
+                file_path_list.append(os.path.join(session_root_path,
+                                                   file_name))
+
+        return file_path_list
 
     def __getitem__(self, index: int) -> Tuple[any, any, int, int, int]:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/folder_dataset.py b/torcheeg/datasets/module/folder_dataset.py
new file mode 100644
index 0000000..5bd8672
--- /dev/null
+++ b/torcheeg/datasets/module/folder_dataset.py
@@ -0,0 +1,206 @@
+import os
+from pathlib import Path
+from typing import Any, Callable, Dict, Tuple, Union
+
+import mne
+import numpy as np
+
+from torcheeg.io import EEGSignalIO, MetaInfoIO
+
+from .base_dataset import BaseDataset
+
+
+def default_read_fn(file_path, **kwargs):
+    # Load EEG file
+    raw = mne.io.read_raw(file_path)
+    # Convert raw to epochs
+    epochs = mne.make_fixed_length_epochs(raw, duration=1)
+    # Return EEG data
+    return epochs
+
+
+class FolderDataset(BaseDataset):
+    '''
+    Read EEG samples and their corresponding labels from a fixed folder structure. This class allows two kinds of common file structures, :obj:`subject_in_label` and :obj:`label_in_subject`. Here, :obj:`subject_in_label` corresponds to the following file structure:
+
+    .. code-block:: python
+
+        tree
+        # outputs
+        label01
+        |- sub01.edf
+        |- sub02.edf
+        label02
+        |- sub01.edf
+        |- sub02.edf
+
+    And :obj:`label_in_subject` corresponds to the following file structure:
+
+    .. code-block:: python
+
+        tree
+        # outputs
+        sub01
+        |- label01.edf
+        |- label02.edf
+        sub02
+        |- label01.edf
+        |- label02.edf
+
+    Args:
+        root_path (str): The path to the root folder. (default: :obj:`'./folder'`)
+        structure (str): Folder structure, which affects how labels and subjects are mapped to EEG signal samples. Please refer to the above description of the structure of the two folders to select the correct parameters. (default: :obj:`'subject_in_label'`)
+        read_fn (Callable): Method for reading files in a folder. By default, this class provides methods for reading files using :obj:`mne.io.read_raw`. At the same time, we allow users to pass in custom file reading methods. The first input parameter of whose is file_path, and other parameters are additional parameters passed in when the class is initialized. For example, you can pass :obj:`chunk_size=32` to :obj:`FolderDataset`, then :obj:`chunk_size` will be received here.
+        online_transform (Callable, optional): The transformation of the EEG signals and baseline EEG signals. The input is a :obj:`np.ndarray`, and the ouput is used as the first and second value of each element in the dataset. (default: :obj:`None`)
+        offline_transform (Callable, optional): The usage is the same as :obj:`online_transform`, but executed before generating IO intermediate results. (default: :obj:`None`)
+        label_transform (Callable, optional): The transformation of the label. The input is an information dictionary, and the ouput is used as the third value of each element in the dataset. (default: :obj:`None`)
+        io_path (str): The path to generated unified data IO, cached as an intermediate result. (default: :obj:`./io/deap`)
+        io_size (int): Maximum size database may grow to; used to size the memory mapping. If database grows larger than ``map_size``, an exception will be raised and the user must close and reopen. (default: :obj:`10485760`)
+        io_mode (str): Storage mode of EEG signal. When io_mode is set to :obj:`lmdb`, TorchEEG provides an efficient database (LMDB) for storing EEG signals. LMDB may not perform well on limited operating systems, where a file system based EEG signal storage is also provided. When io_mode is set to :obj:`pickle`, pickle-based persistence files are used. (default: :obj:`lmdb`)
+        num_worker (str): How many subprocesses to use for data processing. (default: :obj:`0`)
+        verbose (bool): Whether to display logs during processing, such as progress bars, etc. (default: :obj:`True`)
+        in_memory (bool): Whether to load the entire dataset into memory. If :obj:`in_memory` is set to True, then the first time an EEG sample is read, the entire dataset is loaded into memory for subsequent retrieval. Otherwise, the dataset is stored on disk to avoid the out-of-memory problem. (default: :obj:`False`)
+    '''
+    def __init__(self,
+                 root_path: str = './folder',
+                 structure: str = 'subject_in_label',
+                 read_fn: Union[None, Callable] = default_read_fn,
+                 online_transform: Union[None, Callable] = None,
+                 offline_transform: Union[None, Callable] = None,
+                 label_transform: Union[None, Callable] = None,
+                 io_path: str = './io/folder',
+                 io_size: int = 10485760,
+                 io_mode: str = 'lmdb',
+                 num_worker: int = 0,
+                 verbose: bool = True,
+                 in_memory: bool = False,
+                 **kwargs):
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'structure': structure,
+            'read_fn': read_fn,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        params.update(kwargs)
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+
+        file_path, subject_id, label = block
+        transform = kwargs.pop('offline_transform', None)  # Callable
+        read_fn = kwargs.pop('read_fn', None)
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        trial_samples = read_fn(file_path, **kwargs)
+        events = [i[0] for i in trial_samples.events]
+        events.append(
+            events[-1] +
+            np.diff(events)[0])  # time interval between all events are same
+
+        write_pointer = 0
+        for i, trial_signal in enumerate(trial_samples.get_data()):
+            t_eeg = trial_signal
+            if not transform is None:
+                t = transform(eeg=trial_signal)
+                t_eeg = t['eeg']
+
+            clip_id = f'{subject_id}_{label}_{write_pointer}'
+            write_pointer += 1
+
+            record_info = {
+                'subject_id': subject_id,
+                'trial_id': i,
+                'start_at': events[i],
+                'end_at': events[i + 1],
+                'clip_id': clip_id,
+                'label': label
+            }
+
+            with lock:
+                eeg_io.write_eeg(t_eeg, clip_id)
+                info_io.write_info(record_info)
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './folder')  # str
+        folder_mode = kwargs.pop('structure', 'subject_in_label')  # str
+        # get all the subfolders
+        subfolders = [str(i) for i in Path(root_path).iterdir() if i.is_dir()]
+        # get all the files in the subfolders
+        file_path_list = []
+        for subfolder in subfolders:
+            file_path_list += [
+                str(i) for i in Path(subfolder).iterdir() if i.is_file()
+            ]
+        # get the subject id
+        if folder_mode == 'subject_in_label':
+            # get the file name without the extension
+            subjects = [i.split('/')[-1].split('.')[0] for i in file_path_list]
+            labels = [i.split('/')[-2] for i in file_path_list]
+        elif folder_mode == 'label_in_subject':
+            subjects = [i.split('/')[-2] for i in file_path_list]
+            labels = [i.split('/')[-1].split('.')[0] for i in file_path_list]
+        else:
+            raise ValueError('Unknown folder mode: {}'.format(folder_mode))
+
+        file_path_subject_label = list(zip(file_path_list, subjects, labels))
+        return file_path_subject_label
+
+    def __getitem__(self, index: int) -> Tuple[any, any, int, int, int]:
+        info = self.read_info(index)
+
+        eeg_index = str(info['clip_id'])
+        eeg = self.read_eeg(eeg_index)
+
+        signal = eeg
+        label = info
+
+        if self.online_transform:
+            signal = self.online_transform(eeg=eeg)['eeg']
+
+        if self.label_transform:
+            label = self.label_transform(y=info)['y']
+
+        return signal, label
+
+    @property
+    def repr_body(self) -> Dict:
+        return dict(
+            super().repr_body, **{
+                'root_path': self.root_path,
+                'chunk_size': self.chunk_size,
+                'overlap': self.overlap,
+                'num_channel': self.num_channel,
+                'online_transform': self.online_transform,
+                'offline_transform': self.offline_transform,
+                'label_transform': self.label_transform,
+                'before_trial': self.before_trial,
+                'after_trial': self.after_trial,
+                'num_worker': self.num_worker,
+                'verbose': self.verbose,
+                'io_size': self.io_size
+            })
diff --git a/torcheeg/datasets/module/mne_dataset.py b/torcheeg/datasets/module/mne_dataset.py
index 614ea41..a311c77 100644
--- a/torcheeg/datasets/module/mne_dataset.py
+++ b/torcheeg/datasets/module/mne_dataset.py
@@ -1,8 +1,9 @@
-from typing import Callable, Dict, List, Tuple, Union
-
+import os
+from typing import Callable, Dict, List, Tuple, Union, Any
+import numpy as np
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 import mne
 
-from ..functional.mne import mne_constructor
 from .base_dataset import BaseDataset
 
 
@@ -116,7 +117,7 @@ class MNEDataset(BaseDataset):
             # label (int)
 
     Args:
-        epochs_list (list): A list of :obj:`mne.Epochs`. :obj:`MNEDataset` will divide the signals in :obj:`mne.Epochs` into several segments according to the :obj:`chunk_size` and :obj:`overlap` information provided by the user. The divided segments will be transformed and cached in a unified input and output format (IO) for accessing.
+        epochs_list (list): A list of :obj:`mne.Epochs`. :obj:`MNEDataset` will divide the signals in :obj:`mne.Epochs` into several segments according to the :obj:`chunk_size` and :obj:`overlap` information provided by the user. The divided segments will be transformed and cached in a unified input and output format (IO) for accessing. You can also pass through the path list of the mne.Epochs file (can be obtained by .save()).
         metadata_list (list): A list of dictionaries of the same length as :obj:`epochs_list`. Each of these dictionaries is annotated with meta-information about :obj:`mne.Epochs`, such as subject index, experimental dates, etc. These annotated meta-information will be added to the element corresponding to :obj:`mne.Epochs` for use as labels for the sample.
         chunk_size (int): Number of data points included in each EEG chunk as training or test samples. If set to -1, the EEG signal of a trial is used as a sample of a chunk. If set to -1, the EEG signal is not segmented, and the length of the chunk is the length of the event. (default: :obj:`-1`)
         overlap (int): The number of overlapping data points between different chunks when dividing EEG chunks. (default: :obj:`0`)
@@ -133,6 +134,7 @@ class MNEDataset(BaseDataset):
         verbose (bool): Whether to display logs during processing, such as progress bars, etc. (default: :obj:`True`)
         in_memory (bool): Whether to load the entire dataset into memory. If :obj:`in_memory` is set to True, then the first time an EEG sample is read, the entire dataset is loaded into memory for subsequent retrieval. Otherwise, the dataset is stored on disk to avoid the out-of-memory problem. (default: :obj:`False`)    
     '''
+
     def __init__(self,
                  epochs_list: List[mne.Epochs],
                  metadata_list: List[Dict],
@@ -150,34 +152,160 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        mne_constructor(epochs_list=epochs_list,
-                        metadata_list=metadata_list,
-                        chunk_size=chunk_size,
-                        overlap=overlap,
-                        num_channel=num_channel,
-                        before_trial=before_trial,
-                        transform=offline_transform,
-                        after_trial=after_trial,
-                        io_path=io_path,
-                        io_size=io_size,
-                        io_mode=io_mode,
-                        num_worker=num_worker,
-                        verbose=verbose)
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.chunk_size = chunk_size
-        self.overlap = overlap
-        self.num_channel = num_channel
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'chunk_size': chunk_size,
+            'overlap': overlap,
+            'num_channel': num_channel,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params,
+                         epochs_list=epochs_list,
+                         metadata_list=metadata_list)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        mne.set_log_level('CRITICAL')
+
+        tmp_path, metadata, block_id = block
+        epochs = mne.read_epochs(tmp_path, preload=True)
+
+        chunk_size = kwargs.pop('chunk_size', -1)  # int
+        overlap = kwargs.pop('overlap', 0)  # int
+        num_channel = kwargs.pop('num_channel', -1)  # int
+        before_trial = kwargs.pop('before_trial', None)  # Callable
+        transform = kwargs.pop('offline_transform', None)  # Callable
+        after_trial = kwargs.pop('after_trial', None)  # Callable
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        if chunk_size <= 0:
+            chunk_size = len(epochs.times)
+
+        if num_channel == -1:
+            num_channel = len(epochs.info['chs'])
+
+        trial_event_index = epochs.events[:, 2]
+        trial_start_at_list = epochs.events[:, 0]
+
+        trial_end_at = len(epochs.times) - chunk_size
+
+        clip_sample_start_at_list = np.arange(0, trial_end_at + 1,
+                                              chunk_size - overlap)
+
+        sample_events = [[clip_sample_start_at, chunk_size, -1]
+                         for clip_sample_start_at in clip_sample_start_at_list]
+
+        epoch_meta_info = metadata
+
+        write_pointer = 0
+
+        # for loop of trials
+        for trial_id, trial in enumerate(epochs):
+            # split sample from epochs
+            start_at_list = clip_sample_start_at_list + trial_start_at_list[
+                trial_id]
+            end_at_list = clip_sample_start_at_list + trial_start_at_list[
+                trial_id] + chunk_size
+            event_index_list = len(sample_events) * [
+                trial_event_index[trial_id]
+            ]
+
+            trial_samples = mne.Epochs(mne.io.RawArray(trial, epochs.info),
+                                       sample_events,
+                                       baseline=None,
+                                       tmin=0,
+                                       tmax=(chunk_size - 1) /
+                                       epochs.info["sfreq"])
+            trial_samples.drop_bad(reject=None, flat=None)
+            if before_trial:
+                trial_samples = before_trial(trial_samples)
+
+            # for loop of samples
+            trial_queue = []
+            for i, trial_signal in enumerate(trial_samples.get_data()):
+                t_eeg = trial_signal[:num_channel, :]
+                if not transform is None:
+                    t = transform(eeg=trial_signal[:num_channel, :])
+                    t_eeg = t['eeg']
+
+                clip_id = f'{block_id}_{write_pointer}'
+                write_pointer += 1
+
+                record_info = {
+                    'trial_id': trial_id,
+                    'start_at': start_at_list[i],
+                    'end_at': end_at_list[i],
+                    'event': event_index_list[i],
+                    'clip_id': clip_id
+                }
+                record_info.update(epoch_meta_info)
+                if after_trial:
+                    trial_queue.append({
+                        'eeg': t_eeg,
+                        'key': clip_id,
+                        'info': record_info
+                    })
+                else:
+                    with lock:
+                        eeg_io.write_eeg(t_eeg, clip_id)
+                        info_io.write_info(record_info)
+
+            if len(trial_queue) and after_trial:
+                trial_queue = after_trial(trial_queue)
+                for obj in trial_queue:
+                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                    with lock:
+                        eeg_io.write_eeg(obj['eeg'], obj['key'])
+                        info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        io_path = kwargs.pop('io_path', '.')  # str
+        epochs_list = kwargs.pop('epochs_list', [])  # list
+        metadata_list = kwargs.pop('metadata_list', [])  # list
+        chunk_size = kwargs.pop('chunk_size', -1)  # int
+
+        epochs_metadata_block_id_list = []
+        for block_id, (epochs,
+                       metadata) in enumerate(zip(epochs_list, metadata_list)):
+            if isinstance(epochs, str):
+                epochs_path = epochs
+            else:
+                assert (epochs.tmax - epochs.tmin) * epochs.info[
+                    "sfreq"] >= chunk_size, f'chunk_size cannot be larger than (tmax - tmin) * sfreq. Here, tmax is set to {epochs.tmax}, tmin is set to {epochs.tmin}, and sfreq is {epochs.info["sfreq"]}. In the current configuration, chunk_size {chunk_size} is greater than {(epochs.tmax - epochs.tmin) * epochs.info["sfreq"]}!'
+                # save epochs to disk
+                if not os.path.exists(os.path.join(io_path, 'tmp')):
+                    os.makedirs(os.path.join(io_path, 'tmp'))
+                epochs_path = os.path.join(io_path, 'tmp', f'{block_id}.mne')
+                epochs.save(epochs_path, overwrite=True)
+
+            epochs_metadata_block_id_list.append((epochs_path, metadata, block_id))
+
+        return epochs_metadata_block_id_list
 
     def __getitem__(self, index: int) -> Tuple:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/numpy_dataset.py b/torcheeg/datasets/module/numpy_dataset.py
index 86e492d..f2149ed 100644
--- a/torcheeg/datasets/module/numpy_dataset.py
+++ b/torcheeg/datasets/module/numpy_dataset.py
@@ -1,8 +1,10 @@
+import os
+from typing import Any, Callable, Dict, Tuple, Union
+
 import numpy as np
 
-from typing import Callable, Dict, Tuple, Union
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 
-from ..functional.numpy import numpy_constructor
 from .base_dataset import BaseDataset
 
 
@@ -48,10 +50,7 @@ class NumpyDataset(BaseDataset):
             X = np.random.randn(100, 32, 128)
 
             # Mock 100 labels, denoting valence and arousal of subjects during EEG recording.
-            y = {
-                'valence': np.random.randint(10, size=100),
-                'arousal': np.random.randint(10, size=100)
-            }
+            y = np.random.randint(10, size=100, 2)
             dataset = NumpyDataset(X=X,
                                 y=y,
                                 io_path=io_path,
@@ -59,7 +58,7 @@ class NumpyDataset(BaseDataset):
                                     [transforms.BandDifferentialEntropy()]),
                                 online_transform=transforms.ToTensor(),
                                 label_transform=transforms.Compose([
-                                    transforms.Select('valence'),
+                                    transforms.Select('0'),
                                     transforms.Binary(5.0),
                                 ]),
                                 num_worker=2,
@@ -70,8 +69,8 @@ class NumpyDataset(BaseDataset):
             # label (int)
 
     Args:
-        X (np.ndarray): An array in :obj:`numpy.ndarray` format representing the EEG signal samples in the dataset. The shape of the array is :obj:`[num_sample, ...]` where :obj:`num_sample` is the number of samples.
-        y (dict): A dictionary that records the labels corresponding to EEG samples. The keys of the dictionary represent the names of the labels, and the values are lists of labels whose length is consistent with the EEG signal samples.
+        X (np.ndarray): An array in :obj:`numpy.ndarray` format representing the EEG signal samples in the dataset. The shape of the array is :obj:`[num_sample, ...]` where :obj:`num_sample` is the number of samples. :obj:`X` and :obj:`y` also allow lists of strings to be used together, representing paths to corresponding files of :obj:`X` and :obj:`y` (generated using :obj:`np.save`).
+        y (np.ndarray):An array in :obj:`numpy.ndarray` format representing the labels of EEG signal samples, and the values are lists of labels whose length is consistent with the EEG signal samples. The name of the label is automatically generated from the string corresponding to its index.
         online_transform (Callable, optional): The transformation of the EEG signals and baseline EEG signals. The input is a :obj:`np.ndarray`, and the ouput is used as the first and second value of each element in the dataset. (default: :obj:`None`)
         offline_transform (Callable, optional): The usage is the same as :obj:`online_transform`, but executed before generating IO intermediate results. (default: :obj:`None`)
         label_transform (Callable, optional): The transformation of the label. The input is an information dictionary, and the ouput is used as the third value of each element in the dataset. (default: :obj:`None`)
@@ -85,6 +84,7 @@ class NumpyDataset(BaseDataset):
         verbose (bool): Whether to display logs during processing, such as progress bars, etc. (default: :obj:`True`)
         in_memory (bool): Whether to load the entire dataset into memory. If :obj:`in_memory` is set to True, then the first time an EEG sample is read, the entire dataset is loaded into memory for subsequent retrieval. Otherwise, the dataset is stored on disk to avoid the out-of-memory problem. (default: :obj:`False`)    
     '''
+
     def __init__(self,
                  X: np.ndarray,
                  y: Dict,
@@ -100,30 +100,135 @@ def __init__(self,
                  num_samples_per_worker: int = 100,
                  verbose: bool = True,
                  in_memory: bool = False):
-        numpy_constructor(X=X,
-                          y=y,
-                          before_trial=before_trial,
-                          transform=offline_transform,
-                          after_trial=after_trial,
-                          io_path=io_path,
-                          io_size=io_size,
-                          io_mode=io_mode,
-                          num_worker=num_worker,
-                          num_samples_per_worker=num_samples_per_worker,
-                          verbose=verbose)
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.before_trial = before_trial
-        self.after_trial = after_trial
-        self.num_worker = num_worker
-        self.num_samples_per_worker = num_samples_per_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'num_samples_per_worker': num_samples_per_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params, X=X, y=y)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        X_block_path, y_block_path, block_id = block
+        X = np.load(X_block_path)
+        y = np.load(y_block_path)
+
+        before_trial = kwargs.pop('before_trial', None)
+        transform = kwargs.pop('offline_transform', None)
+        after_trial = kwargs.pop('after_trial', None)
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        if before_trial:
+            X = before_trial(X)
+
+        trial_queue = []
+        for write_pointer, clip_sample in enumerate(X):
+
+            t_eeg = clip_sample
+
+            if not transform is None:
+                t = transform(eeg=clip_sample)
+                t_eeg = t['eeg']
+
+            clip_id = f'{block_id}_{write_pointer}'
+
+            # record meta info for each signal
+            record_info = {'clip_id': clip_id}
+            # y is np.ndarray (n_samples, n_labels)
+            record_info.update(
+                {f'{i}': y[write_pointer, i] for i in range(y.shape[1])})
+            
+            if after_trial:
+                trial_queue.append({
+                    'eeg': t_eeg,
+                    'key': clip_id,
+                    'info': record_info
+                })
+            else:
+                with lock:
+                    eeg_io.write_eeg(t_eeg, clip_id)
+                    info_io.write_info(record_info)
+
+        if len(trial_queue) and after_trial:
+            trial_queue = after_trial(trial_queue)
+            for obj in trial_queue:
+                assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                with lock:
+                    eeg_io.write_eeg(obj['eeg'], obj['key'])
+                    info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        io_path = kwargs.pop('io_path', '.')  # str
+        X = kwargs.pop('X', None)  # np.ndarray
+        y = kwargs.pop('y', None)  # dict
+        num_samples_per_worker = kwargs.pop('num_samples_per_worker',
+                                            100)  # int
+
+        # check if X is a list of str
+        X_str = isinstance(X, list) and all([isinstance(x, str) for x in X])
+        y_str = isinstance(y, list) and all([isinstance(y, str) for y in y])
+
+        if X_str and y_str:
+            X_y_block_id_list = []
+            for block_id, (X_block_path, y_block_path) in enumerate(zip(X, y)):
+                X_y_block_id_list.append((X_block_path, y_block_path, block_id))
+            return X_y_block_id_list
+
+        X_ndarray = isinstance(X, np.ndarray)
+        y_ndarray = isinstance(y, np.ndarray)
+
+        if X_ndarray and y_ndarray:
+            indices = np.arange(len(X))
+            block_samples_list = np.array_split(
+                indices,
+                len(X) // num_samples_per_worker)
+
+            X_y_block_id_list = []
+            for block_id, sample_indices in enumerate(block_samples_list):
+                X_block = X[sample_indices]
+                y_block = y[sample_indices]
+                # save block to disk
+                if not os.path.exists(os.path.join(io_path, 'tmp')):
+                    os.makedirs(os.path.join(io_path, 'tmp'))
+
+                X_block_path = os.path.join(io_path, 'tmp', f'{block_id}_x.npy')
+                np.save(X_block_path, X_block)
+
+                y_block_path = os.path.join(io_path, 'tmp', f'{block_id}_y.npy')
+                np.save(y_block_path, y_block)
+
+                X_y_block_id_list.append((X_block_path, y_block_path, block_id))
+
+            return X_y_block_id_list
+
+        raise ValueError(
+            'X and y must be either a list of paths to np.ndarray, or a np.ndarray.'
+        )
 
     def __getitem__(self, index: int) -> Tuple:
         info = self.read_info(index)
diff --git a/torcheeg/datasets/module/personal_identification/m3cv.py b/torcheeg/datasets/module/personal_identification/m3cv.py
index edb047d..e4f02fd 100644
--- a/torcheeg/datasets/module/personal_identification/m3cv.py
+++ b/torcheeg/datasets/module/personal_identification/m3cv.py
@@ -1,7 +1,12 @@
-from typing import Callable, Union, Tuple, Dict
+import os
+from typing import Any, Callable, Dict, Tuple, Union
+
+import pandas as pd
+import scipy.io as scio
+
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 
 from ..base_dataset import BaseDataset
-from ...functional.personal_identification.m3cv import m3cv_constructor
 
 
 class M3CVDataset(BaseDataset):
@@ -134,41 +139,149 @@ def __init__(self,
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        m3cv_constructor(
-            root_path=root_path,
-            subset=subset,
-            chunk_size=chunk_size,
-            overlap=overlap,
-            num_channel=num_channel,
-            before_trial=before_trial,
-            transform=offline_transform,
-            after_trial=after_trial,
-            io_path=io_path,
-            io_size=io_size,
-            io_mode=io_mode,
-            num_worker=num_worker,
-            verbose=verbose,
-        )
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.root_path = root_path
-        self.subset = subset
-        self.chunk_size = chunk_size
-        self.overlap = overlap
-        self.num_channel = num_channel
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.num_worker = num_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'subset': subset,
+            'chunk_size': chunk_size,
+            'overlap': overlap,
+            'num_channel': num_channel,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        start_idx, end_idx = block
+        root_path = kwargs.pop('root_path', './aistudio')  # str
+        subset = kwargs.pop('subset', 'Enrollment')  # str
+        chunk_size = kwargs.pop('chunk_size', 1000)  # int
+        overlap = kwargs.pop('overlap', 0)  # int
+        num_channel = kwargs.pop('num_channel', 64)  # int
+        before_trial = kwargs.pop('before_trial', None)  # Callable
+        transform = kwargs.pop('transform', None)  # Callable
+        after_trial = kwargs.pop('after_trial', None)  # Callable
+        df = pd.read_csv(os.path.join(root_path, f'{subset}_Info.csv'))
+        df = df.iloc[start_idx:end_idx]
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        # calculate moving step
+        write_pointer = 0
+
+        start_epoch = None
+
+        for _, epoch_info in df.iterrows():
+            epoch_meta_info = {
+                'epoch_id': epoch_info['EpochID'],
+                'subject_id': epoch_info['SubjectID'],
+                'session': epoch_info['Session'],
+                'task': epoch_info['Task'],
+                'usage': epoch_info['Usage'],
+            }
+
+            epoch_id = epoch_meta_info['epoch_id']
+
+            if start_epoch is None:
+                start_epoch = epoch_id
 
+            trial_samples = scio.loadmat(
+                os.path.join(root_path, subset, epoch_id))['epoch_data']
+            if before_trial:
+                trial_samples = before_trial(trial_samples)
+
+            start_at = 0
+            if chunk_size <= 0:
+                chunk_size = trial_samples.shape[1] - start_at
+
+            # chunk with chunk size
+            end_at = chunk_size
+            # calculate moving step
+            step = chunk_size - overlap
+
+            trial_queue = []
+            while end_at <= trial_samples.shape[1]:
+                clip_sample = trial_samples[:num_channel, start_at:end_at]
+                t_eeg = clip_sample
+
+                if not transform is None:
+                    t_eeg = transform(eeg=clip_sample)['eeg']
+
+                clip_id = f'after{start_epoch}_{write_pointer}'
+                write_pointer += 1
+
+                # record meta info for each signal
+                record_info = {
+                    'start_at': start_at,
+                    'end_at': end_at,
+                    'clip_id': clip_id
+                }
+                record_info.update(epoch_meta_info)
+                if after_trial:
+                    trial_queue.append({
+                        'eeg': t_eeg,
+                        'key': clip_id,
+                        'info': record_info
+                    })
+                else:
+                    with lock:
+                        eeg_io.write_eeg(t_eeg, clip_id)
+                        info_io.write_info(record_info)
+
+                start_at = start_at + step
+                end_at = start_at + chunk_size
+
+            if len(trial_queue) and after_trial:
+                trial_queue = after_trial(trial_queue)
+                for obj in trial_queue:
+                    assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                    with lock:
+                        eeg_io.write_eeg(obj['eeg'], obj['key'])
+                        info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './aistudio')  # str
+        subset = kwargs.pop('subset', 'Enrollment')  # str
         assert subset in [
             'Enrollment', 'Calibration', 'Testing'
         ], f"Unavailable subset name {subset}, and available options include 'Enrollment', 'Calibration', and 'Testing'."
 
+        df = pd.read_csv(os.path.join(root_path, f'{subset}_Info.csv'))
+        # split the dataset into 60 blocks, each of which contains len(df) // 60 samples, the start and end index of each block are recorded in block_list
+        block_list = []
+        for i in range(60):
+            start = i * len(df) // 60
+            end = (i + 1) * len(df) // 60
+            block_list.append((start, end))
+        # the last block contains the remaining samples
+        if len(df) % 60 != 0:
+            block_list[-1] = (block_list[-1][0], len(df))
+        return block_list
+
     def __getitem__(self, index: int) -> Tuple:
         info = self.read_info(index)
 
diff --git a/torcheeg/datasets/module/sspev/tsu_benchmark.py b/torcheeg/datasets/module/sspev/tsu_benchmark.py
index cec0bfb..56aecbd 100644
--- a/torcheeg/datasets/module/sspev/tsu_benchmark.py
+++ b/torcheeg/datasets/module/sspev/tsu_benchmark.py
@@ -1,9 +1,14 @@
-from typing import Callable, Dict, Tuple, Union
+import os
+import re
+from typing import Any, Callable, Dict, Tuple, Union
+
+import scipy.io as scio
+
+from torcheeg.io import EEGSignalIO, MetaInfoIO
 
 from ...constants.ssvep.tsu_benchmark import (TSUBENCHMARK_ADJACENCY_MATRIX,
                                               TSUBENCHMARK_CHANNEL_LOCATION_DICT
                                               )
-from ...functional.ssvep.tsu_benchmark import tsu_benchmark_constructor
 from ..base_dataset import BaseDataset
 
 
@@ -102,6 +107,8 @@ class TSUBenckmarkDataset(BaseDataset):
         online_transform (Callable, optional): The transformation of the EEG signals and baseline EEG signals. The input is a :obj:`np.ndarray`, and the ouput is used as the first and second value of each element in the dataset. (default: :obj:`None`)
         offline_transform (Callable, optional): The usage is the same as :obj:`online_transform`, but executed before generating IO intermediate results. (default: :obj:`None`)
         label_transform (Callable, optional): The transformation of the label. The input is an information dictionary, and the ouput is used as the third value of each element in the dataset. (default: :obj:`None`)
+        before_trial (Callable, optional): The hook performed on the trial to which the sample belongs. It is performed before the offline transformation and thus typically used to implement context-dependent sample transformations, such as moving averages, etc. The input of this hook function is a 2D EEG signal with shape (number of electrodes, number of data points), whose ideal output shape is also (number of electrodes, number of data points).
+        after_trial (Callable, optional): The hook performed on the trial to which the sample belongs. It is performed after the offline transformation and thus typically used to implement context-dependent sample transformations, such as moving averages, etc. The input and output of this hook function should be a sequence of dictionaries representing a sequence of EEG samples. Each dictionary contains two key-value pairs, indexed by :obj:`eeg` (the EEG signal matrix) and :obj:`key` (the index in the database) respectively.
         io_path (str): The path to generated unified data IO, cached as an intermediate result. (default: :obj:`./io/tsu_benchmark`)
         num_worker (str): How many subprocesses to use for data processing. (default: :obj:`0`)
         verbose (bool): Whether to display logs during processing, such as progress bars, etc. (default: :obj:`True`)
@@ -118,36 +125,152 @@ def __init__(self,
                  online_transform: Union[None, Callable] = None,
                  offline_transform: Union[None, Callable] = None,
                  label_transform: Union[None, Callable] = None,
+                 before_trial: Union[None, Callable] = None,
+                 after_trial: Union[None, Callable] = None,
                  io_path: str = './io/tsu_benchmark',
                  io_size: int = 10485760,
                  io_mode: str = 'lmdb',
                  num_worker: int = 0,
                  verbose: bool = True,
                  in_memory: bool = False):
-        tsu_benchmark_constructor(root_path=root_path,
-                                  chunk_size=chunk_size,
-                                  overlap=overlap,
-                                  num_channel=num_channel,
-                                  transform=offline_transform,
-                                  io_path=io_path,
-                                  io_size=io_size,
-                                  io_mode=io_mode,
-                                  num_worker=num_worker,
-                                  verbose=verbose)
-        super().__init__(io_path=io_path,
-                         io_size=io_size,
-                         io_mode=io_mode,
-                         in_memory=in_memory)
-
-        self.root_path = root_path
-        self.chunk_size = chunk_size
-        self.overlap = overlap
-        self.num_channel = num_channel
-        self.online_transform = online_transform
-        self.offline_transform = offline_transform
-        self.label_transform = label_transform
-        self.num_worker = num_worker
-        self.verbose = verbose
+        # pass all arguments to super class
+        params = {
+            'root_path': root_path,
+            'chunk_size': chunk_size,
+            'overlap': overlap,
+            'num_channel': num_channel,
+            'online_transform': online_transform,
+            'offline_transform': offline_transform,
+            'label_transform': label_transform,
+            'before_trial': before_trial,
+            'after_trial': after_trial,
+            'io_path': io_path,
+            'io_size': io_size,
+            'io_mode': io_mode,
+            'num_worker': num_worker,
+            'verbose': verbose,
+            'in_memory': in_memory
+        }
+        super().__init__(**params)
+        # save all arguments to __dict__
+        self.__dict__.update(params)
+
+    @staticmethod
+    def __io__(io_path: str = None,
+               io_size: int = 10485760,
+               io_mode: str = 'lmdb',
+               block: Any = None,
+               lock: Any = None,
+               **kwargs):
+        file_name = block
+        root_path = kwargs.pop('root_path', './TSUBenchmark')
+        chunk_size = kwargs.pop('chunk_size', 250)
+        overlap = kwargs.pop('overlap', 0)
+        num_channel = kwargs.pop('num_channel', 64)
+        before_trial = kwargs.pop('before_trial', None)
+        transform = kwargs.pop('offline_transform', None)
+        after_trial = kwargs.pop('after_trial', None)
+
+        meta_info_io_path = os.path.join(io_path, 'info.csv')
+        eeg_signal_io_path = os.path.join(io_path, 'eeg')
+
+        info_io = MetaInfoIO(meta_info_io_path)
+        eeg_io = EEGSignalIO(eeg_signal_io_path,
+                             io_size=io_size,
+                             io_mode=io_mode)
+
+        subject = int(re.findall(r'S(\d*).mat', file_name)[0])  # subject (35)
+        freq_phase = scio.loadmat(os.path.join(root_path, 'Freq_Phase.mat'))
+        freqs = freq_phase['freqs'][0]
+        phases = freq_phase['phases'][0]
+
+        samples = scio.loadmat(os.path.join(root_path,
+                                            file_name))['data'].transpose(
+                                                2, 3, 0, 1)
+        # 40, 6, 64, 1500
+        # Target number: 40
+        # Block number: 6
+        # Electrode number: 64
+        # Time points: 1500
+
+        write_pointer = 0
+
+        for trial_id in range(samples.shape[0]):
+            trial_meta_info = {
+                'subject_id': subject,
+                'trial_id': trial_id,
+                'phases': phases[trial_id],
+                'freqs': freqs[trial_id]
+            }
+            trial_samples = samples[trial_id]
+
+            for block_id in range(trial_samples.shape[0]):
+                block_meta_info = {'block_id': block_id}
+                block_meta_info.update(trial_meta_info)
+                block_samples = trial_samples[block_id]
+                if before_trial:
+                    block_samples = before_trial(block_samples)
+
+                start_at = 0
+                if chunk_size <= 0:
+                    chunk_size = block_samples.shape[1] - start_at
+
+                # chunk with chunk size
+                end_at = chunk_size
+                # calculate moving step
+                step = chunk_size - overlap
+
+                block_queue = []
+                while end_at <= block_samples.shape[1]:
+                    clip_sample = block_samples[:num_channel, start_at:end_at]
+
+                    t_eeg = clip_sample
+                    if not transform is None:
+                        t_eeg = transform(eeg=clip_sample)['eeg']
+
+                    clip_id = f'{file_name}_{write_pointer}'
+                    write_pointer += 1
+
+                    # record meta info for each signal
+                    record_info = {
+                        'start_at': start_at,
+                        'end_at': end_at,
+                        'clip_id': clip_id
+                    }
+                    record_info.update(block_meta_info)
+                    if after_trial:
+                        block_queue.append({
+                            'eeg': t_eeg,
+                            'key': clip_id,
+                            'info': record_info
+                        })
+                    else:
+                        with lock:
+                            eeg_io.write_eeg(t_eeg, clip_id)
+                            info_io.write_info(record_info)
+
+                    start_at = start_at + step
+                    end_at = start_at + chunk_size
+
+                if len(block_queue) and after_trial:
+                    block_queue = after_trial(block_queue)
+                    for obj in block_queue:
+                        assert 'eeg' in obj and 'key' in obj and 'info' in obj, 'after_trial must return a list of dictionaries, where each dictionary corresponds to an EEG sample, containing `eeg`, `key` and `info` as keys.'
+                        with lock:
+                            eeg_io.write_eeg(obj['eeg'], obj['key'])
+                            info_io.write_info(obj['info'])
+
+    @staticmethod
+    def __block__(**kwargs):
+        root_path = kwargs.pop('root_path', './TSUBenchmark')  # str
+
+        file_list = os.listdir(root_path)
+        skip_set = [
+            'Readme.txt', 'Sub_info.txt', '64-channels.loc', '64-channels.loc',
+            'Freq_Phase.mat'
+        ]
+        file_list = [f for f in file_list if f not in skip_set]
+        return file_list
 
     def __getitem__(self, index: int) -> Tuple[any, any, int, int, int]:
         info = self.read_info(index)
diff --git a/torcheeg/io/eeg_signal.py b/torcheeg/io/eeg_signal.py
index 91ef64a..8154531 100644
--- a/torcheeg/io/eeg_signal.py
+++ b/torcheeg/io/eeg_signal.py
@@ -91,9 +91,9 @@ def write_eeg(self,
                     with env.begin(write=True) as transaction:
                         transaction.put(key.encode(), pickle.dumps(eeg))
                 except lmdb.MapFullError:
-                    print(
-                        f'The current io_size is not enough, and double the LMDB map size to {self.io_size * 2} automatically.'
-                    )
+                    # print(
+                    #     f'The current io_size is not enough, and double the LMDB map size to {self.io_size * 2} automatically.'
+                    # )
                     self.io_size = self.io_size * 2
                     try_again = True
             if try_again:


Test patch:
diff --git a/test/datasets/test_emotion_recognition.py b/test/datasets/test_emotion_recognition.py
index 978acbe..7d70284 100644
--- a/test/datasets/test_emotion_recognition.py
+++ b/test/datasets/test_emotion_recognition.py
@@ -8,25 +8,14 @@
                                MAHNOBDataset, SEEDDataset, SEEDFeatureDataset,
                                SEEDIVDataset, SEEDIVFeatureDataset,
                                MPEDFeatureDataset)
-from torcheeg.datasets.functional import (
-    amigos_constructor, deap_constructor, dreamer_constructor,
-    mahnob_constructor, seed_constructor, seed_feature_constructor,
-    seed_iv_constructor, seed_iv_feature_constructor, mped_feature_constructor)
 
 
 class TestEmotionRecognitionDataset(unittest.TestCase):
     def setUp(self):
-        shutil.rmtree('./tmp_out/')
+        if os.path.exists('./tmp_out/'):
+            shutil.rmtree('./tmp_out/')
         os.mkdir('./tmp_out/')
 
-    def test_mped_feature_constructor(self):
-        io_path = f'./tmp_out/mped_feature_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        root_path = './tmp_in/EEG_feature'
-
-        mped_feature_constructor(io_path=io_path,
-                                 root_path=root_path,
-                                 num_worker=0)
-
     def test_mped_feature_dataset(self):
         io_path = f'./tmp_out/mped_feature_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         root_path = './tmp_in/EEG_feature'
@@ -47,11 +36,6 @@ def test_mped_feature_dataset(self):
         last_item = dataset[129903]
         self.assertEqual(last_item[0].shape, (62, 5))
 
-    def test_mahnob_constructor(self):
-        io_path = f'./tmp_out/mahnob_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        root_path = './tmp_in/Sessions'
-        mahnob_constructor(io_path=io_path, root_path=root_path, num_worker=0)
-
     def test_mahnob_dataset(self):
         io_path = f'./tmp_out/mahnob_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         root_path = './tmp_in/Sessions'
@@ -71,11 +55,6 @@ def test_mahnob_dataset(self):
         last_item = dataset[16409]
         self.assertEqual(last_item[0].shape, (32, 128))
 
-    def test_amigos_constructor(self):
-        io_path = f'./tmp_out/amigos_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        root_path = './tmp_in/data_preprocessed'
-        amigos_constructor(io_path=io_path, root_path=root_path, num_worker=0)
-
     def test_amigos_dataset(self):
         io_path = f'./tmp_out/amigos_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         root_path = './tmp_in/data_preprocessed'
@@ -96,11 +75,6 @@ def test_amigos_dataset(self):
         last_item = dataset[45473]
         self.assertEqual(last_item[0].shape, (14, 128))
 
-    def test_deap_constructor(self):
-        io_path = f'./tmp_out/deap_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        root_path = './tmp_in/data_preprocessed_python'
-        deap_constructor(io_path=io_path, root_path=root_path, num_worker=0)
-        
     def test_deap_dataset(self):
         io_path = f'./tmp_out/deap_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         root_path = './tmp_in/data_preprocessed_python'
@@ -120,12 +94,6 @@ def test_deap_dataset(self):
         last_item = dataset[76799]
         self.assertEqual(last_item[0].shape, (32, 128))
 
-    def test_dreamer_constructor(self):
-        io_path = f'./tmp_out/dreamer_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        mat_path = './tmp_in/DREAMER.mat'
-
-        dreamer_constructor(io_path=io_path, mat_path=mat_path, num_worker=0)
-
     def test_dreamer_dataset(self):
         io_path = f'./tmp_out/dreamer_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         mat_path = './tmp_in/DREAMER.mat'
@@ -145,12 +113,6 @@ def test_dreamer_dataset(self):
         last_item = dataset[85743]
         self.assertEqual(last_item[0].shape, (14, 128))
 
-    def test_seed_constructor(self):
-        io_path = f'./tmp_out/seed_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        root_path = './tmp_in/Preprocessed_EEG'
-
-        seed_constructor(io_path=io_path, root_path=root_path, num_worker=0)
-
     def test_seed_dataset(self):
         io_path = f'./tmp_out/seed_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         root_path = './tmp_in/Preprocessed_EEG'
@@ -170,14 +132,6 @@ def test_seed_dataset(self):
         last_item = dataset[152729]
         self.assertEqual(last_item[0].shape, (62, 200))
 
-    def test_seed_feature_constructor(self):
-        io_path = f'./tmp_out/seed_feature_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        root_path = './tmp_in/ExtractedFeatures'
-
-        seed_feature_constructor(io_path=io_path,
-                                 root_path=root_path,
-                                 num_worker=0)
-
     def test_seed_feature_dataset(self):
         io_path = f'./tmp_out/seed_feature_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         root_path = './tmp_in/ExtractedFeatures'
@@ -198,12 +152,6 @@ def test_seed_feature_dataset(self):
         last_item = dataset[152729]
         self.assertEqual(last_item[0].shape, (62, 5))
 
-    def test_seed_iv_constructor(self):
-        io_path = f'./tmp_out/seed_iv_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        root_path = './tmp_in/eeg_raw_data'
-
-        seed_iv_constructor(io_path=io_path, root_path=root_path, num_worker=0)
-
     def test_seed_iv_dataset(self):
         io_path = f'./tmp_out/seed_iv_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         root_path = './tmp_in/eeg_raw_data'
@@ -220,14 +168,6 @@ def test_seed_iv_dataset(self):
         last_item = dataset[37574]
         self.assertEqual(last_item[0].shape, (62, 800))
 
-    def test_seed_iv_feature_constructor(self):
-        io_path = f'./tmp_out/seed_iv_feature_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        root_path = './tmp_in/eeg_feature_smooth'
-
-        seed_iv_feature_constructor(io_path=io_path,
-                                    root_path=root_path,
-                                    num_worker=0)
-
     def test_seed_iv_feature_dataset(self):
         io_path = f'./tmp_out/seed_iv_feature_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         root_path = './tmp_in/eeg_feature_smooth'
diff --git a/test/datasets/test_folder.py b/test/datasets/test_folder.py
new file mode 100644
index 0000000..fa24486
--- /dev/null
+++ b/test/datasets/test_folder.py
@@ -0,0 +1,77 @@
+import os
+import shutil
+import unittest
+
+import mne
+import numpy as np
+
+from torcheeg import transforms
+from torcheeg.datasets import FolderDataset
+
+
+class TestFolderDataset(unittest.TestCase):
+    def setUp(self):
+        if os.path.exists('./tmp_out/'):
+            shutil.rmtree('./tmp_out/')
+        os.mkdir('./tmp_out/')
+
+    def generate_dummy_eeg_files(self, num_files, folder_path):
+        # Define EEG file specifications
+        sfreq = 128  # Sampling rate
+        n_channels = 14  # Number of channels
+        duration = 5  # Data collected for 5 seconds
+        for i in range(num_files):
+            # Generate dummy EEG data
+            n_samples = sfreq * duration
+            data = np.random.randn(n_channels, n_samples)
+
+            # Create MNE Raw object
+            ch_names = [f'ch_{i+1:03}' for i in range(n_channels)]
+            ch_types = ['eeg'] * n_channels
+            info = mne.create_info(ch_names, sfreq, ch_types)
+            raw = mne.io.RawArray(data, info)
+
+            # Save to file
+            file_name = f'sub{i+1}.fif'
+            file_path = os.path.join(folder_path, file_name)
+            raw.save(file_path)
+            # print(f'Saved EEG file {file_path}')
+
+    def test_folder_dataset(self):
+        # Generate dummy EEG files and save them to folders
+        folder1 = './tmp_in/data/folder1'
+        folder2 = './tmp_in/data/folder2'
+        if not os.path.exists(folder1):
+            os.makedirs(folder1)
+        if not os.path.exists(folder2):
+            os.makedirs(folder2)
+
+        self.generate_dummy_eeg_files(2, folder1)
+        self.generate_dummy_eeg_files(2, folder2)
+
+        # Define input and output paths for folder_constructor
+        io_path = './tmp_out/eeg_folder'
+        root_path = './tmp_in/data'
+
+        label_map = {'folder1': 0, 'folder2': 1}
+        dataset = FolderDataset(io_path=io_path,
+                                root_path=root_path,
+                                num_channel=14,
+                                online_transform=transforms.ToTensor(),
+                                label_transform=transforms.Compose([
+                                    transforms.Select('label'),
+                                    transforms.Lambda(lambda x: label_map[x])
+                                ]),
+                                num_worker=0)
+
+        self.assertEqual(len(dataset), 20)
+        first_item = dataset[0]
+        self.assertEqual(first_item[0].shape, (14, 128))
+        self.assertEqual(first_item[1], 0)
+        last_item = dataset[-1]
+        self.assertEqual(last_item[0].shape, (14, 128))
+        self.assertEqual(last_item[1], 1)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/test/datasets/test_hooks.py b/test/datasets/test_hooks.py
index 69bc29c..19da182 100644
--- a/test/datasets/test_hooks.py
+++ b/test/datasets/test_hooks.py
@@ -8,12 +8,13 @@
 from torcheeg.datasets.functional.hooks import before_trial_normalize, after_trial_normalize, after_trial_moving_avg
 
 
-class TestEmotionRecognitionDataset(unittest.TestCase):
+class TestHooks(unittest.TestCase):
     def setUp(self):
-        shutil.rmtree('./tmp_out/')
+        if os.path.exists('./tmp_out/'):
+            shutil.rmtree('./tmp_out/')
         os.mkdir('./tmp_out/')
 
-    def test_deap_dataset(self):
+    def test_before_trial_after_trial(self):
         io_path = f'./tmp_out/deap_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         root_path = './tmp_in/data_preprocessed_python'
 
diff --git a/test/datasets/test_mne.py b/test/datasets/test_mne.py
index 2885971..3c2786e 100644
--- a/test/datasets/test_mne.py
+++ b/test/datasets/test_mne.py
@@ -4,19 +4,19 @@
 import unittest
 
 import mne
-import numpy as np
 from torcheeg import transforms
 from torcheeg.datasets import MNEDataset
-from torcheeg.datasets.functional import mne_constructor
 
 
 class TestMNEDataset(unittest.TestCase):
+
     def setUp(self):
-        shutil.rmtree('./tmp_out/')
+        if os.path.exists('./tmp_out/'):
+            shutil.rmtree('./tmp_out/')
         os.mkdir('./tmp_out/')
 
-    def test_numpy_constructor(self):
-        io_path = f'./tmp_out/numpy_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
+    def test_mne_dataset(self):
+        io_path = f'./tmp_out/mne_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
 
         metadata_list = [{
             'subject': 1,
@@ -46,10 +46,28 @@ def test_numpy_constructor(self):
                                    eog=False,
                                    exclude='bads')
             epochs_list.append(mne.Epochs(raw, events, picks=picks))
-        mne_constructor(epochs_list, metadata_list, io_path=io_path, num_worker=0)
 
-    def test_numpy_dataset(self):
-        io_path = f'./tmp_out/numpy_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
+        dataset = MNEDataset(epochs_list=epochs_list,
+                             metadata_list=metadata_list,
+                             chunk_size=50,
+                             overlap=0,
+                             num_channel=58,
+                             io_path=io_path,
+                             offline_transform=transforms.Compose(
+                                 [transforms.BandDifferentialEntropy()]),
+                             online_transform=transforms.ToTensor(),
+                             label_transform=transforms.Compose(
+                                 [transforms.Select('event')]),
+                             num_worker=2)
+
+        self.assertEqual(len(dataset), 174)
+        first_item = dataset[0]
+        self.assertEqual(first_item[0].shape, (58, 4))
+        last_item = dataset[173]
+        self.assertEqual(last_item[0].shape, (58, 4))
+
+    def test_mne_dataset_from_files(self):
+        io_path = f'./tmp_out/mne_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
 
         metadata_list = [{
             'subject': 1,
@@ -67,7 +85,6 @@ def test_numpy_dataset(self):
             physionet_path = mne.datasets.eegbci.load_data(metadata['subject'],
                                                            metadata['run'],
                                                            update_path=False)[0]
-
             raw = mne.io.read_raw_edf(physionet_path,
                                       preload=True,
                                       stim_channel='auto')
@@ -78,7 +95,9 @@ def test_numpy_dataset(self):
                                    stim=False,
                                    eog=False,
                                    exclude='bads')
-            epochs_list.append(mne.Epochs(raw, events, picks=picks))
+            epochs_path = f'./tmp_out/tmp_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
+            mne.Epochs(raw, events, picks=picks).save(epochs_path)
+            epochs_list.append(epochs_path)
 
         dataset = MNEDataset(epochs_list=epochs_list,
                              metadata_list=metadata_list,
@@ -91,7 +110,7 @@ def test_numpy_dataset(self):
                              online_transform=transforms.ToTensor(),
                              label_transform=transforms.Compose(
                                  [transforms.Select('event')]),
-                             num_worker=2)
+                             num_worker=3)
 
         self.assertEqual(len(dataset), 174)
         first_item = dataset[0]
diff --git a/test/datasets/test_numpy.py b/test/datasets/test_numpy.py
index 34b15c6..40d4f6e 100644
--- a/test/datasets/test_numpy.py
+++ b/test/datasets/test_numpy.py
@@ -6,24 +6,15 @@
 
 from torcheeg import transforms
 from torcheeg.datasets import NumpyDataset
-from torcheeg.datasets.functional import numpy_constructor
 
 
 class TestNumpyDataset(unittest.TestCase):
+
     def setUp(self):
-        shutil.rmtree('./tmp_out/')
+        if os.path.exists('./tmp_out/'):
+            shutil.rmtree('./tmp_out/')
         os.mkdir('./tmp_out/')
 
-    def test_numpy_constructor(self):
-        io_path = f'./tmp_out/numpy_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        X = np.random.randn(100, 32, 128)
-        y = {
-            'valence': np.random.randint(10, size=100),
-            'arousal': np.random.randint(10, size=100)
-        }
-
-        numpy_constructor(io_path=io_path, X=X, y=y, num_worker=0)
-
     def test_numpy_dataset(self):
         io_path = f'./tmp_out/numpy_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         X = np.random.randn(100, 32, 128)
@@ -77,6 +68,41 @@ def test_numpy_dataset(self):
             last_item = dataset[99]
             self.assertEqual(last_item[0].shape, (32, 4))
 
+    def test_numpy_dataset_from_files(self):
+        io_path = f'./tmp_out/numpy_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
+        tmp_path = f'./tmp_out/tmp_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
+        X = np.random.randn(100, 32, 128)
+        y = np.random.randint(10, size=(100, 2))
+
+        X_path_1 = os.path.join(tmp_path, 'X_0.npy')
+        X_path_2 = os.path.join(tmp_path, 'X_1.npy')
+        np.save(X_path_1, X[:50])
+        np.save(X_path_2, X[50:])
+        y_path_1 = os.path.join(tmp_path, 'y_0.npy')
+        y_path_2 = os.path.join(tmp_path, 'y_1.npy')
+        np.save(y_path_1, y[:50])
+        np.save(y_path_2, y[50:])
+
+        dataset = NumpyDataset(
+            X=[X_path_1, X_path_2],
+            y=[y_path_1, y_path_2],
+            io_path=io_path,
+            offline_transform=transforms.Compose(
+                [transforms.BandDifferentialEntropy()]),
+            online_transform=transforms.ToTensor(),
+            label_transform=transforms.Compose([
+                transforms.Select('0'),  # first dimension
+                transforms.Binary(5.0)
+            ]),
+            num_worker=2,
+            num_samples_per_worker=50)
+
+        self.assertEqual(len(dataset), 100)
+        first_item = dataset[0]
+        self.assertEqual(first_item[0].shape, (32, 4))
+        last_item = dataset[99]
+        self.assertEqual(last_item[0].shape, (32, 4))
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/test/datasets/test_operators.py b/test/datasets/test_operators.py
new file mode 100644
index 0000000..b7b4465
--- /dev/null
+++ b/test/datasets/test_operators.py
@@ -0,0 +1,50 @@
+import os
+import random
+import shutil
+import unittest
+
+from torcheeg import transforms
+from torcheeg.datasets import DEAPDataset
+from torcheeg.datasets.functional.operators import from_existing
+
+
+class TestOperators(unittest.TestCase):
+    def setUp(self):
+        # if os.path.exists('./tmp_out/'):
+        #     shutil.rmtree('./tmp_out/')
+        # os.mkdir('./tmp_out/')
+        ...
+
+    def test_from_existing(self):
+        io_path_1 = f'./tmp_out/deap_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
+
+        # io_path_1 = './tmp_out/deap_abjxktvgfuedcopnzrwy'
+        root_path = './tmp_in/data_preprocessed_python'
+
+        dataset_1 = DEAPDataset(io_path=io_path_1,
+                                root_path=root_path,
+                                online_transform=transforms.ToTensor(),
+                                label_transform=transforms.Compose([
+                                    transforms.Select('valence'),
+                                    transforms.Binary(5.0),
+                                ]),
+                                num_worker=4)
+
+        io_path_2 = f'./tmp_out/deap_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
+        # io_path_2 = ' ./tmp_out/deap_hsapkcnjuvetflgrzxdq'
+        dataset_2 = from_existing(dataset_1,
+                                  io_path=io_path_2,
+                                  online_transform=transforms.ToTensor(),
+                                  label_transform=transforms.Compose([
+                                      transforms.Select('valence'),
+                                      transforms.Binary(5.0),
+                                  ]),
+                                  num_worker=4)
+
+        self.assertEqual(len(dataset_1), len(dataset_2))
+        # check if the data is the same (the first 10 samples)
+        for i in range(10):
+            self.assertTrue((dataset_1[0][0] == dataset_2[0][0]).all())
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/test/datasets/test_personal_identification.py b/test/datasets/test_personal_identification.py
index f10c3ad..9210bb2 100644
--- a/test/datasets/test_personal_identification.py
+++ b/test/datasets/test_personal_identification.py
@@ -5,19 +5,14 @@
 
 from torcheeg import transforms
 from torcheeg.datasets import M3CVDataset
-from torcheeg.datasets.functional import m3cv_constructor
 
 
 class TestPersonalIdentificationDataset(unittest.TestCase):
     def setUp(self):
-        shutil.rmtree('./tmp_out/')
+        if os.path.exists('./tmp_out/'):
+            shutil.rmtree('./tmp_out/')
         os.mkdir('./tmp_out/')
 
-    def test_m3cv_constructor(self):
-        io_path = f'./tmp_out/m3cv_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        root_path = './tmp_in/aistudio'
-        m3cv_constructor(io_path=io_path, root_path=root_path, num_worker=0)
-
     def test_m3cv_dataset(self):
         io_path = f'./tmp_out/m3cv_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         root_path = './tmp_in/aistudio'
diff --git a/test/datasets/test_ssvep.py b/test/datasets/test_ssvep.py
index aa20d66..04f3b17 100644
--- a/test/datasets/test_ssvep.py
+++ b/test/datasets/test_ssvep.py
@@ -3,11 +3,10 @@
 import shutil
 import unittest
 
+import numpy as np
+
 from torcheeg import transforms
 from torcheeg.datasets import TSUBenckmarkDataset
-from torcheeg.datasets.functional import tsu_benchmark_constructor
-
-import numpy as np
 
 
 def mean_reduce(eeg_list):
@@ -15,17 +14,12 @@ def mean_reduce(eeg_list):
 
 
 class TestSSVEPDataset(unittest.TestCase):
+
     def setUp(self):
-        shutil.rmtree('./tmp_out/')
+        if os.path.exists('./tmp_out/'):
+            shutil.rmtree('./tmp_out/')
         os.mkdir('./tmp_out/')
 
-    def test_tsu_benchmark_constructor(self):
-        io_path = f'./tmp_out/tsu_benchmark_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        root_path = './tmp_in/TSUBenchmark'
-        tsu_benchmark_constructor(io_path=io_path,
-                                  root_path=root_path,
-                                  num_worker=0)
-
     def test_tsu_benchmark_dataset(self):
         io_path = f'./tmp_out/tsu_benchmark_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
         root_path = './tmp_in/TSUBenchmark'
@@ -41,64 +35,6 @@ def test_tsu_benchmark_dataset(self):
         last_item = dataset[50399]
         self.assertEqual(last_item[0].shape, (64, 250))
 
-    def test_tsu_benchmark_dataset_from_existing(self):
-        io_path = f'./tmp_out/tsu_benchmark_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        root_path = './tmp_in/TSUBenchmark'
-
-        dataset = TSUBenckmarkDataset(io_path=io_path,
-                                      root_path=root_path,
-                                      online_transform=transforms.ToTensor(),
-                                      num_worker=4)
-
-        io_path = f'./tmp_out/tsu_benchmark_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        dataset = TSUBenckmarkDataset.from_existing(dataset, io_path)
-
-        self.assertEqual(len(dataset), 50400)
-        first_item = dataset[0]
-        self.assertEqual(first_item[0].shape, (64, 250))
-        last_item = dataset[50399]
-        self.assertEqual(last_item[0].shape, (64, 250))
-
-        io_path = f'./tmp_out/tsu_benchmark_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-        dataset = TSUBenckmarkDataset.from_existing(
-            dataset,
-            io_path,
-            offline_transform=transforms.MeanStdNormalize(),
-            online_transform=transforms.ToTensor())
-
-        self.assertEqual(len(dataset), 50400)
-        first_item = dataset[0]
-        self.assertEqual(first_item[0].shape, (64, 250))
-        last_item = dataset[50399]
-        self.assertEqual(last_item[0].shape, (64, 250))
-
-    def test_tsu_benchmark_dataset_reduce_from_existing(self):
-        io_path = f'./tmp_out/tsu_benchmark_scvrtkbywgiqjdalzfnx'
-        root_path = './tmp_in/TSUBenchmark'
-
-        dataset = TSUBenckmarkDataset(io_path=io_path,
-                                      root_path=root_path,
-                                      online_transform=transforms.ToTensor(),
-                                      num_worker=4)
-
-        io_path = f'./tmp_out/tsu_benchmark_{"".join(random.sample("zyxwvutsrqponmlkjihgfedcba", 20))}'
-
-        dataset = TSUBenckmarkDataset.reduce_from_existing(
-            dataset,
-            io_path,
-            reduce_fn=mean_reduce,
-            reduce_by='trial_id',
-            chunk_size_for_worker=10,
-            num_worker=2,
-            online_transform=transforms.ToTensor()
-        )
-
-        self.assertEqual(len(dataset), 40)
-        first_item = dataset[0]
-        self.assertEqual(first_item[0].shape, (64, 250))
-        last_item = dataset[39]
-        self.assertEqual(last_item[0].shape, (64, 250))
-
 
 if __name__ == '__main__':
     unittest.main()