Skip to content

Commit d41aa87

Browse files
committed
Parallelize share read in.
1 parent 5d2f764 commit d41aa87

1 file changed

Lines changed: 43 additions & 16 deletions

File tree

backend/folde/data.py

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import logging
1212
import os
1313
import re
14+
from concurrent.futures import ThreadPoolExecutor
1415
from pathlib import Path
1516
from typing import Any, Dict, List, Optional, Tuple, Union
1617

@@ -114,6 +115,28 @@ def get_available_proteingym_datasets(
114115
return filtered_metadata
115116

116117

118+
def _parse_embedding_columns_inplace(df: pd.DataFrame) -> pd.DataFrame:
119+
"""Parse embedding columns from JSON strings to numpy arrays in-place.
120+
121+
Modifies embedding columns in-place to avoid memory duplication.
122+
123+
Args:
124+
df: DataFrame with potential embedding columns as JSON strings
125+
126+
Returns:
127+
The same DataFrame with parsed embeddings (modified in-place)
128+
"""
129+
for col in df.columns:
130+
if col == "embedding" or col.startswith("embedding_layer_"):
131+
if len(df) > 0 and isinstance(df[col].iloc[0], str):
132+
# Parse in-place to avoid memory duplication
133+
for idx in df.index:
134+
val = df.at[idx, col]
135+
if isinstance(val, str):
136+
df.at[idx, col] = np.array(json.loads(val))
137+
return df
138+
139+
117140
def try_load_sharded_embedding_file(embeddings_dir: str, prefix: str) -> pd.DataFrame:
118141
"""Load sharded embedding files matching pattern <prefix>-(\d+)_of_(\d+).csv.
119142
@@ -183,14 +206,26 @@ def try_load_sharded_embedding_file(embeddings_dir: str, prefix: str) -> pd.Data
183206
if max_idx > expected_total_shards:
184207
raise ValueError(f"Shard index {max_idx} exceeds total shard count {expected_total_shards}")
185208

186-
# Load and concatenate all shards in order
209+
# Load and concatenate all shards in parallel
187210
logger.info(f"Loading {expected_total_shards} sharded embedding files for {prefix}")
188-
shard_dfs = []
189-
for idx in range(1, expected_total_shards + 1):
211+
212+
def load_and_parse_shard(idx: int) -> pd.DataFrame:
190213
filepath = shard_info[idx][1]
191214
shard_df = pd.read_csv(filepath)
192-
shard_dfs.append(shard_df)
193-
logger.info(f"Loaded shard {idx}/{expected_total_shards} with {len(shard_df)} rows")
215+
_parse_embedding_columns_inplace(shard_df)
216+
logger.info(
217+
f"Loaded and parsed shard {idx}/{expected_total_shards} with {len(shard_df)} rows"
218+
)
219+
return shard_df
220+
221+
with ThreadPoolExecutor(max_workers=4) as executor:
222+
# Submit all shard loading tasks
223+
futures = {
224+
idx: executor.submit(load_and_parse_shard, idx)
225+
for idx in range(1, expected_total_shards + 1)
226+
}
227+
# Collect results in order
228+
shard_dfs = [futures[idx].result() for idx in range(1, expected_total_shards + 1)]
194229

195230
return pd.concat(shard_dfs, ignore_index=True)
196231

@@ -228,8 +263,9 @@ def get_proteingym_dataset(
228263
if os.path.exists(embedding_file_path):
229264
# Single file case
230265
embedding_df = pd.read_csv(embedding_file_path)
266+
_parse_embedding_columns_inplace(embedding_df)
231267
else:
232-
# Try loading sharded files
268+
# Try loading sharded files (parsing happens inside)
233269
prefix = f"{dms_id}_embedding_{embedding_model_id}"
234270
try:
235271
embedding_df = try_load_sharded_embedding_file(str(EMBEDDINGS_DIR), prefix)
@@ -398,16 +434,7 @@ def maybe_convert_seq_id_to_seq(seq_id: str):
398434
category_df = category_df.reindex(activity_df.index)
399435
category_df = category_df.fillna(False)
400436

401-
# Convert embedding column from string to numpy array if needed
402-
for col in embedding_df.columns:
403-
if col == "embedding" or col.startswith("embedding_layer_"):
404-
if isinstance(embedding_df[col].iloc[0], str):
405-
# embedding_df["embedding"] = embedding_df["embedding"].apply(
406-
# lambda x: np.array(ast.literal_eval(x)) if isinstance(x, str) else x
407-
# )
408-
embedding_df[col] = embedding_df[col].apply(
409-
lambda x: np.array(json.loads(x)) if isinstance(x, str) else x
410-
)
437+
# Embeddings are already parsed during loading (via _parse_embedding_columns_inplace)
411438

412439
# We lose ordering with the set operations but recover it with a sort later.
413440
logging.info(

0 commit comments

Comments
 (0)