Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

By default avoiding generating files in temp directory #1609

Merged
merged 26 commits into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1998576
initial commit
dbogunowicz Jun 5, 2023
c686286
all pathways validated, aiming to get tests green
dbogunowicz Jun 6, 2023
20e26cc
all pathways validated, aiming to get tests green
dbogunowicz Jun 6, 2023
e19ed08
Apply suggestions from code review
dbogunowicz Jun 6, 2023
98683a3
Update src/sparseml/yolov8/trainers.py
dbogunowicz Jun 6, 2023
654a266
Update src/sparseml/onnx/optim/quantization/calibration.py
dbogunowicz Jun 6, 2023
d971648
Merge branch 'main' into feature/damian/avoid_tmp_files
dbogunowicz Jun 6, 2023
1de270b
torch and onnx tests green
dbogunowicz Jun 6, 2023
395c481
fix quality
dbogunowicz Jun 6, 2023
f25ddb3
Merge branch 'feature/damian/avoid_tmp_files' of https://github.com/n…
dbogunowicz Jun 6, 2023
0f39955
add print to conftest to see which file is the culprit
dbogunowicz Jun 6, 2023
80d452e
improved diagnosis
dbogunowicz Jun 6, 2023
84c36a2
Merge branch 'main' into feature/damian/avoid_tmp_files
dbogunowicz Jun 6, 2023
81a9947
make sure no files are being created
dbogunowicz Jun 6, 2023
f8c9110
Merge branch 'feature/damian/avoid_tmp_files' of https://github.com/n…
dbogunowicz Jun 6, 2023
af2d297
update conftest
dbogunowicz Jun 6, 2023
097f380
make conftest faster
dbogunowicz Jun 6, 2023
5806b46
quality
dbogunowicz Jun 6, 2023
dce1fd8
ready for review
dbogunowicz Jun 7, 2023
6bc6218
revert to keep a benign script
dbogunowicz Jun 7, 2023
ec62ff4
Merge branch 'main' into feature/damian/avoid_tmp_files
dbogunowicz Jun 11, 2023
6dbf554
Update torch_to_onnx_exporter.py
dbogunowicz Jun 12, 2023
7d9cc4e
Revert "Update torch_to_onnx_exporter.py"
Jun 12, 2023
a3aba6e
Merge branch 'main' into feature/damian/avoid_tmp_files
dbogunowicz Jun 13, 2023
7674735
Merge branch 'main' into feature/damian/avoid_tmp_files
dbogunowicz Jun 16, 2023
ce4cfc4
Merge branch 'main' into feature/damian/avoid_tmp_files
dbogunowicz Jun 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions src/sparseml/onnx/optim/quantization/calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"""


import logging
import os
import tempfile
from typing import Dict, Generator, Iterable, List, Tuple, Union

import numpy as np
Expand All @@ -28,6 +28,8 @@
from sparsezoo.utils import save_onnx, validate_onnx


_LOGGER = logging.getLogger(__name__)

__all__ = ["CalibrationSession"]


Expand Down Expand Up @@ -65,11 +67,11 @@ def __init__(
self._model_augmented = self.generate_augmented_model()

if self._augmented_model_path is None:
self._augmented_model_tmp_file = tempfile.NamedTemporaryFile(
suffix=".onnx", delete=True
self._augmented_model_path = os.path.join(
os.getcwd(), "model_augmented.onnx"
)
self._augmented_model_path = self._augmented_model_tmp_file.name
save_onnx(self._model_augmented, self._augmented_model_path)
_LOGGER.debug(f"Created an augmented model at: {self._augmented_model_path}")

self._sessions = {} # batch_size -> session
self._quantization_thresholds = {} # Dict[node.name, Tuple(min_val, max_val)]
Expand Down Expand Up @@ -103,13 +105,15 @@ def _optimize_model(self) -> Union[str, None]:
# no optimization performed, skip the rest of this block
raise Exception()
validate_onnx(model_optimized) # should raise exception if broken
optimized_model_path = tempfile.NamedTemporaryFile(
suffix=".onnx", delete=False
)
save_onnx(model_optimized, optimized_model_path.name)
optimized_model_path = os.path.join(os.getcwd(), "model_optimized.onnx")
save_onnx(model_optimized, optimized_model_path)
self._model = model_optimized
print("Optimization successful")
return optimized_model_path.name
_LOGGER.debug(
"Optimization successful. "
"Created an optimized model at: "
f"{optimized_model_path}"
)
return optimized_model_path
except Exception as e:
print(e)
print(
Expand Down Expand Up @@ -352,3 +356,5 @@ def __del__(self):
"""
if self._optimized_model_path is not None:
os.remove(self._optimized_model_path)
if self._augmented_model_path is not None:
os.remove(self._augmented_model_path)
9 changes: 5 additions & 4 deletions src/sparseml/pytorch/torch_to_onnx_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import collections
import logging
import tempfile
import os
import warnings
from copy import deepcopy
from typing import Any, Dict, Iterable, List
Expand Down Expand Up @@ -147,9 +147,10 @@ def post_validate(self, model: onnx.ModelProto) -> onnx.ModelProto:
raise TypeError(f"Expected onnx.ModelProto, found {type(model)}")
return model

