mappings.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. import operator
  2. from typing import TYPE_CHECKING
  3. import torch
  4. import torch.ao.nn.intrinsic as nni
  5. import torch.ao.nn.intrinsic.qat as nniqat
  6. import torch.ao.nn.intrinsic.quantized as nniq
  7. import torch.ao.nn.intrinsic.quantized.dynamic as nniqd
  8. import torch.ao.nn.qat as nnqat
  9. import torch.ao.nn.qat.dynamic as nnqatd
  10. import torch.ao.nn.quantized as nnq
  11. import torch.ao.nn.quantized.dynamic as nnqd
  12. import torch.ao.quantization.fx._lower_to_native_backend as _lower_to_native_backend
  13. import torch.ao.quantization.quantization_mappings as quantization_mappings
  14. import torch.nn as nn
  15. import torch.nn.functional as F
  16. from torch.ao.quantization.backend_config import get_native_backend_config
  17. from .ns_types import NSNodeTargetType
  18. if TYPE_CHECKING:
  19. from collections.abc import Callable
  20. toq = torch.ops.quantized
  21. def get_base_name_to_sets_of_related_ops() -> dict[str, set[NSNodeTargetType]]:
  22. # note: this set is modified below by items from backend_config
  23. sets_of_related_ops: list[set[NSNodeTargetType]] = [
  24. # conv modules
  25. {
  26. nn.Conv1d,
  27. },
  28. {
  29. nn.Conv2d,
  30. },
  31. {
  32. nn.Conv3d,
  33. },
  34. # conv functionals
  35. {
  36. F.conv1d,
  37. },
  38. {
  39. F.conv2d,
  40. },
  41. {
  42. F.conv3d,
  43. },
  44. # linear modules
  45. {
  46. nn.Linear,
  47. },
  48. # linear functionals
  49. {
  50. F.linear,
  51. },
  52. # average pool
  53. {
  54. nn.AvgPool1d,
  55. torch.avg_pool1d,
  56. },
  57. {
  58. nn.AvgPool2d,
  59. torch._C._nn.avg_pool2d,
  60. },
  61. {
  62. nn.AvgPool3d,
  63. torch._C._nn.avg_pool3d,
  64. },
  65. # adaptive average pool
  66. {
  67. nn.AdaptiveAvgPool1d,
  68. F.adaptive_avg_pool1d,
  69. },
  70. {
  71. nn.AdaptiveAvgPool2d,
  72. F.adaptive_avg_pool2d,
  73. },
  74. {
  75. nn.AdaptiveAvgPool3d,
  76. F.adaptive_avg_pool3d,
  77. },
  78. # LSTM
  79. {
  80. nn.LSTM,
  81. },
  82. # add
  83. {
  84. torch.add,
  85. operator.add, # x + y
  86. },
  87. # cat
  88. {
  89. torch.cat,
  90. },
  91. # mul
  92. {
  93. torch.mul,
  94. operator.mul,
  95. },
  96. # relu
  97. {
  98. F.relu,
  99. nn.ReLU,
  100. "relu",
  101. "relu_",
  102. torch.relu,
  103. },
  104. # maxpool
  105. {
  106. nn.MaxPool1d,
  107. F.max_pool1d,
  108. },
  109. {
  110. nn.MaxPool2d,
  111. F.max_pool2d,
  112. },
  113. {
  114. nn.MaxPool3d,
  115. F.max_pool3d,
  116. },
  117. # sigmoid
  118. {
  119. torch.sigmoid,
  120. "sigmoid",
  121. "sigmoid_",
  122. nn.Sigmoid,
  123. F.sigmoid,
  124. },
  125. # BatchNorm
  126. {
  127. nn.BatchNorm2d,
  128. },
  129. {
  130. nn.BatchNorm3d,
  131. },
  132. # ConvTranspose
  133. {
  134. nn.ConvTranspose1d,
  135. },
  136. {
  137. nn.ConvTranspose2d,
  138. },
  139. {
  140. nn.ConvTranspose3d,
  141. },
  142. # functional transposed conv
  143. {
  144. F.conv_transpose1d,
  145. },
  146. {
  147. F.conv_transpose2d,
  148. },
  149. {
  150. F.conv_transpose3d,
  151. },
  152. # ELU
  153. {
  154. nn.ELU,
  155. },
  156. # Embedding
  157. {
  158. nn.Embedding,
  159. },
  160. # EmbeddingBag
  161. {
  162. nn.EmbeddingBag,
  163. },
  164. # GroupNorm
  165. {
  166. nn.GroupNorm,
  167. },
  168. # Hardswish
  169. {
  170. nn.Hardswish,
  171. },
  172. # InstanceNorm
  173. {
  174. nn.InstanceNorm1d,
  175. },
  176. {
  177. nn.InstanceNorm2d,
  178. },
  179. {
  180. nn.InstanceNorm3d,
  181. },
  182. # LayerNorm
  183. {
  184. nn.LayerNorm,
  185. },
  186. # LeakyReLU
  187. {
  188. nn.LeakyReLU,
  189. },
  190. # ReLU6
  191. {
  192. nn.ReLU6,
  193. F.relu6,
  194. },
  195. # F.elu
  196. {
  197. F.elu,
  198. },
  199. # F.hardswish
  200. {
  201. F.hardswish,
  202. },
  203. # F.group_norm
  204. {
  205. F.group_norm,
  206. },
  207. # F.instance_norm
  208. {
  209. F.instance_norm,
  210. },
  211. # F.layer_norm
  212. {
  213. F.layer_norm,
  214. },
  215. # F.leaky_relu
  216. {
  217. F.leaky_relu,
  218. },
  219. # F.silu
  220. {
  221. nn.SiLU,
  222. F.silu,
  223. },
  224. # F.mish
  225. {
  226. nn.Mish,
  227. F.mish,
  228. },
  229. # F.tanh
  230. {
  231. nn.Tanh,
  232. F.tanh,
  233. torch.tanh,
  234. "tanh_",
  235. "tanh",
  236. },
  237. # F.hardsigmoid
  238. {
  239. "hardsigmoid_",
  240. "hardsigmoid",
  241. F.hardsigmoid,
  242. nn.Hardsigmoid,
  243. },
  244. # F.hardtanh
  245. {
  246. nn.Hardtanh,
  247. F.hardtanh,
  248. F.hardtanh_,
  249. },
  250. # floordiv
  251. {
  252. operator.floordiv,
  253. },
  254. # unsqueeze
  255. {
  256. torch.unsqueeze,
  257. },
  258. # stack
  259. {
  260. torch.stack,
  261. },
  262. # squeeze
  263. {
  264. torch.squeeze,
  265. },
  266. # sort
  267. {
  268. torch.sort,
  269. },
  270. # repeat_interleave
  271. {
  272. torch.repeat_interleave,
  273. },
  274. # min
  275. {
  276. torch.min,
  277. },
  278. # mean
  279. {
  280. torch.mean,
  281. },
  282. # max
  283. {
  284. torch.max,
  285. },
  286. # transpose
  287. {
  288. torch.transpose,
  289. },
  290. # flatten
  291. {
  292. torch.flatten,
  293. },
  294. # clamp
  295. {
  296. torch.clamp,
  297. },
  298. # chunk
  299. {
  300. torch.chunk,
  301. },
  302. # interpolate
  303. {
  304. torch.nn.functional.interpolate,
  305. },
  306. # dropout
  307. {
  308. nn.Dropout,
  309. },
  310. # F.dropout
  311. {
  312. F.dropout,
  313. },
  314. # matmul
  315. {
  316. torch.matmul,
  317. },
  318. # Softmax
  319. {
  320. nn.Softmax,
  321. },
  322. # PReLU
  323. {
  324. nn.PReLU,
  325. nnq.PReLU,
  326. },
  327. # F.prelu
  328. {
  329. F.prelu,
  330. toq.prelu,
  331. },
  332. # pixel shuffle
  333. {
  334. nn.PixelShuffle,
  335. },
  336. {
  337. F.pixel_shuffle,
  338. },
  339. # pixel unshuffle
  340. {
  341. nn.PixelUnshuffle,
  342. },
  343. {
  344. F.pixel_unshuffle,
  345. },
  346. # narrow
  347. {
  348. torch.narrow,
  349. },
  350. ]
  351. # for each floating point op, add versions of the op added by
  352. # backend_config
  353. backend_config = get_native_backend_config()
  354. new_connections: list[tuple[Callable, Callable]] = [
  355. # technical debt edge case
  356. (nn.Linear, nn.modules.linear.NonDynamicallyQuantizableLinear),
  357. ]
  358. for pattern, config in backend_config._pattern_complex_format_to_config.items():
  359. # pattern format: (c, (b, a))
  360. first_element = pattern
  361. # look from the end, because pattern is in reverse order
  362. while isinstance(first_element, (list, tuple)):
  363. first_element = first_element[-1]
  364. if config.fused_module is not None:
  365. # case 1: pattern fuses a pattern of ops into an op
  366. # example: nn.Conv1d, nn.ReLU fused into nni.ConvReLU1d
  367. # pyrefly: ignore [bad-argument-type]
  368. new_connections.append((first_element, config.fused_module))
  369. if config.qat_module is not None:
  370. # case 2: pattern swaps a module into a QAT module
  371. # example: nni.ConvReLU1d swapped into nniqat.ConvReLU1d
  372. # pyrefly: ignore [bad-argument-type]
  373. new_connections.append((first_element, config.qat_module))
  374. if config.reference_quantized_module is not None:
  375. # case 3: reference version of floating point module, such as
  376. # nn.Conv2d and nnqr.Conv2d
  377. # pyrefly: ignore [bad-argument-type]
  378. new_connections.append((first_element, config.reference_quantized_module))
  379. #
  380. # Add reference module swaps from default lowering path
  381. #
  382. for source_to_target in (
  383. _lower_to_native_backend.STATIC_LOWER_MODULE_MAP,
  384. _lower_to_native_backend.DYNAMIC_LOWER_MODULE_MAP,
  385. _lower_to_native_backend.WEIGHT_ONLY_LOWER_MODULE_MAP,
  386. _lower_to_native_backend.SPECIAL_PATTERN_LOWER_MODULE_MAP,
  387. ):
  388. for source, target in source_to_target.items(): # type: ignore[attr-defined]
  389. new_connections.append((source, target))
  390. for source_to_double_target in (
  391. _lower_to_native_backend.STATIC_LOWER_FUSED_MODULE_MAP,
  392. _lower_to_native_backend.STATIC_LOWER_FUSED_MODULE_TWO_INPUTS_MAP,
  393. _lower_to_native_backend.DYNAMIC_LOWER_FUSED_MODULE_MAP,
  394. ):
  395. for source, (target1, target2) in source_to_double_target.items(): # type: ignore[attr-defined]
  396. new_connections.append((source, target1))
  397. new_connections.append((source, target2))
  398. #
  399. # Add function swaps from default lowering path
  400. #
  401. for source, ( # type:ignore[assignment]
  402. target1,
  403. target2,
  404. ) in _lower_to_native_backend.STATIC_LOWER_FUNCTIONAL_MAP.items():
  405. new_connections.append((source, target1))
  406. # pyrefly: ignore [bad-argument-type]
  407. new_connections.append((source, target2))
  408. for source_to_target in (
  409. _lower_to_native_backend.QBIN_OP_MAPPING,
  410. _lower_to_native_backend.QBIN_RELU_OP_MAPPING,
  411. quantization_mappings.DEFAULT_FLOAT_TO_QUANTIZED_OPERATOR_MAPPINGS,
  412. ):
  413. for source, target in source_to_target.items(): # type:ignore[assignment]
  414. # pyrefly: ignore [bad-argument-type]
  415. new_connections.append((source, target))
  416. #
  417. # Add other swaps, ideally in the future this could be removed
  418. # after the lowering code stops using these.
  419. #
  420. for source_to_target in (
  421. quantization_mappings.DEFAULT_DYNAMIC_QUANT_MODULE_MAPPINGS,
  422. ):
  423. for source, target in source_to_target.items(): # type:ignore[assignment]
  424. new_connections.append((source, target))
  425. # add the new connections from backend_config
  426. for item1, item2 in new_connections:
  427. for set_of_related_ops in sets_of_related_ops:
  428. if item1 in set_of_related_ops or item2 in set_of_related_ops:
  429. set_of_related_ops.add(item1)
  430. set_of_related_ops.add(item2)
  431. break
  432. base_name_to_sets_of_related_ops: dict[str, set[NSNodeTargetType]] = {}
  433. for counter, set_of_related_ops in enumerate(sets_of_related_ops):
  434. base_name = str(counter)
  435. base_name_to_sets_of_related_ops[base_name] = set_of_related_ops
  436. return base_name_to_sets_of_related_ops
  437. def get_base_name_for_op(
  438. base_name_to_sets_of_related_ops: dict[str, set[NSNodeTargetType]],
  439. op: NSNodeTargetType,
  440. ) -> str | None:
  441. for base_name, set_of_related_ops in base_name_to_sets_of_related_ops.items():
  442. if op in set_of_related_ops:
  443. return base_name
  444. return None
  445. def add_op_to_sets_of_related_ops(
  446. base_name_to_sets_of_related_ops: dict[str, set[NSNodeTargetType]],
  447. op: NSNodeTargetType,
  448. related_op: NSNodeTargetType | None,
  449. ) -> None:
  450. if related_op is not None:
  451. for set_of_related_ops in base_name_to_sets_of_related_ops.values():
  452. if related_op in set_of_related_ops:
  453. set_of_related_ops.add(op)
  454. return
  455. # if we got here, related_op was not found
  456. raise AssertionError(f"{related_op} was not found")
  457. else:
  458. counter = 0
  459. while str(counter) in base_name_to_sets_of_related_ops:
  460. counter += 1
  461. base_name_to_sets_of_related_ops[str(counter)] = {op}
  462. # TODO(future PR): clean this up
  463. def get_node_type_to_io_type_map() -> dict[str, set[NSNodeTargetType]]:
  464. FUNS_IO_TYPE_FP32: set[NSNodeTargetType] = {
  465. F.linear,
  466. F.conv1d,
  467. F.conv2d,
  468. F.conv3d,
  469. torch.cat,
  470. F.elu,
  471. F.hardswish,
  472. F.instance_norm,
  473. F.layer_norm,
  474. F.leaky_relu,
  475. F.dropout,
  476. F.silu,
  477. F.mish,
  478. operator.add,
  479. torch.add,
  480. operator.mul,
  481. torch.mul,
  482. torch.sum,
  483. F.prelu,
  484. }
  485. FUNS_IO_TYPE_FP16: set[NSNodeTargetType] = set()
  486. FUNS_IO_TYPE_INT8: set[NSNodeTargetType] = {
  487. toq.linear,
  488. toq.linear_relu,
  489. toq.conv1d,
  490. toq.conv1d_relu,
  491. toq.conv2d,
  492. toq.conv2d_relu,
  493. toq.conv3d,
  494. toq.conv3d_relu,
  495. toq.cat,
  496. toq.elu,
  497. toq.hardswish,
  498. toq.instance_norm,
  499. toq.layer_norm,
  500. toq.leaky_relu,
  501. toq.dropout,
  502. toq.prelu,
  503. # TODO(future PR): implement shadowing for binary ops and
  504. # uncomment below
  505. # toq.add,
  506. # toq.mul,
  507. }
  508. FUNS_IO_TYPE_FP32_OR_INT8: set[NSNodeTargetType] = {
  509. F.relu,
  510. F.tanh,
  511. torch.tanh,
  512. F.sigmoid,
  513. torch.sigmoid,
  514. F.hardsigmoid,
  515. operator.floordiv,
  516. torch.adaptive_avg_pool1d,
  517. F.adaptive_avg_pool2d,
  518. F.adaptive_avg_pool3d,
  519. F.dropout,
  520. F.hardtanh,
  521. F.hardtanh_,
  522. F.interpolate,
  523. F.max_pool1d,
  524. F.max_pool2d,
  525. F.max_pool3d,
  526. F.relu6,
  527. F.pixel_shuffle,
  528. F.pixel_unshuffle,
  529. torch.avg_pool1d,
  530. torch._C._nn.avg_pool2d,
  531. torch._C._nn.avg_pool3d,
  532. torch.cat,
  533. torch.chunk,
  534. torch.clamp,
  535. torch.flatten,
  536. torch.transpose,
  537. torch.max,
  538. torch.mean,
  539. torch.min,
  540. torch.narrow,
  541. torch.repeat_interleave,
  542. torch.sort,
  543. torch.squeeze,
  544. torch.stack,
  545. torch.unsqueeze,
  546. operator.add,
  547. }
  548. MODS_IO_TYPE_FP32: set[NSNodeTargetType] = {
  549. nn.Linear,
  550. nnqat.Linear,
  551. nnqatd.Linear,
  552. nnqd.Linear,
  553. torch.nn.modules.linear.NonDynamicallyQuantizableLinear,
  554. nn.Conv1d,
  555. nn.Conv2d,
  556. nn.Conv3d,
  557. nnqat.Conv1d,
  558. nnqat.Conv2d,
  559. nnqat.Conv3d,
  560. nnqat.Embedding,
  561. nnqat.EmbeddingBag,
  562. nn.LSTM,
  563. # note: nnqd.Linear is an instance of nnq.Linear, so this
  564. # check has to happen before the int8 module check
  565. nnqd.LSTM,
  566. nn.BatchNorm2d,
  567. nn.BatchNorm3d,
  568. nn.Dropout,
  569. nn.ConvTranspose1d,
  570. nn.ConvTranspose2d,
  571. nn.ConvTranspose3d,
  572. nn.ELU,
  573. nn.GroupNorm,
  574. nn.InstanceNorm1d,
  575. nn.InstanceNorm2d,
  576. nn.InstanceNorm3d,
  577. nn.LayerNorm,
  578. nn.Hardswish,
  579. nn.LeakyReLU,
  580. nn.ReLU6,
  581. nn.SiLU,
  582. nn.Mish,
  583. nn.Softmax,
  584. nn.PReLU,
  585. nni.BNReLU2d,
  586. nni.BNReLU3d,
  587. nni.ConvReLU1d,
  588. nni.ConvReLU2d,
  589. nni.ConvReLU3d,
  590. nni.LinearReLU,
  591. nni.LinearBn1d,
  592. nni.ConvBn1d,
  593. nni.ConvBn2d,
  594. nni.ConvBn3d,
  595. nniqat.ConvBn1d,
  596. nniqat.ConvBn2d,
  597. nniqat.ConvBn3d,
  598. nniqat.ConvBnReLU1d,
  599. nniqat.ConvBnReLU2d,
  600. nniqat.ConvBnReLU3d,
  601. nniqat.ConvReLU1d,
  602. nniqat.ConvReLU2d,
  603. nniqat.ConvReLU3d,
  604. nniqat.LinearReLU,
  605. nniqat.LinearBn1d,
  606. nniqd.LinearReLU,
  607. nni.LinearLeakyReLU,
  608. nni.LinearTanh,
  609. nni.ConvAdd2d,
  610. nni.ConvAddReLU2d,
  611. }
  612. MODS_IO_TYPE_INT8: set[NSNodeTargetType] = {
  613. nnq.Linear,
  614. nnq.Conv1d,
  615. nnq.Conv2d,
  616. nnq.Conv3d,
  617. nnq.BatchNorm2d,
  618. nnq.BatchNorm3d,
  619. nnq.Dropout,
  620. nnq.ConvTranspose1d,
  621. nnq.ConvTranspose2d,
  622. nnq.ELU,
  623. nnq.InstanceNorm1d,
  624. nnq.InstanceNorm2d,
  625. nnq.InstanceNorm3d,
  626. nnq.LayerNorm,
  627. nnq.Hardswish,
  628. nnq.LeakyReLU,
  629. nnq.Embedding,
  630. nnq.EmbeddingBag,
  631. nnq.Dropout,
  632. nnq.Softmax,
  633. nnq.PReLU,
  634. nniq.BNReLU2d,
  635. nniq.BNReLU3d,
  636. nniq.ConvReLU1d,
  637. nniq.ConvReLU2d,
  638. nniq.ConvReLU3d,
  639. nniq.LinearReLU,
  640. nniq.LinearLeakyReLU,
  641. nniq.LinearTanh,
  642. nniq.ConvAdd2d,
  643. nniq.ConvAddReLU2d,
  644. }
  645. MODS_IO_TYPE_FP32_OR_INT8: set[NSNodeTargetType] = {
  646. nn.ReLU,
  647. nn.Tanh,
  648. nn.Sigmoid,
  649. nn.Hardsigmoid,
  650. nn.AdaptiveAvgPool1d,
  651. nn.AdaptiveAvgPool2d,
  652. nn.AdaptiveAvgPool3d,
  653. nn.AvgPool1d,
  654. nn.AvgPool2d,
  655. nn.AvgPool3d,
  656. nn.Dropout,
  657. nn.Hardtanh,
  658. nn.Identity,
  659. nn.MaxPool1d,
  660. nn.MaxPool2d,
  661. nn.MaxPool3d,
  662. nn.PixelShuffle,
  663. nn.PixelUnshuffle,
  664. nn.ReLU6,
  665. }
  666. METHS_IO_TYPE_FP32_OR_INT8: set[NSNodeTargetType] = {
  667. "sigmoid_",
  668. "sigmoid",
  669. "tanh_",
  670. "tanh",
  671. "hardsigmoid_",
  672. "hardsigmoid",
  673. "relu_",
  674. "relu",
  675. }
  676. return {
  677. "funs_io_type_fp32": FUNS_IO_TYPE_FP32,
  678. "funs_io_type_fp16": FUNS_IO_TYPE_FP16,
  679. "funs_io_type_int8": FUNS_IO_TYPE_INT8,
  680. "funs_io_type_fp32_or_int8": FUNS_IO_TYPE_FP32_OR_INT8,
  681. "mods_io_type_fp32": MODS_IO_TYPE_FP32,
  682. "mods_io_type_int8": MODS_IO_TYPE_INT8,
  683. "mods_io_type_fp32_or_int8": MODS_IO_TYPE_FP32_OR_INT8,
  684. "meths_io_type_fp32_or_int8": METHS_IO_TYPE_FP32_OR_INT8,
  685. }
  686. def get_unmatchable_types_map() -> dict[str, set[NSNodeTargetType]]:
  687. FUNS_UNMATCHABLE: set[NSNodeTargetType] = {
  688. torch.quantize_per_tensor,
  689. operator.getitem,
  690. }
  691. MODS_UNMATCHABLE: set[NSNodeTargetType] = {
  692. nn.Identity,
  693. }
  694. METHS_UNMATCHABLE: set[NSNodeTargetType] = {
  695. "to",
  696. "dequantize",
  697. "reshape",
  698. "view",
  699. "unsqueeze_",
  700. "unsqueeze",
  701. "transpose",
  702. "squeeze_",
  703. "squeeze",
  704. "size",
  705. "shape",
  706. "resize_",
  707. "repeat_interleave",
  708. "repeat",
  709. "permute",
  710. "numel",
  711. "mean",
  712. "detach_",
  713. "detach",
  714. "contiguous",
  715. "clamp",
  716. "chunk",
  717. }
  718. return {
  719. "funs_unmatchable": FUNS_UNMATCHABLE,
  720. "mods_unmatchable": MODS_UNMATCHABLE,
  721. "meths_unmatchable": METHS_UNMATCHABLE,
  722. }