Skip to content

Commit

Permalink
Don't duplicate data when encoding audio or image (#4187)
Browse files Browse the repository at this point in the history
* don't duplicate data in audio

* don't duplicate data in image

* one more comment
  • Loading branch information
lhoestq authored Apr 21, 2022
1 parent 966d3bc commit b564af7
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 2 deletions.
10 changes: 8 additions & 2 deletions src/datasets/features/audio.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from dataclasses import dataclass, field
from io import BytesIO
from typing import TYPE_CHECKING, Any, ClassVar, Dict, Optional, Union
Expand Down Expand Up @@ -70,11 +71,16 @@ def encode_example(self, value: Union[str, dict]) -> dict:
raise ImportError("To support encoding audio data, please install 'soundfile'.") from err
if isinstance(value, str):
return {"bytes": None, "path": value}
elif isinstance(value, dict) and "array" in value:
elif "array" in value:
# convert the audio array to wav bytes
buffer = BytesIO()
sf.write(buffer, value["array"], value["sampling_rate"], format="wav")
return {"bytes": buffer.getvalue(), "path": value.get("path")}
return {"bytes": buffer.getvalue(), "path": None}
elif value.get("path") is not None and os.path.isfile(value["path"]):
# we set "bytes": None to not duplicate the data if they're already available locally
return {"bytes": None, "path": value.get("path")}
elif value.get("bytes") is not None or value.get("path") is not None:
# store the audio bytes, and path is used to infer the audio format using the file extension
return {"bytes": value.get("bytes"), "path": value.get("path")}
else:
raise ValueError(
Expand Down
7 changes: 7 additions & 0 deletions src/datasets/features/image.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from dataclasses import dataclass, field
from io import BytesIO
from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional, Union
Expand Down Expand Up @@ -69,11 +70,17 @@ def encode_example(self, value: Union[str, dict, np.ndarray, "PIL.Image.Image"])
if isinstance(value, str):
return {"path": value, "bytes": None}
elif isinstance(value, np.ndarray):
# convert the image array to png bytes
image = PIL.Image.fromarray(value.astype(np.uint8))
return {"path": None, "bytes": image_to_bytes(image)}
elif isinstance(value, PIL.Image.Image):
# convert the PIL image to bytes (default format is png)
return encode_pil_image(value)
elif value.get("path") is not None and os.path.isfile(value["path"]):
# we set "bytes": None to not duplicate the data if they're already available locally
return {"bytes": None, "path": value.get("path")}
elif value.get("bytes") is not None or value.get("path") is not None:
# store the image bytes, and path is used to infer the image format using the file extension
return {"bytes": value.get("bytes"), "path": value.get("path")}
else:
raise ValueError(
Expand Down

1 comment on commit b564af7

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Show benchmarks

PyArrow==5.0.0

Show updated benchmarks!

Benchmark: benchmark_array_xd.json

metric read_batch_formatted_as_numpy after write_array2d read_batch_formatted_as_numpy after write_flattened_sequence read_batch_formatted_as_numpy after write_nested_sequence read_batch_unformated after write_array2d read_batch_unformated after write_flattened_sequence read_batch_unformated after write_nested_sequence read_col_formatted_as_numpy after write_array2d read_col_formatted_as_numpy after write_flattened_sequence read_col_formatted_as_numpy after write_nested_sequence read_col_unformated after write_array2d read_col_unformated after write_flattened_sequence read_col_unformated after write_nested_sequence read_formatted_as_numpy after write_array2d read_formatted_as_numpy after write_flattened_sequence read_formatted_as_numpy after write_nested_sequence read_unformated after write_array2d read_unformated after write_flattened_sequence read_unformated after write_nested_sequence write_array2d write_flattened_sequence write_nested_sequence
new / old (diff) 0.010130 / 0.011353 (-0.001223) 0.003602 / 0.011008 (-0.007407) 0.031916 / 0.038508 (-0.006592) 0.035572 / 0.023109 (0.012463) 0.302505 / 0.275898 (0.026607) 0.327537 / 0.323480 (0.004057) 0.008166 / 0.007986 (0.000180) 0.003844 / 0.004328 (-0.000484) 0.009692 / 0.004250 (0.005442) 0.042314 / 0.037052 (0.005261) 0.283322 / 0.258489 (0.024833) 0.326484 / 0.293841 (0.032643) 0.032724 / 0.128546 (-0.095822) 0.010254 / 0.075646 (-0.065392) 0.261577 / 0.419271 (-0.157695) 0.053288 / 0.043533 (0.009755) 0.299158 / 0.255139 (0.044019) 0.329968 / 0.283200 (0.046769) 0.112729 / 0.141683 (-0.028954) 1.753273 / 1.452155 (0.301118) 1.945962 / 1.492716 (0.453246)

Benchmark: benchmark_getitem_100B.json

metric get_batch_of_1024_random_rows get_batch_of_1024_rows get_first_row get_last_row
new / old (diff) 0.259842 / 0.018006 (0.241836) 0.437785 / 0.000490 (0.437295) 0.017808 / 0.000200 (0.017608) 0.000307 / 0.000054 (0.000253)

Benchmark: benchmark_indices_mapping.json

metric select shard shuffle sort train_test_split
new / old (diff) 0.030900 / 0.037411 (-0.006512) 0.116513 / 0.014526 (0.101987) 0.129904 / 0.176557 (-0.046653) 0.180188 / 0.737135 (-0.556947) 0.142965 / 0.296338 (-0.153374)

Benchmark: benchmark_iterating.json

metric read 5000 read 50000 read_batch 50000 10 read_batch 50000 100 read_batch 50000 1000 read_formatted numpy 5000 read_formatted pandas 5000 read_formatted tensorflow 5000 read_formatted torch 5000 read_formatted_batch numpy 5000 10 read_formatted_batch numpy 5000 1000 shuffled read 5000 shuffled read 50000 shuffled read_batch 50000 10 shuffled read_batch 50000 100 shuffled read_batch 50000 1000 shuffled read_formatted numpy 5000 shuffled read_formatted_batch numpy 5000 10 shuffled read_formatted_batch numpy 5000 1000
new / old (diff) 0.486104 / 0.215209 (0.270895) 4.765523 / 2.077655 (2.687868) 2.104584 / 1.504120 (0.600464) 1.934087 / 1.541195 (0.392893) 1.907134 / 1.468490 (0.438644) 0.508986 / 4.584777 (-4.075791) 5.655378 / 3.745712 (1.909666) 2.430440 / 5.269862 (-2.839421) 1.044440 / 4.565676 (-3.521236) 0.061540 / 0.424275 (-0.362735) 0.014659 / 0.007607 (0.007052) 0.583013 / 0.226044 (0.356968) 5.804445 / 2.268929 (3.535517) 2.514936 / 55.444624 (-52.929688) 2.133450 / 6.876477 (-4.743027) 2.330863 / 2.142072 (0.188791) 0.640690 / 4.805227 (-4.164538) 0.140636 / 6.500664 (-6.360029) 0.072869 / 0.075469 (-0.002600)

Benchmark: benchmark_map_filter.json

metric filter map fast-tokenizer batched map identity map identity batched map no-op batched map no-op batched numpy map no-op batched pandas map no-op batched pytorch map no-op batched tensorflow
new / old (diff) 1.923181 / 1.841788 (0.081393) 15.773462 / 8.074308 (7.699154) 28.736714 / 10.191392 (18.545322) 0.926449 / 0.680424 (0.246025) 0.553902 / 0.534201 (0.019701) 0.533602 / 0.579283 (-0.045681) 0.567572 / 0.434364 (0.133208) 0.358488 / 0.540337 (-0.181850) 0.368271 / 1.386936 (-1.018665)
PyArrow==latest
Show updated benchmarks!

Benchmark: benchmark_array_xd.json

metric read_batch_formatted_as_numpy after write_array2d read_batch_formatted_as_numpy after write_flattened_sequence read_batch_formatted_as_numpy after write_nested_sequence read_batch_unformated after write_array2d read_batch_unformated after write_flattened_sequence read_batch_unformated after write_nested_sequence read_col_formatted_as_numpy after write_array2d read_col_formatted_as_numpy after write_flattened_sequence read_col_formatted_as_numpy after write_nested_sequence read_col_unformated after write_array2d read_col_unformated after write_flattened_sequence read_col_unformated after write_nested_sequence read_formatted_as_numpy after write_array2d read_formatted_as_numpy after write_flattened_sequence read_formatted_as_numpy after write_nested_sequence read_unformated after write_array2d read_unformated after write_flattened_sequence read_unformated after write_nested_sequence write_array2d write_flattened_sequence write_nested_sequence
new / old (diff) 0.008739 / 0.011353 (-0.002614) 0.004064 / 0.011008 (-0.006944) 0.031313 / 0.038508 (-0.007195) 0.038080 / 0.023109 (0.014971) 0.321314 / 0.275898 (0.045416) 0.365136 / 0.323480 (0.041656) 0.006567 / 0.007986 (-0.001419) 0.003717 / 0.004328 (-0.000611) 0.007522 / 0.004250 (0.003271) 0.040163 / 0.037052 (0.003111) 0.303159 / 0.258489 (0.044670) 0.350670 / 0.293841 (0.056829) 0.047843 / 0.128546 (-0.080703) 0.008343 / 0.075646 (-0.067304) 0.292614 / 0.419271 (-0.126658) 0.057123 / 0.043533 (0.013590) 0.310026 / 0.255139 (0.054887) 0.355121 / 0.283200 (0.071921) 0.100584 / 0.141683 (-0.041099) 1.995645 / 1.452155 (0.543490) 2.139152 / 1.492716 (0.646436)

Benchmark: benchmark_getitem_100B.json

metric get_batch_of_1024_random_rows get_batch_of_1024_rows get_first_row get_last_row
new / old (diff) 0.239970 / 0.018006 (0.221964) 0.424761 / 0.000490 (0.424271) 0.001311 / 0.000200 (0.001111) 0.000131 / 0.000054 (0.000076)

Benchmark: benchmark_indices_mapping.json

metric select shard shuffle sort train_test_split
new / old (diff) 0.028948 / 0.037411 (-0.008463) 0.123175 / 0.014526 (0.108649) 0.125903 / 0.176557 (-0.050654) 0.179715 / 0.737135 (-0.557420) 0.132756 / 0.296338 (-0.163583)

Benchmark: benchmark_iterating.json

metric read 5000 read 50000 read_batch 50000 10 read_batch 50000 100 read_batch 50000 1000 read_formatted numpy 5000 read_formatted pandas 5000 read_formatted tensorflow 5000 read_formatted torch 5000 read_formatted_batch numpy 5000 10 read_formatted_batch numpy 5000 1000 shuffled read 5000 shuffled read 50000 shuffled read_batch 50000 10 shuffled read_batch 50000 100 shuffled read_batch 50000 1000 shuffled read_formatted numpy 5000 shuffled read_formatted_batch numpy 5000 10 shuffled read_formatted_batch numpy 5000 1000
new / old (diff) 0.489781 / 0.215209 (0.274572) 4.833586 / 2.077655 (2.755932) 2.090041 / 1.504120 (0.585921) 1.945195 / 1.541195 (0.404000) 1.892969 / 1.468490 (0.424479) 0.516438 / 4.584777 (-4.068339) 5.147794 / 3.745712 (1.402082) 3.633920 / 5.269862 (-1.635941) 1.053361 / 4.565676 (-3.512315) 0.053369 / 0.424275 (-0.370906) 0.013490 / 0.007607 (0.005883) 0.535147 / 0.226044 (0.309103) 5.370121 / 2.268929 (3.101193) 2.240477 / 55.444624 (-53.204147) 1.904586 / 6.876477 (-4.971890) 1.974871 / 2.142072 (-0.167202) 0.539061 / 4.805227 (-4.266166) 0.120560 / 6.500664 (-6.380104) 0.059489 / 0.075469 (-0.015981)

Benchmark: benchmark_map_filter.json

metric filter map fast-tokenizer batched map identity map identity batched map no-op batched map no-op batched numpy map no-op batched pandas map no-op batched pytorch map no-op batched tensorflow
new / old (diff) 1.806475 / 1.841788 (-0.035313) 15.578084 / 8.074308 (7.503776) 28.660742 / 10.191392 (18.469350) 0.883451 / 0.680424 (0.203027) 0.531079 / 0.534201 (-0.003122) 0.486631 / 0.579283 (-0.092653) 0.554950 / 0.434364 (0.120586) 0.349961 / 0.540337 (-0.190376) 0.372883 / 1.386936 (-1.014053)

CML watermark

Please sign in to comment.