def transform(self, module: torch.nn.Module) -> onnx.ModelProto:
tmp = tempfile.NamedTemporaryFile("w")
file_path = tmp.name
def transform(
self, module: torch.nn.Module, file_name: str
) -> onnx.ModelProto:
file_path = os.path.join(os.getcwd(), file_name)

_LOGGER.debug(f"Saving onnx model to {file_path}")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ def teardown(self):
"""
Cleanup environment after test completion
"""
pass
if "train" in self.command_types:
self.save_dir.cleanup()


class TestImageClassification(BaseIntegrationTester):
Expand Down
4 changes: 3 additions & 1 deletion tests/integrations/transformers/test_transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ def get_root_commands(self, raw_configs):
return command_stubs_final

def teardown(self):
pass # not yet implemented
# clean up temporary directory
if "train" in self.command_types:
self.save_dir.cleanup()


@flaky(max_runs=2, min_passes=1)
Expand Down
48 changes: 43 additions & 5 deletions tests/sparseml/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import os
import shutil
import tempfile
from typing import List

import pytest

Expand All @@ -28,16 +30,52 @@
os.environ["NM_TEST_LOG_DIR"] = "nm_temp_test_logs"


def _get_files(directory: str) -> List[str]:
list_filepaths = []
for root, dirs, files in os.walk(directory):
for file in files:
list_filepaths.append(os.path.join(os.path.abspath(root), file))
return list_filepaths


@pytest.fixture(scope="session", autouse=True)
def check_for_created_files():
start_file_count = sum(len(files) for _, _, files in os.walk(r"."))
start_files_root = _get_files(directory=r".")
start_files_temp = _get_files(directory=tempfile.gettempdir())
yield
if wandb:
wandb.finish()
log_dir = os.environ.get("NM_TEST_LOG_DIR")
if os.path.isdir(log_dir):
shutil.rmtree(log_dir)
end_file_count = sum(len(files) for _, _, files in os.walk(r"."))
assert (
start_file_count >= end_file_count
), f"{end_file_count - start_file_count} files created during pytest run"

end_files_root = _get_files(directory=r".")
end_files_temp = _get_files(directory=tempfile.gettempdir())

# assert no files created in root directory while running
# the pytest suite
assert len(start_files_root) >= len(end_files_root), (
f"{len(end_files_root) - len(start_files_root)} "
f"files created in current working "
f"directory during pytest run. "
f"Created files: {set(end_files_root) - set(start_files_root)}"
)
max_allowed_sized_temp_files_megabytes = 1
created_temp_files = set(end_files_temp) - set(start_files_temp)
size_of_temp_files_bytes = 0
for file_path in created_temp_files:
try:
size_of_temp_files_bytes += os.path.getsize(file_path)
# if file is deleted between the time we get the list of files
# and the time we get the size of the file, ignore it
except FileNotFoundError:
pass

