Merge pull request #2583 from himanshupathak21061998/add-copylinear
Adding copy constructor in linear layer
This commit is contained in:
@@ -641,6 +641,7 @@ FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::FFN(
|
||||
{
|
||||
this->network.push_back(boost::apply_visitor(copyVisitor,
|
||||
network.network[i]));
|
||||
boost::apply_visitor(resetVisitor, this->network.back());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -52,6 +52,18 @@ class Linear
|
||||
const size_t outSize,
|
||||
RegularizerType regularizer = RegularizerType());
|
||||
|
||||
//! Copy constructor.
|
||||
Linear(const Linear& layer);
|
||||
|
||||
//! Move constructor.
|
||||
Linear(Linear&&);
|
||||
|
||||
//! Copy assignment operator.
|
||||
Linear& operator=(const Linear& layer);
|
||||
|
||||
//! Move assignment operator.
|
||||
Linear& operator=(Linear&& layer);
|
||||
|
||||
/*
|
||||
* Reset the layer parameter.
|
||||
*/
|
||||
|
||||
@@ -41,6 +41,62 @@ Linear<InputDataType, OutputDataType, RegularizerType>::Linear(
|
||||
weights.set_size(outSize * inSize + outSize, 1);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>::Linear(
|
||||
const Linear& layer) :
|
||||
inSize(layer.inSize),
|
||||
outSize(layer.outSize),
|
||||
weights(layer.weights),
|
||||
regularizer(layer.regularizer)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>::Linear(
|
||||
Linear&& layer) :
|
||||
inSize(0),
|
||||
outSize(0),
|
||||
weights(std::move(layer.weights)),
|
||||
regularizer(std::move(layer.regularizer))
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>&
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>::
|
||||
operator=(const Linear& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
{
|
||||
inSize = layer.inSize;
|
||||
outSize = layer.outSize;
|
||||
weights = layer.weights;
|
||||
regularizer = layer.regularizer;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>&
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>::
|
||||
operator=(Linear&& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
{
|
||||
inSize = layer.inSize;
|
||||
outSize = layer.outSize;
|
||||
weights = std::move(layer.weights);
|
||||
regularizer = std::move(layer.regularizer);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
void Linear<InputDataType, OutputDataType, RegularizerType>::Reset()
|
||||
@@ -92,11 +148,7 @@ void Linear<InputDataType, OutputDataType, RegularizerType>::serialize(
|
||||
{
|
||||
ar & BOOST_SERIALIZATION_NVP(inSize);
|
||||
ar & BOOST_SERIALIZATION_NVP(outSize);
|
||||
|
||||
// This is inefficient, but we have to allocate this memory so that
|
||||
// WeightSetVisitor gets the right size.
|
||||
if (Archive::is_loading::value)
|
||||
weights.set_size(outSize * inSize + outSize, 1);
|
||||
ar & BOOST_SERIALIZATION_NVP(weights);
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -57,6 +57,104 @@ void TestNetwork(ModelType& model,
|
||||
REQUIRE(classificationError <= classificationErrorThreshold);
|
||||
}
|
||||
|
||||
// network1 should be allocated with `new`, and trained on some data.
|
||||
template<typename MatType = arma::mat, typename ModelType>
|
||||
void CheckCopyFunction(ModelType* network1,
|
||||
MatType& trainData,
|
||||
MatType& trainLabels,
|
||||
const size_t maxEpochs)
|
||||
{
|
||||
ens::RMSProp opt(0.01, 32, 0.88, 1e-8, maxEpochs * trainData.n_cols, -1);
|
||||
network1->Train(trainData, trainLabels, opt);
|
||||
|
||||
arma::mat predictions1;
|
||||
network1->Predict(trainData, predictions1);
|
||||
FFN<> network2;
|
||||
network2 = *network1;
|
||||
delete network1;
|
||||
|
||||
// Deallocating all of network1's memory, so that
|
||||
// if network2 is trying to use any of that memory.
|
||||
arma::mat predictions2;
|
||||
network2.Predict(trainData, predictions2);
|
||||
CheckMatrices(predictions1, predictions2);
|
||||
}
|
||||
|
||||
// network1 should be allocated with `new`, and trained on some data.
|
||||
template<typename MatType = arma::mat, typename ModelType>
|
||||
void CheckMoveFunction(ModelType* network1,
|
||||
MatType& trainData,
|
||||
MatType& trainLabels,
|
||||
const size_t maxEpochs)
|
||||
{
|
||||
ens::RMSProp opt(0.01, 32, 0.88, 1e-8, maxEpochs * trainData.n_cols, -1);
|
||||
network1->Train(trainData, trainLabels, opt);
|
||||
|
||||
arma::mat predictions1;
|
||||
network1->Predict(trainData, predictions1);
|
||||
FFN<> network2(std::move(*network1));
|
||||
delete network1;
|
||||
|
||||
// Deallocating all of network1's memory, so that
|
||||
// if network2 is trying to use any of that memory.
|
||||
arma::mat predictions2;
|
||||
network2.Predict(trainData, predictions2);
|
||||
CheckMatrices(predictions1, predictions2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether copying and moving Vanila network is working or not.
|
||||
*/
|
||||
TEST_CASE("CheckCopyMovingVanillaNetworkTest", "[FeedForwardNetworkTest]")
|
||||
{
|
||||
// Load the dataset.
|
||||
arma::mat trainData;
|
||||
data::Load("thyroid_train.csv", trainData, true);
|
||||
|
||||
arma::mat trainLabels = trainData.row(trainData.n_rows - 1);
|
||||
trainData.shed_row(trainData.n_rows - 1);
|
||||
|
||||
/*
|
||||
* Construct a feed forward network with trainData.n_rows input nodes,
|
||||
* hiddenLayerSize hidden nodes and trainLabels.n_rows output nodes. The
|
||||
* network structure looks like:
|
||||
*
|
||||
* Input Hidden Output
|
||||
* Layer Layer Layer
|
||||
* +-----+ +-----+ +-----+
|
||||
* | | | | | |
|
||||
* | +------>| +------>| |
|
||||
* | | +>| | +>| |
|
||||
* +-----+ | +--+--+ | +-----+
|
||||
* | |
|
||||
* Bias | Bias |
|
||||
* Layer | Layer |
|
||||
* +-----+ | +-----+ |
|
||||
* | | | | | |
|
||||
* | +-----+ | +-----+
|
||||
* | | | |
|
||||
* +-----+ +-----+
|
||||
*/
|
||||
|
||||
FFN<NegativeLogLikelihood<> > *model = new FFN<NegativeLogLikelihood<> >;
|
||||
model->Add<Linear<> >(trainData.n_rows, 8);
|
||||
model->Add<SigmoidLayer<> >();
|
||||
model->Add<Linear<> >(8, 3);
|
||||
model->Add<LogSoftMax<> >();
|
||||
|
||||
FFN<NegativeLogLikelihood<> > *model1 = new FFN<NegativeLogLikelihood<> >;
|
||||
model1->Add<Linear<> >(trainData.n_rows, 8);
|
||||
model1->Add<SigmoidLayer<> >();
|
||||
model1->Add<Linear<> >(8, 3);
|
||||
model1->Add<LogSoftMax<> >();
|
||||
|
||||
// Check whether copy cpnstructor is working or not.
|
||||
CheckCopyFunction<>(model, trainData, trainLabels, 1);
|
||||
|
||||
// Check whether move cpnstructor is working or not.
|
||||
CheckMoveFunction<>(model1, trainData, trainLabels, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Train the vanilla network on a larger dataset.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user