Added image resizing related nodes and a single image prediction node
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import torch
|
||||
|
||||
PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules")
|
||||
sys.path.append(MODULE_ROOT)
|
||||
from pytorch_wrapper.pt_crop import PtCrop
|
||||
|
||||
|
||||
class TestPtCrop(unittest.TestCase):
|
||||
def setUp(self):
|
||||
"""Set up test instance."""
|
||||
self.node = PtCrop()
|
||||
|
||||
# Test cases: (Input tensor, Height, Width, Expected shape)
|
||||
self.test_cases = [
|
||||
(torch.rand(1, 3, 16, 16), 8, 8, (1, 3, 8, 8)), # Crop 4D tensor
|
||||
(torch.rand(3, 16, 16), 8, 8, (3, 8, 8)), # Crop 3D tensor
|
||||
(torch.rand(1, 3, 16, 16), 16, 16, (1, 3, 16, 16)), # No crop, same size
|
||||
]
|
||||
|
||||
def test_crop(self):
|
||||
"""Test tensor cropping to specific sizes."""
|
||||
for tens, height, width, expected_shape in self.test_cases:
|
||||
with self.subTest(height=height, width=width):
|
||||
result, = self.node.f(tens, height, width)
|
||||
|
||||
# Ensure return value is a tensor
|
||||
self.assertTrue(isinstance(result, torch.Tensor), "Output is not a tensor")
|
||||
|
||||
# Ensure result shape matches expected shape
|
||||
self.assertEqual(result.shape, expected_shape, f"Expected shape {expected_shape}, got {result.shape}")
|
||||
|
||||
def test_invalid_tensor_rank(self):
|
||||
"""Test that an invalid tensor rank raises an error."""
|
||||
tens = torch.rand(16, 16) # 2D tensor (invalid)
|
||||
with self.assertRaises(ValueError, msg="Only rank 3 or 4 tensors are supported for crop."):
|
||||
self.node.f(tens, 8, 8)
|
||||
|
||||
def test_crop_exceeds_dimensions(self):
|
||||
"""Test that cropping beyond tensor dimensions raises an error."""
|
||||
tens = torch.rand(1, 3, 16, 16)
|
||||
with self.assertRaises(ValueError, msg="Specified crop size exceeds tensor dimensions."):
|
||||
self.node.f(tens, 32, 32)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,57 @@
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import torch
|
||||
|
||||
|
||||
PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules")
|
||||
sys.path.append(MODULE_ROOT)
|
||||
|
||||
from pytorch_wrapper.pt_from_image_transpose import PtFromImageTranspose
|
||||
|
||||
|
||||
class TestPtFromImageTranspose(unittest.TestCase):
|
||||
def setUp(self):
|
||||
"""Set up test instance."""
|
||||
self.node = PtFromImageTranspose()
|
||||
|
||||
# Define test cases: (input_tensor, expected_shape)
|
||||
self.test_cases = [
|
||||
# Case 1: 3D tensor (H, W, C) -> (C, H, W)
|
||||
(torch.ones(64, 128, 3), (3, 64, 128)), # (64,128,3) -> (3,64,128)
|
||||
|
||||
# Case 2: 4D tensor (N, H, W, C) -> (N, C, H, W)
|
||||
(torch.ones(10, 64, 128, 3), (10, 3, 64, 128)), # (10,64,128,3) -> (10,3,64,128)
|
||||
|
||||
# Case 3: Invalid input (2D tensor)
|
||||
(torch.ones(64, 128), ValueError), # 2D tensors should raise an error
|
||||
|
||||
# Case 4: Invalid input (5D tensor)
|
||||
(torch.ones(10, 64, 128, 3, 2), ValueError), # 5D tensors should raise an error
|
||||
]
|
||||
|
||||
def test_transpose(self):
|
||||
"""Test image transposition operation with valid and invalid cases."""
|
||||
for input_tensor, expected in self.test_cases:
|
||||
with self.subTest(input_shape=input_tensor.shape):
|
||||
if isinstance(expected, tuple):
|
||||
# Valid cases
|
||||
result, = self.node.f(input_tensor)
|
||||
|
||||
# Ensure return value is a tensor
|
||||
self.assertTrue(isinstance(result, torch.Tensor), "Output is not a tensor")
|
||||
|
||||
# Ensure result has correct shape
|
||||
self.assertEqual(result.shape, torch.Size(expected), f"Expected shape {expected}, got {result.shape}")
|
||||
|
||||
# Ensure result has the same dtype
|
||||
self.assertEqual(result.dtype, input_tensor.dtype, "Dtype mismatch after transpose operation")
|
||||
else:
|
||||
# Invalid cases should raise an error
|
||||
with self.assertRaises(expected):
|
||||
self.node.f(input_tensor)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,60 @@
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import torch
|
||||
|
||||
PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules")
|
||||
sys.path.append(MODULE_ROOT)
|
||||
|
||||
from pytorch_wrapper.pt_interpolate_by_scale_factor import PtInterpolateByScaleFactor
|
||||
|
||||
|
||||
class TestPtInterpolateByScaleFactor(unittest.TestCase):
|
||||
def setUp(self):
|
||||
"""Set up test instance."""
|
||||
self.node = PtInterpolateByScaleFactor()
|
||||
|
||||
# Test cases 3d: (Input tensor, Scale factor, Mode, Expected shape)
|
||||
self.test_cases_3d = [
|
||||
(torch.rand(3, 16, 16), 2.0, "nearest", (3, 32, 32)),
|
||||
(torch.rand(3, 16, 16), 2.0, "nearest-exact", (3, 32, 32)),
|
||||
(torch.rand(3, 16, 16), 0.5, "bilinear", (3, 8, 8)),
|
||||
(torch.rand(3, 16, 16), 1.5, "bicubic", (3, 24, 24)),
|
||||
]
|
||||
|
||||
# Test cases: (Input tensor, Scale factor, Mode, Expected shape)
|
||||
self.test_cases_4d = [
|
||||
(torch.rand(1, 3, 16, 16), 2.0, "nearest", (1, 3, 32, 32)), # Upscale 4D tensor
|
||||
(torch.rand(1, 3, 16, 16), 2.0, "nearest-exact", (1, 3, 32, 32)), # Upscale 4D tensor
|
||||
(torch.rand(1, 3, 16, 16), 0.5, "bilinear", (1, 3, 8, 8)), # Downscale 4D tensor
|
||||
(torch.rand(1, 3, 16, 16), 1.5, "bicubic", (1, 3, 24, 24)), # Bicubic mode with 4D tensor
|
||||
]
|
||||
|
||||
def test_interpolation_3d(self):
|
||||
"""Test tensor interpolation with different scale factors and modes."""
|
||||
for tens, scale_factor, mode, expected_shape in self.test_cases_3d:
|
||||
with self.subTest(scale_factor=scale_factor, mode=mode):
|
||||
result, = self.node.f(tens, scale_factor, mode)
|
||||
|
||||
# Ensure return value is a tensor
|
||||
self.assertTrue(isinstance(result, torch.Tensor), "Output is not a tensor")
|
||||
|
||||
# Ensure result shape matches expected shape
|
||||
self.assertEqual(result.shape, expected_shape, f"Expected shape {expected_shape}, got {result.shape}")
|
||||
|
||||
|
||||
def test_interpolation_4d(self):
|
||||
"""Test tensor interpolation with different scale factors and modes."""
|
||||
for tens, scale_factor, mode, expected_shape in self.test_cases_4d:
|
||||
with self.subTest(scale_factor=scale_factor, mode=mode):
|
||||
result, = self.node.f(tens, scale_factor, mode)
|
||||
|
||||
# Ensure return value is a tensor
|
||||
self.assertTrue(isinstance(result, torch.Tensor), "Output is not a tensor")
|
||||
|
||||
# Ensure result shape matches expected shape
|
||||
self.assertEqual(result.shape, expected_shape, f"Expected shape {expected_shape}, got {result.shape}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,61 @@
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import torch
|
||||
|
||||
PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules")
|
||||
sys.path.append(MODULE_ROOT)
|
||||
|
||||
from pytorch_wrapper.pt_interpolate_to_size import PtInterpolateToSize
|
||||
|
||||
|
||||
class TestPtInterpolateToSize(unittest.TestCase):
|
||||
def setUp(self):
|
||||
"""Set up test instance."""
|
||||
self.node = PtInterpolateToSize()
|
||||
|
||||
# Test cases 3d: (Input tensor, Height, Width, Mode, Expected shape)
|
||||
self.test_cases_3d = [
|
||||
(torch.rand(3, 16, 16), 32, 32, "nearest", (3, 32, 32)), # Upscale 3D tensor
|
||||
(torch.rand(3, 16, 16), 32, 32, "nearest-exact", (3, 32, 32)), # Upscale 3D tensor
|
||||
(torch.rand(3, 16, 16), 8, 8, "bilinear", (3, 8, 8)), # Downscale 3D tensor
|
||||
(torch.rand(3, 16, 16), 24, 24, "bicubic", (3, 24, 24)), # Bicubic mode with 3D tensor
|
||||
]
|
||||
|
||||
# Test cases 4d: (Input tensor, Height, Width, Mode, Expected shape)
|
||||
self.test_cases_4d = [
|
||||
(torch.rand(1, 3, 16, 16), 32, 32, "nearest", (1, 3, 32, 32)), # Upscale 4D tensor
|
||||
(torch.rand(1, 3, 16, 16), 32, 32, "nearest-exact", (1, 3, 32, 32)), # Upscale 4D tensor
|
||||
(torch.rand(1, 3, 16, 16), 8, 8, "bilinear", (1, 3, 8, 8)), # Downscale 4D tensor
|
||||
(torch.rand(1, 3, 16, 16), 24, 24, "bicubic", (1, 3, 24, 24)), # Bicubic mode with 4D tensor
|
||||
]
|
||||
|
||||
def test_interpolation_3d(self):
|
||||
"""Test tensor interpolation with different target sizes and modes."""
|
||||
for tens, height, width, mode, expected_shape in self.test_cases_3d:
|
||||
with self.subTest(height=height, width=width, mode=mode):
|
||||
result, = self.node.f(tens, height, width, mode)
|
||||
|
||||
# Ensure return value is a tensor
|
||||
self.assertTrue(isinstance(result, torch.Tensor), "Output is not a tensor")
|
||||
|
||||
# Ensure result shape matches expected shape
|
||||
self.assertEqual(result.shape, expected_shape, f"Expected shape {expected_shape}, got {result.shape}")
|
||||
|
||||
|
||||
def test_interpolation_4d(self):
|
||||
"""Test tensor interpolation with different target sizes and modes."""
|
||||
for tens, height, width, mode, expected_shape in self.test_cases_4d:
|
||||
with self.subTest(height=height, width=width, mode=mode):
|
||||
result, = self.node.f(tens, height, width, mode)
|
||||
|
||||
# Ensure return value is a tensor
|
||||
self.assertTrue(isinstance(result, torch.Tensor), "Output is not a tensor")
|
||||
|
||||
# Ensure result shape matches expected shape
|
||||
self.assertEqual(result.shape, expected_shape, f"Expected shape {expected_shape}, got {result.shape}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,50 @@
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import torch
|
||||
|
||||
PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules")
|
||||
sys.path.append(MODULE_ROOT)
|
||||
|
||||
from pytorch_wrapper.pt_pad import PtPad
|
||||
|
||||
|
||||
class TestPtPad(unittest.TestCase):
|
||||
def setUp(self):
|
||||
"""Set up test instance."""
|
||||
self.node = PtPad()
|
||||
|
||||
# Test cases: (Input tensor, Height, Width, Expected shape)
|
||||
self.test_cases = [
|
||||
(torch.rand(1, 3, 16, 16), 32, 32, (1, 3, 32, 32)), # Pad 4D tensor
|
||||
(torch.rand(3, 16, 16), 32, 32, (3, 32, 32)), # Pad 3D tensor
|
||||
(torch.rand(1, 3, 16, 16), 16, 16, (1, 3, 16, 16)), # No padding, same size
|
||||
]
|
||||
|
||||
def test_padding(self):
|
||||
"""Test tensor padding to specific sizes."""
|
||||
for tens, height, width, expected_shape in self.test_cases:
|
||||
with self.subTest(height=height, width=width):
|
||||
result, = self.node.f(tens, height, width)
|
||||
|
||||
# Ensure return value is a tensor
|
||||
self.assertTrue(isinstance(result, torch.Tensor), "Output is not a tensor")
|
||||
|
||||
# Ensure result shape matches expected shape
|
||||
self.assertEqual(result.shape, expected_shape, f"Expected shape {expected_shape}, got {result.shape}")
|
||||
|
||||
def test_invalid_tensor_rank(self):
|
||||
"""Test that an invalid tensor rank raises an error."""
|
||||
tens = torch.rand(16, 16) # 2D tensor (invalid)
|
||||
with self.assertRaises(ValueError, msg="Only rank 3 or 4 tensors are supported for padding."):
|
||||
self.node.f(tens, 32, 32)
|
||||
|
||||
def test_padding_smaller_than_tensor(self):
|
||||
"""Test that padding to a smaller size raises an error."""
|
||||
tens = torch.rand(1, 3, 16, 16)
|
||||
with self.assertRaises(ValueError, msg="Specified dimensions must be greater than or equal to tensor dimensions."):
|
||||
self.node.f(tens, 8, 8)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,68 @@
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
|
||||
PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules")
|
||||
sys.path.append(MODULE_ROOT)
|
||||
from pytorch_wrapper.ptn_conv_model import PtnConvModel
|
||||
from pytorch_wrapper.ptv_image_folder_dataset import PtvImageFolderDataset
|
||||
from pytorch_wrapper.ptv_transforms_resize import PtvTransformsResize
|
||||
from pytorch_wrapper.pt_data_loader import PtDataLoader
|
||||
from pytorch_wrapper.pt_predict_classification_model import PtPredictClassificationModel
|
||||
from pytorch_wrapper.pt_load_model import PtLoadModel
|
||||
|
||||
class TestPtPrediction(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test instance."""
|
||||
# Transform
|
||||
compose_node = PtvTransformsResize()
|
||||
transform = compose_node.f(256, 256)[0]
|
||||
|
||||
# Dataset
|
||||
self.node = PtvImageFolderDataset()
|
||||
self.dataset = self.node.f("dog_and_cat/val",
|
||||
transform=transform)[0]
|
||||
|
||||
|
||||
# Model
|
||||
self.model_node = PtnConvModel()
|
||||
self.model = self.model_node.f(
|
||||
input_dim="(3, 256, 256)",
|
||||
penultimate_dim=0,
|
||||
output_dim=2,
|
||||
channel_list="[32,64,128,256,512]", # To 128, 64, 32, 16, 8
|
||||
kernel_size_list="[3,3,3,3,3]",
|
||||
padding_list="[1,1,1,1,1]",
|
||||
downsample_list="[True,True,True,True,True]"
|
||||
)[0]
|
||||
|
||||
# Load weights
|
||||
epochs = 20
|
||||
self.load_model = PtLoadModel()
|
||||
self.loaded_model = self.load_model.f(self.model,f"dog_cat_{epochs}_epochs_conv.pt")
|
||||
|
||||
# Instantiates evaluation node
|
||||
self.predict = PtPredictClassificationModel()
|
||||
|
||||
def test_prediction(self):
|
||||
"""
|
||||
Tests prediction.
|
||||
|
||||
Note that this test requires a trained model file on the file system.
|
||||
Unit test will fail if you run this for the first time.
|
||||
Run the unit test for training to generate the weight, and re-run this unit test.
|
||||
"""
|
||||
inputs, y = next(iter(self.dataset))
|
||||
class_id_to_name_map = {0:"cat", 1:"dog"}
|
||||
class_name, class_id, prob = \
|
||||
self.predict.f(self.model, inputs, class_id_to_name_map, use_gpu=True)
|
||||
self.assertTrue(prob > 0.8)
|
||||
self.assertEqual(class_id, 0)
|
||||
self.assertEqual(class_name, "cat")
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,54 @@
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import torch
|
||||
PROJECT_ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules")
|
||||
sys.path.append(MODULE_ROOT)
|
||||
from pytorch_wrapper.pt_to_image_transpose import PtToImageTranspose
|
||||
|
||||
|
||||
class TestPtToImageTranspose(unittest.TestCase):
|
||||
def setUp(self):
|
||||
"""Set up test instance."""
|
||||
self.node = PtToImageTranspose()
|
||||
|
||||
# Define test cases: (input_tensor, expected_shape)
|
||||
self.test_cases = [
|
||||
# Case 1: 3D tensor (C, H, W) -> (H, W, C)
|
||||
(torch.ones(3, 64, 128), (64, 128, 3)), # (3,64,128) -> (64,128,3)
|
||||
|
||||
# Case 2: 4D tensor (N, C, H, W) -> (N, H, W, C)
|
||||
(torch.ones(10, 3, 64, 128), (10, 64, 128, 3)), # (10,3,64,128) -> (10,64,128,3)
|
||||
|
||||
# Case 3: Invalid input (2D tensor)
|
||||
(torch.ones(64, 128), ValueError), # 2D tensors should raise an error
|
||||
|
||||
# Case 4: Invalid input (5D tensor)
|
||||
(torch.ones(10, 3, 64, 128, 2), ValueError), # 5D tensors should raise an error
|
||||
]
|
||||
|
||||
def test_transpose(self):
|
||||
"""Test tensor to image transposition with valid and invalid cases."""
|
||||
for input_tensor, expected in self.test_cases:
|
||||
with self.subTest(input_shape=input_tensor.shape):
|
||||
if isinstance(expected, tuple):
|
||||
# Valid cases
|
||||
result, = self.node.f(input_tensor)
|
||||
|
||||
# Ensure return value is a tensor
|
||||
self.assertTrue(isinstance(result, torch.Tensor), "Output is not a tensor")
|
||||
|
||||
# Ensure result has correct shape
|
||||
self.assertEqual(result.shape, torch.Size(expected), f"Expected shape {expected}, got {result.shape}")
|
||||
|
||||
# Ensure result has the same dtype
|
||||
self.assertEqual(result.dtype, input_tensor.dtype, "Dtype mismatch after transpose operation")
|
||||
else:
|
||||
# Invalid cases should raise an error
|
||||
with self.assertRaises(expected):
|
||||
self.node.f(input_tensor)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user