Skip to content

Commit

Permalink
ResNet-152
Browse files Browse the repository at this point in the history
  • Loading branch information
ChanLumerico committed Aug 15, 2024
1 parent c128440 commit 347936f
Show file tree
Hide file tree
Showing 3 changed files with 238 additions and 1 deletion.
3 changes: 2 additions & 1 deletion luma/__import__.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
ResNet_34,
ResNet_50,
ResNet_101,
ResNet_152,
)
from luma.neural.autoprop import LayerNode, LayerGraph

Expand Down Expand Up @@ -338,7 +339,7 @@
VGGNet_11, VGGNet_13, VGGNet_16, VGGNet_19,
Inception_V1, Inception_V2, Inception_V3, Inception_V4,
InceptionResNet_V1, InceptionResNet_V2,
ResNet_18, ResNet_34, ResNet_50, ResNet_101
ResNet_18, ResNet_34, ResNet_50, ResNet_101, ResNet_152

# ------------------- [ luma.metric ] ----------------------
Accuracy, Precision, Recall, F1Score, Specificity
Expand Down
133 changes: 133 additions & 0 deletions luma/neural/_models/resnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,3 +596,136 @@ def score(
argmax: bool = True,
) -> float:
return super(_ResNet_101, self).score_nn(X, y, metric, argmax)


class _ResNet_152(Estimator, Supervised, NeuralModel):
def __init__(
self,
activation: Activation.FuncType = Activation.ReLU,
initializer: InitUtil.InitStr = None,
out_features: int = 1000,
batch_size: int = 128,
n_epochs: int = 100,
valid_size: float = 0.1,
lambda_: float = 0.0,
momentum: float = 0.9,
early_stopping: bool = False,
patience: int = 10,
shuffle: bool = True,
random_state: int | None = None,
deep_verbose: bool = False,
) -> None:
self.activation = activation
self.initializer = initializer
self.out_features = out_features
self.lambda_ = lambda_
self.momentum = momentum
self.shuffle = shuffle
self.random_state = random_state
self._fitted = False

super().__init__(
batch_size,
n_epochs,
valid_size,
early_stopping,
patience,
shuffle,
random_state,
deep_verbose,
)
super().init_model()
self.model = Sequential()

self.feature_sizes_ = [
[3, 64],
[64, 64, 256] * 3,
[128, 128, 512] * 8,
[256, 256, 1024] * 36,
[512, 512, 2048] * 3,
]
self.feature_shapes_ = [
self._get_feature_shapes(sizes) for sizes in self.feature_sizes_
]

self.set_param_ranges(
{
"out_features": ("0<,+inf", int),
"batch_size": ("0<,+inf", int),
"n_epochs": ("0<,+inf", int),
"valid_size": ("0<,<1", None),
"momentum": ("0,1", None),
"dropout_rate": ("0,1", None),
"lambda_": ("0,+inf", None),
"patience": ("0<,+inf", int),
}
)
self.check_param_ranges()
self.build_model()

def build_model(self) -> None:
base_args = {
"initializer": self.initializer,
"lambda_": self.lambda_,
"random_state": self.random_state,
}
res_args = BaseBlockArgs(
activation=self.activation,
do_batch_norm=True,
momentum=self.momentum,
**base_args,
)

self.model.extend(
Convolution2D(3, 64, 7, 2, 3, **base_args),
BatchNorm2D(64, self.momentum),
self.activation(),
Pooling2D(3, 2, "max", "same"),
)
self.layer_2, in_channels = _make_layer(
64, 64, Bottleneck, 3, 2, base_args, res_args
)
self.layer_3, in_channels = _make_layer(
in_channels, 128, Bottleneck, 8, 3, base_args, res_args, stride=2
)
self.layer_4, in_channels = _make_layer(
in_channels, 256, Bottleneck, 36, 4, base_args, res_args, stride=2
)
self.layer_5, in_channels = _make_layer(
in_channels, 512, Bottleneck, 3, 5, base_args, res_args, stride=2
)

