Yuri Gorokhov
10/13/2024, 6:45 PMdf = df.with_column(
"thumbnail",
df["image_url"]
.str.replace("conductor", "s3")
.url.download()
.image.decode()
.image.resize(32, 32)
.image.encode(image_format=daft.ImageFormat.JPEG),
)
If not, how to best control memory usage of such operations?jay
10/13/2024, 7:33 PMjay
10/13/2024, 7:34 PMYuri Gorokhov
10/13/2024, 8:13 PMYuri Gorokhov
10/13/2024, 8:13 PMjay
10/13/2024, 8:18 PMdf.explain(True). I’m wondering if this is a purely map-style workload without a shuffleYuri Gorokhov
10/13/2024, 8:29 PMIt should be yes, and I am already making finer partitions indeed. I guess I can try to go even finer.
== Unoptimized Logical Plan ==
* Project: col(id), col(image_width), col(image_height), col(embedding_mofi), col(image_url), col(annotations_url), image_encode(image_resize(image_decode(download(replace(col(image_url),
| lit("xxx"), lit("s3")))))) as thumbnail
|
* Repartition: Scheme = IntoPartitions
| Num partitions = 40000
|
* GlobScanOperator
| Glob paths = [<s3://vedaq-datacuration/datasets/xxx_sa1b/dataset_index/20240214/*.parquet>]
| Coerce int96 timestamp unit = Nanoseconds
| IO config = S3 config = { Region name = us-west-2, Endpoint URL = <https://xxx.data.xxx.com>, Max connections = 8, Retry initial backoff ms = 1000, Connect timeout ms = 300000, Read
| timeout ms = 30000, Max retries = 25, Retry mode = adaptive, Anonymous = false, Use SSL = true, Verify SSL = true, Check hostname SSL = true, Requester pays = false, Force Virtual Addressing
| = false, Profile Name = xxx-notary }, Azure config = { Use Fabric Endpoint = false, Anonymous = false, Use SSL = true }, GCS config = { Anonymous = false }, HTTP config = { user_agent
| = daft/0.0.1 }
| Use multithreading = false
| File schema = id#Binary, image_width#Int32, image_height#Int32, embedding_mofi#List(Float32), image_url#Utf8, annotations_url#Utf8
| Partitioning keys = []
| Output schema = id#Binary, image_width#Int32, image_height#Int32, embedding_mofi#List(Float32), image_url#Utf8, annotations_url#Utf8
== Optimized Logical Plan ==
* Project: col(id), col(image_width), col(image_height), col(embedding_mofi), col(image_url), col(annotations_url), image_encode(image_resize(image_decode(download(replace(col(image_url),
| lit("xxx"), lit("s3")))))) as thumbnail
|
* Repartition: Scheme = IntoPartitions
| Num partitions = 40000
|
* GlobScanOperator
| Glob paths = [<s3://vedaq-datacuration/datasets/xxx_sa1b/dataset_index/20240214/*.parquet>]
| Coerce int96 timestamp unit = Nanoseconds
| IO config = S3 config = { Region name = us-west-2, Endpoint URL = <https://xxx.data.xxx.com>, Max connections = 8, Retry initial backoff ms = 1000, Connect timeout ms = 300000, Read
| timeout ms = 30000, Max retries = 25, Retry mode = adaptive, Anonymous = false, Use SSL = true, Verify SSL = true, Check hostname SSL = true, Requester pays = false, Force Virtual Addressing
| = false, Profile Name = xxx-notary }, Azure config = { Use Fabric Endpoint = false, Anonymous = false, Use SSL = true }, GCS config = { Anonymous = false }, HTTP config = { user_agent
| = daft/0.0.1 }
| Use multithreading = false
| File schema = id#Binary, image_width#Int32, image_height#Int32, embedding_mofi#List(Float32), image_url#Utf8, annotations_url#Utf8
| Partitioning keys = []
| Output schema = id#Binary, image_width#Int32, image_height#Int32, embedding_mofi#List(Float32), image_url#Utf8, annotations_url#Utf8
== Physical Plan ==
* Project: col(id), col(image_width), col(image_height), col(embedding_mofi), col(image_url), col(annotations_url), image_encode(image_resize(image_decode(download(replace(col(image_url),
| lit("xxx"), lit("s3")))))) as thumbnail
| Clustering spec = { Num partitions = 40000 }
|
* Flatten
|
* Split: Input num partitions = 200
| Output num partitions = 40000
|
* TabularScan:
| Num Scan Tasks = 200
| Estimated Scan Bytes = 18624301464
| Clustering spec = { Num partitions = 200 }
| Schema: {id#Binary, image_width#Int32, image_height#Int32, embedding_mofi#List(Float32), image_url#Utf8, annotations_url#Utf8}
| Scan Tasks: [
| {File {<s3://vedaq-datacuration/datasets/xxx_sa1b/dataset_index/20240214/part-00000-25ba56a2-afdc-4530-9cb1-5d54d7f025d5-c000.snappy.parquet}}>
| {File {<s3://vedaq-datacuration/datasets/xxx_sa1b/dataset_index/20240214/part-00001-25ba56a2-afdc-4530-9cb1-5d54d7f025d5-c000.snappy.parquet}}>
| {File {<s3://vedaq-datacuration/datasets/xxx_sa1b/dataset_index/20240214/part-00002-25ba56a2-afdc-4530-9cb1-5d54d7f025d5-c000.snappy.parquet}}>
| ...
| {File {<s3://vedaq-datacuration/datasets/xxx_sa1b/dataset_index/20240214/part-00197-25ba56a2-afdc-4530-9cb1-5d54d7f025d5-c000.snappy.parquet}}>
| {File {<s3://vedaq-datacuration/datasets/xxx_sa1b/dataset_index/20240214/part-00198-25ba56a2-afdc-4530-9cb1-5d54d7f025d5-c000.snappy.parquet}}>
| {File {<s3://vedaq-datacuration/datasets/xxx_sa1b/dataset_index/20240214/part-00199-25ba56a2-afdc-4530-9cb1-5d54d7f025d5-c000.snappy.parquet}}>
| ]jay
10/13/2024, 8:56 PMjay
10/13/2024, 9:21 PMYuri Gorokhov
10/14/2024, 2:17 PMYuri Gorokhov
10/14/2024, 4:22 PMColin Ho
10/14/2024, 9:01 PMAm I to understand that today Daft doesn't support streaming, meaning each phase will fully finish before moving on to the next phase?Yes, the current executor does not support streaming, but the new one will!
jay
10/14/2024, 9:04 PMYuri Gorokhov
10/14/2024, 9:04 PMjay
10/14/2024, 9:05 PMGot it, so that implies that all data must fit into the cluster’s memory (or spill to disk).Not quite, if your workload for example has 1000 partitions, but your cluster only has capacity for 8 partitions at a time, we can pipeline that work.
jay
10/14/2024, 9:05 PMYuri Gorokhov
10/14/2024, 9:06 PMjay
10/14/2024, 9:08 PMjay
10/14/2024, 9:09 PMjay
10/14/2024, 9:09 PMYuri Gorokhov
10/14/2024, 9:27 PMYuri Gorokhov
10/15/2024, 10:48 PMdf = daft.read_parquet(
"s3://..."
)
# df = df.into_partitions(df.num_partitions() * 2)
df = df.with_column("total_pixels", col("image_width") * col("image_height"))
df.write_parquet("s3://...")Yuri Gorokhov
10/15/2024, 10:49 PMinto_partitions() things work great. When I double the partitions, it fails with OOM error. Which is unexpected.Yuri Gorokhov
10/15/2024, 10:49 PM== Physical Plan ==
* Project: col(id), col(image_width), col(image_height), col(embedding_mofi), col(image_url), col(annotations_url), col(image_width) * col(image_height) as total_pixels
| Clustering spec = { Num partitions = 400 }
|
* Flatten
|
* Split: Input num partitions = 200
| Output num partitions = 400
|
* TabularScan:
| Num Scan Tasks = 200
| Estimated Scan Bytes = 18624301464
| Clustering spec = { Num partitions = 200 }
| Schema: {id#Binary, image_width#Int32, image_height#Int32, embedding_mofi#List(Float32), image_url#Utf8, annotations_url#Utf8}
| Scan Tasks: [
| ...Yuri Gorokhov
10/15/2024, 10:49 PMYuri Gorokhov
10/15/2024, 10:50 PM== Physical Plan ==
* Project: col(id), col(image_width), col(image_height), col(embedding_mofi), col(image_url), col(annotations_url), col(image_width) * col(image_height) as total_pixels
| Clustering spec = { Num partitions = 200 }
|
* TabularScan:
| Num Scan Tasks = 200
| Estimated Scan Bytes = 18624301464
| Clustering spec = { Num partitions = 200 }
| Schema: {id#Binary, image_width#Int32, image_height#Int32, embedding_mofi#List(Float32), image_url#Utf8, annotations_url#Utf8}
| Scan Tasks: [
| ...
| ]Yuri Gorokhov
10/15/2024, 10:50 PMYuri Gorokhov
10/15/2024, 10:50 PMYuri Gorokhov
10/15/2024, 10:50 PMYuri Gorokhov
10/15/2024, 10:58 PM|
* Flatten
|
* Split: Input num partitions = 200
| Output num partitions = 400
|
force a materialization of the full dataset?Colin Ho
10/15/2024, 11:40 PMSplit will force a materialization of the full dataset. I think what you could try instead to manipulate the number of partitions is set the scan_tasks_min_size_bytes and scan_tasks_max_size_bytes parameters. Example:
from daft.context import set_execution_config
set_execution_config(scan_tasks_min_size_bytes=48 * 1024 * 1024, scan_tasks_max_size_bytes=192 * 1024 * 1024)
These two parameters essentially set a target range of size bytes per scan task (for load balancing reasons), and do merging/splitting of the parquet files accordingly. The default range is 96 - 384mb. If you set them lower you should in theory end up with more partitionsYuri Gorokhov
10/15/2024, 11:43 PMYuri Gorokhov
10/15/2024, 11:43 PMinto_partitionsYuri Gorokhov
10/15/2024, 11:43 PMYuri Gorokhov
10/15/2024, 11:44 PMColin Ho
10/15/2024, 11:53 PMjay
10/16/2024, 1:44 AMinto_partitions was actually more to do the “split my partitions as it goes”… Would that be useful in this situation?Yuri Gorokhov
10/16/2024, 2:11 AMYuri Gorokhov
10/16/2024, 2:11 AMYuri Gorokhov
10/16/2024, 2:13 AMscan_tasks_min_size_bytes scan_tasks_max_size_bytes seems not straightforward at first try, but I need to play more with it.Yuri Gorokhov
10/16/2024, 2:24 AMdf = daft.read_parquet(
"s3://..."
)
df = df.with_column(
"thumbnail",
df["image_url"]
.str.replace("conductor", "s3")
.url.download()
.image.decode(on_error='null')
.image.resize(32, 32)
.image.encode(image_format=daft.ImageFormat.JPEG),
)
df.write_parquet("s3://...")
I need smaller partitions to control the memory of the image downloading/decoding.Yuri Gorokhov
10/16/2024, 2:24 AMinto_partitions) as it's huge (100M+ rows).Yuri Gorokhov
10/16/2024, 3:26 AMray.data.read_parquet("s3://...", override_num_blocks=100_000) \
.map(get_image_thumbnail_or_null) \
.write_parquet("s3://...")Yuri Gorokhov
10/16/2024, 3:26 AMoverride_num_blocks seems to do the right thingjay
10/16/2024, 4:53 AM.into_partitions is not ideal, but also in the longer term we really shouldn’t need our users to have to worry about partitioning.Yuri Gorokhov
10/16/2024, 4:58 AMYuri Gorokhov
10/16/2024, 6:02 PMds = ray.data.read_parquet("s3://...", override_num_blocks=100_000)
df = daft.from_ray_dataset(ds)
And it seems to work.Yuri Gorokhov
10/16/2024, 6:02 PMjay
10/16/2024, 11:34 PMinto_partitions behavior
2. Better memory estimations for each task
That should give us much better memory stability already. More updates to come in ~1 week!Yuri Gorokhov
10/16/2024, 11:35 PMjay
10/18/2024, 9:35 PMinto_partitions fix coming through! https://github.com/Eventual-Inc/Daft/pull/3080Yuri Gorokhov
10/18/2024, 9:38 PM