ops.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. # LICENSE HEADER MANAGED BY add-license-header
  2. #
  3. # Copyright 2018 Kornia Team
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. from typing import Optional, Tuple
  18. import kornia.augmentation as K
  19. from kornia.augmentation.auto.operations.base import OperationBase
  20. from kornia.core import Tensor
  21. from kornia.grad_estimator import STEFunction
  22. __all__ = [
  23. "AutoContrast",
  24. "Brightness",
  25. "Contrast",
  26. "Equalize",
  27. "Gray",
  28. "HorizontalFlip",
  29. "Hue",
  30. "Invert",
  31. "Posterize",
  32. "Rotate",
  33. "Saturate",
  34. "Sharpness",
  35. "ShearX",
  36. "ShearY",
  37. "Solarize",
  38. "SolarizeAdd",
  39. "TranslateX",
  40. "TranslateY",
  41. "VerticalFlip",
  42. ]
  43. class AutoContrast(OperationBase):
  44. """Apply auto_contrast operation.
  45. Args:
  46. initial_probability: the initial probability. If None, the augmentation will be randomly
  47. applied according to he augmentation sampling range.
  48. temperature: temperature for RelaxedBernoulli distribution used during training.
  49. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  50. """
  51. def __init__(
  52. self, initial_probability: float = 0.5, temperature: float = 0.1, symmetric_megnitude: bool = False
  53. ) -> None:
  54. super().__init__(
  55. K.RandomAutoContrast(same_on_batch=False, p=initial_probability),
  56. initial_magnitude=None,
  57. temperature=temperature,
  58. symmetric_megnitude=symmetric_megnitude,
  59. )
  60. class Brightness(OperationBase):
  61. """Apply brightness operation.
  62. Args:
  63. initial_probability: the initial probability. If None, the augmentation will be randomly
  64. applied according to he augmentation sampling range.
  65. initial_magnitude: the initial magnitude.
  66. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  67. temperature: temperature for RelaxedBernoulli distribution used during training.
  68. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  69. """
  70. def __init__(
  71. self,
  72. initial_magnitude: Optional[float] = 0.5,
  73. initial_probability: float = 0.5,
  74. magnitude_range: Tuple[float, float] = (0.2, 1.8),
  75. temperature: float = 0.1,
  76. symmetric_megnitude: bool = False,
  77. ) -> None:
  78. super().__init__(
  79. K.RandomBrightness(magnitude_range, same_on_batch=False, p=initial_probability),
  80. initial_magnitude=[("brightness_factor", initial_magnitude)],
  81. temperature=temperature,
  82. symmetric_megnitude=symmetric_megnitude,
  83. )
  84. class Contrast(OperationBase):
  85. """Apply contrast operation.
  86. Args:
  87. initial_probability: the initial probability. If None, the augmentation will be randomly
  88. applied according to he augmentation sampling range.
  89. initial_magnitude: the initial magnitude.
  90. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  91. temperature: temperature for RelaxedBernoulli distribution used during training.
  92. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  93. """
  94. def __init__(
  95. self,
  96. initial_magnitude: Optional[float] = 0.5,
  97. initial_probability: float = 0.5,
  98. magnitude_range: Tuple[float, float] = (0.2, 1.8),
  99. temperature: float = 0.1,
  100. symmetric_megnitude: bool = False,
  101. ) -> None:
  102. super().__init__(
  103. K.RandomContrast(magnitude_range, same_on_batch=False, p=initial_probability),
  104. initial_magnitude=[("contrast_factor", initial_magnitude)],
  105. temperature=temperature,
  106. symmetric_megnitude=symmetric_megnitude,
  107. )
  108. class Hue(OperationBase):
  109. """Apply hue operation.
  110. Args:
  111. initial_probability: the initial probability. If None, the augmentation will be randomly
  112. applied according to he augmentation sampling range.
  113. initial_magnitude: the initial magnitude.
  114. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  115. temperature: temperature for RelaxedBernoulli distribution used during training.
  116. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  117. """
  118. def __init__(
  119. self,
  120. initial_magnitude: Optional[float] = 0.0,
  121. initial_probability: float = 0.5,
  122. magnitude_range: Tuple[float, float] = (-0.5, 0.5),
  123. temperature: float = 0.1,
  124. symmetric_megnitude: bool = False,
  125. ) -> None:
  126. super().__init__(
  127. K.RandomHue(magnitude_range, same_on_batch=False, p=initial_probability),
  128. initial_magnitude=[("hue_factor", initial_magnitude)],
  129. temperature=temperature,
  130. symmetric_megnitude=symmetric_megnitude,
  131. )
  132. class Saturate(OperationBase):
  133. """Apply saturation operation.
  134. Args:
  135. initial_probability: the initial probability. If None, the augmentation will be randomly
  136. applied according to he augmentation sampling range.
  137. initial_magnitude: the initial magnitude.
  138. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  139. temperature: temperature for RelaxedBernoulli distribution used during training.
  140. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  141. """
  142. def __init__(
  143. self,
  144. initial_magnitude: Optional[float] = 0.5,
  145. initial_probability: float = 0.5,
  146. magnitude_range: Tuple[float, float] = (0.2, 1.8),
  147. temperature: float = 0.1,
  148. symmetric_megnitude: bool = False,
  149. ) -> None:
  150. super().__init__(
  151. K.RandomSaturation(magnitude_range, same_on_batch=False, p=initial_probability),
  152. initial_magnitude=[("saturation_factor", initial_magnitude)],
  153. temperature=temperature,
  154. symmetric_megnitude=symmetric_megnitude,
  155. )
  156. # TODO: Equalize cannot update probabilities yet.
  157. class Equalize(OperationBase):
  158. """Apply equalize operation.
  159. Args:
  160. initial_probability: the initial probability. If None, the augmentation will be randomly
  161. applied according to he augmentation sampling range.
  162. temperature: temperature for RelaxedBernoulli distribution used during training.
  163. Note:
  164. Equalize cannot update probabilities yet.
  165. Note:
  166. STE gradient estimator applied for back propagation.
  167. """
  168. def __init__(self, initial_probability: float = 0.5, temperature: float = 0.1) -> None:
  169. super().__init__(
  170. K.RandomEqualize(same_on_batch=False, p=initial_probability),
  171. initial_magnitude=None,
  172. temperature=temperature,
  173. symmetric_megnitude=False,
  174. gradient_estimator=STEFunction,
  175. )
  176. class Gray(OperationBase):
  177. """Apply grayscale operation.
  178. Args:
  179. initial_probability: the initial probability. If None, the augmentation will be randomly
  180. applied according to he augmentation sampling range.
  181. temperature: temperature for RelaxedBernoulli distribution used during training.
  182. """
  183. def __init__(self, initial_probability: float = 0.5, temperature: float = 0.1) -> None:
  184. super().__init__(
  185. K.RandomGrayscale(same_on_batch=False, p=initial_probability),
  186. initial_magnitude=None,
  187. temperature=temperature,
  188. symmetric_megnitude=False,
  189. )
  190. class Invert(OperationBase):
  191. """Apply invert operation.
  192. Args:
  193. initial_probability: the initial probability. If None, the augmentation will be randomly
  194. applied according to he augmentation sampling range.
  195. temperature: temperature for RelaxedBernoulli distribution used during training.
  196. """
  197. def __init__(self, initial_probability: float = 0.5, temperature: float = 0.1) -> None:
  198. super().__init__(
  199. K.RandomInvert(same_on_batch=False, p=initial_probability),
  200. initial_magnitude=None,
  201. temperature=temperature,
  202. symmetric_megnitude=False,
  203. )
  204. class Posterize(OperationBase):
  205. """Apply posterize operation.
  206. Args:
  207. initial_magnitude: the initial magnitude.
  208. initial_probability: the initial probability. If None, the augmentation will be randomly
  209. applied according to he augmentation sampling range.
  210. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  211. temperature: temperature for RelaxedBernoulli distribution used during training.
  212. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  213. Note:
  214. STE gradient estimator applied for back propagation.
  215. """
  216. @staticmethod
  217. def _process_magnitude(magnitude: Tensor) -> Tensor:
  218. return magnitude.long()
  219. def __init__(
  220. self,
  221. initial_magnitude: Optional[float] = 4.0,
  222. initial_probability: float = 0.5,
  223. magnitude_range: Tuple[float, float] = (1.0, 8.0),
  224. temperature: float = 0.1,
  225. symmetric_megnitude: bool = False,
  226. ) -> None:
  227. super().__init__(
  228. K.RandomPosterize(magnitude_range, same_on_batch=False, p=initial_probability),
  229. initial_magnitude=[("bits_factor", initial_magnitude)],
  230. temperature=temperature,
  231. symmetric_megnitude=symmetric_megnitude,
  232. magnitude_fn=Posterize._process_magnitude,
  233. gradient_estimator=STEFunction,
  234. )
  235. class Solarize(OperationBase):
  236. """Apply solarize operation.
  237. Args:
  238. initial_magnitude: the initial magnitude.
  239. initial_probability: the initial probability. If None, the augmentation will be randomly
  240. applied according to he augmentation sampling range.
  241. magnitude_range: the sampling range for random sampling and clamping the optimized
  242. symmetric_megnitude: if to randomly assign the magnitude as negative or not.magnitude.
  243. temperature: temperature for RelaxedBernoulli distribution used during training.
  244. Note:
  245. STE gradient estimator applied for back propagation.
  246. """
  247. def __init__(
  248. self,
  249. initial_magnitude: Optional[float] = 0.5,
  250. initial_probability: float = 0.5,
  251. magnitude_range: Tuple[float, float] = (0.0, 1.0),
  252. temperature: float = 0.1,
  253. symmetric_megnitude: bool = False,
  254. ) -> None:
  255. super().__init__(
  256. K.RandomSolarize(magnitude_range, additions=0.0, same_on_batch=False, p=initial_probability),
  257. initial_magnitude=[("thresholds", initial_magnitude)],
  258. temperature=temperature,
  259. symmetric_megnitude=symmetric_megnitude,
  260. gradient_estimator=STEFunction,
  261. )
  262. class SolarizeAdd(OperationBase):
  263. """Apply solarize-addition operation with a fixed thresholds of 0.5.
  264. Args:
  265. initial_magnitude: the initial magnitude.
  266. initial_probability: the initial probability. If None, the augmentation will be randomly
  267. applied according to he augmentation sampling range.
  268. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  269. temperature: temperature for RelaxedBernoulli distribution used during training.
  270. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  271. Note:
  272. STE gradient estimator applied for back propagation.
  273. """
  274. def __init__(
  275. self,
  276. initial_magnitude: Optional[float] = 0.0,
  277. initial_probability: float = 0.5,
  278. magnitude_range: Tuple[float, float] = (-0.3, 0.3),
  279. temperature: float = 0.1,
  280. symmetric_megnitude: bool = False,
  281. ) -> None:
  282. super().__init__(
  283. K.RandomSolarize(thresholds=0.5, additions=magnitude_range, same_on_batch=False, p=initial_probability),
  284. initial_magnitude=[("additions", initial_magnitude)],
  285. temperature=temperature,
  286. symmetric_megnitude=symmetric_megnitude,
  287. gradient_estimator=STEFunction,
  288. )
  289. class Sharpness(OperationBase):
  290. """Apply sharpness operation.
  291. Args:
  292. initial_magnitude: the initial magnitude.
  293. initial_probability: the initial probability. If None, the augmentation will be randomly
  294. applied according to he augmentation sampling range.
  295. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  296. temperature: temperature for RelaxedBernoulli distribution used during training.
  297. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  298. """
  299. def __init__(
  300. self,
  301. initial_magnitude: Optional[float] = 0.5,
  302. initial_probability: float = 0.5,
  303. magnitude_range: Tuple[float, float] = (0.1, 1.9),
  304. temperature: float = 0.1,
  305. symmetric_megnitude: bool = False,
  306. ) -> None:
  307. super().__init__(
  308. K.RandomSharpness(magnitude_range, same_on_batch=False, p=initial_probability),
  309. initial_magnitude=[("sharpness", initial_magnitude)],
  310. temperature=temperature,
  311. symmetric_megnitude=symmetric_megnitude,
  312. )
  313. class HorizontalFlip(OperationBase):
  314. """Apply horizontal flip operation.
  315. Args:
  316. initial_probability: the initial probability. If None, the augmentation will be randomly
  317. applied according to he augmentation sampling range.
  318. temperature: temperature for RelaxedBernoulli distribution used during training.
  319. """
  320. def __init__(self, initial_probability: float = 0.5, temperature: float = 0.1) -> None:
  321. super().__init__(
  322. K.RandomHorizontalFlip(same_on_batch=False, p=initial_probability),
  323. initial_magnitude=None,
  324. temperature=temperature,
  325. symmetric_megnitude=False,
  326. )
  327. class VerticalFlip(OperationBase):
  328. """Apply vertical flip operation.
  329. Args:
  330. initial_magnitude: the initial magnitude.
  331. temperature: temperature for RelaxedBernoulli distribution used during training.
  332. """
  333. def __init__(self, initial_probability: float = 0.5, temperature: float = 0.1) -> None:
  334. super().__init__(
  335. K.RandomVerticalFlip(same_on_batch=False, p=initial_probability),
  336. initial_magnitude=None,
  337. temperature=temperature,
  338. symmetric_megnitude=False,
  339. )
  340. class Rotate(OperationBase):
  341. """Apply rotate operation.
  342. Args:
  343. initial_magnitude: the initial magnitude.
  344. initial_probability: the initial probability. If None, the augmentation will be randomly
  345. applied according to he augmentation sampling range.
  346. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  347. temperature: temperature for RelaxedBernoulli distribution used during training.
  348. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  349. """
  350. def __init__(
  351. self,
  352. initial_magnitude: Optional[float] = 15.0,
  353. initial_probability: float = 0.5,
  354. magnitude_range: Tuple[float, float] = (0.0, 30.0),
  355. temperature: float = 0.1,
  356. symmetric_megnitude: bool = True,
  357. ) -> None:
  358. if symmetric_megnitude and magnitude_range[0] < 0:
  359. raise ValueError(
  360. f"Lower bound of {self.__class__.__name__} is a symmetric operation. "
  361. f"The lower bound must above 0. Got {magnitude_range[0]}."
  362. )
  363. super().__init__(
  364. K.RandomRotation(magnitude_range, same_on_batch=False, p=initial_probability),
  365. initial_magnitude=[("degrees", initial_magnitude)],
  366. temperature=temperature,
  367. symmetric_megnitude=symmetric_megnitude,
  368. )
  369. class ShearX(OperationBase):
  370. """Apply shear operation along x-axis.
  371. Args:
  372. initial_magnitude: the initial magnitude.
  373. initial_probability: the initial probability. If None, the augmentation will be randomly
  374. applied according to he augmentation sampling range.
  375. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  376. temperature: temperature for RelaxedBernoulli distribution used during training.
  377. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  378. """
  379. @staticmethod
  380. def _process_magnitude(magnitude: Tensor) -> Tensor:
  381. # make it sign-agnostic
  382. return magnitude * 180
  383. def __init__(
  384. self,
  385. initial_magnitude: Optional[float] = 0.1,
  386. initial_probability: float = 0.5,
  387. magnitude_range: Tuple[float, float] = (0.0, 0.3),
  388. temperature: float = 0.1,
  389. symmetric_megnitude: bool = True,
  390. ) -> None:
  391. if symmetric_megnitude and magnitude_range[0] < 0:
  392. raise ValueError(
  393. f"Lower bound of {self.__class__.__name__} is a symmetric operation. "
  394. f"The lower bound must above 0. Got {magnitude_range[0]}."
  395. )
  396. super().__init__(
  397. K.RandomShear(magnitude_range, same_on_batch=False, p=initial_probability, align_corners=True),
  398. initial_magnitude=[("shear_x", initial_magnitude)],
  399. temperature=temperature,
  400. symmetric_megnitude=symmetric_megnitude,
  401. magnitude_fn=ShearX._process_magnitude,
  402. )
  403. class ShearY(OperationBase):
  404. """Apply shear operation along y-axis.
  405. Args:
  406. initial_magnitude: the initial magnitude.
  407. initial_probability: the initial probability. If None, the augmentation will be randomly
  408. applied according to he augmentation sampling range.
  409. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  410. temperature: temperature for RelaxedBernoulli distribution used during training.
  411. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  412. """
  413. @staticmethod
  414. def _process_magnitude(magnitude: Tensor) -> Tensor:
  415. # make it sign-agnostic
  416. return magnitude * 180
  417. def __init__(
  418. self,
  419. initial_magnitude: Optional[float] = 0.1,
  420. initial_probability: float = 0.5,
  421. magnitude_range: Tuple[float, float] = (0.0, 0.3),
  422. temperature: float = 0.1,
  423. symmetric_megnitude: bool = True,
  424. ) -> None:
  425. if symmetric_megnitude and magnitude_range[0] < 0:
  426. raise ValueError(
  427. f"Lower bound of {self.__class__.__name__} is a symmetric operation. "
  428. f"The lower bound must above 0. Got {magnitude_range[0]}."
  429. )
  430. super().__init__(
  431. K.RandomShear(
  432. (0.0, 0.0, magnitude_range[0], magnitude_range[1]),
  433. same_on_batch=False,
  434. p=initial_probability,
  435. align_corners=True,
  436. ),
  437. initial_magnitude=[("shear_y", initial_magnitude)],
  438. temperature=temperature,
  439. symmetric_megnitude=symmetric_megnitude,
  440. magnitude_fn=ShearY._process_magnitude,
  441. )
  442. class TranslateX(OperationBase):
  443. """Apply translate operation along x-axis.
  444. Args:
  445. initial_magnitude: the initial magnitude.
  446. initial_probability: the initial probability. If None, the augmentation will be randomly
  447. applied according to he augmentation sampling range.
  448. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  449. temperature: temperature for RelaxedBernoulli distribution used during training.
  450. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  451. """
  452. def __init__(
  453. self,
  454. initial_magnitude: Optional[float] = 0.2,
  455. initial_probability: float = 0.5,
  456. magnitude_range: Tuple[float, float] = (0.0, 0.5),
  457. temperature: float = 0.1,
  458. symmetric_megnitude: bool = True,
  459. ) -> None:
  460. if symmetric_megnitude and magnitude_range[0] < 0:
  461. raise ValueError(
  462. f"Lower bound of {self.__class__.__name__} is a symmetric operation. "
  463. f"The lower bound must above 0. Got {magnitude_range[0]}."
  464. )
  465. super().__init__(
  466. K.RandomTranslate(magnitude_range, same_on_batch=False, p=initial_probability, align_corners=True),
  467. initial_magnitude=[("translate_x", initial_magnitude)],
  468. temperature=temperature,
  469. symmetric_megnitude=symmetric_megnitude,
  470. )
  471. class TranslateY(OperationBase):
  472. """Apply translate operation along y-axis.
  473. Args:
  474. initial_magnitude: the initial magnitude.
  475. initial_probability: the initial probability. If None, the augmentation will be randomly
  476. applied according to he augmentation sampling range.
  477. magnitude_range: the sampling range for random sampling and clamping the optimized magnitude.
  478. temperature: temperature for RelaxedBernoulli distribution used during training.
  479. symmetric_megnitude: if to randomly assign the magnitude as negative or not.
  480. """
  481. def __init__(
  482. self,
  483. initial_magnitude: Optional[float] = 0.2,
  484. initial_probability: float = 0.5,
  485. magnitude_range: Tuple[float, float] = (0.0, 0.5),
  486. temperature: float = 0.1,
  487. symmetric_megnitude: bool = True,
  488. ) -> None:
  489. if symmetric_megnitude and magnitude_range[0] < 0:
  490. raise ValueError(
  491. f"Lower bound of {self.__class__.__name__} is a symmetric operation. "
  492. f"The lower bound must above 0. Got {magnitude_range[0]}."
  493. )
  494. super().__init__(
  495. K.RandomTranslate(None, magnitude_range, same_on_batch=False, p=initial_probability, align_corners=True),
  496. initial_magnitude=[("translate_y", initial_magnitude)],
  497. temperature=temperature,
  498. symmetric_megnitude=symmetric_megnitude,
  499. )