Unverified Commit 7479dbb8 authored by Srihari Humbarwadi's avatar Srihari Humbarwadi Committed by GitHub
Browse files

Merge branch 'tensorflow:master' into panoptic-deeplab-modeling

parents 8b60a5a8 9c8cbd0c
...@@ -49,7 +49,7 @@ REVNET_SPECS = { ...@@ -49,7 +49,7 @@ REVNET_SPECS = {
} }
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class RevNet(tf.keras.Model): class RevNet(tf.keras.Model):
"""Creates a Reversible ResNet (RevNet) family model. """Creates a Reversible ResNet (RevNet) family model.
......
...@@ -124,7 +124,7 @@ def build_block_specs( ...@@ -124,7 +124,7 @@ def build_block_specs(
return [BlockSpec(*b) for b in block_specs] return [BlockSpec(*b) for b in block_specs]
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class SpineNet(tf.keras.Model): class SpineNet(tf.keras.Model):
"""Creates a SpineNet family model. """Creates a SpineNet family model.
......
...@@ -117,7 +117,7 @@ def build_block_specs( ...@@ -117,7 +117,7 @@ def build_block_specs(
return [BlockSpec(*b) for b in block_specs] return [BlockSpec(*b) for b in block_specs]
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class SpineNetMobile(tf.keras.Model): class SpineNetMobile(tf.keras.Model):
"""Creates a Mobile SpineNet family model. """Creates a Mobile SpineNet family model.
......
...@@ -21,7 +21,7 @@ import tensorflow as tf ...@@ -21,7 +21,7 @@ import tensorflow as tf
layers = tf.keras.layers layers = tf.keras.layers
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class ClassificationModel(tf.keras.Model): class ClassificationModel(tf.keras.Model):
"""A classification class builder.""" """A classification class builder."""
......
...@@ -27,7 +27,7 @@ from official.vision.beta.modeling.layers import nn_layers ...@@ -27,7 +27,7 @@ from official.vision.beta.modeling.layers import nn_layers
TensorMapUnion = Union[tf.Tensor, Mapping[str, tf.Tensor]] TensorMapUnion = Union[tf.Tensor, Mapping[str, tf.Tensor]]
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class ASPP(tf.keras.layers.Layer): class ASPP(tf.keras.layers.Layer):
"""Creates an Atrous Spatial Pyramid Pooling (ASPP) layer.""" """Creates an Atrous Spatial Pyramid Pooling (ASPP) layer."""
......
...@@ -25,7 +25,7 @@ from official.vision.beta.modeling.decoders import factory ...@@ -25,7 +25,7 @@ from official.vision.beta.modeling.decoders import factory
from official.vision.beta.ops import spatial_transform_ops from official.vision.beta.ops import spatial_transform_ops
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class FPN(tf.keras.Model): class FPN(tf.keras.Model):
"""Creates a Feature Pyramid Network (FPN). """Creates a Feature Pyramid Network (FPN).
......
...@@ -61,7 +61,7 @@ def build_block_specs( ...@@ -61,7 +61,7 @@ def build_block_specs(
return [BlockSpec(*b) for b in block_specs] return [BlockSpec(*b) for b in block_specs]
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class NASFPN(tf.keras.Model): class NASFPN(tf.keras.Model):
"""Creates a NAS-FPN model. """Creates a NAS-FPN model.
......
...@@ -24,7 +24,7 @@ import tensorflow as tf ...@@ -24,7 +24,7 @@ import tensorflow as tf
from official.modeling import tf_utils from official.modeling import tf_utils
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class RetinaNetHead(tf.keras.layers.Layer): class RetinaNetHead(tf.keras.layers.Layer):
"""Creates a RetinaNet head.""" """Creates a RetinaNet head."""
...@@ -336,7 +336,7 @@ class RetinaNetHead(tf.keras.layers.Layer): ...@@ -336,7 +336,7 @@ class RetinaNetHead(tf.keras.layers.Layer):
return cls(**config) return cls(**config)
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class RPNHead(tf.keras.layers.Layer): class RPNHead(tf.keras.layers.Layer):
"""Creates a Region Proposal Network (RPN) head.""" """Creates a Region Proposal Network (RPN) head."""
......
...@@ -21,7 +21,7 @@ import tensorflow as tf ...@@ -21,7 +21,7 @@ import tensorflow as tf
from official.modeling import tf_utils from official.modeling import tf_utils
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class DetectionHead(tf.keras.layers.Layer): class DetectionHead(tf.keras.layers.Layer):
"""Creates a detection head.""" """Creates a detection head."""
...@@ -216,7 +216,7 @@ class DetectionHead(tf.keras.layers.Layer): ...@@ -216,7 +216,7 @@ class DetectionHead(tf.keras.layers.Layer):
return cls(**config) return cls(**config)
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class MaskHead(tf.keras.layers.Layer): class MaskHead(tf.keras.layers.Layer):
"""Creates a mask head.""" """Creates a mask head."""
......
...@@ -191,7 +191,7 @@ class MaskScoring(tf.keras.Model): ...@@ -191,7 +191,7 @@ class MaskScoring(tf.keras.Model):
return cls(**config) return cls(**config)
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class SegmentationHead(tf.keras.layers.Layer): class SegmentationHead(tf.keras.layers.Layer):
"""Creates a segmentation head.""" """Creates a segmentation head."""
......
...@@ -20,7 +20,7 @@ import tensorflow as tf ...@@ -20,7 +20,7 @@ import tensorflow as tf
from official.vision.beta.ops import sampling_ops from official.vision.beta.ops import sampling_ops
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class BoxSampler(tf.keras.layers.Layer): class BoxSampler(tf.keras.layers.Layer):
"""Creates a BoxSampler to sample positive and negative boxes.""" """Creates a BoxSampler to sample positive and negative boxes."""
......
...@@ -423,7 +423,7 @@ def _generate_detections_batched(boxes: tf.Tensor, scores: tf.Tensor, ...@@ -423,7 +423,7 @@ def _generate_detections_batched(boxes: tf.Tensor, scores: tf.Tensor,
return nmsed_boxes, nmsed_scores, nmsed_classes, valid_detections return nmsed_boxes, nmsed_scores, nmsed_classes, valid_detections
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class DetectionGenerator(tf.keras.layers.Layer): class DetectionGenerator(tf.keras.layers.Layer):
"""Generates the final detected boxes with scores and classes.""" """Generates the final detected boxes with scores and classes."""
...@@ -606,7 +606,7 @@ class DetectionGenerator(tf.keras.layers.Layer): ...@@ -606,7 +606,7 @@ class DetectionGenerator(tf.keras.layers.Layer):
return cls(**config) return cls(**config)
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class MultilevelDetectionGenerator(tf.keras.layers.Layer): class MultilevelDetectionGenerator(tf.keras.layers.Layer):
"""Generates detected boxes with scores and classes for one-stage detector.""" """Generates detected boxes with scores and classes for one-stage detector."""
......
...@@ -100,7 +100,7 @@ def _sample_and_crop_foreground_masks(candidate_rois: tf.Tensor, ...@@ -100,7 +100,7 @@ def _sample_and_crop_foreground_masks(candidate_rois: tf.Tensor,
return foreground_rois, foreground_classes, cropped_foreground_masks return foreground_rois, foreground_classes, cropped_foreground_masks
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class MaskSampler(tf.keras.layers.Layer): class MaskSampler(tf.keras.layers.Layer):
"""Samples and creates mask training targets.""" """Samples and creates mask training targets."""
......
...@@ -52,7 +52,7 @@ def _maybe_downsample(x: tf.Tensor, out_filter: int, strides: int, ...@@ -52,7 +52,7 @@ def _maybe_downsample(x: tf.Tensor, out_filter: int, strides: int,
return x + 0. return x + 0.
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class ResidualBlock(tf.keras.layers.Layer): class ResidualBlock(tf.keras.layers.Layer):
"""A residual block.""" """A residual block."""
...@@ -250,7 +250,7 @@ class ResidualBlock(tf.keras.layers.Layer): ...@@ -250,7 +250,7 @@ class ResidualBlock(tf.keras.layers.Layer):
return self._activation_fn(x + shortcut) return self._activation_fn(x + shortcut)
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class BottleneckBlock(tf.keras.layers.Layer): class BottleneckBlock(tf.keras.layers.Layer):
"""A standard bottleneck block.""" """A standard bottleneck block."""
...@@ -479,7 +479,7 @@ class BottleneckBlock(tf.keras.layers.Layer): ...@@ -479,7 +479,7 @@ class BottleneckBlock(tf.keras.layers.Layer):
return self._activation3(x) return self._activation3(x)
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class InvertedBottleneckBlock(tf.keras.layers.Layer): class InvertedBottleneckBlock(tf.keras.layers.Layer):
"""An inverted bottleneck block.""" """An inverted bottleneck block."""
...@@ -754,7 +754,7 @@ class InvertedBottleneckBlock(tf.keras.layers.Layer): ...@@ -754,7 +754,7 @@ class InvertedBottleneckBlock(tf.keras.layers.Layer):
return x return x
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class ResidualInner(tf.keras.layers.Layer): class ResidualInner(tf.keras.layers.Layer):
"""Creates a single inner block of a residual. """Creates a single inner block of a residual.
...@@ -878,7 +878,7 @@ class ResidualInner(tf.keras.layers.Layer): ...@@ -878,7 +878,7 @@ class ResidualInner(tf.keras.layers.Layer):
return x return x
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class BottleneckResidualInner(tf.keras.layers.Layer): class BottleneckResidualInner(tf.keras.layers.Layer):
"""Creates a single inner block of a bottleneck. """Creates a single inner block of a bottleneck.
...@@ -1018,7 +1018,7 @@ class BottleneckResidualInner(tf.keras.layers.Layer): ...@@ -1018,7 +1018,7 @@ class BottleneckResidualInner(tf.keras.layers.Layer):
return x return x
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class ReversibleLayer(tf.keras.layers.Layer): class ReversibleLayer(tf.keras.layers.Layer):
"""Creates a reversible layer. """Creates a reversible layer.
...@@ -1194,7 +1194,7 @@ class ReversibleLayer(tf.keras.layers.Layer): ...@@ -1194,7 +1194,7 @@ class ReversibleLayer(tf.keras.layers.Layer):
return activations return activations
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class DepthwiseSeparableConvBlock(tf.keras.layers.Layer): class DepthwiseSeparableConvBlock(tf.keras.layers.Layer):
"""Creates an depthwise separable convolution block with batch normalization.""" """Creates an depthwise separable convolution block with batch normalization."""
...@@ -1319,7 +1319,7 @@ class DepthwiseSeparableConvBlock(tf.keras.layers.Layer): ...@@ -1319,7 +1319,7 @@ class DepthwiseSeparableConvBlock(tf.keras.layers.Layer):
return self._activation_fn(x) return self._activation_fn(x)
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class TuckerConvBlock(tf.keras.layers.Layer): class TuckerConvBlock(tf.keras.layers.Layer):
"""An Tucker block (generalized bottleneck).""" """An Tucker block (generalized bottleneck)."""
......
...@@ -20,7 +20,7 @@ from official.modeling import tf_utils ...@@ -20,7 +20,7 @@ from official.modeling import tf_utils
from official.vision.beta.modeling.layers import nn_layers from official.vision.beta.modeling.layers import nn_layers
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class SelfGating(tf.keras.layers.Layer): class SelfGating(tf.keras.layers.Layer):
"""Feature gating as used in S3D-G. """Feature gating as used in S3D-G.
...@@ -67,7 +67,7 @@ class SelfGating(tf.keras.layers.Layer): ...@@ -67,7 +67,7 @@ class SelfGating(tf.keras.layers.Layer):
return tf.math.multiply(x, inputs) return tf.math.multiply(x, inputs)
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class BottleneckBlock3D(tf.keras.layers.Layer): class BottleneckBlock3D(tf.keras.layers.Layer):
"""Creates a 3D bottleneck block.""" """Creates a 3D bottleneck block."""
......
...@@ -85,7 +85,7 @@ def get_padding_for_kernel_size(kernel_size): ...@@ -85,7 +85,7 @@ def get_padding_for_kernel_size(kernel_size):
kernel_size)) kernel_size))
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class SqueezeExcitation(tf.keras.layers.Layer): class SqueezeExcitation(tf.keras.layers.Layer):
"""Creates a squeeze and excitation layer.""" """Creates a squeeze and excitation layer."""
...@@ -223,7 +223,7 @@ def get_stochastic_depth_rate(init_rate, i, n): ...@@ -223,7 +223,7 @@ def get_stochastic_depth_rate(init_rate, i, n):
return rate return rate
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class StochasticDepth(tf.keras.layers.Layer): class StochasticDepth(tf.keras.layers.Layer):
"""Creates a stochastic depth layer.""" """Creates a stochastic depth layer."""
...@@ -261,7 +261,7 @@ class StochasticDepth(tf.keras.layers.Layer): ...@@ -261,7 +261,7 @@ class StochasticDepth(tf.keras.layers.Layer):
return output return output
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
def pyramid_feature_fusion(inputs, target_level): def pyramid_feature_fusion(inputs, target_level):
"""Fuses all feature maps in the feature pyramid at the target level. """Fuses all feature maps in the feature pyramid at the target level.
...@@ -403,7 +403,7 @@ class PanopticFPNFusion(tf.keras.Model): ...@@ -403,7 +403,7 @@ class PanopticFPNFusion(tf.keras.Model):
return self._output_specs return self._output_specs
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class Scale(tf.keras.layers.Layer): class Scale(tf.keras.layers.Layer):
"""Scales the input by a trainable scalar weight. """Scales the input by a trainable scalar weight.
...@@ -456,7 +456,7 @@ class Scale(tf.keras.layers.Layer): ...@@ -456,7 +456,7 @@ class Scale(tf.keras.layers.Layer):
return scale * inputs return scale * inputs
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class TemporalSoftmaxPool(tf.keras.layers.Layer): class TemporalSoftmaxPool(tf.keras.layers.Layer):
"""Creates a network layer corresponding to temporal softmax pooling. """Creates a network layer corresponding to temporal softmax pooling.
...@@ -479,7 +479,7 @@ class TemporalSoftmaxPool(tf.keras.layers.Layer): ...@@ -479,7 +479,7 @@ class TemporalSoftmaxPool(tf.keras.layers.Layer):
return outputs return outputs
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class PositionalEncoding(tf.keras.layers.Layer): class PositionalEncoding(tf.keras.layers.Layer):
"""Creates a network layer that adds a sinusoidal positional encoding. """Creates a network layer that adds a sinusoidal positional encoding.
...@@ -647,7 +647,7 @@ class PositionalEncoding(tf.keras.layers.Layer): ...@@ -647,7 +647,7 @@ class PositionalEncoding(tf.keras.layers.Layer):
return (outputs, states) if output_states else outputs return (outputs, states) if output_states else outputs
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class GlobalAveragePool3D(tf.keras.layers.Layer): class GlobalAveragePool3D(tf.keras.layers.Layer):
"""Creates a global average pooling layer with causal mode. """Creates a global average pooling layer with causal mode.
...@@ -781,7 +781,7 @@ class GlobalAveragePool3D(tf.keras.layers.Layer): ...@@ -781,7 +781,7 @@ class GlobalAveragePool3D(tf.keras.layers.Layer):
return (x, states) if output_states else x return (x, states) if output_states else x
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class SpatialAveragePool3D(tf.keras.layers.Layer): class SpatialAveragePool3D(tf.keras.layers.Layer):
"""Creates a global average pooling layer pooling across spatial dimentions.""" """Creates a global average pooling layer pooling across spatial dimentions."""
...@@ -901,7 +901,7 @@ class CausalConvMixin: ...@@ -901,7 +901,7 @@ class CausalConvMixin:
return spatial_output_shape return spatial_output_shape
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class Conv2D(tf.keras.layers.Conv2D, CausalConvMixin): class Conv2D(tf.keras.layers.Conv2D, CausalConvMixin):
"""Conv2D layer supporting CausalConv. """Conv2D layer supporting CausalConv.
...@@ -949,7 +949,7 @@ class Conv2D(tf.keras.layers.Conv2D, CausalConvMixin): ...@@ -949,7 +949,7 @@ class Conv2D(tf.keras.layers.Conv2D, CausalConvMixin):
return self._buffered_spatial_output_shape(shape) return self._buffered_spatial_output_shape(shape)
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class DepthwiseConv2D(tf.keras.layers.DepthwiseConv2D, CausalConvMixin): class DepthwiseConv2D(tf.keras.layers.DepthwiseConv2D, CausalConvMixin):
"""DepthwiseConv2D layer supporting CausalConv. """DepthwiseConv2D layer supporting CausalConv.
...@@ -1011,7 +1011,7 @@ class DepthwiseConv2D(tf.keras.layers.DepthwiseConv2D, CausalConvMixin): ...@@ -1011,7 +1011,7 @@ class DepthwiseConv2D(tf.keras.layers.DepthwiseConv2D, CausalConvMixin):
return self._buffered_spatial_output_shape(shape) return self._buffered_spatial_output_shape(shape)
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class Conv3D(tf.keras.layers.Conv3D, CausalConvMixin): class Conv3D(tf.keras.layers.Conv3D, CausalConvMixin):
"""Conv3D layer supporting CausalConv. """Conv3D layer supporting CausalConv.
...@@ -1067,7 +1067,7 @@ class Conv3D(tf.keras.layers.Conv3D, CausalConvMixin): ...@@ -1067,7 +1067,7 @@ class Conv3D(tf.keras.layers.Conv3D, CausalConvMixin):
return self._buffered_spatial_output_shape(shape) return self._buffered_spatial_output_shape(shape)
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class SpatialPyramidPooling(tf.keras.layers.Layer): class SpatialPyramidPooling(tf.keras.layers.Layer):
"""Implements the Atrous Spatial Pyramid Pooling. """Implements the Atrous Spatial Pyramid Pooling.
......
...@@ -20,7 +20,7 @@ import tensorflow as tf ...@@ -20,7 +20,7 @@ import tensorflow as tf
from official.vision.beta.ops import spatial_transform_ops from official.vision.beta.ops import spatial_transform_ops
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class MultilevelROIAligner(tf.keras.layers.Layer): class MultilevelROIAligner(tf.keras.layers.Layer):
"""Performs ROIAlign for the second stage processing.""" """Performs ROIAlign for the second stage processing."""
......
...@@ -176,7 +176,7 @@ def _multilevel_propose_rois(raw_boxes: Mapping[str, tf.Tensor], ...@@ -176,7 +176,7 @@ def _multilevel_propose_rois(raw_boxes: Mapping[str, tf.Tensor],
return selected_rois, selected_roi_scores return selected_rois, selected_roi_scores
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class MultilevelROIGenerator(tf.keras.layers.Layer): class MultilevelROIGenerator(tf.keras.layers.Layer):
"""Proposes RoIs for the second stage processing.""" """Proposes RoIs for the second stage processing."""
......
...@@ -23,7 +23,7 @@ from official.vision.beta.ops import iou_similarity ...@@ -23,7 +23,7 @@ from official.vision.beta.ops import iou_similarity
from official.vision.beta.ops import target_gather from official.vision.beta.ops import target_gather
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class ROISampler(tf.keras.layers.Layer): class ROISampler(tf.keras.layers.Layer):
"""Samples ROIs and assigns targets to the sampled ROIs.""" """Samples ROIs and assigns targets to the sampled ROIs."""
......
...@@ -22,7 +22,7 @@ from official.vision.beta.ops import anchor ...@@ -22,7 +22,7 @@ from official.vision.beta.ops import anchor
from official.vision.beta.ops import box_ops from official.vision.beta.ops import box_ops
@tf.keras.utils.register_keras_serializable(package='Vision') @tf.keras.utils.register_keras_serializable(package='Beta')
class MaskRCNNModel(tf.keras.Model): class MaskRCNNModel(tf.keras.Model):
"""The Mask R-CNN(-RS) and Cascade RCNN-RS models.""" """The Mask R-CNN(-RS) and Cascade RCNN-RS models."""
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment