Skip to content

Commit bd4b90a

Browse files
authored
Merge branch 'main' into default-font-size
2 parents c98ce9c + 3e56edb commit bd4b90a

10 files changed

Lines changed: 168 additions & 46 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ set(TORCHVISION_STABLE_SOURCES
106106
${TVCPP}/io/image/cuda/encode_jpegs_cuda.cpp
107107
${TVCPP}/io/image/cpu/encode_png.cpp
108108
${TVCPP}/io/image/cpu/encode_jpeg.cpp
109+
${TVCPP}/io/image/cpu/read_write_file.cpp
110+
${TVCPP}/io/image/cpu/decode_image.cpp
109111
${TVCPP}/io/image/common_stable.cpp
110112
${TVCPP}/vision_stable.cpp)
111113
# Pin them to torch 2.11. Per source, not library-wide: the pin makes ATen headers

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,21 @@ versions.
2121
| `torch` | `torchvision` | Python |
2222
| ------------------ | ------------------ | ------------------- |
2323
| `main` / `nightly` | `main` / `nightly` | `>=3.10`, `<=3.14` |
24+
| `2.13` | `0.28` | `>=3.10`, `<=3.14` |
2425
| `2.12` | `0.27` | `>=3.10`, `<=3.14` |
2526
| `2.11` | `0.26` | `>=3.10`, `<=3.14` |
2627
| `2.10` | `0.25` | `>=3.10`, `<=3.14` |
27-
| `2.9` | `0.24` | `>=3.10`, `<=3.14` |
28-
| `2.8` | `0.23` | `>=3.9`, `<=3.13` |
29-
| `2.7` | `0.22` | `>=3.9`, `<=3.13` |
30-
| `2.6` | `0.21` | `>=3.9`, `<=3.12` |
28+
3129

3230
<details>
3331
<summary>older versions</summary>
3432

3533
| `torch` | `torchvision` | Python |
3634
|---------|-------------------|---------------------------|
35+
| `2.9` | `0.24` | `>=3.10`, `<=3.14` |
36+
| `2.8` | `0.23` | `>=3.9`, `<=3.13` |
37+
| `2.7` | `0.22` | `>=3.9`, `<=3.13` |
38+
| `2.6` | `0.21` | `>=3.9`, `<=3.12` |
3739
| `2.5` | `0.20` | `>=3.9`, `<=3.12` |
3840
| `2.4` | `0.19` | `>=3.8`, `<=3.12` |
3941
| `2.3` | `0.18` | `>=3.8`, `<=3.12` |

setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ def get_macros_and_flags():
167167
CSRS_DIR / "io/image/common_stable.cpp",
168168
CSRS_DIR / "io/image/cpu/encode_png.cpp",
169169
CSRS_DIR / "io/image/cpu/encode_jpeg.cpp",
170+
CSRS_DIR / "io/image/cpu/read_write_file.cpp",
171+
CSRS_DIR / "io/image/cpu/decode_image.cpp",
170172
}
171173
STABLE_SOURCES.add(CSRS_DIR / ("ops/hip/nms_kernel.hip" if IS_ROCM else "ops/cuda/nms_kernel.cu"))
172174
STABLE_SOURCES.add(

torchvision/csrc/io/image/cpu/decode_image.cpp

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,77 @@
11
#include "decode_image.h"
22

3-
#include "decode_gif.h"
4-
#include "decode_jpeg.h"
5-
#include "decode_png.h"
6-
#include "decode_webp.h"
3+
#include <torch/csrc/stable/library.h>
4+
#include <torch/headeronly/util/Exception.h>
5+
6+
#include <cstring>
77

88
namespace vision {
99
namespace image {
1010

11-
torch::Tensor decode_image(
12-
const torch::Tensor& data,
11+
namespace {
12+
13+
// Shims over the legacy image::decode_jpeg, decode_png, decode_gif and
14+
// decode_webp ops not yet on the stable ABI.
15+
// TODO(stable-abi): remove each shim once its decoder is ported.
16+
torch::stable::Tensor decode_jpeg(
17+
const torch::stable::Tensor& data,
18+
ImageReadMode mode,
19+
bool apply_exif_orientation) {
20+
const auto num_args = 3;
21+
std::array<StableIValue, num_args> stack{
22+
torch::stable::detail::from(data),
23+
torch::stable::detail::from(mode),
24+
torch::stable::detail::from(apply_exif_orientation)};
25+
TORCH_ERROR_CODE_CHECK(torch_call_dispatcher(
26+
"image::decode_jpeg", "", stack.data(), TORCH_ABI_VERSION));
27+
return torch::stable::detail::to<torch::stable::Tensor>(stack[0]);
28+
}
29+
30+
torch::stable::Tensor decode_png(
31+
const torch::stable::Tensor& data,
32+
ImageReadMode mode,
33+
bool apply_exif_orientation) {
34+
const auto num_args = 3;
35+
std::array<StableIValue, num_args> stack{
36+
torch::stable::detail::from(data),
37+
torch::stable::detail::from(mode),
38+
torch::stable::detail::from(apply_exif_orientation)};
39+
TORCH_ERROR_CODE_CHECK(torch_call_dispatcher(
40+
"image::decode_png", "", stack.data(), TORCH_ABI_VERSION));
41+
return torch::stable::detail::to<torch::stable::Tensor>(stack[0]);
42+
}
43+
44+
torch::stable::Tensor decode_gif(const torch::stable::Tensor& data) {
45+
const auto num_args = 1;
46+
std::array<StableIValue, num_args> stack{torch::stable::detail::from(data)};
47+
TORCH_ERROR_CODE_CHECK(torch_call_dispatcher(
48+
"image::decode_gif", "", stack.data(), TORCH_ABI_VERSION));
49+
return torch::stable::detail::to<torch::stable::Tensor>(stack[0]);
50+
}
51+
52+
torch::stable::Tensor decode_webp(
53+
const torch::stable::Tensor& data,
54+
ImageReadMode mode) {
55+
const auto num_args = 2;
56+
std::array<StableIValue, num_args> stack{
57+
torch::stable::detail::from(data), torch::stable::detail::from(mode)};
58+
TORCH_ERROR_CODE_CHECK(torch_call_dispatcher(
59+
"image::decode_webp", "", stack.data(), TORCH_ABI_VERSION));
60+
return torch::stable::detail::to<torch::stable::Tensor>(stack[0]);
61+
}
62+
63+
} // namespace
64+
65+
torch::stable::Tensor decode_image(
66+
const torch::stable::Tensor& data,
1367
ImageReadMode mode,
1468
bool apply_exif_orientation) {
1569
// Check that tensor is a CPU tensor
16-
STD_TORCH_CHECK(data.device() == torch::kCPU, "Expected a CPU tensor");
70+
STD_TORCH_CHECK(data.is_cpu(), "Expected a CPU tensor");
1771
// Check that the input tensor dtype is uint8
18-
STD_TORCH_CHECK(data.dtype() == torch::kU8, "Expected a torch.uint8 tensor");
72+
STD_TORCH_CHECK(
73+
data.scalar_type() == torch::headeronly::ScalarType::Byte,
74+
"Expected a torch.uint8 tensor");
1975
// Check that the input tensor is 1-dimensional
2076
STD_TORCH_CHECK(
2177
data.dim() == 1 && data.numel() > 0,
@@ -24,7 +80,7 @@ torch::Tensor decode_image(
2480
auto err_msg =
2581
"Unsupported image file. Only jpeg, png, webp and gif are currently supported. For avif and heic format, please rely on `decode_avif` and `decode_heic` directly.";
2682

27-
auto datap = data.data_ptr<uint8_t>();
83+
auto datap = data.const_data_ptr<uint8_t>();
2884

2985
const uint8_t jpeg_signature[3] = {255, 216, 255}; // == "\xFF\xD8\xFF"
3086
STD_TORCH_CHECK(data.numel() >= 3, err_msg);
@@ -60,5 +116,14 @@ torch::Tensor decode_image(
60116
STD_TORCH_CHECK(false, err_msg);
61117
}
62118

119+
STABLE_TORCH_LIBRARY_FRAGMENT(image, m) {
120+
m.def(
121+
"decode_image(Tensor data, int mode, bool apply_exif_orientation=False) -> Tensor");
122+
}
123+
124+
STABLE_TORCH_LIBRARY_IMPL(image, CompositeExplicitAutograd, m) {
125+
m.impl("decode_image", TORCH_BOX(&decode_image));
126+
}
127+
63128
} // namespace image
64129
} // namespace vision

torchvision/csrc/io/image/cpu/decode_image.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#pragma once
22

3-
#include <torch/types.h>
4-
#include "../common.h"
3+
#include <torch/csrc/stable/tensor.h>
4+
#include "../common_stable.h"
55

66
namespace vision {
77
namespace image {
88

9-
C10_EXPORT torch::Tensor decode_image(
10-
const torch::Tensor& data,
9+
torch::stable::Tensor decode_image(
10+
const torch::stable::Tensor& data,
1111
ImageReadMode mode = IMAGE_READ_MODE_UNCHANGED,
1212
bool apply_exif_orientation = false);
1313

torchvision/csrc/io/image/cpu/read_write_file.cpp

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "read_write_file.h"
22

3+
#include <torch/csrc/stable/library.h>
4+
#include <torch/csrc/stable/ops.h>
35
#include <torch/headeronly/util/Exception.h>
46

57
#include <sys/stat.h>
@@ -12,6 +14,32 @@
1214
namespace vision {
1315
namespace image {
1416

17+
#ifndef _WIN32
18+
namespace {
19+
// Shim for the from_file op missing in stable ABI.
20+
// TODO(stable-abi): remove once from_file lands in the stable ABI upstream.
21+
torch::stable::Tensor stable_from_file(
22+
const std::string& filename,
23+
bool shared,
24+
int64_t size,
25+
torch::headeronly::ScalarType dtype) {
26+
const auto num_args = 7;
27+
std::array<StableIValue, num_args> stack{
28+
torch::stable::detail::from(filename),
29+
torch::stable::detail::from(std::optional<bool>(shared)),
30+
torch::stable::detail::from(std::optional<int64_t>(size)),
31+
torch::stable::detail::from(
32+
std::optional<torch::headeronly::ScalarType>(dtype)),
33+
torch::stable::detail::from(std::nullopt), // layout
34+
torch::stable::detail::from(std::nullopt), // device
35+
torch::stable::detail::from(std::nullopt)}; // pin_memory
36+
TORCH_ERROR_CODE_CHECK(torch_call_dispatcher(
37+
"aten::from_file", "", stack.data(), TORCH_ABI_VERSION));
38+
return torch::stable::detail::to<torch::stable::Tensor>(stack[0]);
39+
}
40+
} // namespace
41+
#endif
42+
1543
#ifdef _WIN32
1644
namespace {
1745
std::wstring utf8_decode(const std::string& str) {
@@ -34,9 +62,7 @@ std::wstring utf8_decode(const std::string& str) {
3462
} // namespace
3563
#endif
3664

37-
torch::Tensor read_file(const std::string& filename) {
38-
C10_LOG_API_USAGE_ONCE(
39-
"torchvision.csrc.io.image.cpu.read_write_file.read_file");
65+
torch::stable::Tensor read_file(const std::string& filename) {
4066
#ifdef _WIN32
4167
// According to
4268
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions?view=vs-2019,
@@ -66,35 +92,38 @@ torch::Tensor read_file(const std::string& filename) {
6692

6793
STD_TORCH_CHECK(infile != nullptr, "Error opening input file");
6894

69-
auto data = torch::empty({size}, torch::kU8);
70-
auto dataBytes = data.data_ptr<uint8_t>();
95+
auto data = torch::stable::empty({size}, torch::headeronly::ScalarType::Byte);
96+
auto dataBytes = data.mutable_data_ptr<uint8_t>();
7197

7298
fread(dataBytes, sizeof(uint8_t), size, infile);
7399
fclose(infile);
74100
#else
75-
auto data =
76-
torch::from_file(filename, /*shared=*/false, /*size=*/size, torch::kU8);
101+
auto data = stable_from_file(
102+
filename,
103+
/*shared=*/false,
104+
/*size=*/size,
105+
torch::headeronly::ScalarType::Byte);
77106
#endif
78107

79108
return data;
80109
}
81110

82-
void write_file(const std::string& filename, torch::Tensor& data) {
83-
C10_LOG_API_USAGE_ONCE(
84-
"torchvision.csrc.io.image.cpu.read_write_file.write_file");
111+
torch::stable::Tensor write_file(
112+
const std::string& filename,
113+
torch::stable::Tensor& data) {
85114
// Check that the input tensor is on CPU
86-
STD_TORCH_CHECK(
87-
data.device() == torch::kCPU, "Input tensor should be on CPU");
115+
STD_TORCH_CHECK(data.is_cpu(), "Input tensor should be on CPU");
88116

89117
// Check that the input tensor dtype is uint8
90118
STD_TORCH_CHECK(
91-
data.dtype() == torch::kU8, "Input tensor dtype should be uint8");
119+
data.scalar_type() == torch::headeronly::ScalarType::Byte,
120+
"Input tensor dtype should be uint8");
92121

93122
// Check that the input tensor is 3-dimensional
94123
STD_TORCH_CHECK(
95124
data.dim() == 1, "Input data should be a 1-dimensional tensor");
96125

97-
auto fileBytes = data.data_ptr<uint8_t>();
126+
auto fileBytes = data.const_data_ptr<uint8_t>();
98127
auto fileCStr = filename.c_str();
99128
#ifdef _WIN32
100129
auto fileW = utf8_decode(filename);
@@ -107,6 +136,21 @@ void write_file(const std::string& filename, torch::Tensor& data) {
107136

108137
fwrite(fileBytes, sizeof(uint8_t), data.numel(), outfile);
109138
fclose(outfile);
139+
140+
return data;
141+
}
142+
143+
STABLE_TORCH_LIBRARY_FRAGMENT(image, m) {
144+
m.def("read_file(str filename) -> Tensor");
145+
// write_file returns its input so TorchScript DCE keeps the call alive
146+
// since a stable def cannot express AliasAnalysisKind::CONSERVATIVE:
147+
// https://github.com/pytorch/pytorch/issues/189309
148+
m.def("write_file(str filename, Tensor data) -> Tensor");
149+
}
150+
151+
STABLE_TORCH_LIBRARY_IMPL(image, CompositeExplicitAutograd, m) {
152+
m.impl("read_file", TORCH_BOX(&read_file));
153+
m.impl("write_file", TORCH_BOX(&write_file));
110154
}
111155

112156
} // namespace image
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
#pragma once
22

3-
#include <torch/types.h>
3+
#include <torch/csrc/stable/tensor.h>
4+
5+
#include <string>
46

57
namespace vision {
68
namespace image {
79

8-
C10_EXPORT torch::Tensor read_file(const std::string& filename);
10+
torch::stable::Tensor read_file(const std::string& filename);
911

10-
C10_EXPORT void write_file(const std::string& filename, torch::Tensor& data);
12+
torch::stable::Tensor write_file(
13+
const std::string& filename,
14+
torch::stable::Tensor& data);
1115

1216
} // namespace image
1317
} // namespace vision

torchvision/csrc/io/image/image.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ static auto registry =
1414
&decode_jpeg)
1515
.op("image::decode_webp(Tensor encoded_data, int mode) -> Tensor",
1616
&decode_webp)
17-
.op("image::read_file", &read_file)
18-
.op("image::write_file", &write_file)
19-
.op("image::decode_image(Tensor data, int mode, bool apply_exif_orientation=False) -> Tensor",
20-
&decode_image)
2117
.op("image::_jpeg_version", &_jpeg_version)
2218
.op("image::_is_compiled_against_turbo", &_is_compiled_against_turbo);
2319

torchvision/csrc/io/image/image.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#pragma once
22

33
#include "cpu/decode_gif.h"
4-
#include "cpu/decode_image.h"
54
#include "cpu/decode_jpeg.h"
65
#include "cpu/decode_png.h"
76
#include "cpu/decode_webp.h"
8-
#include "cpu/read_write_file.h"

0 commit comments

Comments
 (0)