Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update MobileNet Model #85

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to add this file---we could add it to the .gitignore perhaps?

"files.associations": {
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"csetjmp": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"any": "cpp",
"array": "cpp",
"atomic": "cpp",
"strstream": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"coroutine": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"source_location": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"semaphore": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cfenv": "cpp",
"cinttypes": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp"
}
}
142 changes: 142 additions & 0 deletions models/mobilenet/mobilenet.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/**
* @file mobilenet.hpp
* @author Aakash Kaushik
*
* Definition of MobileNet model.
*
* For more information, kindly refer to the following paper.
*
* @code
* @article{Andrew G2017,
* author = {Andrew G. Howard, Menglong Zhu, Bo Chen, Dmitry Kalenichenko,
* Weijun Wang, Tobias Weyand, Marco Andreetto, Hartwig Adam},
* title = {MobileNets: Efficient Convolutional Neural Networks for Mobile
* Vision Applications},
* year = {2017},
* url = {https://arxiv.org/pdf/1704.04861}
* }
* @endcode
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MODELS_MODELS_MOBILENET_MOBILENET_HPP
#define MODELS_MODELS_MOBILENET_MOBILENET_HPP

#define MLPACK_ENABLE_ANN_SERIALIZATION
#include <mlpack.hpp>

#include "separable_convolution.hpp"

#include "./../../utils/utils.hpp"

namespace mlpack {
namespace models {

/**
* Definition of a MobileNet CNN.
*
* @tparam OutputLayerType The output layer type used to evaluate the network.
* @tparam InitializationRuleType Rule used to initialize the weight matrix.
*/
template<
typename MatType = arma::mat
>
class MobileNetType : public MultiLayer<MatType>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a general question about the design. I think it might be cleaner to simply have MobileNetType internally store an FFN that you add the layers to in the constructor. I think several of the other models are built in this way. Is there any particular advantage of this approach that I overlooked? It seems like if you did just hold an FFN internally, you could use default copy/move constructors and operators and reduce the amount of code that you need.

{
public:
//! Create the MobileNet model.
//MobileNetType();

/**
* MobileNetType constructor initializes input shape and number of classes.
*
* @param numClasses Number of classes to classify images into,
* only to be specified if includeTop is true.
* @param includeTop Must be set to true if classifier layers are set.
* * @param alpha Controls the number of output channels in pointwise
* convolution: outSize * depthMultiplier.
* @param depthMultiplier Controls the number of output channels in depthwise
* convolution: inSize * depthMultiplier.
*/
MobileNetType(const size_t numClasses = 1000,
const bool includeTop = true,
const float alpha = 1.0,
const size_t depthMultiplier = 1.0);

//! Copy the given MobileNetType.
MobileNetType(const MobileNetType& other);
//! Take ownership of the layers of the given MobileNetType.
MobileNetType(MobileNetType&& other);
//! Copy the given MobileNetType.
MobileNetType& operator=(const MobileNetType& other);
//! Take ownership of the given MobileNetType.
MobileNetType& operator=(MobileNetType&& other);

//! Virtual destructor: delete all held layers.
virtual ~MobileNetType()
{ /* Nothing to do here. */ }

//! Create a copy of the MobileNetType (this is safe for polymorphic use).
MobileNetType* Clone() const { return new MobileNetType(*this); }

/**
* Get the FFN object representing the network.
*
* @tparam OutputLayerType The output layer type used to evaluate the network.
* @tparam InitializationRuleType Rule used to initialize the weight matrix.
*/
template<
typename OutputLayerType = CrossEntropyError,
typename InitializationRuleType = RandomInitialization
>
FFN<OutputLayerType, InitializationRuleType, MatType>* GetModel()
{
FFN<OutputLayerType, InitializationRuleType, MatType>* mobileNet =
new FFN<OutputLayerType, InitializationRuleType, MatType>();
mobileNet->Add(this);
return mobileNet;
}

//! Serialize the MobileNetType.
template<typename Archive>
void serialize(Archive& ar, const uint32_t /* version */);

private:
//! Generate the layers of the MobileNet.
void MakeModel();

//! Locally stored number of output classes.
size_t numClasses;

//! Locally stored if classifier layers are included or not.
bool includeTop;

//! Locally stored alpha for mobileNet block creation.
float alpha;

//! Locally stored Depth multiplier for mobileNet block creation.
float depthMultiplier;

//! Locally stored map to construct mobileNetV1 blocks.
std::map<size_t, size_t> mobileNetConfig = {
{128, 2},
{256, 2},
{512, 6},
{1024, 2},
};
}; // MobileNetType class