self.model.extend(
self.layer_2,
self.layer_3,
self.layer_4,
self.layer_5,
deep_add=True,
)
self.model.extend(
AdaptiveAvgPooling2D((1, 1)),
Flatten(),
Dense(512 * Bottleneck.expansion, self.out_features, **base_args),
)

input_shape: tuple = (-1, 3, 224, 224)

@Tensor.force_shape(input_shape)
def fit(self, X: Tensor, y: Matrix) -> Self:
return super(_ResNet_152, self).fit_nn(X, y)

@override
@Tensor.force_shape(input_shape)
def predict(self, X: Tensor, argmax: bool = True) -> Matrix | Vector:
return super(_ResNet_152, self).predict_nn(X, argmax)

@override
@Tensor.force_shape(input_shape)
def score(
self,
X: Tensor,
y: Matrix,
metric: Evaluator = Accuracy,
argmax: bool = True,
) -> float:
return super(_ResNet_152, self).score_nn(X, y, metric, argmax)
103 changes: 103 additions & 0 deletions luma/neural/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@
"ResNet_34",
"ResNet_50",
"ResNet_101",
"ResNet_152",
)


NUM_MODELS: int = len(__all__)


class SimpleMLP(_models.simple._SimpleMLP):
"""
An MLP (Multilayer Perceptron) is a type of artificial neural network
Expand Down Expand Up @@ -2256,3 +2260,102 @@ def __init__(
random_state,
deep_verbose,
)


class ResNet_152(_models.resnet._ResNet_152):
"""
ResNet-152 is a 152-layer deep neural network that uses residual blocks
to improve training by learning residuals, helping prevent vanishing
gradients and enabling better performance in image recognition tasks.
Structure
---------
Input:
```py
Tensor[..., 3, 224, 224]
```
Residual Blocks:
```py
Convolution2D(3, 64, filter_size=7, stride=2) -> # conv1
3x ResNetBlock.Bottleneck(64, 64) -> # conv2
8x ResNetBlock.Bottleneck(128, 128, stride=2) -> # conv3
36x ResNetBlock.Bottleneck(256, 256, stride=2) -> # conv4
3x ResNetBlock.Bottleneck(512, 512, stride=2) -> # conv5
AdaptiveAvgPooling2D((1, 1)) -> # avg pool
```
Fully Connected Layers:
```py
Flatten -> Dense(512 * 4, 1000)
```
Output:
```py
Matrix[..., 1000]
```
Parameter Size:
```txt
44,548,160 weights, 53,672 biases -> 44,601,832 params
```
Parameters
----------
`activation` : FuncType, default=Activation.ReLU
Type of activation function
`initializer` : InitStr, default=None
Type of weight initializer
`out_features` : int, default=1000
Number of output features
`batch_size` : int, default=100
Size of a single mini-batch
`n_epochs` : int, default=100
Number of epochs for training
`valid_size` : float, default=0.1
Fractional size of validation set
`lambda_` : float, default=0.0
L2 regularization strength
`early_stopping` : bool, default=False
Whether to early-stop the training when the valid score stagnates
`patience` : int, default=10
Number of epochs to wait until early-stopping
`shuffle` : bool, default=True
Whethter to shuffle the data at the beginning of every epoch
References
----------
1. He, Kaiming, et al. “Deep Residual Learning for Image Recognition.”
Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition
(CVPR), 2016, pp. 770-778.
"""

def __init__(
self,
activation: Activation.FuncType = Activation.ReLU,
initializer: InitUtil.InitStr = None,
out_features: int = 1000,
batch_size: int = 128,
n_epochs: int = 100,
valid_size: float = 0.1,
lambda_: float = 0,
momentum: float = 0.9,
early_stopping: bool = False,
patience: int = 10,
shuffle: bool = True,
random_state: int | None = None,
deep_verbose: bool = False,
) -> None:
super(ResNet_152, self).__init__(
activation,
initializer,
out_features,
batch_size,
n_epochs,
valid_size,
lambda_,
momentum,
early_stopping,
patience,
shuffle,
random_state,
deep_verbose,
)

0 comments on commit 347936f

Please sign in to comment.