size_of_temp_files_megabytes = size_of_temp_files_bytes / 1024 / 1024
# assert no more than 1 megabyte of temp files created in temp directory
# while running the pytest suite
assert max_allowed_sized_temp_files_megabytes >= size_of_temp_files_megabytes, (
f"{size_of_temp_files_megabytes} "
f"megabytes of temp files created in temp directory during pytest run. "
f"Created files: {set(end_files_temp) - set(start_files_temp)}"
)
1 change: 1 addition & 0 deletions tests/sparseml/exporters/transforms/test_onnx_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,4 @@ def test_onnx_transform_from_path(tmp_path):
path = os.path.join(str(tmp_path), "model.onnx")
save_onnx(model, path)
assert transform(path)
os.remove(path)
4 changes: 3 additions & 1 deletion tests/sparseml/optim/test_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ def test_layer_descs():
AnalyzedLayerDesc("layer1", "Linear"),
AnalyzedLayerDesc("layer2", "Conv2d"),
]
save_path = os.path.join(tempfile.gettempdir(), "layer_descs.json")
tempdir = tempfile.gettempdir()
save_path = os.path.join(tempdir, "layer_descs.json")

AnalyzedLayerDesc.save_descs(descs, save_path)
loaded_descs = AnalyzedLayerDesc.load_descs(save_path)

for desc, loaded_desc in zip(descs, loaded_descs):
assert desc.name == loaded_desc.name
assert desc.type_ == loaded_desc.type_
os.remove(save_path)
19 changes: 9 additions & 10 deletions tests/sparseml/optim/test_sensitivity.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ def test_ks_loss_sensitivity_analysis():
assert abs(test["sparse_integral"] - comp.sparse_integral) < 1e-5
assert abs(test["sparse_comparison"] - comp.sparse_comparison()) < 1e-5

path = os.path.join(tempfile.gettempdir(), "ks-sens-analysis.json")
tempdir = tempfile.TemporaryDirectory()
path = os.path.join(tempdir.name, "ks-sens-analysis.json")
analysis.save_json(path)

json_analysis = analysis.load_json(path)
Expand All @@ -160,26 +161,24 @@ def test_ks_loss_sensitivity_analysis():
assert abs(test["sparse_integral"] - comp.sparse_integral) < 1e-5
assert abs(test["sparse_comparison"] - comp.sparse_comparison()) < 1e-5

path = os.path.join(
tempfile.gettempdir(), "ks-sens-analysis-integral-normalized.png"
)
path = os.path.join(tempdir.name, "ks-sens-analysis-integral-normalized.png")
analysis.plot(path, plot_integral=True)
assert os.path.exists(path)

path = os.path.join(
tempfile.gettempdir(), "ks-sens-analysis-integral-normalized.png"
)
path = os.path.join(tempdir.name, "ks-sens-analysis-integral-normalized.png")
analysis.plot(path, plot_integral=True)
assert os.path.exists(path)

path = os.path.join(tempfile.gettempdir(), "ks-sens-analysis-integral.png")
path = os.path.join(tempdir.name, "ks-sens-analysis-integral.png")
analysis.plot(path, plot_integral=True, normalize=False)
assert os.path.exists(path)

path = os.path.join(tempfile.gettempdir(), "ks-sens-analysis-avg-normalized.png")
path = os.path.join(tempdir.name, "ks-sens-analysis-avg-normalized.png")
analysis.plot(path, plot_integral=False)
assert os.path.exists(path)

path = os.path.join(tempfile.gettempdir(), "ks-sens-analysis-avg.png")
path = os.path.join(tempdir.name, "ks-sens-analysis-avg.png")
analysis.plot(path, plot_integral=False, normalize=False)
assert os.path.exists(path)

tempdir.cleanup()
2 changes: 2 additions & 0 deletions tests/sparseml/pytorch/image_classification/test_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import math
import shutil
from pathlib import Path

import onnx
Expand Down Expand Up @@ -96,3 +97,4 @@ def test_export_one_shot(resnet_checkpoint, recipe_path, temp_dir):
node_sparsity = node.parameter_summary.block_structure["single"].sparsity
assert math.isclose(node_sparsity, 0.9, abs_tol=0.01)
assert found_prunable_node
shutil.rmtree(temp_dir)
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import shutil

import pytest

from sparseml.pytorch.image_classification.utils.helpers import save_zoo_directory
Expand Down Expand Up @@ -41,3 +43,5 @@ def test_save_zoo_directory(stub, tmp_path_factory):
)
new_zoo_model = Model(str(save_dir))
assert new_zoo_model.validate(minimal_validation=True, validate_onnxruntime=False)
shutil.rmtree(path_to_training_outputs)
shutil.rmtree(save_dir)
2 changes: 2 additions & 0 deletions tests/sparseml/pytorch/recipe_template/test_end_to_end.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import shutil

import pytest

Expand Down Expand Up @@ -45,3 +46,4 @@ def test_docstring_cli_examples(command, tmp_path):
command.extend(["--file_name", str(tmp_path / "temp.md")])
result = runner.invoke(main, command)
assert result.exit_code == 0
shutil.rmtree(tmp_path)
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,4 @@ def test_structured_pruning_one_shot_e2e(
assert abs(applied_compression - sparsity) < 5e-2
# validate forward pass
assert module(torch.randn(2, 3, 224, 224)) is not None
os.remove(tmp_fp)
3 changes: 3 additions & 0 deletions tests/sparseml/pytorch/test_torch_to_onnx_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import os
import shutil
from collections import Counter

import numpy
Expand Down Expand Up @@ -53,6 +54,7 @@ def test_simple_models_against_module_exporter(tmp_path, model, sample_batch):
str(tmp_path / "new_exporter" / "model.onnx"),
sample_batch,
)
shutil.rmtree(tmp_path)


@pytest.mark.skipif(
Expand Down Expand Up @@ -105,6 +107,7 @@ def test_resnet50_exporters_are_equivalent(tmp_path, quantize: bool, convert_qat
sample_batch,
expect_op_types=["QuantizeLinear", "DequantizeLinear"] if quantize else None,
)
shutil.rmtree(tmp_path)


@pytest.mark.skipif(
Expand Down
9 changes: 7 additions & 2 deletions tests/sparseml/pytorch/utils/test_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@
)
def test_exporter_onnx():
sample_batch = torch.randn(1, 8)
exporter = ModuleExporter(MLPNet(), tempfile.gettempdir())
tempdir = tempfile.TemporaryDirectory()
exporter = ModuleExporter(MLPNet(), tempdir.name)
exporter.export_onnx(sample_batch)
tempdir.cleanup()


@pytest.mark.skipif(
Expand All @@ -47,8 +49,11 @@ def test_exporter_onnx():
@pytest.mark.parametrize("batch_size", [1, 64])
def test_export_batches(batch_size):
sample_batch = torch.randn(batch_size, 8)
exporter = ModuleExporter(MLPNet(), tempfile.gettempdir())
# create a directory in tempdir
tempdir = tempfile.TemporaryDirectory()
exporter = ModuleExporter(MLPNet(), tempdir.name)
exporter.export_samples([sample_batch])
tempdir.cleanup()


def test_fold_identity_initializers():
Expand Down
4 changes: 4 additions & 0 deletions tests/sparseml/pytorch/utils/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,7 @@ def test_tensor_export_npy(tensor, name):

for s1, s2 in zip(exported.shape, tensor.shape):
assert s1 == s2
os.remove(path)


@pytest.mark.skipif(
Expand All @@ -579,6 +580,7 @@ def test_tensor_export_npz(tensor, name):

for s1, s2 in zip(exported.shape, tensor.shape):
assert s1 == s2
os.remove(path)


@pytest.mark.skipif(
Expand All @@ -602,6 +604,7 @@ def test_tensor_export_cuda(tensor, name):

for s1, s2 in zip(exported.shape, tensor.shape):
assert s1 == s2
os.remove(path)


@pytest.mark.skipif(
Expand All @@ -627,6 +630,7 @@ def test_tensors_export(tensors, name):
exported = numpy.load(path)
exported = exported[exported.files[0]]
assert numpy.sum(exported.shape) > 1
os.remove(path)


@flaky(max_runs=2, min_passes=1)
Expand Down
2 changes: 2 additions & 0 deletions tests/sparseml/sparsification/test_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import tempfile

import pytest
Expand Down Expand Up @@ -162,3 +163,4 @@ def test_save_load_sparsification_info():
save_sparsification_info(info, test_path)
loaded_path = load_sparsification_info(test_path)
assert info == loaded_path
os.remove(test_path)
Loading