// convenience typedef.
typedef MobileNetType<arma::mat> Mobilenet;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
typedef MobileNetType<arma::mat> Mobilenet;
typedef MobileNetType<arma::mat> MobileNet;


} // namespace models
} // namespace mlpack

CEREAL_REGISTER_TYPE(mlpack::models::MobileNetType<arma::mat>);

#include "mobilenet_impl.hpp"

#endif
153 changes: 153 additions & 0 deletions models/mobilenet/mobilenet_impl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/**
* @file mobilenet_impl.hpp
* @author Aakash Kaushik
*
* Implementation of MobileNet using mlpack.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MODELS_MODELS_MOBILENET_MOBILENET_IMPL_HPP
#define MODELS_MODELS_MOBILENET_MOBILENET_IMPL_HPP

#include "mobilenet.hpp"

namespace mlpack {
namespace models {

template<typename MatType>
MobileNetType<MatType>::MobileNetType(
const size_t numClasses,
const bool includeTop,
const float alpha,
const size_t depthMultiplier) :
MultiLayer<MatType>(),
numClasses(numClasses),
includeTop(includeTop),
alpha(alpha),
depthMultiplier(depthMultiplier)
{
MakeModel();
}

template<typename MatType>
MobileNetType<MatType>::MobileNetType(
const MobileNetType& other) :
MultiLayer<MatType>(other),
numClasses(other.numClasses),
includeTop(other.includeTop),
alpha(other.alpha),
depthMultiplier(other.depthMultiplier)
{
// Nothing to do here.
}

template<typename MatType>
MobileNetType<MatType>::MobileNetType(
MobileNetType&& other) :
MultiLayer<MatType>(std::move(other)),
numClasses(std::move(other.numClasses)),
includeTop(std::move(other.includeTop)),
alpha(std::move(other.alpha)),
depthMultiplier(std::move(other.depthMultiplier))
{
// Nothing to do here.
}

template<typename MatType>
MobileNetType<MatType>&
MobileNetType<MatType>::operator=(
const MobileNetType& other)
{
if (this != &other)
{
MultiLayer<MatType>::operator=(other);
numClasses = other.numClasses;
includeTop = other.includeTop;
alpha = other.alpha;
depthMultiplier = other.depthMultiplier;
}

return *this;
}

template<typename MatType>
MobileNetType<MatType>&
MobileNetType<MatType>::operator=(
MobileNetType&& other)
{
if (this != &other)
{
MultiLayer<MatType>::operator=(std::move(other));
numClasses = std::move(other.numClasses);
includeTop = std::move(other.includeTop);
alpha = std::move(other.alpha);
depthMultiplier = std::move(other.depthMultiplier);
}

return *this;
}

template<typename MatType>
template<typename Archive>
void MobileNetType<MatType>::serialize(
Archive& ar, const uint32_t /* version */)
{
ar(cereal::base_class<MultiLayer<MatType>>(this));

ar(CEREAL_NVP(numClasses));
ar(CEREAL_NVP(includeTop));
ar(CEREAL_NVP(alpha));
ar(CEREAL_NVP(depthMultiplier));
}

template<typename MatType>
void MobileNetType<MatType>::MakeModel()
{
this->template Add<Convolution>(32, 3, 3, 2, 2, 0, 0);
this->template Add<BatchNorm>();

size_t outSize = size_t(32 * alpha);

this->template Add<SeparableConvolution>(outSize, outSize*depthMultiplier,
alpha, depthMultiplier);

outSize = size_t(64 * alpha);

for (const auto& blockConfig : mobileNetConfig){
this->template Add<Padding>(0, 1, 0, 1);
this->template Add<SeparableConvolution>(outSize, outSize*depthMultiplier,
3, 3, 2, 2, 0, 0, 1, 1, 1, "valid");
this->template Add<BatchNorm>();
this->template Add<ReLU6>();

outSize = size_t(blockConfig.first * alpha);

for (size_t numBlock = 1; numBlock < blockConfig.second; ++numBlock)
{
this->template Add<SeparableConvolution>(outSize, outSize*depthMultiplier,
3, 3, 1, 1, 0, 0, 0, 0, 1, "same");
this->template Add<BatchNorm>();
this->template Add<ReLU6>();

outSize = size_t(blockConfig.first * alpha);
}

this->template Add<AdaptiveMeanPooling>(1,1);
}

if (includeTop)
{
this->template Add<Dropout>(1e-3);
this->template Add<Convolution>(size_t(1024 * alpha), numClasses,
1, 1, 1, 0, 0);
this->template Add<Softmax>();
}
}

} // namespace models
} // namespace mlpack

#endif // MODELS_MODELS_MOBILENET_MOBILENET_IMPL_HPP
Loading
Loading