Squashed commit of the following:
commit54c6ebe03aMerge:775a3b55fb406fc150Author: Ryan Curtin <ryan@ratml.org> Date: Sun May 1 13:24:24 2022 -0400 Merge pull request #3200 from shubham1206agra/go-cli-fix Go Build Fix commit775a3b55f7Merge:8e72ed69854e291443Author: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 30 10:41:45 2022 -0400 Merge pull request #3198 from shubham1206agra/py-cli-fix Python Build Fix commit8e72ed6986Merge:f7cd038661c1182301Author: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 30 10:40:59 2022 -0400 Merge pull request #3199 from shubham1206agra/r-cli-fix R Build Fix commitb406fc1506Author: shubham1206agra <tt1191044@iitd.ac.in> Date: Fri Apr 29 10:42:32 2022 +0530 changes according to suggestion commit54e2914430Author: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Fri Apr 29 10:20:14 2022 +0530 Update src/mlpack/bindings/python/copy_artifacts.py Co-authored-by: Ryan Curtin <ryan@ratml.org> commitf7cd038660Merge:065fcee293eb8ae67eAuthor: Ryan Curtin <ryan@ratml.org> Date: Thu Apr 28 19:00:58 2022 -0700 Merge pull request #2777 from zoq/ann-vtable Swap boost::variant with vtable. commitad4569213aAuthor: shubham1206agra <tt1191044@iitd.ac.in> Date: Thu Apr 28 19:32:14 2022 +0530 temp sol to version issue commit1bfa385663Author: shubham1206agra <tt1191044@iitd.ac.in> Date: Thu Apr 28 18:48:03 2022 +0530 initial fix by disabling go modules commit1c1182301eAuthor: shubham1206agra <tt1191044@iitd.ac.in> Date: Thu Apr 28 12:46:18 2022 +0530 force install pkgbuild commit3cfbb4e65dAuthor: shubham1206agra <tt1191044@iitd.ac.in> Date: Thu Apr 28 12:36:51 2022 +0530 cleanup commitfeab906927Author: shubham1206agra <tt1191044@iitd.ac.in> Date: Thu Apr 28 11:28:32 2022 +0530 missing '/' added commit577cc2d692Author: shubham1206agra <tt1191044@iitd.ac.in> Date: Thu Apr 28 10:33:02 2022 +0530 new directory structure using glob commit3eb8ae67ecMerge:6f98ab7bc065fcee29Author: Ryan Curtin <ryan@ratml.org> Date: Wed Apr 27 20:51:46 2022 -0400 Merge remote-tracking branch 'origin/master' into ann-vtable commit6f98ab7bc9Author: Eshaan Agarwal <eshaan060202@gmail.com> Date: Wed Apr 13 20:13:06 2022 +0530 Fix style issues Co-authored-by: Ryan Curtin <ryan@ratml.org> commitac3097e875Author: eshaanagarwal <eshaan060202@gmail.com> Date: Wed Apr 13 18:22:03 2022 +0530 fix error in size_t cast Signed-off-by: eshaanagarwal <eshaan060202@gmail.com> commitd03aafacf6Author: eshaanagarwal <eshaan060202@gmail.com> Date: Tue Apr 5 13:02:00 2022 +0530 add parameter documentation in size checks commite55609d5beAuthor: eshaanagarwal <eshaan060202@gmail.com> Date: Tue Apr 5 00:51:27 2022 +0530 Add transpose parameter in size check commita485da2b71Author: eshaanagarwal <eshaan060202@gmail.com> Date: Thu Mar 31 04:22:53 2022 +0530 fixed issues in styling commitdff01492edAuthor: eshaanagarwal <eshaan060202@gmail.com> Date: Mon Mar 14 22:25:27 2022 +0530 fixed styling issues commitca50361083Author: eshaanagarwal <eshaan060202@gmail.com> Date: Fri Mar 11 22:50:03 2022 +0530 fix build issue by removing row vector assert condition commit5b7d36db85Author: eshaanagarwal <eshaan060202@gmail.com> Date: Fri Mar 11 20:15:07 2022 +0530 fix failed build commit614f924a4eAuthor: eshaanagarwal <eshaan060202@gmail.com> Date: Fri Mar 11 19:50:54 2022 +0530 fixed redundancy in size-checks commitf67c566a5fAuthor: eshaanagarwal <eshaan060202@gmail.com> Date: Fri Mar 11 19:30:22 2022 +0530 fix matrix completion size-checks commite1e2b5308bAuthor: eshaanagarwal <eshaan060202@gmail.com> Date: Fri Mar 11 12:19:37 2022 +0530 remove incorrect checks in adaboost commite5d701df32Author: eshaanagarwal <eshaan060202@gmail.com> Date: Thu Mar 10 16:30:49 2022 +0530 fix size checks commit2656b300f9Author: eshaanagarwal <eshaan060202@gmail.com> Date: Thu Mar 10 12:24:15 2022 +0530 fix styling issue Signed-off-by: eshaanagarwal <eshaan060202@gmail.com> commitef4d293fedAuthor: eshaanagarwal <eshaan060202@gmail.com> Date: Wed Mar 9 02:33:08 2022 +0530 Add: size checks for kmeans and linear regression commit640dd0cde8Author: eshaanagarwal <eshaan060202@gmail.com> Date: Tue Mar 8 02:27:38 2022 +0530 Add : Size checks for adaboost and matix completion Signed-off-by: eshaanagarwal <eshaan060202@gmail.com> commit66bc9cbe00Author: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 15 21:29:30 2022 -0400 Huh, I guess it is a new year. commit7b0c1e157bAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 15 21:29:15 2022 -0400 Update HISTORY. commite4be17defeAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 15 21:26:42 2022 -0400 Add test for KFoldCV and Perceptron. commita70437ffc3Author: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 15 21:26:28 2022 -0400 Add constructor to Perceptron for weighted data for KFoldCV. commit9b86271002Author: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 15 21:26:08 2022 -0400 Make Classify() set the output predictions' size. commita35fc3b994Author: Yashwants19 <Yashwants19@users.noreply.github.com> Date: Sun Apr 17 10:02:24 2022 +0000 Upgrade Catch to 2.13.9 commita1bb763729Author: Omar Shrit <omar@shrit.me> Date: Sat Apr 16 21:40:15 2022 +0200 Update src/mlpack/core/data/save_image.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit57cec6f081Author: Omar Shrit <omar@shrit.me> Date: Sat Apr 16 16:20:14 2022 +0100 Apply @rcurtin modification to check STB version Signed-off-by: Omar Shrit <omar@shrit.me> commit8e34862cf6Author: Omar Shrit <omar@shrit.me> Date: Sun Mar 13 21:28:32 2022 +0000 Let us see inital try for STB test Signed-off-by: Omar Shrit <omar@shrit.me> commitafcc862cedAuthor: Omar Shrit <omar@shrit.me> Date: Thu Feb 3 21:46:40 2022 +0000 Adding the missing starts, shitty regexp Signed-off-by: Omar Shrit <omar@shrit.me> commit0c076cca19Author: Omar Shrit <omar@shrit.me> Date: Tue Jan 25 12:09:08 2022 +0000 Finish this PR Signed-off-by: Omar Shrit <omar@shrit.me> commitb26f2d2a15Author: Omar Shrit <omar@shrit.me> Date: Mon Jan 24 22:15:55 2022 +0000 Refactor save_image into save_image_impl finally done!! Signed-off-by: Omar Shrit <omar@shrit.me> commit8fffbd55faAuthor: Omar Shrit <omar@shrit.me> Date: Mon Jan 24 21:20:12 2022 +0000 Adjust namespace of mlpack::Log Signed-off-by: Omar Shrit <omar@shrit.me> commit37367c7ec5Author: Omar Shrit <omar@shrit.me> Date: Mon Jan 24 19:51:55 2022 +0100 Update src/mlpack/core/data/image_info_impl.hpp Co-authored-by: Ryan Curtin <ryan@ratml.org> commit3cc2d250b5Author: Omar Shrit <omar@shrit.me> Date: Mon Jan 24 19:51:49 2022 +0100 Update src/mlpack/core/data/image_info_impl.hpp Co-authored-by: Ryan Curtin <ryan@ratml.org> commit55c6cfd7dfAuthor: Omar Shrit <omar@shrit.me> Date: Sun Jan 23 19:38:29 2022 +0000 Apply @rcurtin patch to fix the STB issue. Signed-off-by: Omar Shrit <omar@shrit.me> commit8cdb53a313Author: Omar Shrit <omar@shrit.me> Date: Sun Jan 16 18:20:04 2022 +0000 Commenting all #defines that are causing the problems Signed-off-by: Omar Shrit <omar@shrit.me> commite2e000b06fAuthor: Omar Shrit <omar@shrit.me> Date: Sun Jan 16 16:21:27 2022 +0000 Move constructor to implementation Signed-off-by: Omar Shrit <omar@shrit.me> commit981f57c4beAuthor: Omar Shrit <omar@shrit.me> Date: Sun Jan 16 16:03:30 2022 +0000 Compiling locally, adding all modifications Signed-off-by: Omar Shrit <omar@shrit.me> commit4d29f5f9c1Author: Omar Shrit <omar@shrit.me> Date: Sun Jan 16 12:59:31 2022 +0000 Provide more details for namespace in src/mlpack/methods/det/dtree_impl.hpp Co-authored-by: Ryan Curtin <ryan@ratml.org> commite8a76f8f35Author: Omar Shrit <omar@shrit.me> Date: Sun Jan 16 12:59:03 2022 +0000 Remove mlpack namspace from src/mlpack/methods/hmm/hmm_util_impl.hpp Co-authored-by: Ryan Curtin <ryan@ratml.org> commit9dd15d0865Author: Omar Shrit <omar@shrit.me> Date: Sun Jan 16 12:58:50 2022 +0000 remove mlpack namespace from src/mlpack/methods/reinforcement_learning/q_networks/categorical_dqn.hpp Co-authored-by: Ryan Curtin <ryan@ratml.org> commitaa057ccb8bAuthor: Omar Shrit <omar@shrit.me> Date: Sun Jan 16 12:58:38 2022 +0000 Remove mlpack namespace from src/mlpack/methods/hmm/hmm_util_impl.hpp Co-authored-by: Ryan Curtin <ryan@ratml.org> commit61cc69b1a5Author: Omar Shrit <omar@shrit.me> Date: Sun Jan 16 12:58:22 2022 +0000 Remove mlpack namespace from src/mlpack/methods/reinforcement_learning/q_networks/dueling_dqn.hpp Co-authored-by: Ryan Curtin <ryan@ratml.org> commit31f9545685Author: Omar Shrit <omar@shrit.me> Date: Sun Jan 16 12:58:06 2022 +0000 Remove mlpack namespace from src/mlpack/methods/reinforcement_learning/q_networks/simple_dqn.hpp Co-authored-by: Ryan Curtin <ryan@ratml.org> commit665711b9ceAuthor: Omar Shrit <omar@shrit.me> Date: Thu Dec 16 15:33:51 2021 +0100 Remove additional line in src/mlpack/core/kernels/pspectrum_string_kernel.hpp Co-authored-by: Ryan Curtin <ryan@ratml.org> commit895c885b44Author: Omar Shrit <omar@shrit.me> Date: Thu Dec 16 15:33:08 2021 +0100 Fix indentation in src/mlpack/core/data/detect_file_type.hpp Co-authored-by: Ryan Curtin <ryan@ratml.org> commitcf6f60aee8Author: Omar Shrit <omar@shrit.me> Date: Thu Dec 16 15:32:55 2021 +0100 Add forgetten dot in src/mlpack/core/math/random_basis.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit21e045928aAuthor: Omar Shrit <omar@shrit.me> Date: Thu Dec 16 15:32:38 2021 +0100 Add spaces in src/mlpack/core/math/lin_alg_impl.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit1f79e4fc83Author: Omar Shrit <omar@shrit.me> Date: Thu Dec 16 15:32:16 2021 +0100 Remove additional line in src/mlpack/core/math/lin_alg_impl.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit6dc2d63af6Author: Omar Shrit <omar@shrit.me> Date: Thu Dec 16 15:32:00 2021 +0100 Fix indentation src/mlpack/core/math/lin_alg_impl.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commited07d9f05aAuthor: Omar Shrit <omar@shrit.me> Date: Thu Dec 16 15:31:41 2021 +0100 Fix indentation in src/mlpack/core/math/lin_alg_impl.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit047dc47b3bAuthor: Omar Shrit <omar@shrit.me> Date: Thu Dec 16 15:31:24 2021 +0100 Add parantheses in src/mlpack/core/math/lin_alg_impl.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit2dae84947aAuthor: Omar Shrit <omar@shrit.me> Date: Thu Dec 16 15:31:00 2021 +0100 Fix style in src/mlpack/core/kernels/epanechnikov_kernel_impl.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit8666165293Author: Omar Shrit <omar@shrit.me> Date: Thu Dec 16 15:30:43 2021 +0100 Update style in src/mlpack/core/kernels/epanechnikov_kernel_impl.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit6254b4b49aAuthor: Omar Shrit <omar@shrit.me> Date: Thu Dec 2 23:54:27 2021 +0000 Add forgetten layer name Signed-off-by: Omar Shrit <omar@shrit.me> commit407b563330Author: Omar Shrit <omar@shrit.me> Date: Thu Dec 2 22:54:06 2021 +0000 Clean all using namespaces from the headers. Signed-off-by: Omar Shrit <omar@shrit.me> commit4a713818abAuthor: Omar Shrit <omar@shrit.me> Date: Thu Dec 2 19:40:02 2021 +0000 Fix the random_basis_impl in addition Signed-off-by: Omar Shrit <omar@shrit.me> commit99a485b6beAuthor: Omar Shrit <omar@shrit.me> Date: Thu Dec 2 19:39:05 2021 +0000 Clean partly the namespace. Let us see if this resolve the macOS issues Signed-off-by: Omar Shrit <omar@shrit.me> commit986bdb6bddAuthor: Omar Shrit <omar@shrit.me> Date: Sat Nov 20 22:03:31 2021 +0000 Adjust namespace in preprocess Signed-off-by: Omar Shrit <omar@shrit.me> commitc3691bdf65Author: Omar Shrit <omar@shrit.me> Date: Sat Nov 20 20:33:55 2021 +0000 Remove the mlpack:: namespace Signed-off-by: Omar Shrit <omar@shrit.me> commitadbedb857bAuthor: Omar Shrit <omar@shrit.me> Date: Sat Nov 20 19:56:14 2021 +0000 Adding missing math/random headers Signed-off-by: Omar Shrit <omar@shrit.me> commitd246f94286Author: Omar Shrit <omar@shrit.me> Date: Sat Nov 20 19:29:07 2021 +0000 Fix the gmm error Signed-off-by: Omar Shrit <omar@shrit.me> commit10ed5c1c96Author: Omar Shrit <omar@shrit.me> Date: Sat Nov 20 17:06:11 2021 +0000 Let us if this resolves the binding issues Signed-off-by: Omar Shrit <omar@shrit.me> commit8b0c8038ddAuthor: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 19:52:19 2021 +0000 Adding a missing std string Signed-off-by: Omar Shrit <omar@shrit.me> commitff2f37c4e7Author: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 19:40:23 2021 +0000 Finish the pspectrum_string_kernel Signed-off-by: Omar Shrit <omar@shrit.me> commitc6bf80178aAuthor: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 19:39:32 2021 +0000 Deleting epanechnikov_kernel and adding pspectrum_string_kernel Signed-off-by: Omar Shrit <omar@shrit.me> commit09f508c6deAuthor: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 19:33:05 2021 +0000 Finishing the epanechnikov_kernel Signed-off-by: Omar Shrit <omar@shrit.me> commit61d01a3949Author: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 19:23:57 2021 +0000 remove epanechnikov_kernel Signed-off-by: Omar Shrit <omar@shrit.me> commitbd84bb2d0dAuthor: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 19:15:58 2021 +0000 inline random_basis Signed-off-by: Omar Shrit <omar@shrit.me> commit90b80ea766Author: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 19:11:32 2021 +0000 Adding missing headers Signed-off-by: Omar Shrit <omar@shrit.me> commite0c5ac34fbAuthor: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 18:56:00 2021 +0000 move the impl from .cpp to .impl Signed-off-by: Omar Shrit <omar@shrit.me> commit85a53b486fAuthor: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 18:43:17 2021 +0000 Fix the compilation warning related to include implementations Signed-off-by: Omar Shrit <omar@shrit.me> commitc1d3833ff1Author: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 18:24:15 2021 +0000 Fix comments and compilation bugs Signed-off-by: Omar Shrit <omar@shrit.me> commitb037f4f69fAuthor: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 18:12:02 2021 +0000 Finish inlining the data dir Signed-off-by: Omar Shrit <omar@shrit.me> commit0941f65038Author: Omar Shrit <omar@shrit.me> Date: Sat Nov 13 18:04:01 2021 +0000 Make save image header only Signed-off-by: Omar Shrit <omar@shrit.me> commitba84188163Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Wed Mar 16 23:23:01 2022 -0400 Prettify C++ code used to check for atomic linkage. commitf9cc2f6bfaAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Tue Mar 15 22:14:12 2022 -0400 If we use MSVC no need to check for atomic. commit119da780edAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Feb 20 21:15:50 2022 -0500 Check if libatomic is bundled. commit96f4d9aea6Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Wed Feb 16 21:42:44 2022 -0500 Check if atomics need -latomic linking. commit47f94fbaeeAuthor: zoq <zoq@users.noreply.github.com> Date: Thu Apr 14 10:05:15 2022 +0000 Upgrade Boost Version in CMake script. commitc31961bc46Author: LiuZhuojin <zhuojinliu.cs@gmail.com> Date: Thu Apr 14 09:53:55 2022 +0800 Update contributor list commit2d77be64d9Author: LiuZhuojin <zhuojinliu.cs@gmail.com> Date: Wed Apr 13 09:33:03 2022 +0800 Replace boost::heap::priority_queue with std::vector commitaa4a8b3922Author: LiuZhuojin <zhuojinliu.cs@gmail.com> Date: Wed Apr 13 00:40:08 2022 +0800 Add vector and queue to standard includes commitd9145891a7Author: LiuZhuojin <zhuojinliu.cs@gmail.com> Date: Wed Apr 13 00:38:40 2022 +0800 Replace boost::heap::priority_queue with std::vector commit58518ab811Author: LiuZhuojin <zhuojinliu.cs@gmail.com> Date: Wed Apr 13 00:27:28 2022 +0800 Replace boost::heap::priority_queue with std::vector commitbc30907f5aAuthor: LiuZhuojin <zhuojinliu.cs@gmail.com> Date: Sat Apr 9 15:04:31 2022 +0800 Replace boost::heap::priority_queue with std::vector commite117627c7fAuthor: LiuZhuojin <zhuojinliu.cs@gmail.com> Date: Sat Apr 9 14:58:28 2022 +0800 Replace boost::heap::priority_queue with std::vector commit4d962ebab6Author: LiuZhuojin <zhuojinliu.cs@gmail.com> Date: Fri Apr 8 13:53:10 2022 +0800 Replace boost::heap::priority_queue with std::vector commit65afadc4afAuthor: Yashwants19 <Yashwants19@users.noreply.github.com> Date: Fri Apr 1 10:00:54 2022 +0000 Upgrade CLI11 to 2.2.0 commit5875d3625aAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Apr 27 16:10:15 2022 -0400 Apply suggestions from code review Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commitfef34ea8dbAuthor: shubham1206agra <tt1191044@iitd.ac.in> Date: Wed Apr 27 19:25:31 2022 +0530 trying something else commit64e1f75b65Author: shubham1206agra <tt1191044@iitd.ac.in> Date: Wed Apr 27 19:11:02 2022 +0530 trying config file commit065fcee296Merge:56d3f163601fa1241cAuthor: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 18 15:43:03 2022 -0700 Merge pull request #3164 from eshaanagarwal/size-checks Added Size checks for Matrix Completion, Kmeans and Linear Regression commit56d3f16368Merge:2994570a0152094dbbAuthor: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 18 06:01:10 2022 -0700 Merge pull request #3190 from mlpack/fix-perceptron-cv Add weighted data constructor to `Perceptron` commit2994570a05Merge:fdc7af7a6c47cebdd8Author: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 18 05:55:12 2022 -0700 Merge pull request #3191 from mlpack/catch-header-updates-2.13.9 Upgrade Catch to 2.13.9 commitc47cebdd82Author: Yashwants19 <Yashwants19@users.noreply.github.com> Date: Sun Apr 17 10:02:24 2022 +0000 Upgrade Catch to 2.13.9 commit1645bb22ebAuthor: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 16 21:05:15 2022 -0400 Use `typename` instead of `class` for consistency. commitd8a1c27b7fAuthor: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 16 20:55:50 2022 -0400 Add serialization to GlorotInit. commit152094dbbeAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 15 21:29:30 2022 -0400 Huh, I guess it is a new year. commitc17e9c2f0fAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 15 21:29:15 2022 -0400 Update HISTORY. commit9a6551a1b5Author: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 15 21:26:42 2022 -0400 Add test for KFoldCV and Perceptron. commit3133a4abbdAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 15 21:26:28 2022 -0400 Add constructor to Perceptron for weighted data for KFoldCV. commit80e65d8a5dAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 15 21:26:08 2022 -0400 Make Classify() set the output predictions' size. commit01fa1241ceAuthor: Eshaan Agarwal <eshaan060202@gmail.com> Date: Wed Apr 13 20:13:06 2022 +0530 Fix style issues Co-authored-by: Ryan Curtin <ryan@ratml.org> commitcb35eba204Author: eshaanagarwal <eshaan060202@gmail.com> Date: Wed Apr 13 18:22:03 2022 +0530 fix error in size_t cast Signed-off-by: eshaanagarwal <eshaan060202@gmail.com> commitf12d714c50Author: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 11 13:34:43 2022 -0400 Comment on the weightsPtr parameter. commit44b30019f4Author: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 11 13:32:39 2022 -0400 Add another padding test for Convolution. commit1a9f7ccd5bAuthor: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 11 11:56:39 2022 -0400 Return correct type of Weights(). commitbacd18db55Author: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 11 11:53:54 2022 -0400 Update src/mlpack/methods/ann/layer/concatenate_impl.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit3dfe5a000dAuthor: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 11 11:53:40 2022 -0400 Update src/mlpack/methods/ann/layer/concatenate.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit6b47a9cd67Author: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 11 11:53:33 2022 -0400 Update src/mlpack/methods/ann/layer/alpha_dropout.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit77203b84cfAuthor: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 11 11:53:25 2022 -0400 Update src/mlpack/methods/ann/layer/alpha_dropout.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit845a5a0aedAuthor: eshaanagarwal <eshaan060202@gmail.com> Date: Tue Apr 5 13:02:00 2022 +0530 add parameter documentation in size checks commit07be7313a7Author: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 4 22:23:36 2022 -0400 Use network.Forward() to avoid the extra output copy. commit0710d9f111Author: Ryan Curtin <ryan@ratml.org> Date: Mon Apr 4 22:05:35 2022 -0400 Update src/mlpack/methods/ann/ffn.hpp Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de> commit0e9f05adbcAuthor: eshaanagarwal <eshaan060202@gmail.com> Date: Tue Apr 5 00:51:27 2022 +0530 Add transpose parameter in size check commit2cd38b3c9eAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 22:02:45 2022 -0400 Some additional cleanups. commitc38625f8d4Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 22:01:13 2022 -0400 Change 'rho' to 'bpttSteps' for clarity. commit6eecba768aAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 21:55:50 2022 -0400 Include numeric header for std::accumulate. commit12287174e4Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 21:29:51 2022 -0400 Fix TODOs in LSTM layer. commit71ecddf8f6Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 20:49:03 2022 -0400 Some cleanups of the RNN class. commit83a178dffaAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 16:53:25 2022 -0400 Some additional type fixes. commitf5b3885998Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 16:30:02 2022 -0400 Remove unused typedef. commiteae99cfacaAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 16:27:29 2022 -0400 Simplify Shuffle() implementation. commit250ab5cdd0Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 16:24:42 2022 -0400 Remove unused Swap() function declaration. commit1432420917Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 16:23:28 2022 -0400 Use MakeAlias() in the RNN implementation. commit03045b0235Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 16:08:59 2022 -0400 Fix line wrap. commitfe8a288613Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 16:07:01 2022 -0400 Minor fixes to tests. commit44a18de28cAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 15:58:36 2022 -0400 Clarify RNN comment. commit10d04c4153Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 15:57:02 2022 -0400 Add clarifying comment about where MakeAlias() is used. commit19c60244a7Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 15:56:06 2022 -0400 More CEREAL_NVP() fixes. commitd45d8787b9Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 15:54:58 2022 -0400 Fix serialization: use CEREAL_NVP(). commit194211feecAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 15:53:45 2022 -0400 Fixes for RBFType implementation comments. commit9c33d6b780Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 15:52:02 2022 -0400 Fix header guard name. commit880c95bee5Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 15:50:50 2022 -0400 Fix typo. commit2fdd4b823bAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 15:50:27 2022 -0400 Add explanatory comment. commit416dfc7c4aAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 15:48:36 2022 -0400 Fix inaccurate comment. commit19563e3f63Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 14:49:37 2022 -0400 Update comment. commitff3717bc53Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 14:41:01 2022 -0400 Fix typo in comment. commitac42ea450bAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 14:40:39 2022 -0400 Clarify implementations. commit20c7b5a836Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 14:37:01 2022 -0400 Remove unused method. commit4fb0dd4965Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 14:36:36 2022 -0400 Fix includes. commit5253b1427aAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 14:28:42 2022 -0400 Clarify comment. commitf0aceda809Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 14:27:38 2022 -0400 Fix serialization for base layer. commit2413a1cdf5Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 14:26:38 2022 -0400 Add a comment. commit2f0a9419efAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 14:26:05 2022 -0400 Use MakeAlias() instead. commitc599ecfd1aAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 13:23:32 2022 -0400 Change BaseLayer names for consistency. commit6d69ea45f1Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 13:18:45 2022 -0400 Clear member that is not serialized on loading. commit8f52887fb5Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 13:16:29 2022 -0400 Remove inaccurate comments (we did not drop these). commitcb952537e2Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 13:15:56 2022 -0400 Re-add removed files from CMake. commitc75d03ff6fAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 13:14:53 2022 -0400 Fix line spacing. commit8b2e57d32eAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 13:13:46 2022 -0400 Add a clarifying comment. commit454c746491Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 13:12:52 2022 -0400 Remove duplicated `training` member. commitc6443a43d8Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 13:05:37 2022 -0400 Add clarifying comment. commit6258a8a9fcAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 13:02:25 2022 -0400 Clean up copy and move operators. commit07fc52fba3Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 12:51:28 2022 -0400 Some clarifying comments. commit0ed1971ce0Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 12:50:24 2022 -0400 Some cleanups of Forward() and Backward(). commitcade46d605Author: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 12:31:27 2022 -0400 Some extra paranoia about `Network()`. commit20bf26651cAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Apr 3 12:18:34 2022 -0400 Use a separate file for forward declarations. commit56ef5ded8aAuthor: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 21:38:09 2022 -0400 Oops, revert unintentional CMake changes. commita1e3a8dbefAuthor: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 21:28:20 2022 -0400 Fix minor merge issues. commitf52a977dacMerge:835499fdbc4bb721efAuthor: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 19:15:59 2022 -0400 Merge remote-tracking branch 'origin/master' into ann-vtable commit835499fdb4Author: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 18:39:16 2022 -0400 Fix comments and remove working comments. commit2950e1ff9dAuthor: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 18:36:29 2022 -0400 Add comments to RecurrentLayer implementation. commit23d27c9b5dAuthor: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 18:20:59 2022 -0400 Minor style fixes. commite542fd8404Author: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 18:19:44 2022 -0400 Comment default typedefs. commit59ca9428c6Author: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 18:16:28 2022 -0400 Add standardized comment about MatType. commitcc4e3aec28Author: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 17:52:48 2022 -0400 Use 'Type' and typedef conventions for loss functions. commit232ce2a342Author: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 15:37:55 2022 -0400 Adapt CustomLayer for testing to have only one template parameter. commit9a9b6334a6Author: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 15:37:41 2022 -0400 Adapt tests for FFNs and RNNs having only one template parameter for type. commit9fe42a2d7bAuthor: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 15:37:21 2022 -0400 Adapt to use only one template parameter. commit6ff20e912bAuthor: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 15:36:52 2022 -0400 Adapt to use only one template parameter for types. commit48685d3483Author: Ryan Curtin <ryan@ratml.org> Date: Sat Apr 2 15:36:34 2022 -0400 Adapt to use only one template parameter. commitd79df40382Author: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 1 19:42:59 2022 -0400 Don't allow calling Parameters() on a layer with no weights. commit6cdd49ab88Author: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 1 18:21:50 2022 -0400 Some early attempts to adapt some tests. commit0d73c5e1e2Author: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 1 18:20:50 2022 -0400 Early attempts at refactoring Q-learning code. commita446c67f5aAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Apr 1 17:53:47 2022 -0400 Re-enable RLComponentsTest. commit263d1ddd15Author: Ryan Curtin <ryan@ratml.org> Date: Wed Mar 30 22:07:37 2022 -0400 Allow the Rho parameter to be reset (it should also be renamed). commitbcbeebcf27Author: Ryan Curtin <ryan@ratml.org> Date: Wed Mar 30 22:07:27 2022 -0400 Adapt CustomLayer. commit53d903d1c4Author: Ryan Curtin <ryan@ratml.org> Date: Wed Mar 30 21:17:29 2022 -0400 Re-add the callback tests. commitf34513341fAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Mar 30 21:15:36 2022 -0400 We don't have an arbitrary type; move() should be used here. commit5a2f58f559Author: Ryan Curtin <ryan@ratml.org> Date: Wed Mar 30 20:03:55 2022 -0400 Re-enable some of the activation function tests. commit0155643e72Author: Ryan Curtin <ryan@ratml.org> Date: Wed Mar 30 19:36:28 2022 -0400 Forward() should not worry about whether we are in single mode (that's only relevant for training). commitb3b5c6827aAuthor: eshaanagarwal <eshaan060202@gmail.com> Date: Thu Mar 31 04:22:53 2022 +0530 fixed issues in styling commited424ae4a1Author: Ryan Curtin <ryan@ratml.org> Date: Tue Mar 29 21:23:37 2022 -0400 Remove other bits of boost::visitor things. commitbe9a3882adAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Mar 29 21:23:28 2022 -0400 Comment out RBMNetworkTests. commitf1f5fc7fa2Author: Ryan Curtin <ryan@ratml.org> Date: Tue Mar 29 21:23:22 2022 -0400 Fix includes for moved files. commit112016ccf1Author: Ryan Curtin <ryan@ratml.org> Date: Tue Mar 29 21:22:59 2022 -0400 Remove boost usage. commit2da71b1f36Author: Ryan Curtin <ryan@ratml.org> Date: Tue Mar 29 21:22:46 2022 -0400 Move some files that aren't yet adapted or are unneeded. commit1998227d9cAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Mar 29 19:58:28 2022 -0400 Fix header guard name. commitf2a1b79e99Author: Ryan Curtin <ryan@ratml.org> Date: Sun Mar 27 14:16:58 2022 -0400 Fix incorrect step reference. commit7fa7eb15f0Author: Ryan Curtin <ryan@ratml.org> Date: Sun Mar 27 12:16:33 2022 -0400 Don't forget virtual destructor for LSTMType. commita501389238Author: Ryan Curtin <ryan@ratml.org> Date: Sun Mar 27 12:16:14 2022 -0400 Make sure to be able to serialize RecurrentLayer. commit4c8364c169Author: Ryan Curtin <ryan@ratml.org> Date: Sun Mar 27 12:15:52 2022 -0400 No need to serialize the training-time-only predictors and responses. commitc219a57da3Author: Ryan Curtin <ryan@ratml.org> Date: Sun Mar 27 12:15:38 2022 -0400 Reference local `results` instead of class-wide `responses`. commit9b7b7f875dAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Mar 27 12:15:20 2022 -0400 Add copy and move operator implementation. commitaccce42b35Author: Ryan Curtin <ryan@ratml.org> Date: Sun Mar 27 12:14:55 2022 -0400 Oops, add RecurrentLayer to the repository. commitdf613499f3Author: Ryan Curtin <ryan@ratml.org> Date: Fri Mar 25 11:59:49 2022 -0400 Adapt test to use multiple epochs. commitaa0ce85656Author: Ryan Curtin <ryan@ratml.org> Date: Fri Mar 25 11:58:43 2022 -0400 Fix alias computation. commit20b109fe42Author: Ryan Curtin <ryan@ratml.org> Date: Fri Mar 25 11:57:57 2022 -0400 Set step correctly for forward pass. commit9ff1fb11f5Author: Ryan Curtin <ryan@ratml.org> Date: Wed Mar 23 22:40:52 2022 -0400 Test that the RNN and FFN give the same output for only one time step. commit66d929f923Author: Ryan Curtin <ryan@ratml.org> Date: Wed Mar 23 22:40:42 2022 -0400 Handle series with only one time step. commit0c97b42d80Author: Ryan Curtin <ryan@ratml.org> Date: Wed Mar 23 17:58:28 2022 -0400 Be sure to serialize rho and single too. commit76992e86d6Author: Ryan Curtin <ryan@ratml.org> Date: Tue Mar 22 21:26:19 2022 -0400 Add serialization for some more initializations. commitd6e200ff37Author: Ryan Curtin <ryan@ratml.org> Date: Tue Mar 22 21:26:09 2022 -0400 Fix include issue (this may not be the right fix). commit080dcfccb4Author: Ryan Curtin <ryan@ratml.org> Date: Tue Mar 22 21:25:59 2022 -0400 Correct NumFunctions() implementation. commit4816d7ccfeAuthor: Ryan Curtin <ryan@ratml.org> Date: Sat Mar 19 23:48:10 2022 -0400 Some other minor bugfixes; now the tests pass. commit80efe31e5bAuthor: Ryan Curtin <ryan@ratml.org> Date: Thu Mar 17 22:06:01 2022 -0400 Fix a few bugs---now LSTMBatchSizeTest works! (That doesn't mean that RNNs actually work...) commiteab019541dAuthor: Ryan Curtin <ryan@ratml.org> Date: Thu Mar 17 21:12:19 2022 -0400 Comment out tests that don't work yet. commit9ff8fd401dAuthor: Ryan Curtin <ryan@ratml.org> Date: Thu Mar 17 21:11:47 2022 -0400 Clean up (in some places) RNN implementation. commit5683066a66Author: eshaanagarwal <eshaan060202@gmail.com> Date: Mon Mar 14 22:25:27 2022 +0530 fixed styling issues commit68e40a6b23Author: eshaanagarwal <eshaan060202@gmail.com> Date: Fri Mar 11 22:50:03 2022 +0530 fix build issue by removing row vector assert condition commitca353778a4Author: eshaanagarwal <eshaan060202@gmail.com> Date: Fri Mar 11 20:15:07 2022 +0530 fix failed build commit6883c30cb2Author: eshaanagarwal <eshaan060202@gmail.com> Date: Fri Mar 11 19:50:54 2022 +0530 fixed redundancy in size-checks commit2685d69097Author: eshaanagarwal <eshaan060202@gmail.com> Date: Fri Mar 11 19:30:22 2022 +0530 fix matrix completion size-checks commitf4db66192bAuthor: eshaanagarwal <eshaan060202@gmail.com> Date: Fri Mar 11 12:19:37 2022 +0530 remove incorrect checks in adaboost commit05d74baffdAuthor: eshaanagarwal <eshaan060202@gmail.com> Date: Thu Mar 10 16:30:49 2022 +0530 fix size checks commit54f6506015Author: eshaanagarwal <eshaan060202@gmail.com> Date: Thu Mar 10 12:24:15 2022 +0530 fix styling issue Signed-off-by: eshaanagarwal <eshaan060202@gmail.com> commit8714c77a95Author: eshaanagarwal <eshaan060202@gmail.com> Date: Wed Mar 9 02:33:08 2022 +0530 Add: size checks for kmeans and linear regression commit0a0681f2a5Author: eshaanagarwal <eshaan060202@gmail.com> Date: Tue Mar 8 02:27:38 2022 +0530 Add : Size checks for adaboost and matix completion Signed-off-by: eshaanagarwal <eshaan060202@gmail.com> commitbd08f9a92eAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Feb 16 22:18:54 2022 -0500 Remove debugging output. commitd8b72a862bAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Wed Feb 9 22:14:32 2022 -0500 Some RNN refactoring. commit93fecce9c8Author: Ryan Curtin <ryan@ratml.org> Date: Tue Feb 15 23:00:08 2022 -0500 Significant cleanup of all layers. The ones not in not_adapted/ (other than the LSTM) are ready for review. commitce12cd3e25Author: Ryan Curtin <ryan@ratml.org> Date: Wed Feb 9 22:44:07 2022 -0500 Remove files from CMakeLists.txt. commitee117f355bAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Feb 9 22:43:38 2022 -0500 Remove layer_traits.hpp since it's no longer needed. commit7b969f3014Author: Ryan Curtin <ryan@ratml.org> Date: Wed Feb 9 22:41:54 2022 -0500 Move two layers that got missed. commite2502cbb9cAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Feb 9 22:41:09 2022 -0500 Move unadapted layers into a separate directory (for organization). commitf72340106cAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Feb 9 22:09:08 2022 -0500 Add some documentation about what will happen. commit637b93ddc0Merge:2065e17dfcf190e11fAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Feb 9 22:05:56 2022 -0500 Merge remote-tracking branch 'origin/master' into ann-vtable commit2065e17df8Author: Ryan Curtin <ryan@ratml.org> Date: Wed Feb 9 21:45:29 2022 -0500 Add a test for uneven stride. commitc532632ce9Author: Ryan Curtin <ryan@ratml.org> Date: Sat Feb 5 20:41:43 2022 -0500 Remove comments that turn out to be unnecessary to address. commit5e09ed1671Author: Ryan Curtin <ryan@ratml.org> Date: Sat Feb 5 18:08:06 2022 -0500 Fix implementations of NaiveConvolution for stride and dilation. commit5cd0e38eb6Author: Ryan Curtin <ryan@ratml.org> Date: Sat Feb 5 18:07:39 2022 -0500 Add tests for different strides and dilations. commit8c1a818540Author: Ryan Curtin <ryan@ratml.org> Date: Wed Feb 2 22:55:35 2022 -0500 Fix stride usage for backwards pass. commit110ed75b6fAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Feb 1 18:06:55 2022 -0500 Fix some minor issues and merge problems. commita77d290214Author: Ryan Curtin <ryan@ratml.org> Date: Thu Jan 27 16:28:22 2022 -0500 Add/fix final set of copy/move constructors/operators. commit11cc9a122bAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Jan 26 22:29:45 2022 -0500 Add and fix a bunch more copy/move constructors/operators. commitec06bcbbffAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Jan 25 22:44:34 2022 -0500 Start implementing copy and move constructors correctly. commitf842111039Author: Ryan Curtin <ryan@ratml.org> Date: Tue Jan 25 22:44:25 2022 -0500 Set sizes correctly for test. commit3f5e06e9c5Author: Ryan Curtin <ryan@ratml.org> Date: Sat Jan 22 11:20:35 2022 -0500 Restructure PaddingTest for slight behavior changes. commitabb1450102Author: Ryan Curtin <ryan@ratml.org> Date: Fri Jan 21 23:32:35 2022 -0500 Fix minor bugs in shape computation. commitd600ece415Author: Ryan Curtin <ryan@ratml.org> Date: Fri Jan 21 23:03:24 2022 -0500 Fix failing padding tests. commit94b3294a5dAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Jan 21 14:40:53 2022 -0500 Fix some merge issues. commitc3caed0490Merge:09a28caa93264cd87eAuthor: Ryan Curtin <ryan@ratml.org> Date: Thu Jan 20 20:23:26 2022 -0500 Merge remote-tracking branch 'origin/master' into ann-vtable commit09a28caa90Author: Ryan Curtin <ryan@ratml.org> Date: Wed Jan 19 17:41:18 2022 -0500 Some minor bugfixes to FFN. Some need further cleanup. commit96f97421f2Author: Ryan Curtin <ryan@ratml.org> Date: Wed Jan 19 17:16:57 2022 -0500 Fix bug in Gradient() implementation. commit6dc0596ad6Author: Ryan Curtin <ryan@ratml.org> Date: Wed Jan 19 17:16:44 2022 -0500 Consider bias term in gradient. commit9a71a61aacAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Jan 7 18:16:18 2022 -0500 Fix setting of inputDimensionsAreSet. commita4ee2545f6Author: Ryan Curtin <ryan@ratml.org> Date: Tue Jan 4 20:12:34 2022 -0500 Add a sanity check test. It passes. commitf5c4b95860Author: Ryan Curtin <ryan@ratml.org> Date: Sun Nov 28 21:47:40 2021 -0500 Remove debugging output. commitd8fef7eed6Author: Ryan Curtin <ryan@ratml.org> Date: Sun Nov 28 21:47:17 2021 -0500 Adapt to new mlpack 4 conventions. commitbda6e0969fAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Nov 28 21:46:59 2021 -0500 Fix failing tests. commit8d1c05c36fAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Nov 28 21:46:44 2021 -0500 Update to mlpack 4 conventions. commitead043c9b8Author: Ryan Curtin <ryan@ratml.org> Date: Sun Nov 28 21:45:41 2021 -0500 Oops, make sure to add the bias in the forward pass. commiteae19f7c28Author: Omar Shrit <omar@shrit.me> Date: Tue Nov 16 17:43:09 2021 +0000 Finishing the Alphadroput layer, tests are passing Signed-off-by: Omar Shrit <omar@shrit.me> commitc19e39a152Author: Ryan Curtin <ryan@ratml.org> Date: Sun Nov 14 22:30:39 2021 -0500 Turns out the MaxPooling adaptation I did was wrong---this seems more correct. commita1fd4829a1Author: Ryan Curtin <ryan@ratml.org> Date: Sun Nov 14 22:30:15 2021 -0500 Redo Convolution layer implementation. I think this is right but not 100% sure. commitca010221e9Author: Ryan Curtin <ryan@ratml.org> Date: Sun Nov 14 22:29:26 2021 -0500 Enable LeakyReLU layer. commit49954574e9Author: Ryan Curtin <ryan@ratml.org> Date: Mon Nov 1 19:17:24 2021 -0400 Add gradient test for Convolution layer... but it seems to work? commitbe5b4e5e01Author: Ryan Curtin <ryan@ratml.org> Date: Wed Oct 20 17:46:03 2021 -0400 Fix shape of input to reflect the number of input maps. commit19f06709d4Author: Ryan Curtin <ryan@ratml.org> Date: Tue Oct 19 10:18:14 2021 -0400 Use MakeAlias() to avoid accidental copies. commit081c32593dAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Sep 28 11:35:41 2021 -0400 Bias should be one per output map. commit58f1718be1Author: Ryan Curtin <ryan@ratml.org> Date: Tue Sep 28 11:22:07 2021 -0400 Huh, it seems like this fixes ConvolutionLayerPaddingTest. commit6fff4457c6Author: Ryan Curtin <ryan@ratml.org> Date: Mon Sep 20 11:09:36 2021 -0400 Fix two more tests by making sure the inputs and outputs are right. commitad2cb74d05Author: Ryan Curtin <ryan@ratml.org> Date: Sun Sep 19 00:10:20 2021 -0400 Fix some tests. commit051205d78fAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Sep 15 22:12:20 2021 -0400 Now at least the tests don't segfault. :) commit1152c75d23Author: Ryan Curtin <ryan@ratml.org> Date: Wed Sep 15 13:59:43 2021 -0400 Update some ann_layer tests. commitf05590b878Author: Ryan Curtin <ryan@ratml.org> Date: Wed Sep 15 13:59:29 2021 -0400 Fix convolution. commit1cbdaa8ac5Author: Ryan Curtin <ryan@ratml.org> Date: Wed Sep 15 13:58:09 2021 -0400 Fix bug for uninitialized output. commit3a00d82a23Author: Ryan Curtin <ryan@ratml.org> Date: Thu Sep 9 12:02:31 2021 -0400 Some cleanups for the convolution layer. commit72c0f58a27Author: Ryan Curtin <ryan@ratml.org> Date: Thu Sep 9 12:02:06 2021 -0400 Fix some incorrect dimension usages. commita46542b25fAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Sep 7 18:05:04 2021 -0400 Too much writing Julia... commit06f7b34d73Author: Ryan Curtin <ryan@ratml.org> Date: Fri Sep 3 18:43:21 2021 -0400 Fix max pooling bug. commitc9df713091Author: Ryan Curtin <ryan@ratml.org> Date: Sat Aug 21 10:44:43 2021 -0400 First attempt at refactoring Padding, MaxPooling, and Convolution. commit498afa0ab7Author: Ryan Curtin <ryan@ratml.org> Date: Sat Aug 7 11:15:14 2021 -0400 Fix various bugs in the MultiLayer implementation. commit8105bb8583Author: Ryan Curtin <ryan@ratml.org> Date: Wed Aug 4 21:19:54 2021 -0400 Refactor to use MultiLayer inside an FFN. commit5f7a9cd684Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Mon Aug 2 18:19:58 2021 +0200 Filter some 'unused' layers. commit8a4e5b9bdfAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Aug 1 21:42:09 2021 -0400 Refactor Highway (and fix MultiLayer). commit0375e7d575Author: Ryan Curtin <ryan@ratml.org> Date: Sun Aug 1 21:42:00 2021 -0400 Extra paranoia to avoid include boost::visitor... commitd3972c16daAuthor: Ryan Curtin <ryan@ratml.org> Date: Sun Aug 1 21:41:49 2021 -0400 Just make sure boost isn't included... commit57884df9f6Author: Ryan Curtin <ryan@ratml.org> Date: Sun Aug 1 21:41:33 2021 -0400 Split out into convenience function. commitd136ac3df3Author: Ryan Curtin <ryan@ratml.org> Date: Sun Aug 1 21:41:00 2021 -0400 Hey, this is no longer needed! :) commitbe7eeb134dMerge:ce3c3bceee3f4654a8Author: Ryan Curtin <ryan@ratml.org> Date: Fri Jul 23 16:45:08 2021 -0400 Merge branch 'ann-vtable-attempt' into HEAD commite3f4654a8aAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Jul 23 16:43:46 2021 -0400 Update RBF<> layer so tests pass. commitce3c3bcee6Merge:34cf419bb927fabff8Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Tue Jul 20 08:56:37 2021 -0400 Merge pull request #2 from rcurtin/ann-vtable-attempt Further refactoring of ANN to remove boost::visitor. commit927fabff8aAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Jul 13 17:53:33 2021 -0400 Adapt the last commented test in FeedforwardNetworkTest. commited8881d2b6Author: Ryan Curtin <ryan@ratml.org> Date: Tue Jul 13 17:48:46 2021 -0400 Uncomment another test. commitb05736d42cAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Jul 13 17:48:34 2021 -0400 Make sure Parameters() returns the correct thing. commit522ebd11feAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Jul 13 17:48:27 2021 -0400 Adapt AddType<>. commitc8c0797c9dAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Jul 13 17:19:57 2021 -0400 Adapt a few more layers, and uncomment some more tests. commit2b7429594fAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Jul 13 16:47:06 2021 -0400 Oops, I didn't really need to refactor this, but it might work. commitab67249f9fAuthor: Ryan Curtin <ryan@ratml.org> Date: Thu Jul 8 17:49:57 2021 -0400 Fix additional warnings. commita5bb31b824Author: Ryan Curtin <ryan@ratml.org> Date: Thu Jul 8 17:38:04 2021 -0400 Remove debugging output. commit188759042cAuthor: Ryan Curtin <ryan@ratml.org> Date: Thu Jul 8 17:37:42 2021 -0400 Fix a compilation warning. commit130890c85dAuthor: Ryan Curtin <ryan@ratml.org> Date: Thu Jul 8 17:36:09 2021 -0400 Some additional refactoring and cleanups. Notably, the adapted layers no longer need an input size. commit32b19eb7efAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Jul 7 19:08:32 2021 -0400 Refactor Reparametrization layer. commitd180cc3639Author: Ryan Curtin <ryan@ratml.org> Date: Wed Jul 7 19:08:12 2021 -0400 Serialize output dimensions also. commita87672665cAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Jul 7 18:24:15 2021 -0400 Remove unnecessary copy/move constructor/operators. commitaf68997a6cAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Jul 7 18:22:30 2021 -0400 This function should be const. commit60fe292da9Author: Ryan Curtin <ryan@ratml.org> Date: Wed Jul 7 18:22:10 2021 -0400 These are all the default versions anyway (but don't consider inheritance...). commit30e4ff741bAuthor: Ryan Curtin <ryan@ratml.org> Date: Tue Jul 6 16:22:37 2021 -0400 Update comments. commit7f7f56481fAuthor: Ryan Curtin <ryan@ratml.org> Date: Mon Jul 5 21:53:33 2021 -0400 Remove unnecessary functions. commit30aca349cfAuthor: Ryan Curtin <ryan@ratml.org> Date: Mon Jul 5 19:26:55 2021 -0400 Fix train/test modes. commitffba7a966cAuthor: Ryan Curtin <ryan@ratml.org> Date: Mon Jul 5 18:52:20 2021 -0400 Remove unnecessary utilities. commita3dd3739c6Author: Ryan Curtin <ryan@ratml.org> Date: Mon Jul 5 18:51:18 2021 -0400 Change 'deterministic' to 'training'. commitafa76d6ae8Author: Ryan Curtin <ryan@ratml.org> Date: Sun Jul 4 16:05:47 2021 -0400 Make sure that we save layerOutputs.back() in case we need it later... commit2875194721Author: Ryan Curtin <ryan@ratml.org> Date: Wed Jun 23 19:58:38 2021 -0400 Fix FFNReturnModel test. commit292bfbef9cAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Jun 23 19:32:34 2021 -0400 Serialize deterministic in whatever state it is currently in---no assumptions. commita30e15fca7Author: Ryan Curtin <ryan@ratml.org> Date: Wed Jun 23 19:32:20 2021 -0400 Remove unnecessary output. commit5d27a4d43eAuthor: Ryan Curtin <ryan@ratml.org> Date: Wed Jun 23 19:24:36 2021 -0400 Add the 'MultiLayer', although maybe we can just use the FFN class itself? commitc2b54b7af6Author: Ryan Curtin <ryan@ratml.org> Date: Wed Jun 23 19:24:21 2021 -0400 Set the size correctly in Predict() and fix a few other errors. commit0c307e89deAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Jun 18 14:11:47 2021 -0400 Initialize totalInputSize and totalOutputSize in the right place. commitd2fd462a8cAuthor: Ryan Curtin <ryan@ratml.org> Date: Fri Jun 18 13:51:46 2021 -0400 Use aliases for layer outputs and deltas. commit064cb7b296Author: Ryan Curtin <ryan@ratml.org> Date: Fri Jun 18 12:42:29 2021 -0400 Okay, this passes FFVanillaNetworkTest! commit9a521c8080Author: Ryan Curtin <ryan@ratml.org> Date: Wed Jun 16 14:07:23 2021 -0400 Step 1: something compiles at all. commit5220de7d14Author: Ryan Curtin <ryan@ratml.org> Date: Fri May 28 12:52:21 2021 -0400 Fix some minor compilation issues. commitf8123469e9Author: Ryan Curtin <ryan@ratml.org> Date: Sat May 22 05:27:37 2021 -0400 Add serialization file. commit1b3ea01b45Author: Ryan Curtin <ryan@ratml.org> Date: Sat May 22 05:19:41 2021 -0400 In-progress, does not quite compile yet. commit34cf419bb8Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Jan 31 19:05:00 2021 +0100 Update FFN tests to use the base layer class. commitb700f8d311Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Jan 31 04:36:35 2021 +0100 Update FFN copy/move constructor tests to use the layer base class. commiteafac8609dAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sat Jan 30 04:39:08 2021 +0100 Add Clone() function which handles polymorphism correctly. commit0c4db57106Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Fri Jan 29 10:14:53 2021 +0530 typo fix commit21057324f3Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Thu Jan 28 16:21:27 2021 +0530 add ResetCell and Reward methods to base class and add method to push layer to ffn model commit43e7639e61Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Tue Jan 26 00:47:55 2021 +0100 Use layer base class for the network initialization. commitfadaaa59a2Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Mon Jan 25 00:04:26 2021 +0100 Update layer to use updated layer base class interface. commit3cdd972be8Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Jan 24 23:17:26 2021 +0100 Adjust determenistic parameter interface. commit5b453b712aAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Jan 24 23:14:04 2021 +0100 Add utiliy functions to update layer parameters and states. commitc641bc527cAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Jan 24 23:13:09 2021 +0100 Restructure FFN class to use the layer base class. commit9c29e5b603Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Tue Jan 19 21:17:32 2021 +0530 update weight_norm layer to use abstract class, and some other fixes commit5d62339e02Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Sun Jan 17 18:04:32 2021 +0530 update fast_lstm to use abstract class (without unit test) commitf2f84991ceAuthor: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Sun Jan 17 17:30:36 2021 +0530 migrate vr_class_reward to loss_functions commitecd2fae814Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Sat Jan 16 10:32:18 2021 +0530 update reinforce_normal and reparametrization layer to use abstract class commit826be5b404Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Fri Jan 15 23:29:21 2021 +0530 update virtual_batch_norm to support abstract class commitf694114805Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Fri Jan 15 23:14:22 2021 +0530 update select, subview, padding and transposed convolution to use abstract class commitdfec0f787dAuthor: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Fri Jan 15 18:28:43 2021 +0530 updated sequential layer to use abstract class commitc6675f4ba3Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Fri Jan 15 16:34:30 2021 +0530 update concat and highway layers to use abstract class commit0da7330f01Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Fri Jan 15 09:11:57 2021 +0530 update positional_encoding and multiply_merge layers to use abstract class commitc30d9ed85cAuthor: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Fri Jan 15 07:18:52 2021 +0530 slight style fixes and lexicographical ordering of layer_types commitcfdb84173aAuthor: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Thu Jan 14 11:22:58 2021 +0530 some corrections and updating layer_norm, max_pooling and mean_pooling commit97d865df79Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Thu Jan 14 10:25:47 2021 +0530 correction in convolution and update join and glimpse layer to use abstract class commit270aab791eAuthor: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Thu Jan 14 10:05:39 2021 +0530 update glimpse layer to use abstract class method commit28d56b1693Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Wed Jan 13 10:52:22 2021 +0530 corrected documentation and updated convolution layer commit09e2995346Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Wed Jan 13 09:19:09 2021 +0530 update multihead attention layer commitdd6b70c2f2Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Tue Jan 12 09:34:23 2021 +0530 update concatenate layer commit004818cca2Author: Mrityunjay Tripathi <mrityunjay2668@gmail.com> Date: Mon Jan 11 23:26:42 2021 +0530 update bilinear_interpolation, linear3d, lookup and base_layer commitaef1158187Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Jan 3 23:31:22 2021 +0100 Add Deterministic() to the abstract layer class. commit3f4d24f7f5Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Jan 3 23:06:40 2021 +0100 Update SpatialDropout layer to use the abstract layer class and add typedef. commit5193102f09Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sat Jan 2 20:57:20 2021 +0100 Update PReLU layer to use the abstract layer class and add typedef. commita57d13f838Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sat Jan 2 20:40:07 2021 +0100 Update CELU layer to use the abstract layer class and add typedef. commit47f35337f6Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sat Jan 2 20:25:57 2021 +0100 Update CReLU layer to use the abstract layer class and add typedef. commitcd05cbecd4Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sat Jan 2 18:54:42 2021 +0100 Update MultiplyConstant layer to use the abstract layer class and add typedef. commit8b0abc219aAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Dec 27 22:57:13 2020 +0100 Update Softshrink layer to use the abstract layer class and add typedef. commit8cf621f4fdAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Dec 27 19:57:37 2020 +0100 Update Softmin layer to use the abstract layer class and add typedef. commit3b0318a50dAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Dec 27 17:44:04 2020 +0100 Update Softmax layer to use the abstract layer class and add typedef. commitf4f66af580Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Dec 27 17:23:13 2020 +0100 Update Constant layer to use the abstract layer class and add typedef. commitcebce07398Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Dec 27 16:25:25 2020 +0100 Update LeakyReLU layer to use the abstract layer class and add typedef. commit0217a19b25Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Dec 27 14:39:47 2020 +0100 Update HardShrink layer to use the abstract layer class and add typedef. commit69f0d5b56aAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Dec 27 14:24:29 2020 +0100 Update NoisyLinear layer to use the abstract layer class and add typedef. commitc927971363Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sun Dec 27 13:43:57 2020 +0100 Update LinearNoBias layer to use the abstract layer class and add typedef. commitdea01f7215Author: Aakash kaushik <kaushikaakash7539@gmail.com> Date: Fri Dec 25 22:41:46 2020 +0530 tests pass commit09d905f2e5Author: Aakash kaushik <aakash@pop-os.localdomain> Date: Fri Dec 25 17:28:02 2020 +0530 update adaptive_mean_pooling_layer to use the abstract class and added typedef commita893867f37Author: Aakash kaushik <aakash@pop-os.localdomain> Date: Fri Dec 25 17:27:30 2020 +0530 update adaptive_mean_pooling_layer to use the abstract class and added typedef commit66853d1a5bAuthor: Aakash kaushik <aakash@pop-os.localdomain> Date: Fri Dec 25 16:57:51 2020 +0530 update adaptive_max_pooling_layer to use the abstract class and added typedef commit60afb1e1bcAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Sat Dec 26 01:13:17 2020 +0100 Update Dropconnect layer to use the abstract layer class and add typedef. commit322753be75Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Thu Dec 24 11:57:47 2020 +0100 Update HardTanH layer to use the abstract layer class and add typedef. commit80ecca1356Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Thu Dec 24 11:41:37 2020 +0100 Update Dropout layer to use the abstract layer class and add typedef. commit9acac6838dAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Thu Dec 24 01:23:32 2020 +0100 Update ELU/SELU layer to use the abstract layer class and add typedefs. commit5ea2b93618Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Thu Dec 24 00:59:45 2020 +0100 Update SoftMax layer to use the abstract layer class and add typedef. commit2232915792Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Thu Dec 24 00:39:44 2020 +0100 Update FlexibleReLU layer to use the abstract layer class, add documentation and typedef. commit4fd7ae9da7Author: Marcus Edel <marcus.edel@fu-berlin.de> Date: Thu Dec 24 00:38:25 2020 +0100 Remove functions that are already part of the base class. commita6995f83eeAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Wed Dec 23 17:14:07 2020 +0100 Update Linear layer to use the abstract Layer class and add documentation and typedef. commita3f746580bAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Wed Dec 23 17:12:32 2020 +0100 Clean-up abstract layer class and add some further documentation. commitaa6d2b1aadAuthor: Marcus Edel <marcus.edel@fu-berlin.de> Date: Mon Dec 21 17:23:08 2020 +0100 Swap boost::variant with vtable.
This commit is contained in:
@@ -80,6 +80,7 @@ steps:
|
||||
mkdir build && cd build
|
||||
if [ "$(binding)" == "go" ]; then
|
||||
export GOPATH=$PWD/src/mlpack/bindings/go
|
||||
export GO111MODULE=off
|
||||
go get -u -t gonum.org/v1/gonum/...
|
||||
fi
|
||||
cmake $(CMakeArgs) -DPYTHON_EXECUTABLE=`which python` -DCEREAL_INCLUDE_DIR=/usr/include/ ..
|
||||
|
||||
@@ -33,6 +33,7 @@ steps:
|
||||
mkdir build && cd build
|
||||
if [ "$(binding)" == "go" ]; then
|
||||
export GOPATH=$PWD/src/mlpack/bindings/go
|
||||
export GO111MODULE=off
|
||||
go get -u -t gonum.org/v1/gonum/...
|
||||
fi
|
||||
if [ "$(binding)" == "python" ]; then
|
||||
|
||||
@@ -57,6 +57,7 @@ jobs:
|
||||
run: |
|
||||
remotes::install_deps(dependencies = TRUE)
|
||||
remotes::install_cran("roxygen2")
|
||||
remotes::install_cran("pkgbuild")
|
||||
shell: Rscript {0}
|
||||
|
||||
- name: CMake
|
||||
|
||||
+2
-2
@@ -14,8 +14,8 @@ if (GO_EXECUTABLE)
|
||||
RESULT_VARIABLE RESULT
|
||||
)
|
||||
if (RESULT EQUAL 0)
|
||||
string(REGEX REPLACE ".*([0-9]+\\.[0-9]+\(\\.[0-9]+\)?).*" "\\1"
|
||||
GO_VERSION_STRING ${GO_VERSION_STRING})
|
||||
string(REGEX MATCH "([0-9]+\\.[0-9]+\(\\.[0-9]+\)?)"
|
||||
GO_VERSION_STRING "${GO_VERSION_STRING}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -4,20 +4,21 @@
|
||||
if (GO_EXECUTABLE)
|
||||
execute_process(
|
||||
COMMAND ${GO_EXECUTABLE} list gonum.org/v1/gonum/mat
|
||||
OUTPUT_VARIABLE GONUM_VERSION_STRING
|
||||
OUTPUT_VARIABLE GONUM_RAW_STRING
|
||||
RESULT_VARIABLE RESULT
|
||||
)
|
||||
if (RESULT EQUAL 0)
|
||||
string(REGEX REPLACE ".*([0-9]+\\.[0-9]+\\.[0-9]+[\n]+).*" "\\1"
|
||||
GONUM_VERSION_STRING ${GONUM_VERSION_STRING})
|
||||
string(REGEX REPLACE "\n$" ""
|
||||
GONUM_VERSION_STRING ${GONUM_VERSION_STRING})
|
||||
GONUM_RAW_STRING ${GONUM_RAW_STRING})
|
||||
if ("${GONUM_RAW_STRING}" STREQUAL "gonum.org/v1/gonum/mat")
|
||||
set(GONUM_FOUND 1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(
|
||||
Gonum
|
||||
REQUIRED_VARS GONUM_VERSION_STRING
|
||||
REQUIRED_VARS GONUM_FOUND
|
||||
FAIL_MESSAGE "Gonum not found"
|
||||
)
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ Source:
|
||||
|
||||
Files: *
|
||||
Copyright:
|
||||
Copyright 2008-2021, Ryan Curtin <ryan@ratml.org>
|
||||
Copyright 2008-2022, Ryan Curtin <ryan@ratml.org>
|
||||
Copyright 2008-2013, Bill March <march@gatech.edu>
|
||||
Copyright 2008-2012, Dongryeol Lee <dongryel@cc.gatech.edu>
|
||||
Copyright 2008-2013, Nishant Mehta <niche@cc.gatech.edu>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
### mlpack ?.?.?
|
||||
###### ????-??-??
|
||||
* Fix `Perceptron` to work with cross-validation framework (#3190).
|
||||
|
||||
* Migrate from boost tests to Catch2 framework (#2523), (#2584).
|
||||
|
||||
* Bump minimum armadillo version from 8.400 to 9.800 (#3043), (#3048).
|
||||
|
||||
@@ -6,18 +6,14 @@
|
||||
# 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.
|
||||
import sys
|
||||
import sysconfig
|
||||
import shutil
|
||||
import os
|
||||
import glob
|
||||
|
||||
directory = 'build/lib.' + \
|
||||
sysconfig.get_platform() + \
|
||||
'-' + \
|
||||
str(sys.version_info[0]) + \
|
||||
'.' + \
|
||||
str(sys.version_info[1]) + \
|
||||
'/mlpack/'
|
||||
# Match any lib.$platform*/mlpack/ directory.
|
||||
directory = glob.glob('build/lib.' + sysconfig.get_platform() + '*/mlpack/')[0]
|
||||
directory = directory.replace('\\', '/')
|
||||
|
||||
# Now copy all the files from the directory to the desired location.
|
||||
for f in os.listdir(directory):
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace python {
|
||||
template<typename T>
|
||||
inline bool IsSerializable(
|
||||
util::ParamData& /* d */,
|
||||
const typename boost::disable_if<data::HasSerialize<T>>::type* = 0)
|
||||
const typename std::enable_if<!data::HasSerialize<T>::value>::type* = 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -29,7 +29,7 @@ inline bool IsSerializable(
|
||||
template<typename T>
|
||||
inline bool IsSerializable(
|
||||
util::ParamData& /* d */,
|
||||
const typename boost::enable_if<data::HasSerialize<T>>::type* = 0)
|
||||
const typename std::enable_if<data::HasSerialize<T>::value>::type* = 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ set(SOURCES
|
||||
pair_associative_container.hpp
|
||||
pointer_wrapper.hpp
|
||||
pointer_vector_wrapper.hpp
|
||||
pointer_variant_wrapper.hpp
|
||||
pointer_vector_variant_wrapper.hpp
|
||||
unordered_map.hpp
|
||||
)
|
||||
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/**
|
||||
* @file core/cereal/pointer_variant_wrapper.hpp
|
||||
* @author Omar Shrit
|
||||
*
|
||||
* Implementation of a boost::variant wrapper to enable the serialization of
|
||||
* the pointers inside boost variant in cereal
|
||||
*
|
||||
* 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 MLPACK_CORE_CEREAL_POINTER_VARIANT_WRAPPER_HPP
|
||||
#define MLPACK_CORE_CEREAL_POINTER_VARIANT_WRAPPER_HPP
|
||||
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <cereal/archives/portable_binary.hpp>
|
||||
#include <cereal/archives/xml.hpp>
|
||||
#include <cereal/types/boost_variant.hpp>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/variant/variant_fwd.hpp>
|
||||
#include <boost/variant/static_visitor.hpp>
|
||||
|
||||
#include "pointer_wrapper.hpp"
|
||||
|
||||
namespace cereal {
|
||||
|
||||
// Forward declaration.
|
||||
template<typename... VariantTypes>
|
||||
class PointerVariantWrapper;
|
||||
|
||||
/**
|
||||
* Serialize a boost variant in which the variant it self is a raw pointer.
|
||||
* This wrapper will wrap each variant independently by encapsulating each variant
|
||||
* into the PoninterWrapper we have created already.
|
||||
*
|
||||
* @param t A reference to boost variant that holds raw pointer.
|
||||
*/
|
||||
template<typename... VariantTypes>
|
||||
inline PointerVariantWrapper<VariantTypes...>
|
||||
make_pointer_variant(boost::variant<VariantTypes...>& t)
|
||||
{
|
||||
return PointerVariantWrapper<VariantTypes...>(t);
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
struct save_visitor : public boost::static_visitor<void>
|
||||
{
|
||||
save_visitor(Archive& ar) : ar(ar) {}
|
||||
|
||||
template<class T>
|
||||
void operator()(const T* value) const
|
||||
{
|
||||
ar(CEREAL_POINTER(value));
|
||||
}
|
||||
|
||||
template<typename... Types>
|
||||
void operator()(boost::variant<Types*...>& value) const
|
||||
{
|
||||
ar(make_pointer_variant(value));
|
||||
}
|
||||
|
||||
Archive& ar;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct load_visitor : public boost::static_visitor<void>
|
||||
{
|
||||
template<typename Archive, typename VariantType>
|
||||
static void load_impl(Archive& ar, VariantType& variant, std::true_type)
|
||||
{
|
||||
// Note that T will be a pointer type.
|
||||
T loadVariant;
|
||||
ar(CEREAL_POINTER(loadVariant));
|
||||
variant = loadVariant;
|
||||
}
|
||||
|
||||
template<typename Archive, typename VariantType>
|
||||
static void load_impl(Archive& ar, VariantType& value, std::false_type)
|
||||
{
|
||||
// This must be a nested boost::variant.
|
||||
T loadVariant;
|
||||
ar(make_pointer_variant(loadVariant));
|
||||
value = loadVariant;
|
||||
}
|
||||
|
||||
template<typename Archive, typename VariantType>
|
||||
static void load(Archive& ar, VariantType& variant)
|
||||
{
|
||||
// Delegate to the proper load_impl() overload depending on whether T is a
|
||||
// pointer type. If T is not a pointer type, then we expect it to be a
|
||||
// nested boost::variant.
|
||||
load_impl(ar, variant, typename std::is_pointer<T>::type());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The objective of this class is to create a wrapper for
|
||||
* boost::variant.
|
||||
* Cereal supports the serialization of boost::variant, but
|
||||
* we need to serialize it if it holds a raw pointers.
|
||||
* This class depeds on the PointerWrapper we have already created in which it is
|
||||
* used to serialize each variant independently
|
||||
*/
|
||||
template<typename... VariantTypes>
|
||||
class PointerVariantWrapper
|
||||
{
|
||||
public:
|
||||
PointerVariantWrapper(boost::variant<VariantTypes...>& pointerVar) :
|
||||
pointerVariant(pointerVar)
|
||||
{}
|
||||
|
||||
template<class Archive>
|
||||
void save(Archive& ar) const
|
||||
{
|
||||
// which represents the index in std::variant.
|
||||
int which = pointerVariant.which();
|
||||
ar(CEREAL_NVP(which));
|
||||
save_visitor<Archive> s(ar);
|
||||
boost::apply_visitor(s, pointerVariant);
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive& ar)
|
||||
{
|
||||
// Load the size of the serialized type.
|
||||
int which;
|
||||
ar(CEREAL_NVP(which));
|
||||
|
||||
// Create function pointers to each overload of load_visitor<T>::load, for
|
||||
// all T in VariantTypes.
|
||||
using LoadFuncType = void(*)(Archive&, boost::variant<VariantTypes...>&);
|
||||
LoadFuncType loadFuncArray[] = { &load_visitor<VariantTypes>::load... };
|
||||
|
||||
if (which >= int(sizeof(loadFuncArray)/sizeof(loadFuncArray[0])))
|
||||
throw std::runtime_error("Invalid 'which' selector when"
|
||||
"deserializing boost::variant");
|
||||
|
||||
loadFuncArray[which](ar, pointerVariant);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::variant<VariantTypes...>& pointerVariant;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cereal does not support the serialization of raw pointer.
|
||||
* This macro enable developers to serialize boost::variant that holds raw
|
||||
* pointers by using the above PointerVariantWrapper class which replace the
|
||||
* internal raw pointers by smart pointer internally.
|
||||
*
|
||||
* @param T boost::variant that holds raw pointer to be serialized.
|
||||
*/
|
||||
#define CEREAL_VARIANT_POINTER(T) cereal::make_pointer_variant(T)
|
||||
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_POINTER_VARIANT_WRAPPER_HPP
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
* @file core/cereal/pointer_vector_variant_wrapper.hpp
|
||||
* @author Omar Shrit
|
||||
*
|
||||
* Implementation of a boost::variant wrapper to enable the serialization of
|
||||
* the pointers inside boost variant in cereal
|
||||
*
|
||||
* 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 MLPACK_CORE_CEREAL_POINTER_VECTOR_VARIANT_WRAPPER_HPP
|
||||
#define MLPACK_CORE_CEREAL_POINTER_VECTOR_VARIANT_WRAPPER_HPP
|
||||
|
||||
#include "pointer_wrapper.hpp"
|
||||
#include "pointer_variant_wrapper.hpp"
|
||||
#include "pointer_vector_wrapper.hpp"
|
||||
|
||||
namespace cereal {
|
||||
|
||||
// Forward declaration
|
||||
template<typename... VariantTypes>
|
||||
class PointerVectorVariantWrapper;
|
||||
|
||||
/**
|
||||
* Serialize a std::vector of boost variants in which the variant in each boost
|
||||
* variant is a raw pointer.
|
||||
* This wrapper will wrap each boost variant independently by encapsulating each
|
||||
* boost variant into the PoninterVariantWrapper we have created already.
|
||||
*
|
||||
* @param t A reference to a vector of boost variants that holds raw pointer.
|
||||
*/
|
||||
template<typename... VariantTypes>
|
||||
inline PointerVectorVariantWrapper<VariantTypes...>
|
||||
make_vector_pointer_variant(std::vector<boost::variant<VariantTypes...>>& t)
|
||||
{
|
||||
return PointerVectorVariantWrapper<VariantTypes...>(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* The objective of this class is to create a wrapper for
|
||||
* a vector of boost::variant that holds pointer.
|
||||
* Cereal supports the serialization of boost::variant, but
|
||||
* we need to serialize it if it holds a vector of boost::variant that holds a
|
||||
* pointers.
|
||||
*/
|
||||
template<typename... VariantTypes>
|
||||
class PointerVectorVariantWrapper
|
||||
{
|
||||
public:
|
||||
PointerVectorVariantWrapper(
|
||||
std::vector<boost::variant<VariantTypes...>>& vecPointerVar)
|
||||
: vectorPointerVariant(vecPointerVar)
|
||||
{}
|
||||
|
||||
template<class Archive>
|
||||
void save(Archive& ar) const
|
||||
{
|
||||
size_t vecSize = vectorPointerVariant.size();
|
||||
ar(CEREAL_NVP(vecSize));
|
||||
for (size_t i = 0; i < vectorPointerVariant.size(); ++i)
|
||||
{
|
||||
ar(CEREAL_VARIANT_POINTER(vectorPointerVariant.at(i)));
|
||||
}
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive& ar)
|
||||
{
|
||||
size_t vecSize = 0;
|
||||
ar(CEREAL_NVP(vecSize));
|
||||
vectorPointerVariant.resize(vecSize);
|
||||
for (size_t i = 0; i < vectorPointerVariant.size(); ++i)
|
||||
{
|
||||
ar(CEREAL_VARIANT_POINTER(vectorPointerVariant.at(i)));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<boost::variant<VariantTypes...>>& vectorPointerVariant;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cereal does not support the serialization of raw pointer.
|
||||
* This macro enable developers to serialize a std vector that holds boost::variants
|
||||
* that holds raw pointers by using the above PointerVectorVariantWrapper class
|
||||
* which replace the internal raw pointers by smart pointer internally.
|
||||
*
|
||||
* @param T std::vector<boost::variant> that holds raw pointer to be serialized.
|
||||
*/
|
||||
#define CEREAL_VECTOR_VARIANT_POINTER(T) cereal::make_vector_pointer_variant(T)
|
||||
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_POINTER_VECTOR_VARIANT_WRAPPER_HPP
|
||||
|
||||
@@ -26,18 +26,27 @@ namespace util {
|
||||
* error generation.
|
||||
* @param addInfo Name to use for labels for precise error generation. Default
|
||||
* is "labels"; for example, "weights" could also be used.
|
||||
* @param isDataTranspose Bool parameter which can be set true to transpose data
|
||||
* before size-check. Default is false.
|
||||
* @param isLabelTranspose Bool parameter which can be set true to transpose label
|
||||
* before size-check. Default is false.
|
||||
*/
|
||||
template<typename DataType, typename LabelsType>
|
||||
inline void CheckSameSizes(const DataType& data,
|
||||
const LabelsType& label,
|
||||
const std::string& callerDescription,
|
||||
const std::string& addInfo = "labels")
|
||||
{
|
||||
if (data.n_cols != label.n_cols)
|
||||
const std::string& addInfo = "labels",
|
||||
const bool& isDataTranspose = false,
|
||||
const bool& isLabelTranspose = false)
|
||||
{
|
||||
const size_t dataPoints = (isDataTranspose == true) ? data.n_rows : data.n_cols;
|
||||
const size_t labelPoints = (isLabelTranspose == true) ? label.n_rows : label.n_cols;
|
||||
|
||||
if (dataPoints != labelPoints)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << callerDescription << ": number of points (" << data.n_cols << ") "
|
||||
<< "does not match number of " << addInfo << " (" << label.n_cols
|
||||
oss << callerDescription << ": number of points (" << dataPoints << ") "
|
||||
<< "does not match number of " << addInfo << " (" << labelPoints
|
||||
<< ")!" << std::endl;
|
||||
throw std::invalid_argument(oss.str());
|
||||
}
|
||||
|
||||
@@ -3,24 +3,17 @@
|
||||
set(SOURCES
|
||||
ffn.hpp
|
||||
ffn_impl.hpp
|
||||
forward_decls.hpp
|
||||
make_alias.hpp
|
||||
rnn.hpp
|
||||
rnn_impl.hpp
|
||||
brnn.hpp
|
||||
brnn_impl.hpp
|
||||
layer_names.hpp
|
||||
)
|
||||
|
||||
add_subdirectory(visitor)
|
||||
add_subdirectory(activation_functions)
|
||||
add_subdirectory(init_rules)
|
||||
add_subdirectory(layer)
|
||||
add_subdirectory(loss_functions)
|
||||
add_subdirectory(convolution_rules)
|
||||
add_subdirectory(gan)
|
||||
add_subdirectory(rbm)
|
||||
add_subdirectory(augmented)
|
||||
add_subdirectory(regularizer)
|
||||
add_subdirectory(util)
|
||||
|
||||
# Add directory name to sources.
|
||||
set(DIR_SRCS)
|
||||
|
||||
@@ -57,9 +57,15 @@ class NaiveConvolution
|
||||
const size_t dilationW = 1,
|
||||
const size_t dilationH = 1)
|
||||
{
|
||||
output = arma::zeros<arma::Mat<eT> >(
|
||||
(input.n_rows - (filter.n_rows - 1) * dilationW - 1) / dW + 1,
|
||||
(input.n_cols - (filter.n_cols - 1) * dilationH - 1) / dH + 1);
|
||||
// Compute the output size. The filterRows and filterCols computation must
|
||||
// take into account the fact that dilation only adds rows or columns
|
||||
// *between* filter elements. So, e.g., a dilation of 2 on a kernel size of
|
||||
// 3x3 means an effective kernel size of 5x5, *not* 6x6.
|
||||
const size_t filterRows = filter.n_rows * dilationH - (dilationH - 1);
|
||||
const size_t filterCols = filter.n_cols * dilationW - (dilationW - 1);
|
||||
const size_t outputRows = (input.n_rows - filterRows + dH) / dH;
|
||||
const size_t outputCols = (input.n_cols - filterCols + dW) / dW;
|
||||
output.zeros(outputRows, outputCols);
|
||||
|
||||
// It seems to be about 3.5 times faster to use pointers instead of
|
||||
// filter(ki, kj) * input(leftInput + ki, topInput + kj) and output(i, j).
|
||||
@@ -103,37 +109,22 @@ class NaiveConvolution
|
||||
const size_t dilationW = 1,
|
||||
const size_t dilationH = 1)
|
||||
{
|
||||
size_t outputRows = (input.n_rows - 1) * dW + 2 * (filter.n_rows - 1)
|
||||
* dilationW + 1;
|
||||
size_t outputCols = (input.n_cols - 1) * dH + 2 * (filter.n_cols - 1)
|
||||
* dilationH + 1;
|
||||
|
||||
for (size_t i = 0; i < dW; ++i)
|
||||
{
|
||||
if (((((i + outputRows - 2 * (filter.n_rows - 1) * dilationW - 1) % dW)
|
||||
+ dW) % dW) == i){
|
||||
outputRows += i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < dH; ++i)
|
||||
{
|
||||
if (((((i + outputCols - 2 * (filter.n_cols - 1) * dilationH - 1) % dH)
|
||||
+ dH) % dH) == i){
|
||||
outputCols += i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// First, compute the necessary padding for the full convolution. It is
|
||||
// possible that this might be an overestimate. Note that these variables
|
||||
// only hold the padding on one side of the input.
|
||||
const size_t filterRows = filter.n_rows * dilationH - (dilationH - 1);
|
||||
const size_t filterCols = filter.n_cols * dilationW - (dilationW - 1);
|
||||
const size_t paddingRows = filterRows - 1;
|
||||
const size_t paddingCols = filterCols - 1;
|
||||
|
||||
// Pad filter and input to the working output shape.
|
||||
arma::Mat<eT> inputPadded = arma::zeros<arma::Mat<eT> >(outputRows,
|
||||
outputCols);
|
||||
inputPadded.submat((filter.n_rows - 1) * dilationW, (filter.n_cols - 1)
|
||||
* dilationH, (filter.n_rows - 1) * dilationW + input.n_rows - 1,
|
||||
(filter.n_cols - 1) * dilationH + input.n_cols - 1) = input;
|
||||
arma::Mat<eT> inputPadded(input.n_rows + 2 * paddingRows,
|
||||
input.n_cols + 2 * paddingCols, arma::fill::zeros);
|
||||
inputPadded.submat(paddingRows, paddingCols, paddingRows + input.n_rows - 1,
|
||||
paddingCols + input.n_cols - 1) = input;
|
||||
|
||||
NaiveConvolution<ValidConvolution>::Convolution(inputPadded, filter,
|
||||
output, 1, 1, dilationW, dilationH);
|
||||
output, dW, dH, dilationW, dilationH);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+359
-327
@@ -15,46 +15,49 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "visitor/delete_visitor.hpp"
|
||||
#include "visitor/delta_visitor.hpp"
|
||||
#include "visitor/output_height_visitor.hpp"
|
||||
#include "visitor/output_parameter_visitor.hpp"
|
||||
#include "visitor/output_width_visitor.hpp"
|
||||
#include "visitor/reset_visitor.hpp"
|
||||
#include "visitor/weight_size_visitor.hpp"
|
||||
#include "visitor/copy_visitor.hpp"
|
||||
#include "visitor/loss_visitor.hpp"
|
||||
|
||||
#include "forward_decls.hpp"
|
||||
#include "init_rules/network_init.hpp"
|
||||
|
||||
#include <mlpack/methods/ann/layer/layer_types.hpp>
|
||||
#include <mlpack/methods/ann/layer/layer.hpp>
|
||||
#include <mlpack/methods/ann/layer/multi_layer.hpp>
|
||||
#include <mlpack/methods/ann/init_rules/random_init.hpp>
|
||||
#include <mlpack/methods/ann/layer/layer_traits.hpp>
|
||||
#include <mlpack/methods/ann/loss_functions/negative_log_likelihood.hpp>
|
||||
#include <ensmallen.hpp>
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
/**
|
||||
* Implementation of a standard feed forward network.
|
||||
* Implementation of a standard feed forward network. Any layer that inherits
|
||||
* from the base `Layer` class can be added to this model. For recursive neural
|
||||
* networks, see the `RNN` class.
|
||||
*
|
||||
* In general, a network can be created by using the `Add()` method to add
|
||||
* layers to the network. Then, training can be performed with `Train()`, and
|
||||
* data points can be passed through the trained network with `Predict()`.
|
||||
*
|
||||
* Although the actual types passed as input will be matrix objects with one
|
||||
* data point per column, each data point can be a tensor of arbitrary shape.
|
||||
* If data points are not 1-dimensional vectors, then set the shape of the input
|
||||
* with `InputDimensions()` before calling `Train()`.
|
||||
*
|
||||
* More granular functionality is available with `Forward()`, Backward()`, and
|
||||
* `Evaluate()`, or even by accessing the individual layers directly with
|
||||
* `Network()`.
|
||||
*
|
||||
* @tparam OutputLayerType The output layer type used to evaluate the network.
|
||||
* @tparam InitializationRuleType Rule used to initialize the weight matrix.
|
||||
* @tparam CustomLayers Any set of custom layers that could be a part of the
|
||||
* feed forward network.
|
||||
* @tparam MatType Type of matrix to be given as input to the network.
|
||||
* @tparam MatType Type of matrix to be produced as output from the last
|
||||
* layer.
|
||||
*/
|
||||
template<
|
||||
typename OutputLayerType = NegativeLogLikelihood<>,
|
||||
typename InitializationRuleType = RandomInitialization,
|
||||
typename... CustomLayers
|
||||
>
|
||||
typename OutputLayerType = NegativeLogLikelihood,
|
||||
typename InitializationRuleType = RandomInitialization,
|
||||
typename MatType = arma::mat>
|
||||
class FFN
|
||||
{
|
||||
public:
|
||||
//! Convenience typedef for the internal model construction.
|
||||
using NetworkType = FFN<OutputLayerType, InitializationRuleType>;
|
||||
|
||||
/**
|
||||
* Create the FFN object.
|
||||
*
|
||||
@@ -72,56 +75,73 @@ class FFN
|
||||
InitializationRuleType initializeRule = InitializationRuleType());
|
||||
|
||||
//! Copy constructor.
|
||||
FFN(const FFN&);
|
||||
|
||||
FFN(const FFN& other);
|
||||
//! Move constructor.
|
||||
FFN(FFN&&);
|
||||
|
||||
//! Copy/move assignment operator.
|
||||
FFN& operator = (FFN);
|
||||
|
||||
//! Destructor to release allocated memory.
|
||||
~FFN();
|
||||
FFN(FFN&& other);
|
||||
//! Copy operator.
|
||||
FFN& operator=(const FFN& other);
|
||||
//! Move assignment operator.
|
||||
FFN& operator=(FFN&& other);
|
||||
|
||||
/**
|
||||
* Check if the optimizer has MaxIterations() parameter, if it does
|
||||
* then check if it's value is less than the number of datapoints
|
||||
* in the dataset.
|
||||
* Add a new layer to the model.
|
||||
*
|
||||
* @tparam OptimizerType Type of optimizer to use to train the model.
|
||||
* @param optimizer optimizer used in the training process.
|
||||
* @param samples Number of datapoints in the dataset.
|
||||
* @param args The layer parameter.
|
||||
*/
|
||||
template<typename OptimizerType>
|
||||
typename std::enable_if<
|
||||
HasMaxIterations<OptimizerType, size_t&(OptimizerType::*)()>
|
||||
::value, void>::type
|
||||
WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const;
|
||||
template <typename LayerType, typename... Args>
|
||||
void Add(Args... args)
|
||||
{
|
||||
network.template Add<LayerType>(args...);
|
||||
inputDimensionsAreSet = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the optimizer has MaxIterations() parameter, if it
|
||||
* doesn't then simply return from the function.
|
||||
* Add a new layer to the model. Note that any trainable weights of this
|
||||
* layer will be reset! (Any constant parameters are kept.)
|
||||
*
|
||||
* @tparam OptimizerType Type of optimizer to use to train the model.
|
||||
* @param optimizer optimizer used in the training process.
|
||||
* @param samples Number of datapoints in the dataset.
|
||||
* @param layer The Layer to be added to the model.
|
||||
*/
|
||||
template<typename OptimizerType>
|
||||
typename std::enable_if<
|
||||
!HasMaxIterations<OptimizerType, size_t&(OptimizerType::*)()>
|
||||
::value, void>::type
|
||||
WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const;
|
||||
void Add(Layer<MatType>* layer)
|
||||
{
|
||||
network.Add(layer);
|
||||
inputDimensionsAreSet = false;
|
||||
}
|
||||
|
||||
//! Get the layers of the network.
|
||||
const std::vector<Layer<MatType>*>& Network() const
|
||||
{
|
||||
return network.Network();
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the network model. Be careful! If you change the structure of the
|
||||
* network or parameters for layers, its state may become invalid, and the
|
||||
* next time it is used for any operation the parameters will be reset.
|
||||
*
|
||||
* Don't add any layers like this; use `Add()` instead.
|
||||
*/
|
||||
std::vector<Layer<MatType>*>& Network()
|
||||
{
|
||||
// We can no longer make any assumptions... the user may change anything.
|
||||
inputDimensionsAreSet = false;
|
||||
layerMemoryIsSet = false;
|
||||
|
||||
return network.Network();
|
||||
}
|
||||
|
||||
/**
|
||||
* Train the feedforward network on the given input data using the given
|
||||
* optimizer.
|
||||
*
|
||||
* This will use the existing model parameters as a starting point for the
|
||||
* optimization. If this is not what you want, then you should access the
|
||||
* parameters vector directly with Parameters() and modify it as desired.
|
||||
* If no parameters have ever been set (e.g. if `Parameters()` is an empty
|
||||
* matrix), or if the parameters' size does not match the number of weights
|
||||
* needed for the current input size (as given by `predictors` and optionally
|
||||
* set further by `InputDimensions()`), then the network will be initialized
|
||||
* using `InitializeRuleType`.
|
||||
*
|
||||
* If you want to pass in a parameter and discard the original parameter
|
||||
* object, be sure to use std::move to avoid unnecessary copy.
|
||||
* If parameters are the right size for the given `predictors` and
|
||||
* `InputDimensions()`, then the existing parameters will be used as a
|
||||
* starting point. (If you want to reinitialize, first call `Reset()`.)
|
||||
*
|
||||
* @tparam OptimizerType Type of optimizer to use to train the model.
|
||||
* @tparam CallbackTypes Types of Callback Functions.
|
||||
@@ -133,22 +153,25 @@ class FFN
|
||||
* @return The final objective of the trained model (NaN or Inf on error).
|
||||
*/
|
||||
template<typename OptimizerType, typename... CallbackTypes>
|
||||
double Train(arma::mat predictors,
|
||||
arma::mat responses,
|
||||
OptimizerType& optimizer,
|
||||
CallbackTypes&&... callbacks);
|
||||
typename MatType::elem_type Train(MatType predictors,
|
||||
MatType responses,
|
||||
OptimizerType& optimizer,
|
||||
CallbackTypes&&... callbacks);
|
||||
|
||||
/**
|
||||
* Train the feedforward network on the given input data. By default, the
|
||||
* RMSProp optimization algorithm is used, but others can be specified
|
||||
* (such as ens::SGD).
|
||||
*
|
||||
* This will use the existing model parameters as a starting point for the
|
||||
* optimization. If this is not what you want, then you should access the
|
||||
* parameters vector directly with Parameters() and modify it as desired.
|
||||
* If no parameters have ever been set (e.g. if `Parameters()` is an empty
|
||||
* matrix), or if the parameters' size does not match the number of weights
|
||||
* needed for the current input size (as given by `predictors` and optionally
|
||||
* set further by `InputDimensions()`), then the network will be initialized
|
||||
* using `InitializeRuleType`.
|
||||
*
|
||||
* If you want to pass in a parameter and discard the original parameter
|
||||
* object, be sure to use std::move to avoid unnecessary copy.
|
||||
* If parameters are the right size for the given `predictors` and
|
||||
* `InputDimensions()`, then the existing parameters will be used as a
|
||||
* starting point. (If you want to reinitialize, first call `Reset()`.)
|
||||
*
|
||||
* @tparam OptimizerType Type of optimizer to use to train the model.
|
||||
* @param predictors Input training variables.
|
||||
@@ -159,22 +182,123 @@ class FFN
|
||||
* @return The final objective of the trained model (NaN or Inf on error).
|
||||
*/
|
||||
template<typename OptimizerType = ens::RMSProp, typename... CallbackTypes>
|
||||
double Train(arma::mat predictors,
|
||||
arma::mat responses,
|
||||
CallbackTypes&&... callbacks);
|
||||
typename MatType::elem_type Train(MatType predictors,
|
||||
MatType responses,
|
||||
CallbackTypes&&... callbacks);
|
||||
|
||||
/**
|
||||
* Predict the responses to a given set of predictors. The responses will
|
||||
* reflect the output of the given output layer as returned by the
|
||||
* output layer function.
|
||||
*
|
||||
* If you want to pass in a parameter and discard the original parameter
|
||||
* object, be sure to use std::move to avoid unnecessary copy.
|
||||
* Predict the responses to a given set of predictors. The responses will be
|
||||
* the output of the output layer when `predictors` is passed through the
|
||||
* whole network (`OutputLayerType`).
|
||||
*
|
||||
* @param predictors Input predictors.
|
||||
* @param results Matrix to put output predictions of responses into.
|
||||
* @param batchSize Batch size to use for prediction.
|
||||
*/
|
||||
void Predict(arma::mat predictors, arma::mat& results);
|
||||
void Predict(MatType predictors,
|
||||
MatType& results,
|
||||
const size_t batchSize = 128);
|
||||
|
||||
// Return the number of weights in the model.
|
||||
size_t WeightSize();
|
||||
|
||||
/**
|
||||
* Set the logical dimensions of the input. `Train()` and `Predict()` expect
|
||||
* data to be passed such that one point corresponds to one column, but this
|
||||
* data is allowed to be an arbitrary higher-order tensor.
|
||||
*
|
||||
* So, if the input is meant to be 28x28x3 images, then the
|
||||
* input data to `Train()` or `Predict()` should have 28*28*3 = 2352 rows, and
|
||||
* `InputDimensions()` should be set to `{ 28, 28, 3 }`. Then, the layers of
|
||||
* the network will interpret each input point as a 3-dimensional image
|
||||
* instead of a 1-dimensional vector.
|
||||
*
|
||||
* If `InputDimensions()` is left unset before training, the data will be
|
||||
* assumed to be a 1-dimensional vector.
|
||||
*/
|
||||
std::vector<size_t>& InputDimensions()
|
||||
{
|
||||
// The user may change the input dimensions, so we will have to propagate
|
||||
// these changes to the network.
|
||||
inputDimensionsAreSet = false;
|
||||
return inputDimensions;
|
||||
}
|
||||
//! Get the logical dimensions of the input.
|
||||
const std::vector<size_t>& InputDimensions() const { return inputDimensions; }
|
||||
|
||||
//! Return the current set of weights. These are linearized: this contains
|
||||
//! the weights of every layer.
|
||||
const MatType& Parameters() const { return parameters; }
|
||||
//! Modify the current set of weights. These are linearized: this contains
|
||||
//! the weights of every layer. Be careful! If you change the shape of
|
||||
//! `parameters` to something incorrect, it may be re-initialized the next
|
||||
//! time a forward pass is done.
|
||||
MatType& Parameters() { return parameters; }
|
||||
|
||||
/**
|
||||
* Reset the stored data of the network entirely. This resets all weights of
|
||||
* each layer using `InitializationRuleType`, and prepares the network to
|
||||
* accept a (flat 1-d) input size of `inputDimensionality` (if passed), or
|
||||
* whatever input size has been set with `InputDimensions()`.
|
||||
*
|
||||
* This also resets the mode of the network to prediction mode (not training
|
||||
* mode). See `SetNetworkMode()` for more information.
|
||||
*/
|
||||
void Reset(const size_t inputDimensionality = 0);
|
||||
|
||||
/**
|
||||
* Set all the layers in the network to training mode, if `training` is
|
||||
* `true`, or set all the layers in the network to testing mode, if `training`
|
||||
* is `false`.
|
||||
*/
|
||||
void SetNetworkMode(const bool training);
|
||||
|
||||
/**
|
||||
* Perform a manual forward pass of the data.
|
||||
*
|
||||
* `Forward()` and `Backward()` should be used as a pair, and they are
|
||||
* designed mainly for advanced users. You should try to use `Predict()` and
|
||||
* `Train()`, if you can.
|
||||
*
|
||||
* @param inputs The input data.
|
||||
* @param results The predicted results.
|
||||
*/
|
||||
void Forward(const MatType& inputs, MatType& results);
|
||||
|
||||
/**
|
||||
* Perform a manual partial forward pass of the data.
|
||||
*
|
||||
* This function is meant for the cases when users require a forward pass only
|
||||
* through certain layers and not the entire network. `Forward()` and
|
||||
* `Backward()` should be used as a pair, and they are designed mainly for
|
||||
* advanced users. You should try to use `Predict()` and `Train()`, if you
|
||||
* can.
|
||||
*
|
||||
* @param inputs The input data for the specified first layer.
|
||||
* @param results The predicted results from the specified last layer.
|
||||
* @param begin The index of the first layer.
|
||||
* @param end The index of the last layer.
|
||||
*/
|
||||
void Forward(const MatType& inputs,
|
||||
MatType& results,
|
||||
const size_t begin,
|
||||
const size_t end);
|
||||
|
||||
/**
|
||||
* Perform a manual backward pass of the data.
|
||||
*
|
||||
* `Forward()` and `Backward()` should be used as a pair, and they are
|
||||
* designed mainly for advanced users. You should try to use `Predict()` and
|
||||
* `Train()` instead, if you can.
|
||||
*
|
||||
* @param inputs Inputs of current pass.
|
||||
* @param targets The training target.
|
||||
* @param gradients Computed gradients.
|
||||
* @return Training error of the current pass.
|
||||
*/
|
||||
typename MatType::elem_type Backward(const MatType& inputs,
|
||||
const MatType& targets,
|
||||
MatType& gradients);
|
||||
|
||||
/**
|
||||
* Evaluate the feedforward network with the given predictors and responses.
|
||||
@@ -183,41 +307,38 @@ class FFN
|
||||
* @param predictors Input variables.
|
||||
* @param responses Target outputs for input variables.
|
||||
*/
|
||||
template<typename PredictorsType, typename ResponsesType>
|
||||
double Evaluate(const PredictorsType& predictors,
|
||||
const ResponsesType& responses);
|
||||
typename MatType::elem_type Evaluate(const MatType& predictors,
|
||||
const MatType& responses);
|
||||
|
||||
//! Serialize the model.
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
//
|
||||
// Only ensmallen utility functions for training are found below here.
|
||||
// They aren't generally useful otherwise.
|
||||
//
|
||||
|
||||
/**
|
||||
* Evaluate the feedforward network with the given parameters. This function
|
||||
* is usually called by the optimizer to train the model.
|
||||
* Note: this function is implemented so that it can be used by ensmallen's
|
||||
* optimizers. It's not generally meant to be used otherwise.
|
||||
*
|
||||
* Evaluate the feedforward network with the given parameters.
|
||||
*
|
||||
* @param parameters Matrix model parameters.
|
||||
*/
|
||||
double Evaluate(const arma::mat& parameters);
|
||||
typename MatType::elem_type Evaluate(const MatType& parameters);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Note: this function is implemented so that it can be used by ensmallen's
|
||||
* optimizers. It's not generally meant to be used otherwise.
|
||||
*
|
||||
* Evaluate the feedforward network with the given parameters, but using only
|
||||
* a number of data points. This is useful for optimizers such as SGD, which
|
||||
* require a separable objective function.
|
||||
*
|
||||
* @param parameters Matrix model parameters.
|
||||
* @param begin Index of the starting point to use for objective function
|
||||
* evaluation.
|
||||
* @param batchSize Number of points to be passed at a time to use for
|
||||
* objective function evaluation.
|
||||
* @param deterministic Whether or not to train or test the model. Note some
|
||||
* layer act differently in training or testing mode.
|
||||
*/
|
||||
double Evaluate(const arma::mat& parameters,
|
||||
const size_t begin,
|
||||
const size_t batchSize,
|
||||
const bool deterministic);
|
||||
|
||||
/**
|
||||
* Evaluate the feedforward network with the given parameters, but using only
|
||||
* a number of data points. This is useful for optimizers such as SGD, which
|
||||
* require a separable objective function. This just calls the overload of
|
||||
* Evaluate() with deterministic = true.
|
||||
* Note that the network may return different results depending on the mode it
|
||||
* is in (see `SetNetworkMode()`).
|
||||
*
|
||||
* @param parameters Matrix model parameters.
|
||||
* @param begin Index of the starting point to use for objective function
|
||||
@@ -225,11 +346,14 @@ class FFN
|
||||
* @param batchSize Number of points to be passed at a time to use for
|
||||
* objective function evaluation.
|
||||
*/
|
||||
double Evaluate(const arma::mat& parameters,
|
||||
const size_t begin,
|
||||
const size_t batchSize);
|
||||
typename MatType::elem_type Evaluate(const MatType& parameters,
|
||||
const size_t begin,
|
||||
const size_t batchSize);
|
||||
|
||||
/**
|
||||
* Note: this function is implemented so that it can be used by ensmallen's
|
||||
* optimizers. It's not generally meant to be used otherwise.
|
||||
*
|
||||
* Evaluate the feedforward network with the given parameters.
|
||||
* This function is usually called by the optimizer to train the model.
|
||||
* This just calls the overload of EvaluateWithGradient() with batchSize = 1.
|
||||
@@ -237,10 +361,13 @@ class FFN
|
||||
* @param parameters Matrix model parameters.
|
||||
* @param gradient Matrix to output gradient into.
|
||||
*/
|
||||
template<typename GradType>
|
||||
double EvaluateWithGradient(const arma::mat& parameters, GradType& gradient);
|
||||
typename MatType::elem_type EvaluateWithGradient(const MatType& parameters,
|
||||
MatType& gradient);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Note: this function is implemented so that it can be used by ensmallen's
|
||||
* optimizers. It's not generally meant to be used otherwise.
|
||||
*
|
||||
* Evaluate the feedforward network with the given parameters, but using only
|
||||
* a number of data points. This is useful for optimizers such as SGD, which
|
||||
* require a separable objective function.
|
||||
@@ -252,13 +379,15 @@ class FFN
|
||||
* @param batchSize Number of points to be passed at a time to use for
|
||||
* objective function evaluation.
|
||||
*/
|
||||
template<typename GradType>
|
||||
double EvaluateWithGradient(const arma::mat& parameters,
|
||||
const size_t begin,
|
||||
GradType& gradient,
|
||||
const size_t batchSize);
|
||||
typename MatType::elem_type EvaluateWithGradient(const MatType& parameters,
|
||||
const size_t begin,
|
||||
MatType& gradient,
|
||||
const size_t batchSize);
|
||||
|
||||
/**
|
||||
* Note: this function is implemented so that it can be used by ensmallen's
|
||||
* optimizers. It's not generally meant to be used otherwise.
|
||||
*
|
||||
* Evaluate the gradient of the feedforward network with the given parameters,
|
||||
* and with respect to only a number of points in the dataset. This is useful
|
||||
* for optimizers such as SGD, which require a separable objective function.
|
||||
@@ -270,253 +399,156 @@ class FFN
|
||||
* @param batchSize Number of points to be processed as a batch for objective
|
||||
* function gradient evaluation.
|
||||
*/
|
||||
void Gradient(const arma::mat& parameters,
|
||||
void Gradient(const MatType& parameters,
|
||||
const size_t begin,
|
||||
arma::mat& gradient,
|
||||
MatType& gradient,
|
||||
const size_t batchSize);
|
||||
|
||||
/**
|
||||
* Shuffle the order of function visitation. This may be called by the
|
||||
* optimizer.
|
||||
* Note: this function is implemented so that it can be used by ensmallen's
|
||||
* optimizers. It's not generally meant to be used otherwise.
|
||||
*
|
||||
* Return the number of separable functions (the number of predictor points).
|
||||
*/
|
||||
size_t NumFunctions() const { return responses.n_cols; }
|
||||
|
||||
/**
|
||||
* Note: this function is implemented so that it can be used by ensmallen's
|
||||
* optimizers. It's not generally meant to be used otherwise.
|
||||
*
|
||||
* Shuffle the order of function visitation. (This is equivalent to shuffling
|
||||
* the dataset during training.)
|
||||
*/
|
||||
void Shuffle();
|
||||
|
||||
/*
|
||||
* Add a new module to the model.
|
||||
*
|
||||
* @param args The layer parameter.
|
||||
*/
|
||||
template <class LayerType, class... Args>
|
||||
void Add(Args... args) { network.push_back(new LayerType(args...)); }
|
||||
|
||||
/*
|
||||
* Add a new module to the model.
|
||||
*
|
||||
* @param layer The Layer to be added to the model.
|
||||
*/
|
||||
void Add(LayerTypes<CustomLayers...> layer) { network.push_back(layer); }
|
||||
|
||||
//! Get the network model.
|
||||
const std::vector<LayerTypes<CustomLayers...> >& Model() const
|
||||
{
|
||||
return network;
|
||||
}
|
||||
//! Modify the network model. Be careful! If you change the structure of the
|
||||
//! network or parameters for layers, its state may become invalid, so be sure
|
||||
//! to call ResetParameters() afterwards.
|
||||
std::vector<LayerTypes<CustomLayers...> >& Model() { return network; }
|
||||
|
||||
//! Return the number of separable functions (the number of predictor points).
|
||||
size_t NumFunctions() const { return numFunctions; }
|
||||
|
||||
//! Return the initial point for the optimization.
|
||||
const arma::mat& Parameters() const { return parameter; }
|
||||
//! Modify the initial point for the optimization.
|
||||
arma::mat& Parameters() { return parameter; }
|
||||
|
||||
//! Get the matrix of responses to the input data points.
|
||||
const arma::mat& Responses() const { return responses; }
|
||||
//! Modify the matrix of responses to the input data points.
|
||||
arma::mat& Responses() { return responses; }
|
||||
|
||||
//! Get the matrix of data points (predictors).
|
||||
const arma::mat& Predictors() const { return predictors; }
|
||||
//! Modify the matrix of data points (predictors).
|
||||
arma::mat& Predictors() { return predictors; }
|
||||
|
||||
/**
|
||||
* Reset the module infomration (weights/parameters).
|
||||
*/
|
||||
void ResetParameters();
|
||||
|
||||
//! Serialize the model.
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
/**
|
||||
* Perform the forward pass of the data in real batch mode.
|
||||
* Prepare the network for training on the given data.
|
||||
*
|
||||
* Forward and Backward should be used as a pair, and they are designed mainly
|
||||
* for advanced users. User should try to use Predict and Train unless those
|
||||
* two functions can't satisfy some special requirements.
|
||||
*
|
||||
* @param inputs The input data.
|
||||
* @param results The predicted results.
|
||||
*/
|
||||
template<typename PredictorsType, typename ResponsesType>
|
||||
void Forward(const PredictorsType& inputs, ResponsesType& results);
|
||||
|
||||
/**
|
||||
* Perform a partial forward pass of the data.
|
||||
*
|
||||
* This function is meant for the cases when users require a forward pass only
|
||||
* through certain layers and not the entire network.
|
||||
*
|
||||
* @param inputs The input data for the specified first layer.
|
||||
* @param results The predicted results from the specified last layer.
|
||||
* @param begin The index of the first layer.
|
||||
* @param end The index of the last layer.
|
||||
*/
|
||||
template<typename PredictorsType, typename ResponsesType>
|
||||
void Forward(const PredictorsType& inputs ,
|
||||
ResponsesType& results,
|
||||
const size_t begin,
|
||||
const size_t end);
|
||||
|
||||
/**
|
||||
* Perform the backward pass of the data in real batch mode.
|
||||
*
|
||||
* Forward and Backward should be used as a pair, and they are designed mainly
|
||||
* for advanced users. User should try to use Predict and Train unless those
|
||||
* two functions can't satisfy some special requirements.
|
||||
*
|
||||
* @param inputs Inputs of current pass.
|
||||
* @param targets The training target.
|
||||
* @param gradients Computed gradients.
|
||||
* @return Training error of the current pass.
|
||||
*/
|
||||
template<typename PredictorsType,
|
||||
typename TargetsType,
|
||||
typename GradientsType>
|
||||
double Backward(const PredictorsType& inputs,
|
||||
const TargetsType& targets,
|
||||
GradientsType& gradients);
|
||||
|
||||
private:
|
||||
// Helper functions.
|
||||
/**
|
||||
* The Forward algorithm (part of the Forward-Backward algorithm). Computes
|
||||
* forward probabilities for each module.
|
||||
*
|
||||
* @param input Data sequence to compute probabilities for.
|
||||
*/
|
||||
template<typename InputType>
|
||||
void Forward(const InputType& input);
|
||||
|
||||
/**
|
||||
* Prepare the network for the given data.
|
||||
* This function won't actually trigger training process.
|
||||
* This function won't actually trigger the training process, and is
|
||||
* generally only useful internally.
|
||||
*
|
||||
* @param predictors Input data variables.
|
||||
* @param responses Outputs results from input data variables.
|
||||
*/
|
||||
void ResetData(arma::mat predictors, arma::mat responses);
|
||||
void ResetData(MatType predictors, MatType responses);
|
||||
|
||||
private:
|
||||
// Helper functions.
|
||||
|
||||
//! Use the InitializationPolicy to initialize all the weights in the network.
|
||||
void InitializeWeights();
|
||||
|
||||
//! Make the memory of each layer point to the right place, by calling
|
||||
//! SetWeightPtr() on each layer.
|
||||
void SetLayerMemory();
|
||||
|
||||
/**
|
||||
* The Backward algorithm (part of the Forward-Backward algorithm). Computes
|
||||
* backward pass for module.
|
||||
*/
|
||||
void Backward();
|
||||
|
||||
/**
|
||||
* Iterate through all layer modules and update the the gradient using the
|
||||
* layer defined optimizer.
|
||||
*/
|
||||
template<typename InputType>
|
||||
void Gradient(const InputType& input);
|
||||
|
||||
/**
|
||||
* Reset the module status by setting the current deterministic parameter
|
||||
* for all modules that implement the Deterministic function.
|
||||
*/
|
||||
void ResetDeterministic();
|
||||
|
||||
/**
|
||||
* Reset the gradient for all modules that implement the Gradient function.
|
||||
*/
|
||||
void ResetGradients(arma::mat& gradient);
|
||||
|
||||
/**
|
||||
* Swap the content of this network with given network.
|
||||
* Ensure that all the locally-cached information about the network is valid,
|
||||
* all parameter memory is initialized, and we can make forward and backward
|
||||
* passes.
|
||||
*
|
||||
* @param network Desired source network.
|
||||
* @param functionName Name of function to use if an exception is thrown.
|
||||
* @param inputDimensionality Given dimensionality of the input data.
|
||||
* @param setMode If true, the mode of the network will be set to the
|
||||
* parameter given in `training`. Otherwise the mode of the network is
|
||||
* left unmodified.
|
||||
* @param training Mode to set the network to; `true` indicates the network
|
||||
* should be set to training mode; `false` indicates testing mode.
|
||||
*/
|
||||
void Swap(FFN& network);
|
||||
void CheckNetwork(const std::string& functionName,
|
||||
const size_t inputDimensionality,
|
||||
const bool setMode = false,
|
||||
const bool training = false);
|
||||
|
||||
//! Instantiated outputlayer used to evaluate the network.
|
||||
/**
|
||||
* Set the input and output dimensions of each layer in the network correctly.
|
||||
* The size of the input is taken, in case `inputDimensions` has not been set
|
||||
* otherwise (e.g. via `InputDimensions()`). If `InputDimensions()` is not
|
||||
* empty, then `inputDimensionality` is ignored.
|
||||
*/
|
||||
void UpdateDimensions(const std::string& functionName,
|
||||
const size_t inputDimensionality = 0);
|
||||
|
||||
/**
|
||||
* Check if the optimizer has MaxIterations() parameter, if it does then check
|
||||
* if its value is less than the number of datapoints in the dataset.
|
||||
*
|
||||
* @tparam OptimizerType Type of optimizer to use to train the model.
|
||||
* @param optimizer optimizer used in the training process.
|
||||
* @param samples Number of datapoints in the dataset.
|
||||
*/
|
||||
template<typename OptimizerType>
|
||||
typename std::enable_if<
|
||||
ens::traits::HasMaxIterationsSignature<OptimizerType>::value, void
|
||||
>::type
|
||||
WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const;
|
||||
|
||||
/**
|
||||
* Check if the optimizer has MaxIterations() parameter; if it doesn't then
|
||||
* simply return from the function.
|
||||
*
|
||||
* @tparam OptimizerType Type of optimizer to use to train the model.
|
||||
* @param optimizer optimizer used in the training process.
|
||||
* @param samples Number of datapoints in the dataset.
|
||||
*/
|
||||
template<typename OptimizerType>
|
||||
typename std::enable_if<
|
||||
!ens::traits::HasMaxIterationsSignature<OptimizerType>::value, void
|
||||
>::type
|
||||
WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const;
|
||||
|
||||
//! Instantiated output layer used to evaluate the network.
|
||||
OutputLayerType outputLayer;
|
||||
|
||||
//! Instantiated InitializationRule object for initializing the network
|
||||
//! parameter.
|
||||
InitializationRuleType initializeRule;
|
||||
|
||||
//! The input width.
|
||||
size_t width;
|
||||
//! All of the network is stored inside this multilayer.
|
||||
MultiLayer<MatType> network;
|
||||
|
||||
//! The input height.
|
||||
size_t height;
|
||||
/**
|
||||
* Matrix of (trainable) parameters. Each weight here corresponds to a layer,
|
||||
* and each layer's `parameters` member is an alias pointing to parameters in
|
||||
* this matrix.
|
||||
*
|
||||
* Note: although each layer may have its own MatType and MatType,
|
||||
* ensmallen optimization requires everything to be stored in one matrix
|
||||
* object, so we have chosen MatType. This could be made more flexible
|
||||
* with a "wrapper" class implementing the Armadillo API.
|
||||
*/
|
||||
MatType parameters;
|
||||
|
||||
//! Indicator if we already trained the model.
|
||||
bool reset;
|
||||
//! Dimensions of input data.
|
||||
std::vector<size_t> inputDimensions;
|
||||
|
||||
//! Locally-stored model modules.
|
||||
std::vector<LayerTypes<CustomLayers...> > network;
|
||||
//! The matrix of data points (predictors). This member is empty, except
|
||||
//! during training---we must store a local copy of the training data since
|
||||
//! the ensmallen optimizer will not provide training data.
|
||||
MatType predictors;
|
||||
|
||||
//! The matrix of data points (predictors).
|
||||
arma::mat predictors;
|
||||
//! The matrix of responses to the input data points. This member is empty,
|
||||
//! except during training.
|
||||
MatType responses;
|
||||
|
||||
//! The matrix of responses to the input data points.
|
||||
arma::mat responses;
|
||||
//! Locally-stored output of the network from a forward pass; used by the
|
||||
//! backward pass.
|
||||
MatType networkOutput;
|
||||
//! Locally-stored output of the backward pass; used by the gradient pass.
|
||||
MatType networkDelta;
|
||||
//! Locally-stored error of the backward pass; used by the gradient pass.
|
||||
MatType error;
|
||||
|
||||
//! Matrix of (trained) parameters.
|
||||
arma::mat parameter;
|
||||
//! If true, each layer has its memory properly set for a forward/backward
|
||||
//! pass.
|
||||
bool layerMemoryIsSet;
|
||||
|
||||
//! The number of separable functions (the number of predictor points).
|
||||
size_t numFunctions;
|
||||
//! If true, each layer has its inputDimensions properly set, and
|
||||
//! `totalInputSize` and `totalOutputSize` are valid.
|
||||
bool inputDimensionsAreSet;
|
||||
|
||||
//! The current error for the backward pass.
|
||||
arma::mat error;
|
||||
|
||||
//! Locally-stored delta visitor.
|
||||
DeltaVisitor deltaVisitor;
|
||||
|
||||
//! Locally-stored output parameter visitor.
|
||||
OutputParameterVisitor outputParameterVisitor;
|
||||
|
||||
//! Locally-stored weight size visitor.
|
||||
WeightSizeVisitor weightSizeVisitor;
|
||||
|
||||
//! Locally-stored output width visitor.
|
||||
OutputWidthVisitor outputWidthVisitor;
|
||||
|
||||
//! Locally-stored output height visitor.
|
||||
OutputHeightVisitor outputHeightVisitor;
|
||||
|
||||
//! Locally-stored loss visitor
|
||||
LossVisitor lossVisitor;
|
||||
|
||||
//! Locally-stored reset visitor.
|
||||
ResetVisitor resetVisitor;
|
||||
|
||||
//! Locally-stored delete visitor.
|
||||
DeleteVisitor deleteVisitor;
|
||||
|
||||
//! The current evaluation mode (training or testing).
|
||||
bool deterministic;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
arma::mat delta;
|
||||
|
||||
//! Locally-stored input parameter object.
|
||||
arma::mat inputParameter;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
arma::mat outputParameter;
|
||||
|
||||
//! Locally-stored gradient parameter.
|
||||
arma::mat gradient;
|
||||
|
||||
//! Locally-stored copy visitor
|
||||
CopyVisitor<CustomLayers...> copyVisitor;
|
||||
|
||||
// The GAN class should have access to internal members.
|
||||
template<
|
||||
typename Model,
|
||||
typename InitializerType,
|
||||
typename NoiseType,
|
||||
typename PolicyType
|
||||
>
|
||||
friend class GAN;
|
||||
// RNN will call `CheckNetwork()`, which is private.
|
||||
friend class RNN<OutputLayerType, InitializationRuleType, MatType>;
|
||||
}; // class FFN
|
||||
|
||||
} // namespace ann
|
||||
|
||||
+597
-565
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file forward_decls.hpp
|
||||
* @author Ryan Curtin
|
||||
*
|
||||
* Forward declarations of network types. This is needed for some `friend`
|
||||
* functionality.
|
||||
*/
|
||||
#ifndef MLPACK_METHODS_ANN_FORWARD_DECLS_HPP
|
||||
#define MLPACK_METHODS_ANN_FORWARD_DECLS_HPP
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann {
|
||||
|
||||
// See ffn.hpp.
|
||||
template<typename OutputLayerType,
|
||||
typename InitializationRuleType,
|
||||
typename MatType>
|
||||
class FFN;
|
||||
|
||||
// See rnn.hpp.
|
||||
template<typename OutputLayerType,
|
||||
typename InitializationRuleType,
|
||||
typename MatType>
|
||||
class RNN;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -98,7 +98,13 @@ class ConstInitialization
|
||||
//! Get the initialization value.
|
||||
double const& InitValue() const { return initVal; }
|
||||
//! Modify the initialization value.
|
||||
double& initValue() { return initVal; }
|
||||
double& InitValue() { return initVal; }
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(initVal));
|
||||
}
|
||||
|
||||
private:
|
||||
//! Value to be initialized with
|
||||
|
||||
@@ -104,13 +104,19 @@ class GlorotInitializationType
|
||||
*/
|
||||
template<typename eT>
|
||||
void Initialize(arma::Cube<eT>& W);
|
||||
|
||||
/**
|
||||
* Serialize the initialization. (Nothing to serialize for this one.)
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& /* ar */, const uint32_t /* version */) { }
|
||||
}; // class GlorotInitializationType
|
||||
|
||||
template <>
|
||||
template<>
|
||||
template<typename eT>
|
||||
inline void GlorotInitializationType<false>::Initialize(arma::Mat<eT>& W,
|
||||
const size_t rows,
|
||||
const size_t cols)
|
||||
const size_t rows,
|
||||
const size_t cols)
|
||||
{
|
||||
if (W.is_empty())
|
||||
W.set_size(rows, cols);
|
||||
@@ -120,7 +126,7 @@ inline void GlorotInitializationType<false>::Initialize(arma::Mat<eT>& W,
|
||||
normalInit.Initialize(W, rows, cols);
|
||||
}
|
||||
|
||||
template <>
|
||||
template<>
|
||||
template<typename eT>
|
||||
inline void GlorotInitializationType<false>::Initialize(arma::Mat<eT>& W)
|
||||
{
|
||||
@@ -132,7 +138,7 @@ inline void GlorotInitializationType<false>::Initialize(arma::Mat<eT>& W)
|
||||
normalInit.Initialize(W);
|
||||
}
|
||||
|
||||
template <>
|
||||
template<>
|
||||
template<typename eT>
|
||||
inline void GlorotInitializationType<true>::Initialize(arma::Mat<eT>& W,
|
||||
const size_t rows,
|
||||
@@ -147,7 +153,7 @@ inline void GlorotInitializationType<true>::Initialize(arma::Mat<eT>& W,
|
||||
randomInit.Initialize(W, rows, cols);
|
||||
}
|
||||
|
||||
template <>
|
||||
template<>
|
||||
template<typename eT>
|
||||
inline void GlorotInitializationType<true>::Initialize(arma::Mat<eT>& W)
|
||||
{
|
||||
|
||||
@@ -136,6 +136,12 @@ class HeInitialization
|
||||
for (size_t i = 0; i < W.n_slices; ++i)
|
||||
Initialize(W.slice(i));
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive& /* ar */, const uint32_t /* version */)
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
}; // class HeInitialization
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -14,14 +14,10 @@
|
||||
#define MLPACK_METHODS_ANN_INIT_RULES_NETWORK_INIT_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include <mlpack/methods/ann/layer/layer.hpp>
|
||||
|
||||
#include "../visitor/reset_visitor.hpp"
|
||||
#include "../visitor/weight_size_visitor.hpp"
|
||||
#include "../visitor/weight_set_visitor.hpp"
|
||||
#include "init_rules_traits.hpp"
|
||||
|
||||
#include <mlpack/methods/ann/layer/layer_types.hpp>
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
@@ -29,7 +25,7 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* This class is used to initialize the network with the given initialization
|
||||
* rule.
|
||||
*/
|
||||
template<typename InitializationRuleType, typename... CustomLayers>
|
||||
template<typename InitializationRuleType>
|
||||
class NetworkInitialization
|
||||
{
|
||||
public:
|
||||
@@ -54,16 +50,18 @@ class NetworkInitialization
|
||||
* @param parameterOffset Offset for network paramater, default 0.
|
||||
*/
|
||||
template <typename eT>
|
||||
void Initialize(const std::vector<LayerTypes<CustomLayers...> >& network,
|
||||
arma::Mat<eT>& parameter, size_t parameterOffset = 0)
|
||||
void Initialize(const std::vector<Layer<arma::Mat<eT>>*>& network,
|
||||
arma::Mat<eT>& parameters,
|
||||
size_t parameterOffset = 0)
|
||||
{
|
||||
// Determine the number of parameter/weights of the given network.
|
||||
if (parameter.is_empty())
|
||||
// Determine the total number of parameters/weights of the given network.
|
||||
if (parameters.is_empty())
|
||||
{
|
||||
size_t weights = 0;
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
weights += boost::apply_visitor(weightSizeVisitor, network[i]);
|
||||
parameter.set_size(weights, 1);
|
||||
weights += network[i]->WeightSize();
|
||||
|
||||
parameters.set_size(weights, 1);
|
||||
}
|
||||
|
||||
// Initialize the network layer by layer or the complete network.
|
||||
@@ -73,9 +71,8 @@ class NetworkInitialization
|
||||
{
|
||||
// Initialize the layer with the specified parameter/weight
|
||||
// initialization rule.
|
||||
const size_t weight = boost::apply_visitor(weightSizeVisitor,
|
||||
network[i]);
|
||||
arma::Mat<eT> tmp = arma::mat(parameter.memptr() + offset,
|
||||
const size_t weight = network[i]->WeightSize();
|
||||
arma::Mat<eT> tmp = arma::mat(parameters.memptr() + offset,
|
||||
weight, 1, false, false);
|
||||
initializeRule.Initialize(tmp, tmp.n_elem, 1);
|
||||
|
||||
@@ -85,19 +82,7 @@ class NetworkInitialization
|
||||
}
|
||||
else
|
||||
{
|
||||
initializeRule.Initialize(parameter, parameter.n_elem, 1);
|
||||
}
|
||||
|
||||
// Note: We can't merge the for loop into the for loop above because
|
||||
// WeightSetVisitor also sets the parameter/weights of the inner modules.
|
||||
// Inner Modules are held by the parent module e.g. the concat module can
|
||||
// hold various other modules.
|
||||
for (size_t i = 0, offset = parameterOffset; i < network.size(); ++i)
|
||||
{
|
||||
offset += boost::apply_visitor(WeightSetVisitor(parameter, offset),
|
||||
network[i]);
|
||||
|
||||
boost::apply_visitor(resetVisitor, network[i]);
|
||||
initializeRule.Initialize(parameters, parameters.n_elem, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,12 +90,6 @@ class NetworkInitialization
|
||||
//! Instantiated InitializationRule object for initializing the network
|
||||
//! parameter.
|
||||
InitializationRuleType initializeRule;
|
||||
|
||||
//! Locally-stored reset visitor.
|
||||
ResetVisitor resetVisitor;
|
||||
|
||||
//! Locally-stored weight size visitor.
|
||||
WeightSizeVisitor weightSizeVisitor;
|
||||
}; // class NetworkInitialization
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -47,15 +47,13 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* w_i &=& \hat{w} \cdot \sqrt{a_i + 1}
|
||||
* @f}
|
||||
*
|
||||
* Where f is the transfer function epsilon, k custom parameters, n the number of
|
||||
* neurons in the outgoing layer and gamma a parameter that defines the random
|
||||
* interval.
|
||||
* Where f is the transfer function epsilon, k custom parameters, n the number
|
||||
* of neurons in the outgoing layer and gamma a parameter that defines the
|
||||
* random interval.
|
||||
*
|
||||
* @tparam ActivationFunction The activation function used for the oivs method.
|
||||
*/
|
||||
template<
|
||||
class ActivationFunction = LogisticFunction
|
||||
>
|
||||
template<class ActivationFunction = LogisticFunction>
|
||||
class OivsInitialization
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -115,6 +115,13 @@ class RandomInitialization
|
||||
Initialize(W.slice(i));
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(lowerBound));
|
||||
ar(CEREAL_NVP(upperBound));
|
||||
}
|
||||
|
||||
private:
|
||||
//! The number used as lower bound.
|
||||
double lowerBound;
|
||||
|
||||
@@ -3,67 +3,18 @@
|
||||
set(SOURCES
|
||||
add.hpp
|
||||
add_impl.hpp
|
||||
add_merge.hpp
|
||||
add_merge_impl.hpp
|
||||
adaptive_max_pooling.hpp
|
||||
adaptive_max_pooling_impl.hpp
|
||||
adaptive_mean_pooling.hpp
|
||||
adaptive_mean_pooling_impl.hpp
|
||||
alpha_dropout.hpp
|
||||
alpha_dropout_impl.hpp
|
||||
atrous_convolution.hpp
|
||||
atrous_convolution_impl.hpp
|
||||
base_layer.hpp
|
||||
batch_norm.hpp
|
||||
batch_norm_impl.hpp
|
||||
bicubic_interpolation.hpp
|
||||
bicubic_interpolation_impl.hpp
|
||||
bilinear_interpolation.hpp
|
||||
bilinear_interpolation_impl.hpp
|
||||
channel_shuffle.hpp
|
||||
channel_shuffle_impl.hpp
|
||||
concat.hpp
|
||||
concat_impl.hpp
|
||||
concat_performance.hpp
|
||||
concat_performance_impl.hpp
|
||||
concatenate.hpp
|
||||
concatenate_impl.hpp
|
||||
constant.hpp
|
||||
constant_impl.hpp
|
||||
convolution.hpp
|
||||
convolution_impl.hpp
|
||||
dropconnect.hpp
|
||||
dropconnect_impl.hpp
|
||||
dropout.hpp
|
||||
dropout_impl.hpp
|
||||
elu.hpp
|
||||
elu_impl.hpp
|
||||
fast_lstm.hpp
|
||||
fast_lstm_impl.hpp
|
||||
flatten_t_swish.hpp
|
||||
flatten_t_swish_impl.hpp
|
||||
flexible_relu.hpp
|
||||
flexible_relu_impl.hpp
|
||||
glimpse.hpp
|
||||
glimpse_impl.hpp
|
||||
group_norm.hpp
|
||||
group_norm_impl.hpp
|
||||
gru.hpp
|
||||
gru_impl.hpp
|
||||
hard_tanh.hpp
|
||||
hard_tanh_impl.hpp
|
||||
highway.hpp
|
||||
highway_impl.hpp
|
||||
instance_norm.hpp
|
||||
instance_norm_impl.hpp
|
||||
isrlu.hpp
|
||||
isrlu_impl.hpp
|
||||
join.hpp
|
||||
join_impl.hpp
|
||||
layer.hpp
|
||||
layer_norm.hpp
|
||||
layer_norm_impl.hpp
|
||||
layer_traits.hpp
|
||||
layer_types.hpp
|
||||
leaky_relu.hpp
|
||||
leaky_relu_impl.hpp
|
||||
@@ -71,73 +22,22 @@ set(SOURCES
|
||||
linear_impl.hpp
|
||||
linear_no_bias.hpp
|
||||
linear_no_bias_impl.hpp
|
||||
linear3d.hpp
|
||||
linear3d_impl.hpp
|
||||
log_softmax.hpp
|
||||
log_softmax_impl.hpp
|
||||
lookup.hpp
|
||||
lookup_impl.hpp
|
||||
lp_pooling.hpp
|
||||
lp_pooling_impl.hpp
|
||||
lstm.hpp
|
||||
lstm_impl.hpp
|
||||
max_pooling.hpp
|
||||
max_pooling_impl.hpp
|
||||
mean_pooling.hpp
|
||||
mean_pooling_impl.hpp
|
||||
minibatch_discrimination.hpp
|
||||
minibatch_discrimination_impl.hpp
|
||||
multihead_attention_impl.hpp
|
||||
multihead_attention.hpp
|
||||
multiply_constant.hpp
|
||||
multiply_constant_impl.hpp
|
||||
multiply_merge.hpp
|
||||
multiply_merge_impl.hpp
|
||||
nearest_interpolation.hpp
|
||||
nearest_interpolation_impl.hpp
|
||||
multi_layer.hpp
|
||||
multi_layer_impl.hpp
|
||||
noisylinear.hpp
|
||||
noisylinear_impl.hpp
|
||||
parametric_relu.hpp
|
||||
parametric_relu_impl.hpp
|
||||
pixel_shuffle.hpp
|
||||
pixel_shuffle_impl.hpp
|
||||
positional_encoding.hpp
|
||||
positional_encoding_impl.hpp
|
||||
recurrent.hpp
|
||||
recurrent_impl.hpp
|
||||
recurrent_attention.hpp
|
||||
recurrent_attention_impl.hpp
|
||||
reinforce_normal.hpp
|
||||
reinforce_normal_impl.hpp
|
||||
relu6.hpp
|
||||
relu6_impl.hpp
|
||||
reparametrization.hpp
|
||||
reparametrization_impl.hpp
|
||||
padding.hpp
|
||||
radial_basis_function.hpp
|
||||
radial_basis_function_impl.hpp
|
||||
select.hpp
|
||||
select_impl.hpp
|
||||
sequential.hpp
|
||||
sequential_impl.hpp
|
||||
softmax_impl.hpp
|
||||
softmax.hpp
|
||||
spatial_dropout.hpp
|
||||
spatial_dropout_impl.hpp
|
||||
subview.hpp
|
||||
transposed_convolution.hpp
|
||||
transposed_convolution_impl.hpp
|
||||
vr_class_reward.hpp
|
||||
vr_class_reward_impl.hpp
|
||||
c_relu.hpp
|
||||
c_relu_impl.hpp
|
||||
weight_norm.hpp
|
||||
weight_norm_impl.hpp
|
||||
hardshrink.hpp
|
||||
hardshrink_impl.hpp
|
||||
celu.hpp
|
||||
celu_impl.hpp
|
||||
softshrink.hpp
|
||||
softshrink_impl.hpp
|
||||
softmin.hpp
|
||||
softmin_impl.hpp
|
||||
serialization.hpp
|
||||
)
|
||||
|
||||
# Add directory name to sources.
|
||||
|
||||
@@ -13,98 +13,90 @@
|
||||
#define MLPACK_METHODS_ANN_LAYER_ADD_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include <mlpack/methods/ann/layer/layer_traits.hpp>
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
/**
|
||||
* Implementation of the Add module class. The Add module applies a bias term
|
||||
* to the incoming data.
|
||||
* Implementation of the Add layer. The Add module applies a bias term to the
|
||||
* incoming data.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class Add
|
||||
template<typename MatType>
|
||||
class AddType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create the Add object using the specified number of output units.
|
||||
*
|
||||
* @param outSize The number of output units.
|
||||
* Create the AddType object. The output size of the layer will be the same
|
||||
* as the input size.
|
||||
*/
|
||||
Add(const size_t outSize = 0);
|
||||
AddType();
|
||||
|
||||
//! Clone the AddType object. This handles polymorphism correctly.
|
||||
AddType* Clone() const { return new AddType(*this); }
|
||||
|
||||
// Virtual destructor.
|
||||
virtual ~AddType() { }
|
||||
|
||||
//! Copy the given AddType layer.
|
||||
AddType(const AddType& other);
|
||||
//! Take ownership of the given AddType layer.
|
||||
AddType(AddType&& other);
|
||||
//! Copy the given AddType layer.
|
||||
AddType& operator=(const AddType& other);
|
||||
//! Take ownership of the given AddType layer.
|
||||
AddType& operator=(AddType&& other);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
* f(x) by propagating the activity forward through f.
|
||||
* Forward pass: add the bias to the input.
|
||||
*
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
* f(x) by propagating x backwards trough f. Using the results from the feed
|
||||
* forward pass.
|
||||
* Backward pass: send weights backwards (the bias does not affect anything).
|
||||
*
|
||||
* @param * (input) The propagated input activation.
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
void Backward(const MatType& /* input */,
|
||||
const MatType& gy,
|
||||
MatType& g);
|
||||
|
||||
/**
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
* Calculate the gradient using the output and the input activation.
|
||||
*
|
||||
* @param * (input) The propagated input.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient);
|
||||
void Gradient(const MatType& /* input */,
|
||||
const MatType& error,
|
||||
MatType& gradient);
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return gradient; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return gradient; }
|
||||
|
||||
//! Get the output size.
|
||||
size_t OutputSize() const { return outSize; }
|
||||
//! Return the weights of the network.
|
||||
const MatType& Parameters() const { return weights; }
|
||||
//! Modify the weights of the network.
|
||||
MatType& Parameters() { return weights; }
|
||||
|
||||
//! Get the size of weights.
|
||||
size_t WeightSize() const { return outSize; }
|
||||
|
||||
//! Compute the output dimensions of the layer, based on the internal values
|
||||
//! of `InputDimensions()`.
|
||||
void ComputeOutputDimensions();
|
||||
|
||||
//! Set the weights of the layer to use the given memory.
|
||||
void SetWeights(typename MatType::elem_type* weightPtr);
|
||||
|
||||
/**
|
||||
* Serialize the layer
|
||||
* Serialize the layer.
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
@@ -114,18 +106,12 @@ class Add
|
||||
size_t outSize;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
MatType weights;
|
||||
}; // class Add
|
||||
|
||||
// Standard Add layer.
|
||||
typedef AddType<arma::mat> Add;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
@@ -19,51 +19,103 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Add<InputDataType, OutputDataType>::Add(const size_t outSize) :
|
||||
outSize(outSize)
|
||||
template<typename MatType>
|
||||
AddType<MatType>::AddType() : outSize(0)
|
||||
{
|
||||
weights.set_size(WeightSize(), 1);
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void Add<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
template<typename MatType>
|
||||
AddType<MatType>::AddType(const AddType& other) :
|
||||
Layer<MatType>(other),
|
||||
outSize(other.outSize)
|
||||
{
|
||||
output = input;
|
||||
output.each_col() += weights;
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void Add<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
template<typename MatType>
|
||||
AddType<MatType>::AddType(AddType&& other) :
|
||||
Layer<MatType>(std::move(other)),
|
||||
outSize(std::move(other.outSize))
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
AddType<MatType>&
|
||||
AddType<MatType>::operator=(const AddType& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
Layer<MatType>::operator=(other);
|
||||
outSize = other.outSize;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
AddType<MatType>&
|
||||
AddType<MatType>::operator=(AddType&& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
Layer<MatType>::operator=(std::move(other));
|
||||
outSize = std::move(other.outSize);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void AddType<MatType>::Forward(const MatType& input, MatType& output)
|
||||
{
|
||||
output = input + arma::repmat(arma::vectorise(weights), 1, input.n_cols);
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void AddType<MatType>::Backward(
|
||||
const MatType& /* input */,
|
||||
const MatType& gy,
|
||||
MatType& g)
|
||||
{
|
||||
g = gy;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void Add<InputDataType, OutputDataType>::Gradient(
|
||||
const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient)
|
||||
template<typename MatType>
|
||||
void AddType<MatType>::Gradient(
|
||||
const MatType& /* input */,
|
||||
const MatType& error,
|
||||
MatType& gradient)
|
||||
{
|
||||
gradient = error;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename Archive>
|
||||
void Add<InputDataType, OutputDataType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
template<typename MatType>
|
||||
void AddType<MatType>::SetWeights(typename MatType::elem_type* weightPtr)
|
||||
{
|
||||
ar(CEREAL_NVP(outSize));
|
||||
// Set the weights to wrap the given memory.
|
||||
MakeAlias(weights, weightPtr, 1, outSize);
|
||||
}
|
||||
|
||||
if (cereal::is_loading<Archive>())
|
||||
weights.set_size(outSize, 1);
|
||||
template<typename MatType>
|
||||
void AddType<MatType>::ComputeOutputDimensions()
|
||||
{
|
||||
this->outputDimensions = this->inputDimensions;
|
||||
|
||||
outSize = this->outputDimensions[0];
|
||||
for (size_t i = 1; i < this->outputDimensions.size(); ++i)
|
||||
outSize *= this->outputDimensions[i];
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
template<typename Archive>
|
||||
void AddType<MatType>::serialize(Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(outSize));
|
||||
ar(CEREAL_NVP(weights));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/add_merge_impl.hpp
|
||||
* @author Marcus Edel
|
||||
*
|
||||
* Definition of the AddMerge module which accumulates the output of the given
|
||||
* modules.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_ADD_MERGE_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_ADD_MERGE_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "add_merge.hpp"
|
||||
|
||||
#include "../visitor/forward_visitor.hpp"
|
||||
#include "../visitor/backward_visitor.hpp"
|
||||
#include "../visitor/gradient_visitor.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
AddMerge<InputDataType, OutputDataType, CustomLayers...>::AddMerge(
|
||||
const bool model, const bool run) :
|
||||
model(model), run(run), ownsLayers(!model)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
AddMerge<InputDataType, OutputDataType, CustomLayers...>::AddMerge(
|
||||
const bool model, const bool run, const bool ownsLayers) :
|
||||
model(model), run(run), ownsLayers(ownsLayers)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
AddMerge<InputDataType, OutputDataType, CustomLayers...>::~AddMerge()
|
||||
{
|
||||
if (!model && ownsLayers)
|
||||
{
|
||||
std::for_each(network.begin(), network.end(),
|
||||
boost::apply_visitor(deleteVisitor));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename InputType, typename OutputType>
|
||||
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
if (run)
|
||||
{
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
boost::apply_visitor(ForwardVisitor(input,
|
||||
boost::apply_visitor(outputParameterVisitor, network[i])),
|
||||
network[i]);
|
||||
}
|
||||
}
|
||||
|
||||
output = boost::apply_visitor(outputParameterVisitor, network.front());
|
||||
for (size_t i = 1; i < network.size(); ++i)
|
||||
{
|
||||
output += boost::apply_visitor(outputParameterVisitor, network[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::Backward(
|
||||
const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
{
|
||||
if (run)
|
||||
{
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, network[i]), gy,
|
||||
boost::apply_visitor(deltaVisitor, network[i])), network[i]);
|
||||
}
|
||||
|
||||
g = boost::apply_visitor(deltaVisitor, network[0]);
|
||||
for (size_t i = 1; i < network.size(); ++i)
|
||||
{
|
||||
g += boost::apply_visitor(deltaVisitor, network[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
g = gy;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::Backward(
|
||||
const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g,
|
||||
const size_t index)
|
||||
{
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, network[index]), gy,
|
||||
boost::apply_visitor(deltaVisitor, network[index])), network[index]);
|
||||
g = boost::apply_visitor(deltaVisitor, network[index]);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& /* gradient */ )
|
||||
{
|
||||
if (run)
|
||||
{
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
boost::apply_visitor(GradientVisitor(input, error), network[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& /* gradient */,
|
||||
const size_t index)
|
||||
{
|
||||
boost::apply_visitor(GradientVisitor(input, error), network[index]);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename Archive>
|
||||
void AddMerge<InputDataType, OutputDataType, CustomLayers...>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
// Be sure to clear other layers before loading.
|
||||
if (cereal::is_loading<Archive>())
|
||||
network.clear();
|
||||
|
||||
ar(CEREAL_VECTOR_VARIANT_POINTER(network));
|
||||
ar(CEREAL_NVP(model));
|
||||
ar(CEREAL_NVP(run));
|
||||
ar(CEREAL_NVP(ownsLayers));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -17,6 +17,7 @@
|
||||
#define MLPACK_METHODS_ANN_LAYER_ALPHA_DROPOUT_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
@@ -40,14 +41,11 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template <typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat>
|
||||
class AlphaDropout
|
||||
template<typename MatType = arma::mat>
|
||||
class AlphaDropoutType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -56,17 +54,33 @@ class AlphaDropout
|
||||
* @param ratio The probability of setting a value to alphaDash.
|
||||
* @param alphaDash The dropout scaling parameter.
|
||||
*/
|
||||
AlphaDropout(const double ratio = 0.5,
|
||||
const double alphaDash = -alpha * lambda);
|
||||
AlphaDropoutType(const double ratio = 0.5,
|
||||
const double alphaDash = -alpha * lambda);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of the alpha_dropout layer.
|
||||
* Clone the AlphaDropoutType object. This handles polymorphism correctly.
|
||||
*/
|
||||
AlphaDropoutType* Clone() const { return new AlphaDropoutType(*this); }
|
||||
|
||||
// Virtual destructor.
|
||||
virtual ~AlphaDropoutType() { }
|
||||
|
||||
//! Copy the given AlphaDropoutType layer.
|
||||
AlphaDropoutType(const AlphaDropoutType& other);
|
||||
//! Take ownership of the given AlphaDropoutType layer.
|
||||
AlphaDropoutType(AlphaDropoutType&& other);
|
||||
//! Copy the given AlphaDropoutType layer.
|
||||
AlphaDropoutType& operator=(const AlphaDropoutType& other);
|
||||
//! Take ownership of the given AlphaDropoutType layer.
|
||||
AlphaDropoutType& operator=(AlphaDropoutType&& other);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of the AlphaDropout layer.
|
||||
*
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of the alpha_dropout layer.
|
||||
@@ -75,25 +89,7 @@ class AlphaDropout
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the detla.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! The value of the deterministic parameter.
|
||||
bool Deterministic() const { return deterministic; }
|
||||
//! Modify the value of the deterministic parameter.
|
||||
bool& Deterministic() { return deterministic; }
|
||||
void Backward(const MatType& /* input */, const MatType& gy, MatType& g);
|
||||
|
||||
//! The probability of setting a value to alphaDash.
|
||||
double Ratio() const { return ratio; }
|
||||
@@ -105,10 +101,10 @@ class AlphaDropout
|
||||
double B() const { return b; }
|
||||
|
||||
//! Value of alphaDash.
|
||||
double AlphaDash() const {return alphaDash; }
|
||||
double AlphaDash() const { return alphaDash; }
|
||||
|
||||
//! Get the mask.
|
||||
OutputDataType const& Mask() const {return mask;}
|
||||
const MatType& Mask() const { return mask; }
|
||||
|
||||
//! Modify the probability of setting a value to alphaDash. As
|
||||
//! 'a' and 'b' depend on 'ratio', modify them as well.
|
||||
@@ -126,14 +122,8 @@ class AlphaDropout
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
|
||||
//! Locally-stored mast object.
|
||||
OutputDataType mask;
|
||||
//! Locally-stored mask object.
|
||||
MatType mask;
|
||||
|
||||
//! The probability of setting a value to aplhaDash.
|
||||
double ratio;
|
||||
@@ -141,9 +131,6 @@ class AlphaDropout
|
||||
//! The low variance value of SELU activation function.
|
||||
double alphaDash;
|
||||
|
||||
//! If true dropout and scaling is disabled, see notes above.
|
||||
bool deterministic;
|
||||
|
||||
//! Value of alpha for normalized inputs (taken from SELU).
|
||||
static constexpr double alpha = 1.6732632423543772848170429916717;
|
||||
|
||||
@@ -155,7 +142,9 @@ class AlphaDropout
|
||||
|
||||
//! Value to be added to a*x for affine transformation.
|
||||
double b;
|
||||
}; // class AlphaDropout
|
||||
}; // class AlphaDropoutType
|
||||
|
||||
typedef AlphaDropoutType<arma::mat> AlphaDropout;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -22,25 +22,79 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
AlphaDropout<InputDataType, OutputDataType>::AlphaDropout(
|
||||
template<typename MatType>
|
||||
AlphaDropoutType<MatType>::AlphaDropoutType(
|
||||
const double ratio,
|
||||
const double alphaDash) :
|
||||
ratio(ratio),
|
||||
alphaDash(alphaDash),
|
||||
deterministic(false)
|
||||
alphaDash(alphaDash)
|
||||
{
|
||||
Ratio(ratio);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void AlphaDropout<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
template<typename MatType>
|
||||
AlphaDropoutType<MatType>::AlphaDropoutType(const AlphaDropoutType& other) :
|
||||
Layer<MatType>(other),
|
||||
mask(other.mask),
|
||||
ratio(other.ratio),
|
||||
alphaDash(other.alphaDash),
|
||||
a(other.a),
|
||||
b(other.b)
|
||||
{
|
||||
// The dropout mask will not be multiplied in the deterministic mode
|
||||
// (during testing).
|
||||
if (deterministic)
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
AlphaDropoutType<MatType>::AlphaDropoutType(AlphaDropoutType&& other) :
|
||||
Layer<MatType>(std::move(other)),
|
||||
mask(std::move(other.mask)),
|
||||
ratio(std::move(other.ratio)),
|
||||
alphaDash(std::move(other.alphaDash)),
|
||||
a(std::move(other.a)),
|
||||
b(std::move(other.b))
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
AlphaDropoutType<MatType>&
|
||||
AlphaDropoutType<MatType>::operator=(const AlphaDropoutType& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
Layer<MatType>::operator=(other);
|
||||
mask = other.mask;
|
||||
ratio = other.ratio;
|
||||
alphaDash = other.alphaDash;
|
||||
a = other.a;
|
||||
b = other.b;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
AlphaDropoutType<MatType>&
|
||||
AlphaDropoutType<MatType>::operator=(AlphaDropoutType&& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
Layer<MatType>::operator=(std::move(other));
|
||||
mask = std::move(other.mask);
|
||||
ratio = std::move(other.ratio);
|
||||
alphaDash = std::move(other.alphaDash);
|
||||
a = std::move(other.a);
|
||||
b = std::move(other.b);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void AlphaDropoutType<MatType>::Forward(const MatType& input, MatType& output)
|
||||
{
|
||||
// The dropout mask will not be multiplied during testing.
|
||||
if (!this->training)
|
||||
{
|
||||
output = input;
|
||||
}
|
||||
@@ -49,29 +103,35 @@ void AlphaDropout<InputDataType, OutputDataType>::Forward(
|
||||
// Set values to alphaDash with probability ratio. Then apply affine
|
||||
// transformation so as to keep mean and variance of outputs to their
|
||||
// original values.
|
||||
mask = arma::randu< arma::Mat<eT> >(input.n_rows, input.n_cols);
|
||||
mask = arma::randu<MatType>(input.n_rows, input.n_cols);
|
||||
mask.transform( [&](double val) { return (val > ratio); } );
|
||||
output = (input % mask + alphaDash * (1 - mask)) * a + b;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void AlphaDropout<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
|
||||
template<typename MatType>
|
||||
void AlphaDropoutType<MatType>::Backward(
|
||||
const MatType& /* input */, const MatType& gy, MatType& g)
|
||||
{
|
||||
g = gy % mask * a;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename MatType>
|
||||
template<typename Archive>
|
||||
void AlphaDropout<InputDataType, OutputDataType>::serialize(
|
||||
void AlphaDropoutType<MatType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(ratio));
|
||||
ar(CEREAL_NVP(alphaDash));
|
||||
ar(CEREAL_NVP(a));
|
||||
ar(CEREAL_NVP(b));
|
||||
|
||||
// No need to serialize the mask, since it will be recomputed on the next
|
||||
// forward pass. But we should clear it if we are loading.
|
||||
if (Archive::is_loading::value)
|
||||
mask.clear();
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <mlpack/methods/ann/activation_functions/hard_swish_function.hpp>
|
||||
#include <mlpack/methods/ann/activation_functions/tanh_exponential_function.hpp>
|
||||
#include <mlpack/methods/ann/activation_functions/silu_function.hpp>
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
@@ -40,102 +41,83 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
*
|
||||
* A few convenience typedefs are given:
|
||||
*
|
||||
* - SigmoidLayer
|
||||
* - IdentityLayer
|
||||
* - ReLULayer
|
||||
* - TanHLayer
|
||||
* - SoftplusLayer
|
||||
* - HardSigmoidLayer
|
||||
* - SwishLayer
|
||||
* - MishLayer
|
||||
* - LiSHTLayer
|
||||
* - GELULayer
|
||||
* - ELiSHLayer
|
||||
* - ElliotLayer
|
||||
* - GaussianLayer
|
||||
* - HardSwishLayer
|
||||
* - TanhExpLayer
|
||||
* - SILULayer
|
||||
* - Sigmoid
|
||||
* - ReLU
|
||||
* - TanH
|
||||
* - Softplus
|
||||
* - HardSigmoid
|
||||
* - Swish
|
||||
* - Mish
|
||||
* - LiSHT
|
||||
* - GELU
|
||||
* - ELiSH
|
||||
* - Elliot
|
||||
* - Gaussian
|
||||
* - HardSwish
|
||||
* - TanhExp
|
||||
* - SILU
|
||||
*
|
||||
* @tparam ActivationFunction Activation function used for the embedding layer.
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = LogisticFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
typename MatType = arma::mat
|
||||
>
|
||||
class BaseLayer
|
||||
class BaseLayer : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create the BaseLayer object.
|
||||
*/
|
||||
BaseLayer()
|
||||
BaseLayer() : Layer<MatType>()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
// Virtual destructor.
|
||||
virtual ~BaseLayer() { }
|
||||
|
||||
// No copy constructor or operators needed here, since the class has no
|
||||
// members.
|
||||
|
||||
//! Clone the BaseLayer object. This handles polymorphism correctly.
|
||||
BaseLayer* Clone() const { return new BaseLayer(*this); }
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
* f(x) by propagating the activity forward through f.
|
||||
* Forward pass: apply the activation to the inputs.
|
||||
*
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void Forward(const InputType& input, OutputType& output)
|
||||
void Forward(const MatType& input, MatType& output)
|
||||
{
|
||||
ActivationFunction::Fn(input, output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
* f(x) by propagating x backwards trough f. Using the results from the feed
|
||||
* forward pass.
|
||||
* Backward pass: compute the function f(x) by propagating x backwards through
|
||||
* f, using the results from the forward pass.
|
||||
*
|
||||
* @param input The propagated input activation.
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
void Backward(const MatType& input, const MatType& gy, MatType& g)
|
||||
{
|
||||
arma::Mat<eT> derivative;
|
||||
MatType derivative;
|
||||
ActivationFunction::Deriv(input, derivative);
|
||||
g = gy % derivative;
|
||||
}
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& /* ar */, const uint32_t /* version */)
|
||||
void serialize(Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
/* Nothing to do here */
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
// Nothing to serialize.
|
||||
}
|
||||
|
||||
private:
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
}; // class BaseLayer
|
||||
|
||||
// Convenience typedefs.
|
||||
@@ -143,179 +125,122 @@ class BaseLayer
|
||||
/**
|
||||
* Standard Sigmoid-Layer using the logistic activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = LogisticFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using SigmoidLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<LogisticFunction, arma::mat> Sigmoid;
|
||||
|
||||
/**
|
||||
* Standard Identity-Layer using the identity activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = IdentityFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using IdentityLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
template<typename MatType = arma::mat>
|
||||
using SigmoidType = BaseLayer<LogisticFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard rectified linear unit non-linearity layer.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = RectifierFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using ReLULayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<RectifierFunction, arma::mat> ReLU;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using ReLUType = BaseLayer<RectifierFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard hyperbolic tangent layer.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = TanhFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using TanHLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<TanhFunction, arma::mat> TanH;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using TanHType = BaseLayer<TanhFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard Softplus-Layer using the Softplus activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = SoftplusFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using SoftPlusLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<SoftplusFunction, arma::mat> SoftPlus;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using SoftPlusType = BaseLayer<SoftplusFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard HardSigmoid-Layer using the HardSigmoid activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = HardSigmoidFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using HardSigmoidLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<HardSigmoidFunction, arma::mat> HardSigmoid;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using HardSigmoidType = BaseLayer<HardSigmoidFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard Swish-Layer using the Swish activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = SwishFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using SwishFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<SwishFunction, arma::mat> Swish;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using SwishType = BaseLayer<SwishFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard Mish-Layer using the Mish activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = MishFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using MishFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<MishFunction, arma::mat> Mish;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using MishType = BaseLayer<MishFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard LiSHT-Layer using the LiSHT activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = LiSHTFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using LiSHTFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<LiSHTFunction, arma::mat> LiSHT;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using LiSHTType = BaseLayer<LiSHTFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard GELU-Layer using the GELU activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = GELUFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using GELUFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<GELUFunction, arma::mat> GELU;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using GELUType = BaseLayer<GELUFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard Elliot-Layer using the Elliot activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = ElliotFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using ElliotFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<ElliotFunction, arma::mat> Elliot;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using ElliotType = BaseLayer<ElliotFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard ELiSH-Layer using the ELiSH activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = ElishFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using ElishFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<ElishFunction, arma::mat> Elish;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using ElishType = BaseLayer<ElishFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard Gaussian-Layer using the Gaussian activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = GaussianFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using GaussianFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<GaussianFunction, arma::mat> Gaussian;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using GaussianType = BaseLayer<GaussianFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard HardSwish-Layer using the HardSwish activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = HardSwishFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using HardSwishFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<HardSwishFunction, arma::mat> HardSwish;
|
||||
|
||||
template <typename MatType = arma::mat>
|
||||
using HardSwishType = BaseLayer<HardSwishFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard TanhExp-Layer using the TanhExp activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = TanhExpFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using TanhExpFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType>;
|
||||
typedef BaseLayer<TanhExpFunction, arma::mat> TanhExp;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using TanhExpType = BaseLayer<TanhExpFunction, MatType>;
|
||||
|
||||
/**
|
||||
* Standard SILU-Layer using the SILU activation function.
|
||||
*/
|
||||
template <
|
||||
class ActivationFunction = SILUFunction,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
using SILUFunctionLayer = BaseLayer<
|
||||
ActivationFunction, InputDataType, OutputDataType
|
||||
>;
|
||||
typedef BaseLayer<SILUFunction, arma::mat> SILU;
|
||||
|
||||
template<typename MatType = arma::mat>
|
||||
using SILUType = BaseLayer<SILUFunction, MatType>;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -1,263 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/concat.hpp
|
||||
* @author Marcus Edel
|
||||
* @author Mehul Kumar Nirala
|
||||
*
|
||||
* Definition of the Concat class, which acts as a concatenation container.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_CONCAT_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_CONCAT_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "../visitor/delete_visitor.hpp"
|
||||
#include "../visitor/delta_visitor.hpp"
|
||||
#include "../visitor/output_parameter_visitor.hpp"
|
||||
|
||||
#include "layer_types.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
/**
|
||||
* Implementation of the Concat class. The Concat class works as a
|
||||
* feed-forward fully connected network container which plugs various layers
|
||||
* together.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam CustomLayers Additional custom layers if required.
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat,
|
||||
typename... CustomLayers
|
||||
>
|
||||
class Concat
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create the Concat object using the specified parameters.
|
||||
*
|
||||
* @param model Expose all network modules.
|
||||
* @param run Call the Forward/Backward method before the output is merged.
|
||||
*/
|
||||
Concat(const bool model = false,
|
||||
const bool run = true);
|
||||
|
||||
/**
|
||||
* Create the Concat object using the specified parameters.
|
||||
*
|
||||
* @param inputSize A vector denoting input size of each layer added.
|
||||
* @param axis Concat axis.
|
||||
* @param model Expose all network modules.
|
||||
* @param run Call the Forward/Backward method before the output is merged.
|
||||
*/
|
||||
Concat(arma::Row<size_t>& inputSize,
|
||||
const size_t axis,
|
||||
const bool model = false,
|
||||
const bool run = true);
|
||||
|
||||
/**
|
||||
* Destroy the layers held by the model.
|
||||
*/
|
||||
~Concat();
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
* f(x) by propagating the activity forward through f.
|
||||
*
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, using 3rd-order tensors as
|
||||
* input, calculating the function f(x) by propagating x backwards through f.
|
||||
* Using the results from the feed forward pass.
|
||||
*
|
||||
* @param * (input) The propagated input activation.
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
|
||||
/**
|
||||
* This is the overload of Backward() that runs only a specific layer with
|
||||
* the given input.
|
||||
*
|
||||
* @param * (input) The propagated input activation.
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
* @param index The index of the layer to run.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g,
|
||||
const size_t index);
|
||||
|
||||
/*
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
*
|
||||
* @param input The input parameter used for calculating the gradient.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& /* gradient */);
|
||||
|
||||
/*
|
||||
* This is the overload of Gradient() that runs a specific layer with the
|
||||
* given input.
|
||||
*
|
||||
* @param input The input parameter used for calculating the gradient.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
* @param The index of the layer to run.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient,
|
||||
const size_t index);
|
||||
|
||||
/*
|
||||
* Add a new module to the model.
|
||||
*
|
||||
* @param args The layer parameter.
|
||||
*/
|
||||
template <class LayerType, class... Args>
|
||||
void Add(Args... args) { network.push_back(new LayerType(args...)); }
|
||||
|
||||
/*
|
||||
* Add a new module to the model.
|
||||
*
|
||||
* @param layer The Layer to be added to the model.
|
||||
*/
|
||||
void Add(LayerTypes<CustomLayers...> layer) { network.push_back(layer); }
|
||||
|
||||
//! Return the model modules.
|
||||
std::vector<LayerTypes<CustomLayers...> >& Model()
|
||||
{
|
||||
if (model)
|
||||
{
|
||||
return network;
|
||||
}
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
//! Return the initial point for the optimization.
|
||||
const arma::mat& Parameters() const { return weights; }
|
||||
//! Modify the initial point for the optimization.
|
||||
arma::mat& Parameters() { return weights; }
|
||||
|
||||
//! Get the value of run parameter.
|
||||
bool Run() const { return run; }
|
||||
//! Modify the value of run parameter.
|
||||
bool& Run() { return run; }
|
||||
|
||||
arma::mat const& InputParameter() const { return inputParameter; }
|
||||
//! Modify the input parameter.
|
||||
arma::mat& InputParameter() { return inputParameter; }
|
||||
|
||||
//! Get the output parameter.
|
||||
arma::mat const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
arma::mat& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.e
|
||||
arma::mat const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
arma::mat& Delta() { return delta; }
|
||||
|
||||
//! Get the gradient.
|
||||
arma::mat const& Gradient() const { return gradient; }
|
||||
//! Modify the gradient.
|
||||
arma::mat& Gradient() { return gradient; }
|
||||
|
||||
//! Get the axis of concatenation.
|
||||
size_t const& ConcatAxis() const { return axis; }
|
||||
|
||||
//! Get the size of the weight matrix.
|
||||
size_t WeightSize() const { return 0; }
|
||||
|
||||
/**
|
||||
* Serialize the layer
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Parameter which indicates the input size of modules.
|
||||
arma::Row<size_t> inputSize;
|
||||
|
||||
//! Parameter which indicates the axis of concatenation.
|
||||
size_t axis;
|
||||
|
||||
//! Parameter which indicates whether to use the axis of concatenation.
|
||||
bool useAxis;
|
||||
|
||||
//! Parameter which indicates if the modules should be exposed.
|
||||
bool model;
|
||||
|
||||
//! Parameter which indicates if the Forward/Backward method should be called
|
||||
//! before merging the output.
|
||||
bool run;
|
||||
|
||||
//! Parameter to store channels.
|
||||
size_t channels;
|
||||
|
||||
//! Locally-stored network modules.
|
||||
std::vector<LayerTypes<CustomLayers...> > network;
|
||||
|
||||
//! Locally-stored model weights.
|
||||
OutputDataType weights;
|
||||
|
||||
//! Locally-stored delta visitor.
|
||||
DeltaVisitor deltaVisitor;
|
||||
|
||||
//! Locally-stored output parameter visitor.
|
||||
OutputParameterVisitor outputParameterVisitor;
|
||||
|
||||
//! Locally-stored delete visitor.
|
||||
DeleteVisitor deleteVisitor;
|
||||
|
||||
//! Locally-stored empty list of modules.
|
||||
std::vector<LayerTypes<CustomLayers...> > empty;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
arma::mat delta;
|
||||
|
||||
//! Locally-stored input parameter object.
|
||||
arma::mat inputParameter;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
arma::mat outputParameter;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
arma::mat gradient;
|
||||
}; // class Concat
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
// Include implementation.
|
||||
#include "concat_impl.hpp"
|
||||
|
||||
#endif
|
||||
@@ -1,293 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/concat_impl.hpp
|
||||
* @author Marcus Edel
|
||||
* @author Mehul Kumar Nirala
|
||||
*
|
||||
* Implementation of the Concat class, which acts as a concatenation contain.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_CONCAT_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_CONCAT_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "concat.hpp"
|
||||
|
||||
#include "../visitor/forward_visitor.hpp"
|
||||
#include "../visitor/backward_visitor.hpp"
|
||||
#include "../visitor/gradient_visitor.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
Concat<InputDataType, OutputDataType, CustomLayers...>::Concat(
|
||||
const bool model, const bool run) :
|
||||
axis(0),
|
||||
useAxis(false),
|
||||
model(model),
|
||||
run(run),
|
||||
channels(1)
|
||||
{
|
||||
weights.set_size(0, 0);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
Concat<InputDataType, OutputDataType, CustomLayers...>::Concat(
|
||||
arma::Row<size_t>& inputSize,
|
||||
const size_t axis,
|
||||
const bool model,
|
||||
const bool run) :
|
||||
inputSize(inputSize),
|
||||
axis(axis),
|
||||
useAxis(true),
|
||||
model(model),
|
||||
run(run)
|
||||
{
|
||||
weights.set_size(0, 0);
|
||||
|
||||
// Parameters to help calculate the number of channels.
|
||||
size_t oldColSize = 1, newColSize = 1;
|
||||
// Axis is specified and useAxis is true.
|
||||
if (useAxis)
|
||||
{
|
||||
// Axis is specified without input dimension.
|
||||
// Throw an error.
|
||||
if (inputSize.n_elem > 0)
|
||||
{
|
||||
// Calculate rowSize, newColSize based on the axis
|
||||
// of concatenation. Finally concat along cols and
|
||||
// reshape to original format i.e. (input, batch_size).
|
||||
size_t i = std::min(axis + 1, (size_t) inputSize.n_elem);
|
||||
for (; i < inputSize.n_elem; ++i)
|
||||
{
|
||||
newColSize *= inputSize[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("Input dimensions not specified.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
channels = 1;
|
||||
}
|
||||
if (newColSize <= 0)
|
||||
{
|
||||
throw std::logic_error("Col size is zero.");
|
||||
}
|
||||
channels = newColSize / oldColSize;
|
||||
inputSize.clear();
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
Concat<InputDataType, OutputDataType, CustomLayers...>::~Concat()
|
||||
{
|
||||
if (!model)
|
||||
{
|
||||
// Clear memory.
|
||||
std::for_each(network.begin(), network.end(),
|
||||
boost::apply_visitor(deleteVisitor));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void Concat<InputDataType, OutputDataType, CustomLayers...>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
{
|
||||
if (run)
|
||||
{
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
boost::apply_visitor(ForwardVisitor(input,
|
||||
boost::apply_visitor(outputParameterVisitor, network[i])),
|
||||
network[i]);
|
||||
}
|
||||
}
|
||||
|
||||
output = boost::apply_visitor(outputParameterVisitor, network.front());
|
||||
|
||||
// Reshape output to incorporate the channels.
|
||||
output.reshape(output.n_rows / channels, output.n_cols * channels);
|
||||
|
||||
for (size_t i = 1; i < network.size(); ++i)
|
||||
{
|
||||
arma::Mat<eT> out = boost::apply_visitor(outputParameterVisitor,
|
||||
network[i]);
|
||||
|
||||
out.reshape(out.n_rows / channels, out.n_cols * channels);
|
||||
|
||||
// Vertically concatentate output from each layer.
|
||||
output = arma::join_cols(output, out);
|
||||
}
|
||||
// Reshape output to its original shape.
|
||||
output.reshape(output.n_rows * channels, output.n_cols / channels);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void Concat<InputDataType, OutputDataType, CustomLayers...>::Backward(
|
||||
const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
|
||||
{
|
||||
size_t rowCount = 0;
|
||||
if (run)
|
||||
{
|
||||
arma::Mat<eT> delta;
|
||||
arma::Mat<eT> gyTmp(((arma::Mat<eT>&) gy).memptr(), gy.n_rows / channels,
|
||||
gy.n_cols * channels, false, false);
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
// Use rows from the error corresponding to the output from each layer.
|
||||
size_t rows = boost::apply_visitor(
|
||||
outputParameterVisitor, network[i]).n_rows;
|
||||
|
||||
// Extract from gy the parameters for the i-th network.
|
||||
delta = gyTmp.rows(rowCount / channels, (rowCount + rows) / channels - 1);
|
||||
delta.reshape(delta.n_rows * channels, delta.n_cols / channels);
|
||||
|
||||
boost::apply_visitor(BackwardVisitor(
|
||||
boost::apply_visitor(outputParameterVisitor,
|
||||
network[i]), delta,
|
||||
boost::apply_visitor(deltaVisitor, network[i])), network[i]);
|
||||
rowCount += rows;
|
||||
}
|
||||
|
||||
g = boost::apply_visitor(deltaVisitor, network[0]);
|
||||
for (size_t i = 1; i < network.size(); ++i)
|
||||
{
|
||||
g += boost::apply_visitor(deltaVisitor, network[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g = gy;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void Concat<InputDataType, OutputDataType, CustomLayers...>::Backward(
|
||||
const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g,
|
||||
const size_t index)
|
||||
{
|
||||
size_t rowCount = 0, rows = 0;
|
||||
|
||||
for (size_t i = 0; i < index; ++i)
|
||||
{
|
||||
rowCount += boost::apply_visitor(
|
||||
outputParameterVisitor, network[i]).n_rows;
|
||||
}
|
||||
rows = boost::apply_visitor(outputParameterVisitor, network[index]).n_rows;
|
||||
|
||||
// Reshape gy to extract the i-th layer gy.
|
||||
arma::Mat<eT> gyTmp(((arma::Mat<eT>&) gy).memptr(), gy.n_rows / channels,
|
||||
gy.n_cols * channels, false, false);
|
||||
|
||||
arma::Mat<eT> delta = gyTmp.rows(rowCount / channels, (rowCount + rows) /
|
||||
channels - 1);
|
||||
delta.reshape(delta.n_rows * channels, delta.n_cols / channels);
|
||||
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, network[index]), delta,
|
||||
boost::apply_visitor(deltaVisitor, network[index])), network[index]);
|
||||
|
||||
g = boost::apply_visitor(deltaVisitor, network[index]);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void Concat<InputDataType, OutputDataType, CustomLayers...>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& /* gradient */)
|
||||
{
|
||||
if (run)
|
||||
{
|
||||
size_t rowCount = 0;
|
||||
// Reshape error to extract the i-th layer error.
|
||||
arma::Mat<eT> errorTmp(((arma::Mat<eT>&) error).memptr(),
|
||||
error.n_rows / channels, error.n_cols * channels, false, false);
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
size_t rows = boost::apply_visitor(
|
||||
outputParameterVisitor, network[i]).n_rows;
|
||||
|
||||
// Extract from error the parameters for the i-th network.
|
||||
arma::Mat<eT> err = errorTmp.rows(rowCount / channels, (rowCount + rows) /
|
||||
channels - 1);
|
||||
err.reshape(err.n_rows * channels, err.n_cols / channels);
|
||||
|
||||
boost::apply_visitor(GradientVisitor(input, err), network[i]);
|
||||
rowCount += rows;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void Concat<InputDataType, OutputDataType, CustomLayers...>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& /* gradient */,
|
||||
const size_t index)
|
||||
{
|
||||
size_t rowCount = 0;
|
||||
for (size_t i = 0; i < index; ++i)
|
||||
{
|
||||
rowCount += boost::apply_visitor(outputParameterVisitor,
|
||||
network[i]).n_rows;
|
||||
}
|
||||
size_t rows = boost::apply_visitor(
|
||||
outputParameterVisitor, network[index]).n_rows;
|
||||
|
||||
arma::Mat<eT> errorTmp(((arma::Mat<eT>&) error).memptr(),
|
||||
error.n_rows / channels, error.n_cols * channels, false, false);
|
||||
arma::Mat<eT> err = errorTmp.rows(rowCount / channels, (rowCount + rows) /
|
||||
channels - 1);
|
||||
err.reshape(err.n_rows * channels, err.n_cols / channels);
|
||||
|
||||
boost::apply_visitor(GradientVisitor(input, err), network[index]);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename Archive>
|
||||
void Concat<InputDataType, OutputDataType, CustomLayers...>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(model));
|
||||
ar(CEREAL_NVP(run));
|
||||
|
||||
// Do we have to load or save a model?
|
||||
if (model)
|
||||
{
|
||||
// Clear memory first, if needed.
|
||||
if (cereal::is_loading<Archive>())
|
||||
{
|
||||
std::for_each(network.begin(), network.end(),
|
||||
boost::apply_visitor(deleteVisitor));
|
||||
}
|
||||
ar(CEREAL_VECTOR_VARIANT_POINTER(network));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
#endif
|
||||
@@ -14,7 +14,7 @@
|
||||
#define MLPACK_METHODS_ANN_LAYER_CONCATENATE_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include <mlpack/methods/ann/layer/layer_traits.hpp>
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
@@ -22,36 +22,39 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
/**
|
||||
* Implementation of the Concatenate module class. The Concatenate module
|
||||
* concatenates a constant given matrix to the incoming data.
|
||||
* Note: Users need to use the Concat() function to provide the concat matrix.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* The Concat() function provides the concat matrix, or it can be passed to
|
||||
* the constructor.
|
||||
*
|
||||
* After this layer is applied, the shape of the data will be a vector.
|
||||
*
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class Concatenate
|
||||
template<typename MatType = arma::mat>
|
||||
class ConcatenateType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create the Concatenate object using the specified number of output units.
|
||||
* Create the ConcatenateType object using the given constant matrix as the
|
||||
* data to be concatenated to the output of the forward pass.
|
||||
*/
|
||||
Concatenate();
|
||||
ConcatenateType(const MatType& concat = MatType());
|
||||
|
||||
//! Copy constructor.
|
||||
Concatenate(const Concatenate& layer);
|
||||
//! Clone the ConcatenateType object. This handles polymorphism correctly.
|
||||
ConcatenateType* Clone() const { return new ConcatenateType(*this); }
|
||||
|
||||
//! Move constructor.
|
||||
Concatenate(Concatenate&& layer);
|
||||
// Virtual destructor.
|
||||
virtual ~ConcatenateType() { }
|
||||
|
||||
//! Operator= copy constructor.
|
||||
Concatenate& operator=(const Concatenate& layer);
|
||||
|
||||
//! Operator= move constructor.
|
||||
Concatenate& operator=(Concatenate&& layer);
|
||||
//! Copy the given ConcatenateType layer.
|
||||
ConcatenateType(const ConcatenateType& other);
|
||||
//! Take ownership of the given ConcatenateType layer.
|
||||
ConcatenateType(ConcatenateType&& other);
|
||||
//! Copy the given ConcatenateType layer.
|
||||
ConcatenateType& operator=(const ConcatenateType& other);
|
||||
//! Take ownership of the given ConcatenateType layer.
|
||||
ConcatenateType& operator=(ConcatenateType&& other);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -60,8 +63,7 @@ class Concatenate
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
@@ -72,57 +74,31 @@ class Concatenate
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
void Backward(const MatType& /* input */, const MatType& gy, MatType& g);
|
||||
|
||||
//! Get the concat matrix.
|
||||
OutputDataType const& Concat() const { return concat; }
|
||||
MatType const& Concat() const { return concat; }
|
||||
//! Modify the concat.
|
||||
OutputDataType& Concat() { return concat; }
|
||||
MatType& Concat() { return concat; }
|
||||
|
||||
//! Compute the output dimensions of the layer based on `InputDimensions()`.
|
||||
void ComputeOutputDimensions();
|
||||
|
||||
/**
|
||||
* Serialize the layer
|
||||
* Serialize the layer.
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& /* ar */, const uint32_t /* version */)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally-stored number of input rows.
|
||||
size_t inRows;
|
||||
//! Matrix to be concatenated to input.
|
||||
MatType concat;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
|
||||
//! Locally-stored matrix to be concatenated to input.
|
||||
OutputDataType concat;
|
||||
}; // class Concatenate
|
||||
|
||||
// Standard Concatenate layer.
|
||||
typedef ConcatenateType<arma::mat> Concatenate;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
@@ -19,91 +19,106 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Concatenate<InputDataType, OutputDataType>::Concatenate() :
|
||||
inRows(0)
|
||||
template<typename MatType>
|
||||
ConcatenateType<MatType>::
|
||||
ConcatenateType(const MatType& concat) :
|
||||
concat(concat)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Concatenate<InputDataType, OutputDataType>::Concatenate(
|
||||
const Concatenate& layer) :
|
||||
inRows(layer.inRows),
|
||||
weights(layer.weights),
|
||||
delta(layer.delta),
|
||||
concat(layer.concat)
|
||||
template<typename MatType>
|
||||
ConcatenateType<MatType>::
|
||||
ConcatenateType(const ConcatenateType& other) :
|
||||
Layer<MatType>(other),
|
||||
concat(other.concat)
|
||||
{
|
||||
// Nothing to to here.
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Concatenate<InputDataType, OutputDataType>::Concatenate(Concatenate&& layer) :
|
||||
inRows(layer.inRows),
|
||||
weights(std::move(layer.weights)),
|
||||
delta(std::move(layer.delta)),
|
||||
concat(std::move(layer.concat))
|
||||
template<typename MatType>
|
||||
ConcatenateType<MatType>::
|
||||
ConcatenateType(ConcatenateType&& other) :
|
||||
Layer<MatType>(std::move(other)),
|
||||
concat(other.concat)
|
||||
{
|
||||
// Nothing to do here.
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Concatenate<InputDataType, OutputDataType>&
|
||||
Concatenate<InputDataType, OutputDataType>::
|
||||
operator=(const Concatenate& layer)
|
||||
template<typename MatType>
|
||||
ConcatenateType<MatType>&
|
||||
ConcatenateType<MatType>::operator=(const ConcatenateType& other)
|
||||
{
|
||||
if (this != &layer)
|
||||
if (&other != this)
|
||||
{
|
||||
inRows = layer.inRows;
|
||||
weights = layer.weights;
|
||||
delta = layer.delta;
|
||||
concat = layer.concat;
|
||||
Layer<MatType>::operator=(other);
|
||||
concat = other.concat;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Concatenate<InputDataType, OutputDataType>&
|
||||
Concatenate<InputDataType, OutputDataType>::
|
||||
operator=(Concatenate&& layer)
|
||||
template<typename MatType>
|
||||
ConcatenateType<MatType>&
|
||||
ConcatenateType<MatType>::operator=(ConcatenateType&& other)
|
||||
{
|
||||
if (this != &layer)
|
||||
if (&other != this)
|
||||
{
|
||||
inRows = layer.inRows;
|
||||
weights = std::move(layer.weights);
|
||||
delta = std::move(layer.delta);
|
||||
concat = std::move(layer.concat);
|
||||
Layer<MatType>::operator=(std::move(other));
|
||||
concat = std::move(other.concat);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void Concatenate<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
template<typename MatType>
|
||||
void ConcatenateType<MatType>::Forward(const MatType& input, MatType& output)
|
||||
{
|
||||
if (concat.is_empty())
|
||||
Log::Warn << "The concat matrix has not been provided." << std::endl;
|
||||
|
||||
if (input.n_cols != concat.n_cols)
|
||||
{
|
||||
Log::Fatal << "The number of columns of the concat matrix should be equal "
|
||||
<< "to the number of columns of input matrix." << std::endl;
|
||||
Log::Warn << "Concatenate::Forward(): the concat matrix is empty or was "
|
||||
<< "not provided." << std::endl;
|
||||
}
|
||||
|
||||
inRows = input.n_rows;
|
||||
output = arma::join_cols(input, concat);
|
||||
output.submat(0, 0, input.n_rows - 1, input.n_cols - 1) = input;
|
||||
output.submat(input.n_rows, 0, output.n_rows - 1, input.n_cols - 1) =
|
||||
arma::repmat(arma::vectorise(concat), 1, input.n_cols);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void Concatenate<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
template<typename MatType>
|
||||
void ConcatenateType<MatType>::Backward(
|
||||
const MatType& /* input */,
|
||||
const MatType& gy,
|
||||
MatType& g)
|
||||
{
|
||||
g = gy.submat(0, 0, inRows - 1, concat.n_cols - 1);
|
||||
// Pass back the non-concatenated part.
|
||||
g = gy.submat(0, 0, gy.n_rows - 1 - concat.n_elem, gy.n_cols - 1);
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void ConcatenateType<MatType>::ComputeOutputDimensions()
|
||||
{
|
||||
// This flattens the input.
|
||||
size_t inSize = this->inputDimensions[0];
|
||||
for (size_t i = 1; i < this->inputDimensions.size(); ++i)
|
||||
inSize *= this->inputDimensions[i];
|
||||
|
||||
this->outputDimensions = std::vector<size_t>(this->inputDimensions.size(),
|
||||
1);
|
||||
this->outputDimensions[0] = inSize + concat.n_elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
*/
|
||||
template<typename MatType>
|
||||
template<typename Archive>
|
||||
void ConcatenateType<MatType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(concat));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/constant_impl.hpp
|
||||
* @author Marcus Edel
|
||||
*
|
||||
* Implementation of the Constant class, which outputs a constant value given
|
||||
* any input.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_CONSTANT_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_CONSTANT_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "constant.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Constant<InputDataType, OutputDataType>::Constant(
|
||||
const size_t outSize,
|
||||
const double scalar) :
|
||||
inSize(0),
|
||||
outSize(outSize)
|
||||
{
|
||||
constantOutput = OutputDataType(outSize, 1);
|
||||
constantOutput.fill(scalar);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
void Constant<InputDataType, OutputDataType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
if (inSize == 0)
|
||||
{
|
||||
inSize = input.n_elem;
|
||||
}
|
||||
|
||||
output = constantOutput;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename DataType>
|
||||
void Constant<InputDataType, OutputDataType>::Backward(
|
||||
const DataType& /* input */, const DataType& /* gy */, DataType& g)
|
||||
{
|
||||
g = arma::zeros<DataType>(inSize, 1);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename Archive>
|
||||
void Constant<InputDataType, OutputDataType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(constantOutput));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <mlpack/methods/ann/convolution_rules/svd_convolution.hpp>
|
||||
#include <mlpack/core/util/to_lower.hpp>
|
||||
|
||||
#include "layer_types.hpp"
|
||||
#include "layer.hpp"
|
||||
#include "padding.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
@@ -30,7 +30,7 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* Implementation of the Convolution class. The Convolution class represents a
|
||||
* single layer of a neural network.
|
||||
* Example usage:
|
||||
*
|
||||
*
|
||||
* Suppose we want to pass a matrix M (2744x100) to a `Convolution` layer;
|
||||
* in this example, `M` was obtained from "flattening" 100 images (or Mel
|
||||
* cepstral coefficients, if we talk about speech, or whatever you like) of
|
||||
@@ -62,100 +62,95 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* @tparam ForwardConvolutionRule Convolution to perform forward process.
|
||||
* @tparam BackwardConvolutionRule Convolution to perform backward process.
|
||||
* @tparam GradientConvolutionRule Convolution to calculate gradient.
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template <
|
||||
typename ForwardConvolutionRule = NaiveConvolution<ValidConvolution>,
|
||||
typename BackwardConvolutionRule = NaiveConvolution<FullConvolution>,
|
||||
typename GradientConvolutionRule = NaiveConvolution<ValidConvolution>,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
typename MatType = arma::mat
|
||||
>
|
||||
class Convolution
|
||||
class ConvolutionType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
//! Create the Convolution object.
|
||||
Convolution();
|
||||
//! Create the ConvolutionType object.
|
||||
ConvolutionType();
|
||||
|
||||
/**
|
||||
* Create the Convolution object using the specified number of input maps,
|
||||
* output maps, filter size, stride and padding parameter.
|
||||
* Create the ConvolutionType object using the specified number of output
|
||||
* maps, filter size, stride and padding parameter.
|
||||
*
|
||||
* @param inSize The number of input maps.
|
||||
* @param outSize The number of output maps.
|
||||
* @param maps The number of output maps.
|
||||
* @param kernelWidth Width of the filter/kernel.
|
||||
* @param kernelHeight Height of the filter/kernel.
|
||||
* @param strideWidth Stride of filter application in the x direction.
|
||||
* @param strideHeight Stride of filter application in the y direction.
|
||||
* @param padW Padding width of the input.
|
||||
* @param padH Padding height of the input.
|
||||
* @param inputWidth The width of the input data.
|
||||
* @param inputHeight The height of the input data.
|
||||
* @param paddingType The type of padding (Valid or Same). Defaults to None.
|
||||
* @param paddingType The type of padding ("valid" or "same"). Defaults to
|
||||
* "none". If not specified or "none", the values for `padW` and `padH`
|
||||
* will be used.
|
||||
*/
|
||||
Convolution(const size_t inSize,
|
||||
const size_t outSize,
|
||||
const size_t kernelWidth,
|
||||
const size_t kernelHeight,
|
||||
const size_t strideWidth = 1,
|
||||
const size_t strideHeight = 1,
|
||||
const size_t padW = 0,
|
||||
const size_t padH = 0,
|
||||
const size_t inputWidth = 0,
|
||||
const size_t inputHeight = 0,
|
||||
const std::string& paddingType = "None");
|
||||
ConvolutionType(const size_t maps,
|
||||
const size_t kernelWidth,
|
||||
const size_t kernelHeight,
|
||||
const size_t strideWidth = 1,
|
||||
const size_t strideHeight = 1,
|
||||
const size_t padW = 0,
|
||||
const size_t padH = 0,
|
||||
const std::string& paddingType = "none");
|
||||
|
||||
/**
|
||||
* Create the Convolution object using the specified number of input maps,
|
||||
* output maps, filter size, stride and padding parameter.
|
||||
*
|
||||
* @param inSize The number of input maps.
|
||||
* @param outSize The number of output maps.
|
||||
* @param maps The number of output maps.
|
||||
* @param kernelWidth Width of the filter/kernel.
|
||||
* @param kernelHeight Height of the filter/kernel.
|
||||
* @param strideWidth Stride of filter application in the x direction.
|
||||
* @param strideHeight Stride of filter application in the y direction.
|
||||
* @param padW A two-value tuple indicating padding widths of the input.
|
||||
* First value is padding at left side. Second value is padding on
|
||||
* right side.
|
||||
* @param padH A two-value tuple indicating padding heights of the input.
|
||||
* First value is padding at top. Second value is padding on
|
||||
* bottom.
|
||||
* @param inputWidth The width of the input data.
|
||||
* @param inputHeight The height of the input data.
|
||||
* @param paddingType The type of padding (Valid or Same). Defaults to None.
|
||||
* @param padW A two-value tuple indicating padding widths of the input. The
|
||||
* first value is the padding for the left side; the second value is the
|
||||
* padding on the right side.
|
||||
* @param padH A two-value tuple indicating padding heights of the input. The
|
||||
* first value is the padding for the top; the second value is the
|
||||
* padding on the bottom.
|
||||
* @param paddingType The type of padding ("valid" or "same"). Defaults to
|
||||
* "none". If not specified or "none", the values for `padW` and `padH`
|
||||
* will be used.
|
||||
*/
|
||||
Convolution(const size_t inSize,
|
||||
const size_t outSize,
|
||||
const size_t kernelWidth,
|
||||
const size_t kernelHeight,
|
||||
const size_t strideWidth,
|
||||
const size_t strideHeight,
|
||||
const std::tuple<size_t, size_t>& padW,
|
||||
const std::tuple<size_t, size_t>& padH,
|
||||
const size_t inputWidth = 0,
|
||||
const size_t inputHeight = 0,
|
||||
const std::string& paddingType = "None");
|
||||
ConvolutionType(const size_t maps,
|
||||
const size_t kernelWidth,
|
||||
const size_t kernelHeight,
|
||||
const size_t strideWidth,
|
||||
const size_t strideHeight,
|
||||
const std::tuple<size_t, size_t>& padW,
|
||||
const std::tuple<size_t, size_t>& padH,
|
||||
const std::string& paddingType = "none");
|
||||
|
||||
//! Copy constructor.
|
||||
Convolution(const Convolution& layer);
|
||||
//! Clone the ConvolutionType object. This handles polymorphism correctly.
|
||||
ConvolutionType* Clone() const { return new ConvolutionType(*this); }
|
||||
|
||||
//! Move constructor.
|
||||
Convolution(Convolution&&);
|
||||
//! Copy the given ConvolutionType (but not weights).
|
||||
ConvolutionType(const ConvolutionType& layer);
|
||||
|
||||
//! Copy assignment operator.
|
||||
Convolution& operator=(const Convolution& layer);
|
||||
//! Take ownership of the given ConvolutionType (but not weights).
|
||||
ConvolutionType(ConvolutionType&&);
|
||||
|
||||
//! Move assignment operator.
|
||||
Convolution& operator=(Convolution&& layer);
|
||||
//! Copy the given ConvolutionType (but not weights).
|
||||
ConvolutionType& operator=(const ConvolutionType& layer);
|
||||
|
||||
//! Take ownership of the given ConvolutionType (but not weights).
|
||||
ConvolutionType& operator=(ConvolutionType&& layer);
|
||||
|
||||
// Virtual destructor.
|
||||
virtual ~ConvolutionType() { }
|
||||
|
||||
/*
|
||||
* Set the weight and bias term.
|
||||
*/
|
||||
void Reset();
|
||||
void SetWeights(typename MatType::elem_type* weightsPtr);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -164,8 +159,7 @@ class Convolution
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
@@ -176,135 +170,91 @@ class Convolution
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
void Backward(const MatType& /* input */,
|
||||
const MatType& gy,
|
||||
MatType& g);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
*
|
||||
* @param input The input parameter used for calculating the gradient.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient);
|
||||
void Gradient(const MatType& /* input */,
|
||||
const MatType& error,
|
||||
MatType& gradient);
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
MatType const& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
MatType& Parameters() { return weights; }
|
||||
|
||||
//! Get the weight of the layer.
|
||||
arma::cube const& Weight() const { return weight; }
|
||||
//! Modify the weight of the layer.
|
||||
arma::cube& Weight() { return weight; }
|
||||
//! Get the weight of the layer as a cube.
|
||||
arma::Cube<typename MatType::elem_type> const& Weight() const
|
||||
{
|
||||
return weight;
|
||||
}
|
||||
//! Modify the weight of the layer as a cube.
|
||||
arma::Cube<typename MatType::elem_type>& Weight() { return weight; }
|
||||
|
||||
//! Get the bias of the layer.
|
||||
arma::mat const& Bias() const { return bias; }
|
||||
MatType const& Bias() const { return bias; }
|
||||
//! Modify the bias of the layer.
|
||||
arma::mat& Bias() { return bias; }
|
||||
|
||||
//! Get the input parameter.
|
||||
InputDataType const& InputParameter() const { return inputParameter; }
|
||||
//! Modify the input parameter.
|
||||
InputDataType& InputParameter() { return inputParameter; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return gradient; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return gradient; }
|
||||
|
||||
//! Get the input width.
|
||||
size_t InputWidth() const { return inputWidth; }
|
||||
//! Modify input the width.
|
||||
size_t& InputWidth() { return inputWidth; }
|
||||
|
||||
//! Get the input height.
|
||||
size_t InputHeight() const { return inputHeight; }
|
||||
//! Modify the input height.
|
||||
size_t& InputHeight() { return inputHeight; }
|
||||
|
||||
//! Get the output width.
|
||||
size_t OutputWidth() const { return outputWidth; }
|
||||
//! Modify the output width.
|
||||
size_t& OutputWidth() { return outputWidth; }
|
||||
|
||||
//! Get the output height.
|
||||
size_t OutputHeight() const { return outputHeight; }
|
||||
//! Modify the output height.
|
||||
size_t& OutputHeight() { return outputHeight; }
|
||||
|
||||
//! Get the number of input maps.
|
||||
size_t InputSize() const { return inSize; }
|
||||
MatType& Bias() { return bias; }
|
||||
|
||||
//! Get the number of output maps.
|
||||
size_t OutputSize() const { return outSize; }
|
||||
size_t const& Maps() const { return maps; }
|
||||
|
||||
//! Get the kernel width.
|
||||
size_t KernelWidth() const { return kernelWidth; }
|
||||
size_t const& KernelWidth() const { return kernelWidth; }
|
||||
//! Modify the kernel width.
|
||||
size_t& KernelWidth() { return kernelWidth; }
|
||||
|
||||
//! Get the kernel height.
|
||||
size_t KernelHeight() const { return kernelHeight; }
|
||||
size_t const& KernelHeight() const { return kernelHeight; }
|
||||
//! Modify the kernel height.
|
||||
size_t& KernelHeight() { return kernelHeight; }
|
||||
|
||||
//! Get the stride width.
|
||||
size_t StrideWidth() const { return strideWidth; }
|
||||
size_t const& StrideWidth() const { return strideWidth; }
|
||||
//! Modify the stride width.
|
||||
size_t& StrideWidth() { return strideWidth; }
|
||||
|
||||
//! Get the stride height.
|
||||
size_t StrideHeight() const { return strideHeight; }
|
||||
size_t const& StrideHeight() const { return strideHeight; }
|
||||
//! Modify the stride height.
|
||||
size_t& StrideHeight() { return strideHeight; }
|
||||
|
||||
//! Get the top padding height.
|
||||
size_t PadHTop() const { return padHTop; }
|
||||
size_t const& PadHTop() const { return padHTop; }
|
||||
//! Modify the top padding height.
|
||||
size_t& PadHTop() { return padHTop; }
|
||||
|
||||
//! Get the bottom padding height.
|
||||
size_t PadHBottom() const { return padHBottom; }
|
||||
size_t const& PadHBottom() const { return padHBottom; }
|
||||
//! Modify the bottom padding height.
|
||||
size_t& PadHBottom() { return padHBottom; }
|
||||
|
||||
//! Get the left padding width.
|
||||
size_t PadWLeft() const { return padWLeft; }
|
||||
size_t const& PadWLeft() const { return padWLeft; }
|
||||
//! Modify the left padding width.
|
||||
size_t& PadWLeft() { return padWLeft; }
|
||||
|
||||
//! Get the right padding width.
|
||||
size_t PadWRight() const { return padWRight; }
|
||||
size_t const& PadWRight() const { return padWRight; }
|
||||
//! Modify the right padding width.
|
||||
size_t& PadWRight() { return padWRight; }
|
||||
|
||||
//! Get size of weights for the layer.
|
||||
size_t WeightSize() const
|
||||
{
|
||||
return (outSize * inSize * kernelWidth * kernelHeight) + outSize;
|
||||
return (maps * inMaps * higherInDimensions * kernelWidth * kernelHeight) +
|
||||
maps;
|
||||
}
|
||||
|
||||
//! Get the shape of the input.
|
||||
size_t InputShape() const
|
||||
{
|
||||
return inputHeight * inputWidth * inSize;
|
||||
}
|
||||
//! Compute the output dimensions of the layer based on `InputDimensions()`.
|
||||
void ComputeOutputDimensions();
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
@@ -313,7 +263,7 @@ class Convolution
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
/*
|
||||
/**
|
||||
* Return the convolution output size.
|
||||
*
|
||||
* @param size The size of the input (row or column).
|
||||
@@ -332,12 +282,12 @@ class Convolution
|
||||
return std::floor(size + pSideOne + pSideTwo - k) / s + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Function to assign padding such that output size is same as input size.
|
||||
*/
|
||||
void InitializeSamePadding();
|
||||
|
||||
/*
|
||||
/**
|
||||
* Rotates a 3rd-order tensor counterclockwise by 180 degrees.
|
||||
*
|
||||
* @param input The input data to be rotated.
|
||||
@@ -353,7 +303,7 @@ class Convolution
|
||||
output.slice(s) = arma::fliplr(arma::flipud(input.slice(s)));
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Rotates a dense matrix counterclockwise by 180 degrees.
|
||||
*
|
||||
* @param input The input data to be rotated.
|
||||
@@ -366,11 +316,8 @@ class Convolution
|
||||
output = arma::fliplr(arma::flipud(input));
|
||||
}
|
||||
|
||||
//! Locally-stored number of input channels.
|
||||
size_t inSize;
|
||||
|
||||
//! Locally-stored number of output channels.
|
||||
size_t outSize;
|
||||
size_t maps;
|
||||
|
||||
//! Locally-stored number of input units.
|
||||
size_t batchSize;
|
||||
@@ -400,54 +347,46 @@ class Convolution
|
||||
size_t padHTop;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
MatType weights;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
arma::cube weight;
|
||||
arma::Cube<typename MatType::elem_type> weight;
|
||||
|
||||
//! Locally-stored bias term object.
|
||||
arma::mat bias;
|
||||
|
||||
//! Locally-stored input width.
|
||||
size_t inputWidth;
|
||||
|
||||
//! Locally-stored input height.
|
||||
size_t inputHeight;
|
||||
|
||||
//! Locally-stored output width.
|
||||
size_t outputWidth;
|
||||
|
||||
//! Locally-stored output height.
|
||||
size_t outputHeight;
|
||||
MatType bias;
|
||||
|
||||
//! Locally-stored transformed output parameter.
|
||||
arma::cube outputTemp;
|
||||
arma::Cube<typename MatType::elem_type> outputTemp;
|
||||
|
||||
//! Locally-stored transformed padded input parameter.
|
||||
arma::cube inputPaddedTemp;
|
||||
MatType inputPadded;
|
||||
|
||||
//! Locally-stored transformed error parameter.
|
||||
arma::cube gTemp;
|
||||
arma::Cube<typename MatType::elem_type> gTemp;
|
||||
|
||||
//! Locally-stored transformed gradient parameter.
|
||||
arma::cube gradientTemp;
|
||||
arma::Cube<typename MatType::elem_type> gradientTemp;
|
||||
|
||||
//! Locally-stored padding layer.
|
||||
ann::Padding<> padding;
|
||||
ann::Padding padding;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
//! Type of padding.
|
||||
std::string paddingType;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
|
||||
//! Locally-stored input parameter object.
|
||||
InputDataType inputParameter;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
//! Locally-cached number of input maps.
|
||||
size_t inMaps;
|
||||
//! Locally-cached higher-order input dimensions.
|
||||
size_t higherInDimensions;
|
||||
}; // class Convolution
|
||||
|
||||
// Standard Convolution layer.
|
||||
typedef ConvolutionType<
|
||||
NaiveConvolution<ValidConvolution>,
|
||||
NaiveConvolution<FullConvolution>,
|
||||
NaiveConvolution<ValidConvolution>,
|
||||
arma::mat
|
||||
> Convolution;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,10 +16,7 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "layer_types.hpp"
|
||||
#include "add_merge.hpp"
|
||||
#include "linear.hpp"
|
||||
#include "sequential.hpp"
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
@@ -28,55 +25,58 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* The DropConnect layer is a regularizer that randomly with probability
|
||||
* ratio sets the connection values to zero and scales the remaining
|
||||
* elements by factor 1 /(1 - ratio). The output is scaled with 1 / (1 - p)
|
||||
* when deterministic is false. In the deterministic mode(during testing),
|
||||
* the layer just computes the output. The output is computed according
|
||||
* to the input layer. If no input layer is given, it will take a linear layer
|
||||
* as default.
|
||||
* when in training mode. During testing, the layer just computes the output.
|
||||
* The output is computed according to the input layer. If no input layer is
|
||||
* given, it will take a linear layer as default.
|
||||
*
|
||||
* Note:
|
||||
* During training you should set deterministic to false and during testing
|
||||
* you should set deterministic to true.
|
||||
*
|
||||
* For more information, see the following.
|
||||
* For more information, see the following.
|
||||
*
|
||||
* @code
|
||||
* @inproceedings{WanICML2013,
|
||||
* title={Regularization of Neural Networks using DropConnect},
|
||||
* title = {Regularization of Neural Networks using DropConnect},
|
||||
* booktitle = {Proceedings of the 30th International Conference on Machine
|
||||
* Learning(ICML - 13)},
|
||||
* author = {Li Wan and Matthew Zeiler and Sixin Zhang and Yann L. Cun and
|
||||
* Rob Fergus},
|
||||
* year = {2013},
|
||||
* url = {http://proceedings.mlr.press/v28/wan13.pdf}
|
||||
* author = {Li Wan and Matthew Zeiler and Sixin Zhang and Yann L. Cun and
|
||||
* Rob Fergus},
|
||||
* year = {2013},
|
||||
* url = {http://proceedings.mlr.press/v28/wan13.pdf}
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template<
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class DropConnect
|
||||
template<typename MatType = arma::mat>
|
||||
class DropConnectType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
//! Create the DropConnect object.
|
||||
DropConnect();
|
||||
DropConnectType();
|
||||
|
||||
/**
|
||||
* Creates the DropConnect Layer as a Linear Object that takes input size,
|
||||
* output size and ratio as parameter.
|
||||
* Creates the DropConnect Layer as a Linear Object that takes the number of
|
||||
* output units and a ratio as parameter.
|
||||
*
|
||||
* @param inSize The number of input units.
|
||||
* @param outSize The number of output units.
|
||||
* @param ratio The probability of setting a value to zero.
|
||||
*/
|
||||
DropConnect(const size_t inSize,
|
||||
const size_t outSize,
|
||||
const double ratio = 0.5);
|
||||
DropConnectType(const size_t outSize,
|
||||
const double ratio = 0.5);
|
||||
|
||||
//! Clone the DropConnectType object. This handles polymorphism correctly.
|
||||
DropConnectType* Clone() const { return new DropConnectType(*this); }
|
||||
|
||||
// Virtual destructor.
|
||||
virtual ~DropConnectType();
|
||||
|
||||
//! Copy the given DropConnectType (except for weights).
|
||||
DropConnectType(const DropConnectType& other);
|
||||
//! Take ownership of the given DropConnectType (except for weights).
|
||||
DropConnectType(DropConnectType&& other);
|
||||
//! Copy the given DropConnectType (except for weights).
|
||||
DropConnectType& operator=(const DropConnectType& other);
|
||||
//! Take ownership of the given DropConnectType (except for weights).
|
||||
DropConnectType& operator=(DropConnectType&& other);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of the DropConnect layer.
|
||||
@@ -84,8 +84,7 @@ class DropConnect
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of the DropConnect layer.
|
||||
@@ -94,10 +93,7 @@ class DropConnect
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
void Backward(const MatType& input, const MatType& gy, MatType& g);
|
||||
|
||||
/**
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
@@ -106,39 +102,7 @@ class DropConnect
|
||||
* @param error The calculated error.
|
||||
* @param * (gradient) The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& /* gradient */);
|
||||
|
||||
//! Get the model modules.
|
||||
std::vector<LayerTypes<> >& Model() { return network; }
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return gradient; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return gradient; }
|
||||
|
||||
//! The value of the deterministic parameter.
|
||||
bool Deterministic() const { return deterministic; }
|
||||
|
||||
//! Modify the value of the deterministic parameter.
|
||||
bool &Deterministic() { return deterministic; }
|
||||
void Gradient(const MatType& input, const MatType& error, MatType& gradient);
|
||||
|
||||
//! The probability of setting a value to zero.
|
||||
double Ratio() const { return ratio; }
|
||||
@@ -150,8 +114,14 @@ class DropConnect
|
||||
scale = 1.0 / (1.0 - ratio);
|
||||
}
|
||||
|
||||
//! Return the size of the weight matrix.
|
||||
size_t WeightSize() const { return 0; }
|
||||
//! Compute the output dimensions of the layer based on `InputDimensions()`.
|
||||
void ComputeOutputDimensions();
|
||||
|
||||
//! Return the size of the weights.
|
||||
size_t WeightSize() const { return baseLayer->WeightSize(); }
|
||||
|
||||
// Set the weights to use the given memory `weightsPtr`.
|
||||
void SetWeights(typename MatType::elem_type* weightsPtr);
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
@@ -166,34 +136,21 @@ class DropConnect
|
||||
//! The scale fraction.
|
||||
double scale;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
|
||||
//! Locally-stored mask object.
|
||||
OutputDataType mask;
|
||||
|
||||
//! If true dropout and scaling is disabled, see notes above.
|
||||
bool deterministic;
|
||||
MatType mask;
|
||||
|
||||
//! Denoise mask for the weights.
|
||||
OutputDataType denoise;
|
||||
MatType denoise;
|
||||
|
||||
//! Locally-stored layer module.
|
||||
LayerTypes<> baseLayer;
|
||||
|
||||
//! Locally-stored network modules.
|
||||
std::vector<LayerTypes<> > network;
|
||||
Layer<MatType>* baseLayer;
|
||||
}; // class DropConnect.
|
||||
|
||||
// Convenience typedefs.
|
||||
|
||||
// Standard DropConnect layer.
|
||||
typedef DropConnectType<arma::mat> DropConnect;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
@@ -17,112 +17,160 @@
|
||||
// In case it hasn't yet been included.
|
||||
#include "dropconnect.hpp"
|
||||
|
||||
#include "../visitor/delete_visitor.hpp"
|
||||
#include "../visitor/forward_visitor.hpp"
|
||||
#include "../visitor/backward_visitor.hpp"
|
||||
#include "../visitor/gradient_visitor.hpp"
|
||||
#include "../visitor/parameters_set_visitor.hpp"
|
||||
#include "../visitor/parameters_visitor.hpp"
|
||||
#include "linear.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
DropConnect<InputDataType, OutputDataType>::DropConnect() :
|
||||
template<typename MatType>
|
||||
DropConnectType<MatType>::DropConnectType() :
|
||||
Layer<MatType>(),
|
||||
ratio(0.5),
|
||||
scale(2.0),
|
||||
deterministic(true)
|
||||
baseLayer(new LinearType<MatType>(0))
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
DropConnect<InputDataType, OutputDataType>::DropConnect(
|
||||
const size_t inSize,
|
||||
template<typename MatType>
|
||||
DropConnectType<MatType>::DropConnectType(
|
||||
const size_t outSize,
|
||||
const double ratio) :
|
||||
Layer<MatType>(),
|
||||
ratio(ratio),
|
||||
scale(1.0 / (1 - ratio)),
|
||||
baseLayer(new Linear<InputDataType, OutputDataType>(inSize, outSize))
|
||||
baseLayer(new LinearType<MatType>(outSize))
|
||||
{
|
||||
network.push_back(baseLayer);
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void DropConnect<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input,
|
||||
arma::Mat<eT>& output)
|
||||
template<typename MatType>
|
||||
DropConnectType<MatType>::~DropConnectType()
|
||||
{
|
||||
// The DropConnect mask will not be multiplied in the deterministic mode
|
||||
// (during testing).
|
||||
if (deterministic)
|
||||
delete baseLayer;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
DropConnectType<MatType>::DropConnectType(const DropConnectType& other) :
|
||||
Layer<MatType>(other),
|
||||
ratio(other.ratio),
|
||||
scale(other.scale),
|
||||
baseLayer(other.baseLayer->Clone())
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
DropConnectType<MatType>::DropConnectType(DropConnectType&& other) :
|
||||
Layer<MatType>(std::move(other)),
|
||||
ratio(std::move(other.ratio)),
|
||||
scale(std::move(other.scale)),
|
||||
baseLayer(std::move(other.baseLayer))
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
DropConnectType<MatType>&
|
||||
DropConnectType<MatType>::operator=(const DropConnectType& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
boost::apply_visitor(ForwardVisitor(input, output), baseLayer);
|
||||
Layer<MatType>::operator=(other);
|
||||
ratio = other.ratio;
|
||||
scale = other.scale;
|
||||
baseLayer = other.baseLayer->Clone();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
DropConnectType<MatType>&
|
||||
DropConnectType<MatType>::operator=(DropConnectType&& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
Layer<MatType>::operator=(std::move(other));
|
||||
ratio = std::move(other.ratio);
|
||||
scale = std::move(other.scale);
|
||||
baseLayer = std::move(other.baseLayer);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void DropConnectType<MatType>::Forward(const MatType& input, MatType& output)
|
||||
{
|
||||
// The DropConnect mask will not be multiplied in testing mode.
|
||||
if (!this->training)
|
||||
{
|
||||
baseLayer->Forward(input, output);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save weights for denoising.
|
||||
boost::apply_visitor(ParametersVisitor(denoise), baseLayer);
|
||||
denoise = baseLayer->Parameters();
|
||||
|
||||
// Scale with input / (1 - ratio) and set values to zero with
|
||||
// probability ratio.
|
||||
mask = arma::randu<arma::Mat<eT> >(denoise.n_rows, denoise.n_cols);
|
||||
mask = arma::randu<MatType>(denoise.n_rows, denoise.n_cols);
|
||||
mask.transform([&](double val) { return (val > ratio); });
|
||||
|
||||
arma::mat tmp = denoise % mask;
|
||||
boost::apply_visitor(ParametersSetVisitor(tmp), baseLayer);
|
||||
|
||||
boost::apply_visitor(ForwardVisitor(input, output), baseLayer);
|
||||
baseLayer->Parameters() = denoise % mask;
|
||||
baseLayer->Forward(input, output);
|
||||
|
||||
output = output * scale;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void DropConnect<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
template<typename MatType>
|
||||
void DropConnectType<MatType>::Backward(
|
||||
const MatType& input,
|
||||
const MatType& gy,
|
||||
MatType& g)
|
||||
{
|
||||
boost::apply_visitor(BackwardVisitor(input, gy, g), baseLayer);
|
||||
baseLayer->Backward(input, gy, g);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void DropConnect<InputDataType, OutputDataType>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& /* gradient */)
|
||||
template<typename MatType>
|
||||
void DropConnectType<MatType>::Gradient(
|
||||
const MatType& input,
|
||||
const MatType& error,
|
||||
MatType& gradient)
|
||||
{
|
||||
boost::apply_visitor(GradientVisitor(input, error),
|
||||
baseLayer);
|
||||
baseLayer->Gradient(input, error, gradient);
|
||||
|
||||
// Denoise the weights.
|
||||
boost::apply_visitor(ParametersSetVisitor(denoise), baseLayer);
|
||||
baseLayer->Parameters() = denoise;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename MatType>
|
||||
void DropConnectType<MatType>::ComputeOutputDimensions()
|
||||
{
|
||||
// Propagate input dimensions to the base layer.
|
||||
baseLayer->InputDimensions() = this->inputDimensions;
|
||||
this->outputDimensions = baseLayer->OutputDimensions();
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void DropConnectType<MatType>::SetWeights(
|
||||
typename MatType::elem_type* weightsPtr)
|
||||
{
|
||||
baseLayer->SetWeights(weightsPtr);
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
template<typename Archive>
|
||||
void DropConnect<InputDataType, OutputDataType>::serialize(
|
||||
void DropConnectType<MatType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
// Delete the old network first, if needed.
|
||||
if (cereal::is_loading<Archive>())
|
||||
{
|
||||
boost::apply_visitor(DeleteVisitor(), baseLayer);
|
||||
}
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(ratio));
|
||||
ar(CEREAL_NVP(scale));
|
||||
ar(CEREAL_VARIANT_POINTER(baseLayer));
|
||||
|
||||
if (cereal::is_loading<Archive>())
|
||||
{
|
||||
network.clear();
|
||||
network.push_back(baseLayer);
|
||||
}
|
||||
ar(CEREAL_POINTER(baseLayer));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -15,18 +15,16 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
|
||||
/**
|
||||
* The dropout layer is a regularizer that randomly with probability 'ratio'
|
||||
* sets input values to zero and scales the remaining elements by factor 1 /
|
||||
* (1 - ratio) rather than during test time so as to keep the expected sum same.
|
||||
* In the deterministic mode (during testing), there is no change in the input.
|
||||
*
|
||||
* Note: During training you should set deterministic to false and during
|
||||
* testing you should set deterministic to true.
|
||||
* When the layer is in testing mode, there is no change in the input.
|
||||
*
|
||||
* For more information, see the following.
|
||||
*
|
||||
@@ -43,14 +41,11 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template<typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat>
|
||||
class Dropout
|
||||
template<typename MatType = arma::mat>
|
||||
class DropoutType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -58,19 +53,22 @@ class Dropout
|
||||
*
|
||||
* @param ratio The probability of setting a value to zero.
|
||||
*/
|
||||
Dropout(const double ratio = 0.5);
|
||||
DropoutType(const double ratio = 0.5);
|
||||
|
||||
//! Copy Constructor
|
||||
Dropout(const Dropout& layer);
|
||||
//! Clone the DropoutType object. This handles polymorphism correctly.
|
||||
DropoutType* Clone() const { return new DropoutType(*this); }
|
||||
|
||||
//! Move Constructor
|
||||
Dropout(const Dropout&&);
|
||||
// Virtual destructor.
|
||||
virtual ~DropoutType() { }
|
||||
|
||||
//! Copy assignment operator
|
||||
Dropout& operator=(const Dropout& layer);
|
||||
|
||||
//! Move assignment operator
|
||||
Dropout& operator=(Dropout&& layer);
|
||||
//! Copy the given DropoutType.
|
||||
DropoutType(const DropoutType& other);
|
||||
//! Take ownership of the given DropoutType.
|
||||
DropoutType(DropoutType&& other);
|
||||
//! Copy the given DropoutType.
|
||||
DropoutType& operator=(const DropoutType& other);
|
||||
//! Take ownership of the given DropoutType.
|
||||
DropoutType& operator=(DropoutType&& other);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of the dropout layer.
|
||||
@@ -78,8 +76,7 @@ class Dropout
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of the dropout layer.
|
||||
@@ -88,25 +85,7 @@ class Dropout
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the detla.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! The value of the deterministic parameter.
|
||||
bool Deterministic() const { return deterministic; }
|
||||
//! Modify the value of the deterministic parameter.
|
||||
bool& Deterministic() { return deterministic; }
|
||||
void Backward(const MatType& /* input */, const MatType& gy, MatType& g);
|
||||
|
||||
//! The probability of setting a value to zero.
|
||||
double Ratio() const { return ratio; }
|
||||
@@ -125,24 +104,20 @@ class Dropout
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
|
||||
//! Locally-stored mast object.
|
||||
OutputDataType mask;
|
||||
//! Locally-stored mask object.
|
||||
MatType mask;
|
||||
|
||||
//! The probability of setting a value to zero.
|
||||
double ratio;
|
||||
|
||||
//! The scale fraction.
|
||||
double scale;
|
||||
}; // class DropoutType
|
||||
|
||||
//! If true dropout and scaling is disabled, see notes above.
|
||||
bool deterministic;
|
||||
}; // class Dropout
|
||||
// Convenience typedefs.
|
||||
|
||||
// Standard Dropout layer.
|
||||
typedef DropoutType<arma::mat> Dropout;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -19,73 +19,66 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Dropout<InputDataType, OutputDataType>::Dropout(
|
||||
template<typename MatType>
|
||||
DropoutType<MatType>::DropoutType(
|
||||
const double ratio) :
|
||||
ratio(ratio),
|
||||
scale(1.0 / (1.0 - ratio)),
|
||||
deterministic(false)
|
||||
scale(1.0 / (1.0 - ratio))
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Dropout<InputDataType, OutputDataType>::Dropout(
|
||||
const Dropout& layer) :
|
||||
ratio(layer.ratio),
|
||||
scale(layer.scale),
|
||||
deterministic(layer.deterministic)
|
||||
template<typename MatType>
|
||||
DropoutType<MatType>::DropoutType(const DropoutType& other) :
|
||||
Layer<MatType>(other),
|
||||
ratio(other.ratio),
|
||||
scale(other.scale)
|
||||
{
|
||||
// Nothing to do here.
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Dropout<InputDataType, OutputDataType>::Dropout(
|
||||
const Dropout&& layer) :
|
||||
ratio(std::move(layer.ratio)),
|
||||
scale(std::move(scale)),
|
||||
deterministic(std::move(deterministic))
|
||||
template<typename MatType>
|
||||
DropoutType<MatType>::DropoutType(DropoutType&& other) :
|
||||
Layer<MatType>(std::move(other)),
|
||||
ratio(std::move(other.ratio)),
|
||||
scale(std::move(other.scale))
|
||||
{
|
||||
// Nothing to do here.
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Dropout<InputDataType, OutputDataType>&
|
||||
Dropout<InputDataType, OutputDataType>::
|
||||
operator=(const Dropout& layer)
|
||||
template<typename MatType>
|
||||
DropoutType<MatType>&
|
||||
DropoutType<MatType>::operator=(const DropoutType& other)
|
||||
{
|
||||
if (this != &layer)
|
||||
if (&other != this)
|
||||
{
|
||||
ratio = layer.ratio;
|
||||
scale = layer.scale;
|
||||
deterministic = layer.deterministic;
|
||||
Layer<MatType>::operator=(other);
|
||||
ratio = other.ratio;
|
||||
scale = other.scale;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
Dropout<InputDataType, OutputDataType>&
|
||||
Dropout<InputDataType, OutputDataType>::
|
||||
operator=(Dropout&& layer)
|
||||
template<typename MatType>
|
||||
DropoutType<MatType>&
|
||||
DropoutType<MatType>::operator=(DropoutType&& other)
|
||||
{
|
||||
if (this != &layer)
|
||||
if (&other != this)
|
||||
{
|
||||
ratio = std::move(layer.ratio);
|
||||
scale = std::move(layer.scale);
|
||||
deterministic = std::move(layer.deterministic);
|
||||
Layer<MatType>::operator=(std::move(other));
|
||||
ratio = std::move(other.ratio);
|
||||
scale = std::move(other.scale);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void Dropout<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input,
|
||||
arma::Mat<eT>& output)
|
||||
template<typename MatType>
|
||||
void DropoutType<MatType>::Forward(const MatType& input, MatType& output)
|
||||
{
|
||||
// The dropout mask will not be multiplied in the deterministic mode
|
||||
// (during testing).
|
||||
if (deterministic)
|
||||
// The dropout mask will not be multiplied in testing mode.
|
||||
if (!this->training)
|
||||
{
|
||||
output = input;
|
||||
}
|
||||
@@ -93,28 +86,29 @@ void Dropout<InputDataType, OutputDataType>::Forward(
|
||||
{
|
||||
// Scale with input / (1 - ratio) and set values to zero with probability
|
||||
// 'ratio'.
|
||||
mask = arma::randu<arma::Mat<eT> >(input.n_rows, input.n_cols);
|
||||
mask = arma::randu<MatType>(input.n_rows, input.n_cols);
|
||||
mask.transform([&](double val) { return (val > ratio); });
|
||||
output = input % mask * scale;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void Dropout<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
template<typename MatType>
|
||||
void DropoutType<MatType>::Backward(
|
||||
const MatType& /* input */,
|
||||
const MatType& gy,
|
||||
MatType& g)
|
||||
{
|
||||
g = gy % mask * scale;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename MatType>
|
||||
template<typename Archive>
|
||||
void Dropout<InputDataType, OutputDataType>::serialize(
|
||||
void DropoutType<MatType>::serialize(
|
||||
Archive& ar,
|
||||
const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(ratio));
|
||||
|
||||
// Reset scale.
|
||||
|
||||
@@ -1,411 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/gru_impl.hpp
|
||||
* @author Sumedh Ghaisas
|
||||
*
|
||||
* Implementation of the GRU class, which implements a gru network
|
||||
* layer.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_GRU_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_GRU_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "gru.hpp"
|
||||
|
||||
#include "../visitor/forward_visitor.hpp"
|
||||
#include "../visitor/backward_visitor.hpp"
|
||||
#include "../visitor/gradient_visitor.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
GRU<InputDataType, OutputDataType>::GRU()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType>
|
||||
GRU<InputDataType, OutputDataType>::GRU(
|
||||
const size_t inSize,
|
||||
const size_t outSize,
|
||||
const size_t rho) :
|
||||
inSize(inSize),
|
||||
outSize(outSize),
|
||||
rho(rho),
|
||||
batchSize(1),
|
||||
forwardStep(0),
|
||||
backwardStep(0),
|
||||
gradientStep(0),
|
||||
deterministic(false)
|
||||
{
|
||||
// Input specific linear layers(for zt, rt, ot).
|
||||
input2GateModule = new Linear<>(inSize, 3 * outSize);
|
||||
|
||||
// Previous output gates (for zt and rt).
|
||||
output2GateModule = new LinearNoBias<>(outSize, 2 * outSize);
|
||||
|
||||
// Previous output gate for ot.
|
||||
outputHidden2GateModule = new LinearNoBias<>(outSize, outSize);
|
||||
|
||||
network.push_back(input2GateModule);
|
||||
network.push_back(output2GateModule);
|
||||
network.push_back(outputHidden2GateModule);
|
||||
|
||||
inputGateModule = new SigmoidLayer<>();
|
||||
forgetGateModule = new SigmoidLayer<>();
|
||||
hiddenStateModule = new TanHLayer<>();
|
||||
|
||||
network.push_back(inputGateModule);
|
||||
network.push_back(hiddenStateModule);
|
||||
network.push_back(forgetGateModule);
|
||||
|
||||
prevError = arma::zeros<arma::mat>(3 * outSize, batchSize);
|
||||
|
||||
allZeros = arma::zeros<arma::mat>(outSize, batchSize);
|
||||
|
||||
outParameter.emplace_back(allZeros.memptr(),
|
||||
allZeros.n_rows, allZeros.n_cols, false, true);
|
||||
|
||||
prevOutput = outParameter.begin();
|
||||
backIterator = outParameter.end();
|
||||
gradIterator = outParameter.end();
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void GRU<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
{
|
||||
if (input.n_cols != batchSize)
|
||||
{
|
||||
batchSize = input.n_cols;
|
||||
prevError.resize(3 * outSize, batchSize);
|
||||
allZeros.zeros(outSize, batchSize);
|
||||
// Batch size better not change during an iteration...
|
||||
if (outParameter.size() > 1)
|
||||
{
|
||||
Log::Fatal << "GRU<>::Forward(): batch size cannot change during a "
|
||||
<< "forward pass!" << std::endl;
|
||||
}
|
||||
|
||||
outParameter.clear();
|
||||
outParameter.emplace_back(allZeros.memptr(),
|
||||
allZeros.n_rows, allZeros.n_cols, false, true);
|
||||
|
||||
prevOutput = outParameter.begin();
|
||||
backIterator = outParameter.end();
|
||||
gradIterator = outParameter.end();
|
||||
}
|
||||
|
||||
// Process the input linearly(zt, rt, ot).
|
||||
boost::apply_visitor(ForwardVisitor(input,
|
||||
boost::apply_visitor(outputParameterVisitor, input2GateModule)),
|
||||
input2GateModule);
|
||||
|
||||
// Process the output(zt, rt) linearly.
|
||||
boost::apply_visitor(ForwardVisitor(*prevOutput,
|
||||
boost::apply_visitor(outputParameterVisitor, output2GateModule)),
|
||||
output2GateModule);
|
||||
|
||||
// Merge the outputs(zt and rt).
|
||||
output = (boost::apply_visitor(outputParameterVisitor,
|
||||
input2GateModule).submat(0, 0, 2 * outSize - 1, batchSize - 1) +
|
||||
boost::apply_visitor(outputParameterVisitor, output2GateModule));
|
||||
|
||||
// Pass the first outSize through inputGate(it).
|
||||
boost::apply_visitor(ForwardVisitor(output.submat(
|
||||
0, 0, 1 * outSize - 1, batchSize - 1), boost::apply_visitor(
|
||||
outputParameterVisitor, inputGateModule)), inputGateModule);
|
||||
|
||||
// Pass the second through forgetGate.
|
||||
boost::apply_visitor(ForwardVisitor(output.submat(
|
||||
1 * outSize, 0, 2 * outSize - 1, batchSize - 1),
|
||||
boost::apply_visitor(outputParameterVisitor, forgetGateModule)),
|
||||
forgetGateModule);
|
||||
|
||||
arma::mat modInput = (boost::apply_visitor(outputParameterVisitor,
|
||||
forgetGateModule) % *prevOutput);
|
||||
|
||||
// Pass that through the outputHidden2GateModule.
|
||||
boost::apply_visitor(ForwardVisitor(modInput,
|
||||
boost::apply_visitor(outputParameterVisitor, outputHidden2GateModule)),
|
||||
outputHidden2GateModule);
|
||||
|
||||
// Merge for ot.
|
||||
arma::mat outputH = boost::apply_visitor(outputParameterVisitor,
|
||||
input2GateModule).submat(2 * outSize, 0, 3 * outSize - 1, batchSize - 1) +
|
||||
boost::apply_visitor(outputParameterVisitor, outputHidden2GateModule);
|
||||
|
||||
// Pass it through hiddenGate.
|
||||
boost::apply_visitor(ForwardVisitor(outputH,
|
||||
boost::apply_visitor(outputParameterVisitor, hiddenStateModule)),
|
||||
hiddenStateModule);
|
||||
|
||||
// Update the output (nextOutput): cmul1 + cmul2
|
||||
// Where cmul1 is input gate * prevOutput and
|
||||
// cmul2 is (1 - input gate) * hidden gate.
|
||||
output = (boost::apply_visitor(outputParameterVisitor, inputGateModule)
|
||||
% (*prevOutput - boost::apply_visitor(outputParameterVisitor,
|
||||
hiddenStateModule))) + boost::apply_visitor(outputParameterVisitor,
|
||||
hiddenStateModule);
|
||||
|
||||
forwardStep++;
|
||||
if (forwardStep == rho)
|
||||
{
|
||||
forwardStep = 0;
|
||||
if (!deterministic)
|
||||
{
|
||||
outParameter.emplace_back(allZeros.memptr(),
|
||||
allZeros.n_rows, allZeros.n_cols, false, true);
|
||||
prevOutput = --outParameter.end();
|
||||
}
|
||||
else
|
||||
{
|
||||
*prevOutput = arma::mat(allZeros.memptr(),
|
||||
allZeros.n_rows, allZeros.n_cols, false, true);
|
||||
}
|
||||
}
|
||||
else if (!deterministic)
|
||||
{
|
||||
outParameter.push_back(output);
|
||||
prevOutput = --outParameter.end();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (forwardStep == 1)
|
||||
{
|
||||
outParameter.clear();
|
||||
outParameter.push_back(output);
|
||||
|
||||
prevOutput = outParameter.begin();
|
||||
}
|
||||
else
|
||||
{
|
||||
*prevOutput = output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void GRU<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& input, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
|
||||
{
|
||||
if (input.n_cols != batchSize)
|
||||
{
|
||||
batchSize = input.n_cols;
|
||||
prevError.resize(3 * outSize, batchSize);
|
||||
allZeros.zeros(outSize, batchSize);
|
||||
// Batch size better not change during an iteration...
|
||||
if (outParameter.size() > 1)
|
||||
{
|
||||
Log::Fatal << "GRU<>::Forward(): batch size cannot change during a "
|
||||
<< "forward pass!" << std::endl;
|
||||
}
|
||||
|
||||
outParameter.clear();
|
||||
outParameter.emplace_back(allZeros.memptr(),
|
||||
allZeros.n_rows, allZeros.n_cols, false, true);
|
||||
|
||||
prevOutput = outParameter.begin();
|
||||
backIterator = outParameter.end();
|
||||
gradIterator = outParameter.end();
|
||||
}
|
||||
|
||||
arma::Mat<eT> gyLocal;
|
||||
if ((outParameter.size() - backwardStep - 1) % rho != 0 && backwardStep != 0)
|
||||
{
|
||||
gyLocal = gy + boost::apply_visitor(deltaVisitor, output2GateModule);
|
||||
}
|
||||
else
|
||||
{
|
||||
gyLocal = arma::Mat<eT>(((arma::Mat<eT>&) gy).memptr(), gy.n_rows,
|
||||
gy.n_cols, false, false);
|
||||
}
|
||||
|
||||
if (backIterator == outParameter.end())
|
||||
{
|
||||
backIterator = --(--outParameter.end());
|
||||
}
|
||||
|
||||
// Delta zt.
|
||||
arma::mat dZt = gyLocal % (*backIterator -
|
||||
boost::apply_visitor(outputParameterVisitor,
|
||||
hiddenStateModule));
|
||||
|
||||
// Delta ot.
|
||||
arma::mat dOt = gyLocal % (arma::ones<arma::mat>(outSize, batchSize) -
|
||||
boost::apply_visitor(outputParameterVisitor, inputGateModule));
|
||||
|
||||
// Delta of input gate.
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, inputGateModule), dZt,
|
||||
boost::apply_visitor(deltaVisitor, inputGateModule)),
|
||||
inputGateModule);
|
||||
|
||||
// Delta of hidden gate.
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, hiddenStateModule), dOt,
|
||||
boost::apply_visitor(deltaVisitor, hiddenStateModule)),
|
||||
hiddenStateModule);
|
||||
|
||||
// Delta of outputHidden2GateModule.
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, outputHidden2GateModule),
|
||||
boost::apply_visitor(deltaVisitor, hiddenStateModule),
|
||||
boost::apply_visitor(deltaVisitor, outputHidden2GateModule)),
|
||||
outputHidden2GateModule);
|
||||
|
||||
// Delta rt.
|
||||
arma::mat dRt = boost::apply_visitor(deltaVisitor, outputHidden2GateModule) %
|
||||
*backIterator;
|
||||
|
||||
// Delta of forget gate.
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, forgetGateModule), dRt,
|
||||
boost::apply_visitor(deltaVisitor, forgetGateModule)),
|
||||
forgetGateModule);
|
||||
|
||||
// Put delta zt.
|
||||
prevError.submat(0, 0, 1 * outSize - 1, batchSize - 1) = boost::apply_visitor(
|
||||
deltaVisitor, inputGateModule);
|
||||
|
||||
// Put delta rt.
|
||||
prevError.submat(1 * outSize, 0, 2 * outSize - 1, batchSize - 1) =
|
||||
boost::apply_visitor(deltaVisitor, forgetGateModule);
|
||||
|
||||
// Put delta ot.
|
||||
prevError.submat(2 * outSize, 0, 3 * outSize - 1, batchSize - 1) =
|
||||
boost::apply_visitor(deltaVisitor, hiddenStateModule);
|
||||
|
||||
// Get delta ht - 1 for input gate and forget gate.
|
||||
arma::mat prevErrorSubview = prevError.submat(0, 0, 2 * outSize - 1,
|
||||
batchSize - 1);
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, input2GateModule),
|
||||
prevErrorSubview,
|
||||
boost::apply_visitor(deltaVisitor, output2GateModule)),
|
||||
output2GateModule);
|
||||
|
||||
// Add delta ht - 1 from hidden state.
|
||||
boost::apply_visitor(deltaVisitor, output2GateModule) +=
|
||||
boost::apply_visitor(deltaVisitor, outputHidden2GateModule) %
|
||||
boost::apply_visitor(outputParameterVisitor, forgetGateModule);
|
||||
|
||||
// Add delta ht - 1 from ht.
|
||||
boost::apply_visitor(deltaVisitor, output2GateModule) += gyLocal %
|
||||
boost::apply_visitor(outputParameterVisitor, inputGateModule);
|
||||
|
||||
// Get delta input.
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, input2GateModule), prevError,
|
||||
boost::apply_visitor(deltaVisitor, input2GateModule)),
|
||||
input2GateModule);
|
||||
|
||||
backwardStep++;
|
||||
backIterator--;
|
||||
|
||||
g = boost::apply_visitor(deltaVisitor, input2GateModule);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void GRU<InputDataType, OutputDataType>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& /* error */,
|
||||
arma::Mat<eT>& /* gradient */)
|
||||
{
|
||||
if (input.n_cols != batchSize)
|
||||
{
|
||||
batchSize = input.n_cols;
|
||||
prevError.resize(3 * outSize, batchSize);
|
||||
allZeros.zeros(outSize, batchSize);
|
||||
// Batch size better not change during an iteration...
|
||||
if (outParameter.size() > 1)
|
||||
{
|
||||
Log::Fatal << "GRU<>::Forward(): batch size cannot change during a "
|
||||
<< "forward pass!" << std::endl;
|
||||
}
|
||||
|
||||
outParameter.clear();
|
||||
outParameter.emplace_back(allZeros.memptr(),
|
||||
allZeros.n_rows, allZeros.n_cols, false, true);
|
||||
|
||||
prevOutput = outParameter.begin();
|
||||
backIterator = outParameter.end();
|
||||
gradIterator = outParameter.end();
|
||||
}
|
||||
|
||||
if (gradIterator == outParameter.end())
|
||||
{
|
||||
gradIterator = --(--outParameter.end());
|
||||
}
|
||||
|
||||
boost::apply_visitor(GradientVisitor(input, prevError), input2GateModule);
|
||||
|
||||
boost::apply_visitor(GradientVisitor(
|
||||
*gradIterator,
|
||||
prevError.submat(0, 0, 2 * outSize - 1, batchSize - 1)),
|
||||
output2GateModule);
|
||||
|
||||
boost::apply_visitor(GradientVisitor(
|
||||
*gradIterator % boost::apply_visitor(outputParameterVisitor,
|
||||
forgetGateModule),
|
||||
prevError.submat(2 * outSize, 0, 3 * outSize - 1, batchSize - 1)),
|
||||
outputHidden2GateModule);
|
||||
|
||||
gradIterator--;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
void GRU<InputDataType, OutputDataType>::ResetCell(const size_t /* size */)
|
||||
{
|
||||
outParameter.clear();
|
||||
outParameter.emplace_back(allZeros.memptr(),
|
||||
allZeros.n_rows, allZeros.n_cols, false, true);
|
||||
|
||||
prevOutput = outParameter.begin();
|
||||
backIterator = outParameter.end();
|
||||
gradIterator = outParameter.end();
|
||||
|
||||
forwardStep = 0;
|
||||
backwardStep = 0;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename Archive>
|
||||
void GRU<InputDataType, OutputDataType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
// If necessary, clean memory from the old model.
|
||||
if (cereal::is_loading<Archive>())
|
||||
{
|
||||
boost::apply_visitor(deleteVisitor, input2GateModule);
|
||||
boost::apply_visitor(deleteVisitor, output2GateModule);
|
||||
boost::apply_visitor(deleteVisitor, outputHidden2GateModule);
|
||||
boost::apply_visitor(deleteVisitor, inputGateModule);
|
||||
boost::apply_visitor(deleteVisitor, forgetGateModule);
|
||||
boost::apply_visitor(deleteVisitor, hiddenStateModule);
|
||||
}
|
||||
|
||||
ar(CEREAL_NVP(inSize));
|
||||
ar(CEREAL_NVP(outSize));
|
||||
ar(CEREAL_NVP(rho));
|
||||
|
||||
ar(CEREAL_VARIANT_POINTER(input2GateModule));
|
||||
ar(CEREAL_VARIANT_POINTER(output2GateModule));
|
||||
ar(CEREAL_VARIANT_POINTER(outputHidden2GateModule));
|
||||
ar(CEREAL_VARIANT_POINTER(inputGateModule));
|
||||
ar(CEREAL_VARIANT_POINTER(forgetGateModule));
|
||||
ar(CEREAL_VARIANT_POINTER(hiddenStateModule));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -1,270 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/highway.hpp
|
||||
* @author Konstantin Sidorov
|
||||
* @author Saksham Bansal
|
||||
*
|
||||
* Definition of the Highway layer.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_HIGHWAY_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_HIGHWAY_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "../visitor/delete_visitor.hpp"
|
||||
#include "../visitor/delta_visitor.hpp"
|
||||
#include "../visitor/output_height_visitor.hpp"
|
||||
#include "../visitor/output_parameter_visitor.hpp"
|
||||
#include "../visitor/output_width_visitor.hpp"
|
||||
|
||||
#include "layer_types.hpp"
|
||||
#include "add_merge.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
/**
|
||||
* Implementation of the Highway layer. The Highway class can vary its behavior
|
||||
* between that of feed-forward fully connected network container and that
|
||||
* of a layer which simply passes its inputs through depending on the transform
|
||||
* gate. Note that the size of the input and output matrices of this class
|
||||
* should be equal.
|
||||
*
|
||||
* For more information, refer the following paper.
|
||||
*
|
||||
* @code
|
||||
* @article{Srivastava2015,
|
||||
* author = {Rupesh Kumar Srivastava, Klaus Greff, Jurgen Schmidhuber},
|
||||
* title = {Training Very Deep Networks},
|
||||
* journal = {Advances in Neural Information Processing Systems},
|
||||
* year = {2015},
|
||||
* url = {https://arxiv.org/abs/1507.06228},
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat,
|
||||
typename... CustomLayers>
|
||||
class Highway
|
||||
{
|
||||
public:
|
||||
//! Create the Highway object.
|
||||
Highway();
|
||||
|
||||
/**
|
||||
* Create the Highway object.
|
||||
*
|
||||
* @param inSize The number of input units.
|
||||
* @param model Expose all the network modules.
|
||||
*/
|
||||
Highway(const size_t inSize, const bool model = true);
|
||||
|
||||
//! Destroy the Highway object.
|
||||
~Highway();
|
||||
|
||||
/**
|
||||
* Reset the layer parameter.
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* Ordinary feed-forward pass of a neural network, evaluating the function
|
||||
* f(x) by propagating the activity forward through f.
|
||||
*
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed-backward pass of a neural network, calculating the function
|
||||
* f(x) by propagating x backwards through f. Using the results from the
|
||||
* feed-forward pass.
|
||||
*
|
||||
* @param * (input) The propagated input activation.
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
|
||||
/**
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
*
|
||||
* @param input The input parameter used for calculating the gradient.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient);
|
||||
|
||||
/**
|
||||
* Add a new module to the model.
|
||||
*
|
||||
* @param args The layer parameter.
|
||||
*/
|
||||
template <class LayerType, class... Args>
|
||||
void Add(Args... args)
|
||||
{
|
||||
network.push_back(new LayerType(args...));
|
||||
networkOwnerships.push_back(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new module to the model.
|
||||
*
|
||||
* @param layer The Layer to be added to the model.
|
||||
*/
|
||||
void Add(LayerTypes<CustomLayers...> layer)
|
||||
{
|
||||
network.push_back(layer);
|
||||
networkOwnerships.push_back(false);
|
||||
}
|
||||
|
||||
//! Return the modules of the model.
|
||||
std::vector<LayerTypes<CustomLayers...> >& Model()
|
||||
{
|
||||
if (model)
|
||||
{
|
||||
return network;
|
||||
}
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
|
||||
//! Get the input parameter.
|
||||
InputDataType const& InputParameter() const { return inputParameter; }
|
||||
//! Modify the input parameter.
|
||||
InputDataType& InputParameter() { return inputParameter; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return gradient; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return gradient; }
|
||||
|
||||
//! Get the number of input units.
|
||||
size_t InSize() const { return inSize; }
|
||||
|
||||
//! Get the shape of the input.
|
||||
size_t InputShape() const
|
||||
{
|
||||
return inSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally-stored number of input units.
|
||||
size_t inSize;
|
||||
|
||||
//! Parameter which indicates if the modules should be exposed.
|
||||
bool model;
|
||||
|
||||
//! Indicator if we already initialized the model.
|
||||
bool reset;
|
||||
|
||||
//! Locally-stored network modules.
|
||||
std::vector<LayerTypes<CustomLayers...> > network;
|
||||
|
||||
//! The list of network modules we are responsible for.
|
||||
std::vector<bool> networkOwnerships;
|
||||
|
||||
//! Locally-stored empty list of modules.
|
||||
std::vector<LayerTypes<CustomLayers...> > empty;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
|
||||
//! Weights for transformation of output.
|
||||
OutputDataType transformWeight;
|
||||
|
||||
//! Bias for transformation of output.
|
||||
OutputDataType transformBias;
|
||||
|
||||
//! Locally-stored transform gate parameters.
|
||||
OutputDataType transformGate;
|
||||
|
||||
//! Locally-stored transform gate activation.
|
||||
OutputDataType transformGateActivation;
|
||||
|
||||
//! Locally-stored transform gate error.
|
||||
OutputDataType transformGateError;
|
||||
|
||||
//! Locally-stored input parameter object.
|
||||
InputDataType inputParameter;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
|
||||
//! The input width.
|
||||
size_t width;
|
||||
|
||||
//! The input height.
|
||||
size_t height;
|
||||
|
||||
//! The normal output without highway network.
|
||||
OutputDataType networkOutput;
|
||||
|
||||
//! Locally-stored delta visitor.
|
||||
DeltaVisitor deltaVisitor;
|
||||
|
||||
//! Locally-stored output parameter visitor.
|
||||
OutputParameterVisitor outputParameterVisitor;
|
||||
|
||||
//! Locally-stored delete visitor.
|
||||
DeleteVisitor deleteVisitor;
|
||||
|
||||
//! Locally-stored output width visitor.
|
||||
OutputWidthVisitor outputWidthVisitor;
|
||||
|
||||
//! Locally-stored output height visitor.
|
||||
OutputHeightVisitor outputHeightVisitor;
|
||||
}; // class Highway
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
// Include implementation.
|
||||
#include "highway_impl.hpp"
|
||||
|
||||
#endif
|
||||
@@ -1,238 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/highway_impl.hpp
|
||||
* @author Konstantin Sidorov
|
||||
* @author Saksham Bansal
|
||||
*
|
||||
* Implementation of Highway layer.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_HIGHWAY_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_HIGHWAY_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "highway.hpp"
|
||||
|
||||
#include "../visitor/forward_visitor.hpp"
|
||||
#include "../visitor/backward_visitor.hpp"
|
||||
#include "../visitor/gradient_visitor.hpp"
|
||||
#include "../visitor/set_input_height_visitor.hpp"
|
||||
#include "../visitor/set_input_width_visitor.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
Highway<InputDataType, OutputDataType, CustomLayers...>::Highway() :
|
||||
inSize(0),
|
||||
model(true),
|
||||
reset(false),
|
||||
width(0),
|
||||
height(0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<
|
||||
typename InputDataType, typename OutputDataType, typename... CustomLayers>
|
||||
Highway<InputDataType, OutputDataType, CustomLayers...>::Highway(
|
||||
const size_t inSize,
|
||||
const bool model) :
|
||||
inSize(inSize),
|
||||
model(model),
|
||||
reset(false),
|
||||
width(0),
|
||||
height(0)
|
||||
{
|
||||
weights.set_size(inSize * inSize + inSize, 1);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
Highway<InputDataType, OutputDataType, CustomLayers...>::~Highway()
|
||||
{
|
||||
if (!model)
|
||||
{
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
if (networkOwnerships[i])
|
||||
boost::apply_visitor(deleteVisitor, network[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
void Highway<InputDataType, OutputDataType, CustomLayers...>::Reset()
|
||||
{
|
||||
transformWeight = arma::mat(weights.memptr(), inSize, inSize, false, false);
|
||||
transformBias = arma::mat(weights.memptr() + transformWeight.n_elem,
|
||||
inSize, 1, false, false);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void Highway<InputDataType, OutputDataType, CustomLayers...>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
{
|
||||
boost::apply_visitor(ForwardVisitor(input,
|
||||
boost::apply_visitor(outputParameterVisitor, network.front())),
|
||||
network.front());
|
||||
|
||||
if (!reset)
|
||||
{
|
||||
if (boost::apply_visitor(outputWidthVisitor, network.front()) != 0)
|
||||
{
|
||||
width = boost::apply_visitor(outputWidthVisitor, network.front());
|
||||
}
|
||||
|
||||
if (boost::apply_visitor(outputHeightVisitor, network.front()) != 0)
|
||||
{
|
||||
height = boost::apply_visitor(outputHeightVisitor, network.front());
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < network.size(); ++i)
|
||||
{
|
||||
if (!reset)
|
||||
{
|
||||
// Set the input width.
|
||||
boost::apply_visitor(SetInputWidthVisitor(width), network[i]);
|
||||
|
||||
// Set the input height.
|
||||
boost::apply_visitor(SetInputHeightVisitor(height), network[i]);
|
||||
}
|
||||
|
||||
boost::apply_visitor(ForwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, network[i - 1]),
|
||||
boost::apply_visitor(outputParameterVisitor, network[i])),
|
||||
network[i]);
|
||||
|
||||
if (!reset)
|
||||
{
|
||||
// Get the output width.
|
||||
if (boost::apply_visitor(outputWidthVisitor, network[i]) != 0)
|
||||
{
|
||||
width = boost::apply_visitor(outputWidthVisitor, network[i]);
|
||||
}
|
||||
|
||||
// Get the output height.
|
||||
if (boost::apply_visitor(outputHeightVisitor, network[i]) != 0)
|
||||
{
|
||||
height = boost::apply_visitor(outputHeightVisitor, network[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!reset)
|
||||
{
|
||||
reset = true;
|
||||
}
|
||||
|
||||
output = boost::apply_visitor(outputParameterVisitor, network.back());
|
||||
|
||||
if (arma::size(output) != arma::size(input))
|
||||
{
|
||||
Log::Fatal << "The sizes of the output and input matrices of the Highway"
|
||||
<< " network should be equal. Please examine the network layers.";
|
||||
}
|
||||
|
||||
transformGate = transformWeight * input;
|
||||
transformGate.each_col() += transformBias;
|
||||
transformGateActivation = 1.0 /(1 + arma::exp(-transformGate));
|
||||
inputParameter = input;
|
||||
networkOutput = output;
|
||||
output = (output % transformGateActivation) +
|
||||
(input % (1 - transformGateActivation));
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void Highway<InputDataType, OutputDataType, CustomLayers...>::Backward(
|
||||
const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
{
|
||||
arma::Mat<eT> gyTransform = gy % transformGateActivation;
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, network.back()),
|
||||
gyTransform,
|
||||
boost::apply_visitor(deltaVisitor, network.back())),
|
||||
network.back());
|
||||
|
||||
for (size_t i = 2; i < network.size() + 1; ++i)
|
||||
{
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, network[network.size() - i]),
|
||||
boost::apply_visitor(deltaVisitor, network[network.size() - i + 1]),
|
||||
boost::apply_visitor(deltaVisitor,
|
||||
network[network.size() - i])), network[network.size() - i]);
|
||||
}
|
||||
|
||||
g = boost::apply_visitor(deltaVisitor, network.front());
|
||||
|
||||
transformGateError = gy % (networkOutput - inputParameter) %
|
||||
transformGateActivation % (1.0 - transformGateActivation);
|
||||
g += transformWeight.t() * transformGateError;
|
||||
g += gy % (1 - transformGateActivation);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void Highway<InputDataType, OutputDataType, CustomLayers...>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient)
|
||||
{
|
||||
arma::Mat<eT> errorTransform = error % transformGateActivation;
|
||||
boost::apply_visitor(GradientVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, network[network.size() - 2]),
|
||||
errorTransform), network.back());
|
||||
|
||||
for (size_t i = 2; i < network.size(); ++i)
|
||||
{
|
||||
boost::apply_visitor(GradientVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, network[network.size() - i - 1]),
|
||||
boost::apply_visitor(deltaVisitor, network[network.size() - i + 1])),
|
||||
network[network.size() - i]);
|
||||
}
|
||||
|
||||
boost::apply_visitor(GradientVisitor(input,
|
||||
boost::apply_visitor(deltaVisitor, network[1])), network.front());
|
||||
|
||||
gradient.submat(0, 0, transformWeight.n_elem - 1, 0) = arma::vectorise(
|
||||
transformGateError * input.t());
|
||||
gradient.submat(transformWeight.n_elem, 0, gradient.n_elem - 1, 0) =
|
||||
arma::sum(transformGateError, 1);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename Archive>
|
||||
void Highway<InputDataType, OutputDataType, CustomLayers...>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
// If loading, delete the old layers and set size for weights.
|
||||
if (cereal::is_loading<Archive>())
|
||||
{
|
||||
for (LayerTypes<CustomLayers...>& layer : network)
|
||||
{
|
||||
boost::apply_visitor(deleteVisitor, layer);
|
||||
}
|
||||
weights.set_size(inSize * inSize + inSize, 1);
|
||||
}
|
||||
|
||||
ar(CEREAL_NVP(model));
|
||||
ar(CEREAL_VECTOR_VARIANT_POINTER(network));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@
|
||||
* @file methods/ann/layer/layer.hpp
|
||||
* @author Marcus Edel
|
||||
*
|
||||
* This includes various layers to construct a model.
|
||||
* Base class for neural network layers.
|
||||
*
|
||||
* 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
|
||||
@@ -12,73 +12,312 @@
|
||||
#ifndef MLPACK_METHODS_ANN_LAYER_LAYER_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_LAYER_HPP
|
||||
|
||||
#include "add.hpp"
|
||||
#include "adaptive_max_pooling.hpp"
|
||||
#include "adaptive_mean_pooling.hpp"
|
||||
#include "add_merge.hpp"
|
||||
#include "alpha_dropout.hpp"
|
||||
#include "atrous_convolution.hpp"
|
||||
#include "base_layer.hpp"
|
||||
#include "batch_norm.hpp"
|
||||
#include "bicubic_interpolation.hpp"
|
||||
#include "bilinear_interpolation.hpp"
|
||||
#include "c_relu.hpp"
|
||||
#include "celu.hpp"
|
||||
#include "concat_performance.hpp"
|
||||
#include "concat.hpp"
|
||||
#include "concatenate.hpp"
|
||||
#include "constant.hpp"
|
||||
#include "convolution.hpp"
|
||||
#include "dropconnect.hpp"
|
||||
#include "dropout.hpp"
|
||||
#include "elu.hpp"
|
||||
#include "fast_lstm.hpp"
|
||||
#include "flatten_t_swish.hpp"
|
||||
#include "flexible_relu.hpp"
|
||||
#include "glimpse.hpp"
|
||||
#include "gru.hpp"
|
||||
#include "hard_tanh.hpp"
|
||||
#include "hardshrink.hpp"
|
||||
#include "highway.hpp"
|
||||
#include "instance_norm.hpp"
|
||||
#include "join.hpp"
|
||||
#include "layer_norm.hpp"
|
||||
#include "layer_types.hpp"
|
||||
#include "leaky_relu.hpp"
|
||||
#include "linear.hpp"
|
||||
#include "linear_no_bias.hpp"
|
||||
#include "linear3d.hpp"
|
||||
#include "log_softmax.hpp"
|
||||
#include "lookup.hpp"
|
||||
#include "lp_pooling.hpp"
|
||||
#include "lstm.hpp"
|
||||
#include "max_pooling.hpp"
|
||||
#include "mean_pooling.hpp"
|
||||
#include "minibatch_discrimination.hpp"
|
||||
#include "multihead_attention.hpp"
|
||||
#include "multiply_constant.hpp"
|
||||
#include "multiply_merge.hpp"
|
||||
#include "nearest_interpolation.hpp"
|
||||
#include "noisylinear.hpp"
|
||||
#include "padding.hpp"
|
||||
#include "parametric_relu.hpp"
|
||||
#include "pixel_shuffle.hpp"
|
||||
#include "positional_encoding.hpp"
|
||||
#include "recurrent_attention.hpp"
|
||||
#include "recurrent.hpp"
|
||||
#include "reinforce_normal.hpp"
|
||||
#include "relu6.hpp"
|
||||
#include "reparametrization.hpp"
|
||||
#include "select.hpp"
|
||||
#include "sequential.hpp"
|
||||
#include "softshrink.hpp"
|
||||
#include "softmax.hpp"
|
||||
#include "softmin.hpp"
|
||||
#include "spatial_dropout.hpp"
|
||||
#include "subview.hpp"
|
||||
#include "transposed_convolution.hpp"
|
||||
#include "virtual_batch_norm.hpp"
|
||||
#include "vr_class_reward.hpp"
|
||||
#include "weight_norm.hpp"
|
||||
namespace mlpack {
|
||||
namespace ann {
|
||||
|
||||
/**
|
||||
* A layer is an abstract class implementing common neural networks operations,
|
||||
* such as convolution, batch norm, etc. These operations require managing
|
||||
* weights, losses, updates, and inter-layer connectivity.
|
||||
*
|
||||
* Users will just instantiate a layer by inherited from the abstract class and
|
||||
* implement the layer specific methods. It is recommend that descendants of
|
||||
* Layer implement the following methods:
|
||||
*
|
||||
* - Constructor: Defines custom layer attributes, and creates layer state
|
||||
* variables.
|
||||
*
|
||||
* - Forward(input, output): Performs the forward logic of applying the layer
|
||||
* to the input object and storing the result in the output object.
|
||||
*
|
||||
* - Backward(input, gy, g): Performs a backpropagation step through the layer,
|
||||
* with respect to the given input.
|
||||
*
|
||||
* - Gradient(input, error, gradient): Computing the gradient of the layer with
|
||||
* respect to its own input.
|
||||
*
|
||||
* The memory for the layer's parameters (weights and biases) is not allocated
|
||||
* by the layer itself, instead it is allocated by the network that the layer
|
||||
* belongs to, and passed to the layer when it needs to use it.
|
||||
*
|
||||
* See the linear layer implementation for a basic example. It's a layer with
|
||||
* two variables, w and b, that returns y = w * x + b. It shows how to implement
|
||||
* Forward(), Backward() and Gradient(). The weights of the layers are tracked
|
||||
* in layer.Parameters().
|
||||
*
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template<typename MatType = arma::mat>
|
||||
class Layer
|
||||
{
|
||||
public:
|
||||
//! Default constructor.
|
||||
Layer() : validOutputDimensions(false), training(false)
|
||||
{ /* Nothing to do here */ }
|
||||
|
||||
//! Default deconstructor.
|
||||
virtual ~Layer() { /* Nothing to do here */ }
|
||||
|
||||
//! Copy constructor. This is not responsible for copying weights!
|
||||
Layer(const Layer& layer) :
|
||||
inputDimensions(layer.inputDimensions),
|
||||
outputDimensions(layer.outputDimensions),
|
||||
validOutputDimensions(layer.validOutputDimensions),
|
||||
training(layer.training)
|
||||
{ /* Nothing to do here */ }
|
||||
|
||||
//! Make a copy of the object.
|
||||
virtual Layer* Clone() const = 0;
|
||||
|
||||
//! Move constructor. This is not responsible for moving weights!
|
||||
Layer(Layer&& layer) :
|
||||
inputDimensions(std::move(layer.inputDimensions)),
|
||||
outputDimensions(std::move(layer.outputDimensions)),
|
||||
validOutputDimensions(std::move(layer.validOutputDimensions)),
|
||||
training(std::move(layer.training))
|
||||
{ /* Nothing to do here */ }
|
||||
|
||||
//! Copy assignment operator. This is not responsible for copying weights!
|
||||
virtual Layer& operator=(const Layer& layer)
|
||||
{
|
||||
if (&layer != this)
|
||||
{
|
||||
inputDimensions = layer.inputDimensions;
|
||||
outputDimensions = layer.outputDimensions;
|
||||
validOutputDimensions = layer.validOutputDimensions;
|
||||
training = layer.training;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Move assignment operator. This is not responsible for moving weights!
|
||||
virtual Layer& operator=(Layer&& layer)
|
||||
{
|
||||
if (&layer != this)
|
||||
{
|
||||
inputDimensions = std::move(layer.inputDimensions);
|
||||
outputDimensions = std::move(layer.outputDimensions);
|
||||
validOutputDimensions = std::move(layer.validOutputDimensions);
|
||||
training = std::move(layer.training);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an input object, and computes the corresponding output of the layer.
|
||||
* In general input and output are matrices. However, some special layers like
|
||||
* table layers might expect something else. Please, refer to each layer
|
||||
* specification for further information.
|
||||
*
|
||||
* @param * (input) Input data used for evaluating the specified layer.
|
||||
* @param * (output) Resulting output.
|
||||
*/
|
||||
virtual void Forward(const MatType& /* input */,
|
||||
MatType& /* output */)
|
||||
{ /* Nothing to do here */ }
|
||||
|
||||
/**
|
||||
* Takes an input and output object, and computes the corresponding loss of
|
||||
* the layer. In general input and output are matrices. However, some special
|
||||
* layers like table layers might expect something else. Please, refer to each
|
||||
* layer specification for further information.
|
||||
*
|
||||
* @param * (input) Input data used for evaluating the specified layer.
|
||||
* @param * (output) Resulting output.
|
||||
*/
|
||||
virtual void Forward(const MatType& /* input */,
|
||||
const MatType& /* output */)
|
||||
{ /* Nothing to do here */ }
|
||||
|
||||
/**
|
||||
* Performs a backpropagation step through the layer, with respect to the
|
||||
* given input. In general this method makes the assumption Forward(input,
|
||||
* output) has been called before, with the same input. If you do not respect
|
||||
* this rule, Backward(input, gy, g) might compute incorrect results.
|
||||
*
|
||||
* In general input and gy and g are matrices. However, some special
|
||||
* sub-classes like table layers might expect something else. Please, refer to
|
||||
* each module specification for further information.
|
||||
*
|
||||
* A backpropagation step consist of computing of computing the gradient
|
||||
* output input with respect to the output of the layer and given error.
|
||||
*
|
||||
* During the backward pass our goal is to use 'gy' in order to compute the
|
||||
* downstream gradients (g). We assume that the upstream gradient (gy) has
|
||||
* already been computed and is passed to the layer.
|
||||
*
|
||||
* @param * (input) The propagated input activation.
|
||||
* @param * (gy) The backpropagated error.
|
||||
* @param * (g) The calculated gradient.
|
||||
*/
|
||||
virtual void Backward(const MatType& /* input */,
|
||||
const MatType& /* gy */,
|
||||
MatType& /* g */)
|
||||
{ /* Nothing to do here */ }
|
||||
|
||||
/**
|
||||
* Computing the gradient of the layer with respect to its own input. This is
|
||||
* returned in gradient.
|
||||
*
|
||||
* The layer parameters (weights and biases) are updated accordingly using the
|
||||
* computed gradient not by the layer itself, instead they are updated by the
|
||||
* network that holds the instantiated layer.
|
||||
*
|
||||
* @param * (input) The input parameter used for calculating the gradient.
|
||||
* @param * (error) The calculated error.
|
||||
* @param * (gradient) The calculated gradient.
|
||||
*/
|
||||
virtual void Gradient(const MatType& /* input */,
|
||||
const MatType& /* error */,
|
||||
MatType& /* gradient */)
|
||||
{ /* Nothing to do here */ }
|
||||
|
||||
/**
|
||||
* Reset the layer parameter. The method is called to assigned the allocated
|
||||
* memory to the internal layer parameters like weights and biases. The method
|
||||
* should be called before the first call of Forward(input, output). If you
|
||||
* do not respect this rule, Forward(input, output) and Backward(input, gy, g)
|
||||
* might compute incorrect results.
|
||||
*
|
||||
* @param weightsPtr This pointer should be used as the first element of the
|
||||
* memory that is allocated for this layer. In general, SetWeights()
|
||||
* implementations should use MakeAlias() with weightsPtr to wrap the
|
||||
* weights of a layer.
|
||||
*/
|
||||
virtual void SetWeights(typename MatType::elem_type* /* weightsPtr */) { }
|
||||
|
||||
/**
|
||||
* Get the total number of trainable weights in the layer.
|
||||
*/
|
||||
virtual size_t WeightSize() const { return 0; }
|
||||
|
||||
/**
|
||||
* Get whether the layer is currently in training mode.
|
||||
*
|
||||
* @note During network training, this should be set to `true` for each layer
|
||||
* in the network, and when predicting/testing the network, this should be set
|
||||
* to `false`. (This is handled automatically by the `FFN` class and other
|
||||
* related classes.)
|
||||
*/
|
||||
virtual bool const& Training() const { return training; }
|
||||
|
||||
/**
|
||||
* Modify whether the layer is currently in training mode.
|
||||
*
|
||||
* @note During network training, this should be set to `true` for each layer
|
||||
* in the network, and when predicting/testing the network, this should be set
|
||||
* to `false`. (This is handled automatically by the `FFN` class and other
|
||||
* related classes.)
|
||||
*/
|
||||
virtual bool& Training() { return training; }
|
||||
|
||||
//! Get the layer loss. Overload this if the layer should add any extra loss
|
||||
//! to the loss function when computing the objective. (TODO: better comment)
|
||||
virtual double Loss() { return 0; }
|
||||
|
||||
//! Get the input dimensions.
|
||||
const std::vector<size_t>& InputDimensions() const { return inputDimensions; }
|
||||
//! Modify the input dimensions.
|
||||
std::vector<size_t>& InputDimensions()
|
||||
{
|
||||
validOutputDimensions = false;
|
||||
return inputDimensions;
|
||||
}
|
||||
|
||||
//! Get the output dimensions.
|
||||
const std::vector<size_t>& OutputDimensions()
|
||||
{
|
||||
if (!validOutputDimensions)
|
||||
{
|
||||
this->ComputeOutputDimensions();
|
||||
validOutputDimensions = true;
|
||||
}
|
||||
|
||||
return outputDimensions;
|
||||
}
|
||||
|
||||
//! Get the parameters.
|
||||
virtual const MatType& Parameters() const
|
||||
{
|
||||
throw std::invalid_argument("Layer::Parameters(): cannot access parameters "
|
||||
"of a layer with no weights!");
|
||||
}
|
||||
//! Set the parameters.
|
||||
virtual MatType& Parameters()
|
||||
{
|
||||
throw std::invalid_argument("Layer::Parameters(): cannot modify parameters "
|
||||
"of a layer with no weights!");
|
||||
}
|
||||
|
||||
//! Compute the output dimensions. This should be overloaded if the layer is
|
||||
//! meant to work on higher-dimensional objects. When this is called, it is a
|
||||
//! safe assumption that InputDimensions() is correct.
|
||||
virtual void ComputeOutputDimensions()
|
||||
{
|
||||
// The default implementation is to assume that the output size is the same
|
||||
// as the input.
|
||||
outputDimensions = inputDimensions;
|
||||
}
|
||||
|
||||
//! Get the number of elements in the output from this layer. This cannot be
|
||||
//! overloaded! Overload `ComputeOutputDimensions()` instead.
|
||||
virtual size_t OutputSize() final
|
||||
{
|
||||
if (!validOutputDimensions)
|
||||
{
|
||||
this->ComputeOutputDimensions();
|
||||
validOutputDimensions = true;
|
||||
}
|
||||
|
||||
size_t outputSize = 1;
|
||||
for (size_t i = 0; i < this->outputDimensions.size(); ++i)
|
||||
outputSize *= this->outputDimensions[i];
|
||||
return outputSize;
|
||||
}
|
||||
|
||||
//! Serialize the layer.
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(inputDimensions));
|
||||
ar(CEREAL_NVP(outputDimensions));
|
||||
ar(CEREAL_NVP(validOutputDimensions));
|
||||
ar(CEREAL_NVP(training));
|
||||
|
||||
// Note that layer weights are serialized by the FFN!
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Logical input dimensions of each point. Although each point given to !
|
||||
* `Forward()` will be represented as a column in a matrix, logically
|
||||
* speaking it can be a higher-order tensor. So, for instance, if the point
|
||||
* is 2-dimensional images of size 10x10, `Forward()` will contain columns
|
||||
* with 100 rows, and `inputDimensions` will be `{10, 10}`. This generalizes
|
||||
* to higher dimensions.
|
||||
*/
|
||||
std::vector<size_t> inputDimensions;
|
||||
|
||||
/**
|
||||
* Logical output dimensions of each point. If the layer only performs
|
||||
* elementwise operations, this is most likely equal to `inputDimensions`; but
|
||||
* if the layer performs more complicated transformations, it may be
|
||||
* different.
|
||||
*/
|
||||
std::vector<size_t> outputDimensions;
|
||||
|
||||
//! This is `true` if `ComputeOutputDimensions()` has been called, and
|
||||
//! `outputDimensions` can be considered to be up-to-date.
|
||||
bool validOutputDimensions;
|
||||
|
||||
//! If true, the layer is in training mode; otherwise, it is in testing mode.
|
||||
bool training;
|
||||
};
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/layer_traits.hpp
|
||||
* @author Marcus Edel
|
||||
*
|
||||
* This provides the LayerTraits class, a template class to get information
|
||||
* about various layers.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_LAYER_TRAITS_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_LAYER_TRAITS_HPP
|
||||
|
||||
#include <mlpack/core/util/sfinae_utility.hpp>
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann {
|
||||
|
||||
/**
|
||||
* This is a template class that can provide information about various layers.
|
||||
* By default, this class will provide the weakest possible assumptions on
|
||||
* layer, and each layer should override values as necessary. If a layer
|
||||
* doesn't need to override a value, then there's no need to write a LayerTraits
|
||||
* specialization for that class.
|
||||
*/
|
||||
template<typename LayerType>
|
||||
class LayerTraits
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This is true if the layer is a binary layer.
|
||||
*/
|
||||
static const bool IsBinary = false;
|
||||
|
||||
/**
|
||||
* This is true if the layer is an output layer.
|
||||
*/
|
||||
static const bool IsOutputLayer = false;
|
||||
|
||||
/**
|
||||
* This is true if the layer is a bias layer.
|
||||
*/
|
||||
static const bool IsBiasLayer = false;
|
||||
|
||||
/*
|
||||
* This is true if the layer is a LSTM layer.
|
||||
**/
|
||||
static const bool IsLSTMLayer = false;
|
||||
|
||||
/*
|
||||
* This is true if the layer is a connection layer.
|
||||
**/
|
||||
static const bool IsConnection = false;
|
||||
};
|
||||
|
||||
// This gives us a HasGradientCheck<T, U> type (where U is a function pointer)
|
||||
// we can use with SFINAE to catch when a type has a Gradient(...) function.
|
||||
HAS_MEM_FUNC(Gradient, HasGradientCheck);
|
||||
|
||||
// This gives us a HasDeterministicCheck<T, U> type (where U is a function
|
||||
// pointer) we can use with SFINAE to catch when a type has a Deterministic()
|
||||
// function.
|
||||
HAS_MEM_FUNC(Deterministic, HasDeterministicCheck);
|
||||
|
||||
// This gives us a HasParametersCheck<T, U> type (where U is a function pointer)
|
||||
// we can use with SFINAE to catch when a type has a Parameters() function.
|
||||
HAS_MEM_FUNC(Parameters, HasParametersCheck);
|
||||
|
||||
// This gives us a HasAddCheck<T, U> type (where U is a function pointer) we
|
||||
// can use with SFINAE to catch when a type has a Add() function.
|
||||
HAS_MEM_FUNC(Add, HasAddCheck);
|
||||
|
||||
// This gives us a HasModelCheck<T> type we can use with SFINAE to catch when
|
||||
// a type has a function named Model.
|
||||
HAS_ANY_METHOD_FORM(Model, HasModelCheck);
|
||||
|
||||
// This gives us a HasLocationCheck<T, U> type (where U is a function pointer)
|
||||
// we can use with SFINAE to catch when a type has a Location() function.
|
||||
HAS_MEM_FUNC(Location, HasLocationCheck);
|
||||
|
||||
// This gives us a HasResetCheck<T, U> type (where U is a function pointer)
|
||||
// we can use with SFINAE to catch when a type has a Reset() function.
|
||||
HAS_MEM_FUNC(Reset, HasResetCheck);
|
||||
|
||||
// This gives us a HasResetCheck<T, U> type (where U is a function pointer)
|
||||
// we can use with SFINAE to catch when a type has a ResetCell() function.
|
||||
HAS_MEM_FUNC(ResetCell, HasResetCellCheck);
|
||||
|
||||
// This gives us a HasRewardCheck<T, U> type (where U is a function pointer) we
|
||||
// can use with SFINAE to catch when a type has a Reward() function.
|
||||
HAS_MEM_FUNC(Reward, HasRewardCheck);
|
||||
|
||||
// This gives us a HasInputWidth<T, U> type (where U is a function pointer) we
|
||||
// can use with SFINAE to catch when a type has a InputWidth() function.
|
||||
HAS_MEM_FUNC(InputWidth, HasInputWidth);
|
||||
|
||||
// This gives us a HasInputHeight<T, U> type (where U is a function pointer) we
|
||||
// can use with SFINAE to catch when a type has a InputHeight() function.
|
||||
HAS_MEM_FUNC(InputHeight, HasInputHeight);
|
||||
|
||||
// This gives us a HasRho<T, U> type (where U is a function pointer) we
|
||||
// can use with SFINAE to catch when a type has a Rho() function.
|
||||
HAS_MEM_FUNC(Rho, HasRho);
|
||||
|
||||
// This gives us a HasLoss<T, U> type (where U is a function pointer) we
|
||||
// can use with SFINAE to catch when a type has a Loss() function.
|
||||
HAS_MEM_FUNC(Loss, HasLoss);
|
||||
|
||||
// This gives us a HasRunCheck<T, U> type (where U is a function pointer) we
|
||||
// can use with SFINAE to catch when a type has a Run() function.
|
||||
HAS_MEM_FUNC(Run, HasRunCheck);
|
||||
|
||||
// This gives us a HasBiasCheck<T, U> type (where U is a function pointer) we
|
||||
// can use with SFINAE to catch when a type has a Bias() function.
|
||||
HAS_MEM_FUNC(Bias, HasBiasCheck);
|
||||
|
||||
// This gives us a HasMaxIterationsC<T, U> type (where U is a function pointer)
|
||||
// we can use with SFINAE to catch when a type has a MaxIterations() function.
|
||||
HAS_MEM_FUNC(MaxIterations, HasMaxIterations);
|
||||
|
||||
// This gives us a HasInShapeCheck<T> type we can use with SFINAE to catch when
|
||||
// a type has a function named InputShape.
|
||||
HAS_ANY_METHOD_FORM(InputShape, HasInputShapeCheck);
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -12,62 +12,33 @@
|
||||
#ifndef MLPACK_METHODS_ANN_LAYER_LAYER_TYPES_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_LAYER_TYPES_HPP
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <mlpack/methods/ann/layer/layer.hpp>
|
||||
#include <mlpack/methods/ann/layer/multi_layer.hpp>
|
||||
#include <mlpack/methods/ann/layer/recurrent_layer.hpp>
|
||||
|
||||
// Layer modules.
|
||||
// Include each layer.
|
||||
#include <mlpack/methods/ann/layer/add.hpp>
|
||||
#include <mlpack/methods/ann/layer/alpha_dropout.hpp>
|
||||
#include <mlpack/methods/ann/layer/base_layer.hpp>
|
||||
#include <mlpack/methods/ann/layer/batch_norm.hpp>
|
||||
#include <mlpack/methods/ann/layer/bicubic_interpolation.hpp>
|
||||
#include <mlpack/methods/ann/layer/bilinear_interpolation.hpp>
|
||||
#include <mlpack/methods/ann/layer/channel_shuffle.hpp>
|
||||
#include <mlpack/methods/ann/layer/constant.hpp>
|
||||
#include <mlpack/methods/ann/layer/concatenate.hpp>
|
||||
#include <mlpack/methods/ann/layer/convolution.hpp>
|
||||
#include <mlpack/methods/ann/layer/dropconnect.hpp>
|
||||
#include <mlpack/methods/ann/layer/dropout.hpp>
|
||||
#include <mlpack/methods/ann/layer/elu.hpp>
|
||||
#include <mlpack/methods/ann/layer/hard_tanh.hpp>
|
||||
#include <mlpack/methods/ann/layer/instance_norm.hpp>
|
||||
#include <mlpack/methods/ann/layer/group_norm.hpp>
|
||||
#include <mlpack/methods/ann/layer/join.hpp>
|
||||
#include <mlpack/methods/ann/layer/layer_norm.hpp>
|
||||
#include <mlpack/methods/ann/layer/leaky_relu.hpp>
|
||||
#include <mlpack/methods/ann/layer/c_relu.hpp>
|
||||
#include <mlpack/methods/ann/layer/flexible_relu.hpp>
|
||||
#include <mlpack/methods/ann/layer/linear.hpp>
|
||||
#include <mlpack/methods/ann/layer/linear_no_bias.hpp>
|
||||
#include <mlpack/methods/ann/layer/linear3d.hpp>
|
||||
#include <mlpack/methods/ann/layer/log_softmax.hpp>
|
||||
#include <mlpack/methods/ann/layer/lookup.hpp>
|
||||
#include <mlpack/methods/ann/layer/multihead_attention.hpp>
|
||||
#include <mlpack/methods/ann/layer/multiply_constant.hpp>
|
||||
#include <mlpack/methods/ann/layer/lstm.hpp>
|
||||
#include <mlpack/methods/ann/layer/max_pooling.hpp>
|
||||
#include <mlpack/methods/ann/layer/mean_pooling.hpp>
|
||||
#include <mlpack/methods/ann/layer/lp_pooling.hpp>
|
||||
#include <mlpack/methods/ann/layer/nearest_interpolation.hpp>
|
||||
#include <mlpack/methods/ann/layer/noisylinear.hpp>
|
||||
#include <mlpack/methods/ann/layer/adaptive_max_pooling.hpp>
|
||||
#include <mlpack/methods/ann/layer/adaptive_mean_pooling.hpp>
|
||||
#include <mlpack/methods/ann/layer/parametric_relu.hpp>
|
||||
#include <mlpack/methods/ann/layer/pixel_shuffle.hpp>
|
||||
#include <mlpack/methods/ann/layer/positional_encoding.hpp>
|
||||
#include <mlpack/methods/ann/layer/reinforce_normal.hpp>
|
||||
#include <mlpack/methods/ann/layer/relu6.hpp>
|
||||
#include <mlpack/methods/ann/layer/reparametrization.hpp>
|
||||
#include <mlpack/methods/ann/layer/select.hpp>
|
||||
#include <mlpack/methods/ann/layer/softmax.hpp>
|
||||
#include <mlpack/methods/ann/layer/spatial_dropout.hpp>
|
||||
#include <mlpack/methods/ann/layer/subview.hpp>
|
||||
#include <mlpack/methods/ann/layer/virtual_batch_norm.hpp>
|
||||
#include <mlpack/methods/ann/layer/hardshrink.hpp>
|
||||
#include <mlpack/methods/ann/layer/celu.hpp>
|
||||
#include <mlpack/methods/ann/layer/isrlu.hpp>
|
||||
#include <mlpack/methods/ann/layer/softshrink.hpp>
|
||||
#include <mlpack/methods/ann/layer/padding.hpp>
|
||||
#include <mlpack/methods/ann/layer/radial_basis_function.hpp>
|
||||
|
||||
// Convolution modules.
|
||||
// Convolution modes.
|
||||
#include <mlpack/methods/ann/convolution_rules/border_modes.hpp>
|
||||
#include <mlpack/methods/ann/convolution_rules/naive_convolution.hpp>
|
||||
#include <mlpack/methods/ann/convolution_rules/fft_convolution.hpp>
|
||||
#include <mlpack/methods/ann/convolution_rules/naive_convolution.hpp>
|
||||
|
||||
// Regularizers.
|
||||
#include <mlpack/methods/ann/regularizer/no_regularizer.hpp>
|
||||
@@ -75,250 +46,7 @@
|
||||
// Loss function modules.
|
||||
#include <mlpack/methods/ann/loss_functions/negative_log_likelihood.hpp>
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType> class BatchNorm;
|
||||
template<typename InputDataType, typename OutputDataType> class DropConnect;
|
||||
template<typename InputDataType, typename OutputDataType> class Glimpse;
|
||||
template<typename InputDataType, typename OutputDataType> class LayerNorm;
|
||||
template<typename InputDataType, typename OutputDataType> class LSTM;
|
||||
template<typename InputDataType, typename OutputDataType> class GRU;
|
||||
template<typename InputDataType, typename OutputDataType> class FastLSTM;
|
||||
template<typename InputDataType, typename OutputDataType> class VRClassReward;
|
||||
template<typename InputDataType, typename OutputDataType> class Concatenate;
|
||||
template<typename InputDataType, typename OutputDataType> class Padding;
|
||||
template<typename InputDataType, typename OutputDataType> class ReLU6;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
class Linear;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType,
|
||||
typename Activation>
|
||||
class RBF;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
class LinearNoBias;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType>
|
||||
class NoisyLinear;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
class Linear3D;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType
|
||||
>
|
||||
class VirtualBatchNorm;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType
|
||||
>
|
||||
class MiniBatchDiscrimination;
|
||||
|
||||
template <typename InputDataType,
|
||||
typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
class MultiheadAttention;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType
|
||||
>
|
||||
class Reparametrization;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType,
|
||||
typename... CustomLayers
|
||||
>
|
||||
class AddMerge;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType,
|
||||
bool residual,
|
||||
typename... CustomLayers
|
||||
>
|
||||
class Sequential;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType,
|
||||
typename... CustomLayers
|
||||
>
|
||||
class Highway;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType,
|
||||
typename... CustomLayers
|
||||
>
|
||||
class Recurrent;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType,
|
||||
typename... CustomLayers
|
||||
>
|
||||
class Concat;
|
||||
|
||||
template<
|
||||
typename OutputLayerType,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
>
|
||||
class ConcatPerformance;
|
||||
|
||||
template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
>
|
||||
class Convolution;
|
||||
|
||||
template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
>
|
||||
class TransposedConvolution;
|
||||
|
||||
template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
>
|
||||
class AtrousConvolution;
|
||||
|
||||
template<
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
>
|
||||
class RecurrentAttention;
|
||||
|
||||
template<typename InputDataType,
|
||||
typename OutputDataType,
|
||||
typename... CustomLayers
|
||||
>
|
||||
class MultiplyMerge;
|
||||
|
||||
template <typename InputDataType,
|
||||
typename OutputDataType,
|
||||
typename... CustomLayers
|
||||
>
|
||||
class WeightNorm;
|
||||
|
||||
template <typename InputDataType,
|
||||
typename OutputDataType
|
||||
>
|
||||
class AdaptiveMaxPooling;
|
||||
|
||||
template <typename InputDataType,
|
||||
typename OutputDataType
|
||||
>
|
||||
class AdaptiveMeanPooling;
|
||||
|
||||
using MoreTypes = boost::variant<
|
||||
FlexibleReLU<arma::mat, arma::mat>*,
|
||||
Linear3D<arma::mat, arma::mat, NoRegularizer>*,
|
||||
LpPooling<arma::mat, arma::mat>*,
|
||||
PixelShuffle<arma::mat, arma::mat>*,
|
||||
ChannelShuffle<arma::mat, arma::mat>*,
|
||||
Glimpse<arma::mat, arma::mat>*,
|
||||
Highway<arma::mat, arma::mat>*,
|
||||
MultiheadAttention<arma::mat, arma::mat, NoRegularizer>*,
|
||||
Recurrent<arma::mat, arma::mat>*,
|
||||
RecurrentAttention<arma::mat, arma::mat>*,
|
||||
ReinforceNormal<arma::mat, arma::mat>*,
|
||||
ReLU6<arma::mat, arma::mat>*,
|
||||
Reparametrization<arma::mat, arma::mat>*,
|
||||
Select<arma::mat, arma::mat>*,
|
||||
SpatialDropout<arma::mat, arma::mat>*,
|
||||
Subview<arma::mat, arma::mat>*,
|
||||
VRClassReward<arma::mat, arma::mat>*,
|
||||
VirtualBatchNorm<arma::mat, arma::mat>*,
|
||||
RBF<arma::mat, arma::mat, GaussianFunction>*,
|
||||
BaseLayer<GaussianFunction, arma::mat, arma::mat>*,
|
||||
PositionalEncoding<arma::mat, arma::mat>*,
|
||||
ISRLU<arma::mat, arma::mat>*,
|
||||
BicubicInterpolation<arma::mat, arma::mat>*,
|
||||
NearestInterpolation<arma::mat, arma::mat>*,
|
||||
GroupNorm<arma::mat, arma::mat>*,
|
||||
InstanceNorm<arma::mat, arma::mat>*
|
||||
>;
|
||||
|
||||
template <typename... CustomLayers>
|
||||
using LayerTypes = boost::variant<
|
||||
AdaptiveMaxPooling<arma::mat, arma::mat>*,
|
||||
AdaptiveMeanPooling<arma::mat, arma::mat>*,
|
||||
Add<arma::mat, arma::mat>*,
|
||||
AddMerge<arma::mat, arma::mat>*,
|
||||
AlphaDropout<arma::mat, arma::mat>*,
|
||||
AtrousConvolution<NaiveConvolution<ValidConvolution>,
|
||||
NaiveConvolution<FullConvolution>,
|
||||
NaiveConvolution<ValidConvolution>,
|
||||
arma::mat, arma::mat>*,
|
||||
BaseLayer<LogisticFunction, arma::mat, arma::mat>*,
|
||||
BaseLayer<IdentityFunction, arma::mat, arma::mat>*,
|
||||
BaseLayer<TanhFunction, arma::mat, arma::mat>*,
|
||||
BaseLayer<SoftplusFunction, arma::mat, arma::mat>*,
|
||||
BaseLayer<RectifierFunction, arma::mat, arma::mat>*,
|
||||
BatchNorm<arma::mat, arma::mat>*,
|
||||
BilinearInterpolation<arma::mat, arma::mat>*,
|
||||
CELU<arma::mat, arma::mat>*,
|
||||
Concat<arma::mat, arma::mat>*,
|
||||
Concatenate<arma::mat, arma::mat>*,
|
||||
ConcatPerformance<NegativeLogLikelihood<arma::mat, arma::mat>,
|
||||
arma::mat, arma::mat>*,
|
||||
Constant<arma::mat, arma::mat>*,
|
||||
Convolution<NaiveConvolution<ValidConvolution>,
|
||||
NaiveConvolution<FullConvolution>,
|
||||
NaiveConvolution<ValidConvolution>, arma::mat, arma::mat>*,
|
||||
CReLU<arma::mat, arma::mat>*,
|
||||
DropConnect<arma::mat, arma::mat>*,
|
||||
Dropout<arma::mat, arma::mat>*,
|
||||
ELU<arma::mat, arma::mat>*,
|
||||
FastLSTM<arma::mat, arma::mat>*,
|
||||
GRU<arma::mat, arma::mat>*,
|
||||
HardTanH<arma::mat, arma::mat>*,
|
||||
Join<arma::mat, arma::mat>*,
|
||||
LayerNorm<arma::mat, arma::mat>*,
|
||||
LeakyReLU<arma::mat, arma::mat>*,
|
||||
Linear<arma::mat, arma::mat, NoRegularizer>*,
|
||||
LinearNoBias<arma::mat, arma::mat, NoRegularizer>*,
|
||||
LogSoftMax<arma::mat, arma::mat>*,
|
||||
Lookup<arma::mat, arma::mat>*,
|
||||
LSTM<arma::mat, arma::mat>*,
|
||||
MaxPooling<arma::mat, arma::mat>*,
|
||||
MeanPooling<arma::mat, arma::mat>*,
|
||||
MiniBatchDiscrimination<arma::mat, arma::mat>*,
|
||||
MultiplyConstant<arma::mat, arma::mat>*,
|
||||
MultiplyMerge<arma::mat, arma::mat>*,
|
||||
NegativeLogLikelihood<arma::mat, arma::mat>*,
|
||||
NoisyLinear<arma::mat, arma::mat>*,
|
||||
Padding<arma::mat, arma::mat>*,
|
||||
PReLU<arma::mat, arma::mat>*,
|
||||
Sequential<arma::mat, arma::mat, false>*,
|
||||
Sequential<arma::mat, arma::mat, true>*,
|
||||
Softmax<arma::mat, arma::mat>*,
|
||||
TransposedConvolution<NaiveConvolution<ValidConvolution>,
|
||||
NaiveConvolution<ValidConvolution>,
|
||||
NaiveConvolution<ValidConvolution>, arma::mat, arma::mat>*,
|
||||
WeightNorm<arma::mat, arma::mat>*,
|
||||
MoreTypes,
|
||||
CustomLayers*...
|
||||
>;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
// Include definitions for polymorphic serialization.
|
||||
#include <mlpack/methods/ann/layer/serialization.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
@@ -32,16 +34,11 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* \right.
|
||||
* @f}
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class LeakyReLU
|
||||
template<typename MatType = arma::mat>
|
||||
class LeakyReLUType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -49,9 +46,24 @@ class LeakyReLU
|
||||
* The non zero gradient can be adjusted by specifying the parameter
|
||||
* alpha in the range 0 to 1. Default (alpha = 0.03)
|
||||
*
|
||||
* @param alpha Non zero gradient
|
||||
* @param alpha Non zero gradient.
|
||||
*/
|
||||
LeakyReLU(const double alpha = 0.03);
|
||||
LeakyReLUType(const double alpha = 0.03);
|
||||
|
||||
//! Clone the LeakyReLUType object. This handles polymorphism correctly.
|
||||
LeakyReLUType* Clone() const { return new LeakyReLUType(*this); }
|
||||
|
||||
// Virtual destructor.
|
||||
virtual ~LeakyReLUType() { }
|
||||
|
||||
//! Copy the given LeakyReLUType.
|
||||
LeakyReLUType(const LeakyReLUType& other);
|
||||
//! Take ownership of the given LeakyReLUType.
|
||||
LeakyReLUType(LeakyReLUType&& other);
|
||||
//! Copy the given LeakyReLUType.
|
||||
LeakyReLUType& operator=(const LeakyReLUType& other);
|
||||
//! Take ownership of the given LeakyReLUType.
|
||||
LeakyReLUType& operator=(LeakyReLUType&& other);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -60,8 +72,7 @@ class LeakyReLU
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
@@ -72,43 +83,27 @@ class LeakyReLU
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename DataType>
|
||||
void Backward(const DataType& input, const DataType& gy, DataType& g);
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
void Backward(const MatType& input, const MatType& gy, MatType& g);
|
||||
|
||||
//! Get the non zero gradient.
|
||||
double const& Alpha() const { return alpha; }
|
||||
//! Modify the non zero gradient.
|
||||
double& Alpha() { return alpha; }
|
||||
|
||||
//! Get size of weights.
|
||||
size_t WeightSize() const { return 0; }
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
*/
|
||||
//! Serialize the layer.
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
|
||||
//! Leakyness Parameter in the range 0 <alpha< 1
|
||||
double alpha;
|
||||
}; // class LeakyReLU
|
||||
}; // class LeakyReLUType
|
||||
|
||||
// Convenience typedefs.
|
||||
|
||||
// Standard LeakyReLU layer.
|
||||
typedef LeakyReLUType<arma::mat> LeakyReLU;
|
||||
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -20,27 +20,68 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
LeakyReLU<InputDataType, OutputDataType>::LeakyReLU(
|
||||
const double alpha) : alpha(alpha)
|
||||
template<typename MatType>
|
||||
LeakyReLUType<MatType>::LeakyReLUType(const double alpha) :
|
||||
Layer<MatType>(),
|
||||
alpha(alpha)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
void LeakyReLU<InputDataType, OutputDataType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
template<typename MatType>
|
||||
LeakyReLUType<MatType>::LeakyReLUType(const LeakyReLUType& other) :
|
||||
Layer<MatType>(other),
|
||||
alpha(other.alpha)
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
LeakyReLUType<MatType>::LeakyReLUType(
|
||||
LeakyReLUType&& other) :
|
||||
Layer<MatType>(std::move(other)),
|
||||
alpha(std::move(other.alpha))
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
LeakyReLUType<MatType>&
|
||||
LeakyReLUType<MatType>::operator=(const LeakyReLUType& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
Layer<MatType>::operator=(other);
|
||||
alpha = other.alpha;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
LeakyReLUType<MatType>&
|
||||
LeakyReLUType<MatType>::operator=(LeakyReLUType&& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
Layer<MatType>::operator=(std::move(other));
|
||||
alpha = std::move(other.alpha);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void LeakyReLUType<MatType>::Forward(const MatType& input, MatType& output)
|
||||
{
|
||||
output = arma::max(input, alpha * input);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename DataType>
|
||||
void LeakyReLU<InputDataType, OutputDataType>::Backward(
|
||||
const DataType& input, const DataType& gy, DataType& g)
|
||||
template<typename MatType>
|
||||
void LeakyReLUType<MatType>::Backward(
|
||||
const MatType& input, const MatType& gy, MatType& g)
|
||||
{
|
||||
DataType derivative;
|
||||
MatType derivative;
|
||||
derivative.set_size(arma::size(input));
|
||||
for (size_t i = 0; i < input.n_elem; ++i)
|
||||
derivative(i) = (input(i) >= 0) ? 1 : alpha;
|
||||
@@ -48,12 +89,14 @@ void LeakyReLU<InputDataType, OutputDataType>::Backward(
|
||||
g = gy % derivative;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename MatType>
|
||||
template<typename Archive>
|
||||
void LeakyReLU<InputDataType, OutputDataType>::serialize(
|
||||
void LeakyReLUType<MatType>::serialize(
|
||||
Archive& ar,
|
||||
const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(alpha));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include <mlpack/methods/ann/regularizer/no_regularizer.hpp>
|
||||
|
||||
#include "layer_types.hpp"
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
@@ -25,142 +25,120 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* Implementation of the Linear layer class. The Linear class represents a
|
||||
* single layer of a neural network.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* The linear layer applies a linear transformation to the incoming data
|
||||
* (input), i.e. y = Ax + b. The input matrix given in Forward(input, output)
|
||||
* must be either a vector or matrix. If the input is a matrix, then each column
|
||||
* is assumed to be an input sample of given batch.
|
||||
*
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
* @tparam RegularizerType Type of the regularizer to be used (Default no
|
||||
* regularizer).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat,
|
||||
template<
|
||||
typename MatType = arma::mat,
|
||||
typename RegularizerType = NoRegularizer
|
||||
>
|
||||
class Linear
|
||||
class LinearType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
//! Create the Linear object.
|
||||
Linear();
|
||||
LinearType();
|
||||
|
||||
/**
|
||||
* Create the Linear layer object using the specified number of units.
|
||||
* Create the Linear layer object with the specified number of output
|
||||
* dimensions.
|
||||
*
|
||||
* @param inSize The number of input units.
|
||||
* @param outSize The number of output units.
|
||||
* @param regularizer The regularizer to use, optional.
|
||||
* @param outSize The output dimension.
|
||||
* @param regularizer The regularizer to use, optional (default: no
|
||||
* regularizer).
|
||||
*/
|
||||
Linear(const size_t inSize,
|
||||
const size_t outSize,
|
||||
RegularizerType regularizer = RegularizerType());
|
||||
LinearType(const size_t outSize,
|
||||
RegularizerType regularizer = RegularizerType());
|
||||
|
||||
//! Copy constructor.
|
||||
Linear(const Linear& layer);
|
||||
virtual ~LinearType() { }
|
||||
|
||||
//! Move constructor.
|
||||
Linear(Linear&&);
|
||||
//! Clone the LinearType object. This handles polymorphism correctly.
|
||||
LinearType* Clone() const { return new LinearType(*this); }
|
||||
|
||||
//! Copy assignment operator.
|
||||
Linear& operator=(const Linear& layer);
|
||||
//! Copy the other Linear layer (but not weights).
|
||||
LinearType(const LinearType& layer);
|
||||
|
||||
//! Move assignment operator.
|
||||
Linear& operator=(Linear&& layer);
|
||||
//! Take ownership of the members of the other Linear layer (but not weights).
|
||||
LinearType(LinearType&& layer);
|
||||
|
||||
/*
|
||||
* Reset the layer parameter.
|
||||
//! Copy the other Linear layer (but not weights).
|
||||
LinearType& operator=(const LinearType& layer);
|
||||
|
||||
//! Take ownership of the members of the other Linear layer (but not weights).
|
||||
LinearType& operator=(LinearType&& layer);
|
||||
|
||||
/**
|
||||
* Reset the layer parameter (weights and bias). The method is called to
|
||||
* assign the allocated memory to the internal learnable parameters.
|
||||
*/
|
||||
void Reset();
|
||||
void SetWeights(typename MatType::elem_type* weightsPtr);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
* f(x) by propagating the activity forward through f.
|
||||
*
|
||||
* f(x) is a linear transformation: Ax + b, where x is the given input, x are
|
||||
* the layer weights and b is the layer bias.
|
||||
*
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
* f(x) by propagating x backwards trough f. Using the results from the feed
|
||||
* forward pass.
|
||||
*
|
||||
* To compute the downstream gradient (g) the chain rule is used.
|
||||
*
|
||||
* @param * (input) The propagated input activation.
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
void Backward(const MatType& /* input */,
|
||||
const MatType& gy,
|
||||
MatType& g);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
*
|
||||
* @param input The input parameter used for calculating the gradient.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient);
|
||||
void Gradient(const MatType& input,
|
||||
const MatType& error,
|
||||
MatType& gradient);
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
const MatType& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
|
||||
//! Get the input parameter.
|
||||
InputDataType const& InputParameter() const { return inputParameter; }
|
||||
//! Modify the input parameter.
|
||||
InputDataType& InputParameter() { return inputParameter; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the input size.
|
||||
size_t InputSize() const { return inSize; }
|
||||
|
||||
//! Get the output size.
|
||||
size_t OutputSize() const { return outSize; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return gradient; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return gradient; }
|
||||
MatType& Parameters() { return weights; }
|
||||
|
||||
//! Get the weight of the layer.
|
||||
OutputDataType const& Weight() const { return weight; }
|
||||
MatType const& Weight() const { return weight; }
|
||||
//! Modify the weight of the layer.
|
||||
OutputDataType& Weight() { return weight; }
|
||||
MatType& Weight() { return weight; }
|
||||
|
||||
//! Get the bias of the layer.
|
||||
OutputDataType const& Bias() const { return bias; }
|
||||
MatType const& Bias() const { return bias; }
|
||||
//! Modify the bias weights of the layer.
|
||||
OutputDataType& Bias() { return bias; }
|
||||
MatType& Bias() { return bias; }
|
||||
|
||||
//! Get the size of the weights.
|
||||
size_t WeightSize() const
|
||||
{
|
||||
return (inSize * outSize) + outSize;
|
||||
}
|
||||
size_t WeightSize() const { return (inSize * outSize) + outSize; }
|
||||
|
||||
//! Get the shape of the input.
|
||||
size_t InputShape() const
|
||||
{
|
||||
return inSize;
|
||||
}
|
||||
//! Compute the output dimensions of the layer given `InputDimensions()`.
|
||||
void ComputeOutputDimensions();
|
||||
|
||||
/**
|
||||
* Serialize the layer
|
||||
*/
|
||||
//! Serialize the layer.
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
@@ -171,30 +149,24 @@ class Linear
|
||||
//! Locally-stored number of output units.
|
||||
size_t outSize;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
//! Locally-stored weight object. This holds all the weights in a vectorized
|
||||
//! form; i.e., the weights and the bias.
|
||||
MatType weights;
|
||||
|
||||
//! Locally-stored weight parameters.
|
||||
OutputDataType weight;
|
||||
MatType weight;
|
||||
|
||||
//! Locally-stored bias term parameters.
|
||||
OutputDataType bias;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
|
||||
//! Locally-stored input parameter object.
|
||||
InputDataType inputParameter;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
MatType bias;
|
||||
|
||||
//! Locally-stored regularizer object.
|
||||
RegularizerType regularizer;
|
||||
}; // class Linear
|
||||
}; // class LinearType
|
||||
|
||||
// Convenience typedefs.
|
||||
|
||||
// Standard Linear layer using no regularization.
|
||||
typedef LinearType<arma::mat, NoRegularizer> Linear;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
#define MLPACK_METHODS_ANN_LAYER_LINEAR3D_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include <mlpack/methods/ann/layer/layer_types.hpp>
|
||||
#include <mlpack/methods/ann/regularizer/no_regularizer.hpp>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
@@ -27,49 +28,48 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* Shape of input : (inSize * nPoints, batchSize)
|
||||
* Shape of output : (outSize * nPoints, batchSize)
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat,
|
||||
template<
|
||||
typename MatType = arma::mat,
|
||||
typename RegularizerType = NoRegularizer
|
||||
>
|
||||
class Linear3D
|
||||
class Linear3DType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
//! Create the Linear3D object.
|
||||
Linear3D();
|
||||
Linear3DType();
|
||||
|
||||
/**
|
||||
* Create the Linear3D layer object using the specified number of units.
|
||||
* Create the Linear3D layer object using the specified number of output
|
||||
* units.
|
||||
*
|
||||
* @param inSize The number of input units.
|
||||
* @param outSize The number of output units.
|
||||
* @param regularizer The regularizer to use, optional.
|
||||
*/
|
||||
Linear3D(const size_t inSize,
|
||||
const size_t outSize,
|
||||
RegularizerType regularizer = RegularizerType());
|
||||
Linear3DType(const size_t outSize,
|
||||
RegularizerType regularizer = RegularizerType());
|
||||
|
||||
//! Copy constructor.
|
||||
Linear3D(const Linear3D& layer);
|
||||
//! Clone the Linear3DType object. This handles polymorphism correctly.
|
||||
Linear3DType* Clone() const { return new Linear3DType(*this); }
|
||||
|
||||
//! Move constructor.
|
||||
Linear3D(Linear3D&&);
|
||||
// Virtual destructor.
|
||||
virtual ~Linear3DType() { }
|
||||
|
||||
//! Copy assignment operator.
|
||||
Linear3D& operator=(const Linear3D& layer);
|
||||
|
||||
//! Move assignment operator.
|
||||
Linear3D& operator=(Linear3D&& layer);
|
||||
//! Copy the given Linear3DType (but not weights).
|
||||
Linear3DType(const Linear3DType& other);
|
||||
//! Take ownership of the given Linear3DType (but not weights).
|
||||
Linear3DType(Linear3DType&& other);
|
||||
//! Copy the given Linear3DType (but not weights).
|
||||
Linear3DType& operator=(const Linear3DType& other);
|
||||
//! Take ownership of the given Linear3DType (but not weights).
|
||||
Linear3DType& operator=(Linear3DType&& other);
|
||||
|
||||
/*
|
||||
* Reset the layer parameter.
|
||||
*/
|
||||
void Reset();
|
||||
void SetWeights(typename MatType::elem_type* weightsPtr);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -78,8 +78,7 @@ class Linear3D
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
@@ -90,69 +89,41 @@ class Linear3D
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
void Backward(const MatType& /* input */,
|
||||
const MatType& gy,
|
||||
MatType& g);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
*
|
||||
* @param input The input parameter used for calculating the gradient.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient);
|
||||
void Gradient(const MatType& input,
|
||||
const MatType& error,
|
||||
MatType& gradient);
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
MatType const& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
|
||||
//! Get the input parameter.
|
||||
InputDataType const& InputParameter() const { return inputParameter; }
|
||||
//! Modify the input parameter.
|
||||
InputDataType& InputParameter() { return inputParameter; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the input size.
|
||||
size_t InputSize() const { return inSize; }
|
||||
|
||||
//! Get the output size.
|
||||
size_t OutputSize() const { return outSize; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return gradient; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return gradient; }
|
||||
MatType& Parameters() { return weights; }
|
||||
|
||||
//! Get the weight of the layer.
|
||||
OutputDataType const& Weight() const { return weight; }
|
||||
MatType const& Weight() const { return weight; }
|
||||
//! Modify the weight of the layer.
|
||||
OutputDataType& Weight() { return weight; }
|
||||
MatType& Weight() { return weight; }
|
||||
|
||||
//! Get the bias of the layer.
|
||||
OutputDataType const& Bias() const { return bias; }
|
||||
MatType const& Bias() const { return bias; }
|
||||
//! Modify the bias weights of the layer.
|
||||
OutputDataType& Bias() { return bias; }
|
||||
MatType& Bias() { return bias; }
|
||||
|
||||
//! Get the shape of the input.
|
||||
size_t InputShape() const
|
||||
{
|
||||
return inSize;
|
||||
}
|
||||
//! Return the number of weight elements.
|
||||
size_t WeightSize() const { return outSize * (this->inputDimensions[0] + 1); }
|
||||
|
||||
//! Compute the output dimensions for the layer, using `InputDimensions()`.
|
||||
void ComputeOutputDimensions();
|
||||
|
||||
/**
|
||||
* Serialize the layer
|
||||
@@ -161,37 +132,25 @@ class Linear3D
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally-stored number of input units.
|
||||
size_t inSize;
|
||||
|
||||
//! Locally-stored number of output units.
|
||||
size_t outSize;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
MatType weights;
|
||||
|
||||
//! Locally-stored weight parameters.
|
||||
OutputDataType weight;
|
||||
MatType weight;
|
||||
|
||||
//! Locally-stored bias term parameters.
|
||||
OutputDataType bias;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
|
||||
//! Locally-stored input parameter object.
|
||||
InputDataType inputParameter;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
MatType bias;
|
||||
|
||||
//! Locally-stored regularizer object.
|
||||
RegularizerType regularizer;
|
||||
}; // class Linear
|
||||
|
||||
// Standard Linear3D layer.
|
||||
typedef Linear3DType<arma::mat, NoRegularizer> Linear3D;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
@@ -18,116 +18,94 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear3D<InputDataType, OutputDataType, RegularizerType>::Linear3D() :
|
||||
inSize(0),
|
||||
template<typename MatType, typename RegularizerType>
|
||||
Linear3DType<MatType, RegularizerType>::Linear3DType() :
|
||||
Layer<MatType>(),
|
||||
outSize(0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear3D<InputDataType, OutputDataType, RegularizerType>::Linear3D(
|
||||
const size_t inSize,
|
||||
template<typename MatType, typename RegularizerType>
|
||||
Linear3DType<MatType, RegularizerType>::Linear3DType(
|
||||
const size_t outSize,
|
||||
RegularizerType regularizer) :
|
||||
inSize(inSize),
|
||||
Layer<MatType>(),
|
||||
outSize(outSize),
|
||||
regularizer(regularizer)
|
||||
{ }
|
||||
|
||||
template<typename MatType, typename RegularizerType>
|
||||
Linear3DType<MatType, RegularizerType>::Linear3DType(
|
||||
const Linear3DType& other) :
|
||||
Layer<MatType>(other),
|
||||
outSize(other.outSize),
|
||||
regularizer(other.regularizer)
|
||||
{
|
||||
weights.set_size(outSize * inSize + outSize, 1);
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear3D<InputDataType, OutputDataType, RegularizerType>::Linear3D(
|
||||
const Linear3D& layer) :
|
||||
inSize(layer.inSize),
|
||||
outSize(layer.outSize),
|
||||
weights(layer.weights),
|
||||
regularizer(layer.regularizer)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
Linear3DType<MatType, RegularizerType>::Linear3DType(
|
||||
Linear3DType&& other) :
|
||||
Layer<MatType>(std::move(other)),
|
||||
outSize(std::move(other.outSize)),
|
||||
regularizer(std::move(other.regularizer))
|
||||
{
|
||||
// Nothing to do here.
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear3D<InputDataType, OutputDataType, RegularizerType>::Linear3D(
|
||||
Linear3D&& layer) :
|
||||
inSize(0),
|
||||
outSize(0),
|
||||
weights(std::move(layer.weights)),
|
||||
regularizer(std::move(layer.regularizer))
|
||||
template<typename MatType, typename RegularizerType>
|
||||
Linear3DType<MatType, RegularizerType>&
|
||||
Linear3DType<MatType, RegularizerType>::operator=(
|
||||
const Linear3DType& other)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear3D<InputDataType, OutputDataType, RegularizerType>&
|
||||
Linear3D<InputDataType, OutputDataType, RegularizerType>::
|
||||
operator=(const Linear3D& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
if (&other != this)
|
||||
{
|
||||
inSize = layer.inSize;
|
||||
outSize = layer.outSize;
|
||||
weights = layer.weights;
|
||||
regularizer = layer.regularizer;
|
||||
Layer<MatType>::operator=(other);
|
||||
outSize = other.outSize;
|
||||
regularizer = other.regularizer;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear3D<InputDataType, OutputDataType, RegularizerType>&
|
||||
Linear3D<InputDataType, OutputDataType, RegularizerType>::
|
||||
operator=(Linear3D&& layer)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
Linear3DType<MatType, RegularizerType>&
|
||||
Linear3DType<MatType, RegularizerType>::operator=(
|
||||
Linear3DType&& other)
|
||||
{
|
||||
if (this != &layer)
|
||||
if (&other != this)
|
||||
{
|
||||
inSize = 0;
|
||||
outSize = 0;
|
||||
weights = std::move(layer.weights);
|
||||
regularizer = std::move(layer.regularizer);
|
||||
Layer<MatType>::operator=(std::move(other));
|
||||
outSize = std::move(other.outSize);
|
||||
regularizer = std::move(other.regularizer);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
void Linear3D<InputDataType, OutputDataType, RegularizerType>::Reset()
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void Linear3DType<MatType, RegularizerType>::SetWeights(
|
||||
typename MatType::elem_type* weightsPtr)
|
||||
{
|
||||
typedef typename arma::Mat<typename OutputDataType::elem_type> MatType;
|
||||
|
||||
weight = MatType(weights.memptr(), outSize, inSize, false, false);
|
||||
bias = MatType(weights.memptr() + weight.n_elem, outSize, 1, false, false);
|
||||
MakeAlias(weights, weightsPtr, outSize * this->inputDimensions[0] + outSize,
|
||||
1);
|
||||
MakeAlias(weight, weightsPtr, outSize, this->inputDimensions[0]);
|
||||
MakeAlias(bias, weightsPtr + weight.n_elem, outSize, 1);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename eT>
|
||||
void Linear3D<InputDataType, OutputDataType, RegularizerType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void Linear3DType<MatType, RegularizerType>::Forward(
|
||||
const MatType& input, MatType& output)
|
||||
{
|
||||
typedef typename arma::Mat<eT> MatType;
|
||||
typedef typename arma::Cube<eT> CubeType;
|
||||
typedef typename arma::Cube<typename MatType::elem_type> CubeType;
|
||||
|
||||
if (input.n_rows % inSize != 0)
|
||||
{
|
||||
Log::Fatal << "Number of features in the input must be divisible by inSize."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
const size_t nPoints = input.n_rows / inSize;
|
||||
const size_t nPoints = input.n_rows / this->inputDimensions[0];
|
||||
const size_t batchSize = input.n_cols;
|
||||
|
||||
output.set_size(outSize * nPoints, batchSize);
|
||||
|
||||
const CubeType inputTemp(const_cast<MatType&>(input).memptr(), inSize,
|
||||
nPoints, batchSize, false, false);
|
||||
const CubeType inputTemp(const_cast<MatType&>(input).memptr(),
|
||||
this->inputDimensions[0], nPoints, batchSize, false, false);
|
||||
|
||||
for (size_t i = 0; i < batchSize; ++i)
|
||||
{
|
||||
@@ -139,16 +117,13 @@ void Linear3D<InputDataType, OutputDataType, RegularizerType>::Forward(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename eT>
|
||||
void Linear3D<InputDataType, OutputDataType, RegularizerType>::Backward(
|
||||
const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void Linear3DType<MatType, RegularizerType>::Backward(
|
||||
const MatType& /* input */,
|
||||
const MatType& gy,
|
||||
MatType& g)
|
||||
{
|
||||
typedef typename arma::Mat<eT> MatType;
|
||||
typedef typename arma::Cube<eT> CubeType;
|
||||
typedef typename arma::Cube<typename MatType::elem_type> CubeType;
|
||||
|
||||
if (gy.n_rows % outSize != 0)
|
||||
{
|
||||
@@ -162,8 +137,6 @@ void Linear3D<InputDataType, OutputDataType, RegularizerType>::Backward(
|
||||
const CubeType gyTemp(const_cast<MatType&>(gy).memptr(), outSize,
|
||||
nPoints, batchSize, false, false);
|
||||
|
||||
g.set_size(inSize * nPoints, batchSize);
|
||||
|
||||
for (size_t i = 0; i < gyTemp.n_slices; ++i)
|
||||
{
|
||||
// Shape of weight : (outSize, inSize).
|
||||
@@ -172,29 +145,26 @@ void Linear3D<InputDataType, OutputDataType, RegularizerType>::Backward(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename eT>
|
||||
void Linear3D<InputDataType, OutputDataType, RegularizerType>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void Linear3DType<MatType, RegularizerType>::Gradient(
|
||||
const MatType& input,
|
||||
const MatType& error,
|
||||
MatType& gradient)
|
||||
{
|
||||
typedef typename arma::Mat<eT> MatType;
|
||||
typedef typename arma::Cube<eT> CubeType;
|
||||
typedef typename arma::Cube<typename MatType::elem_type> CubeType;
|
||||
|
||||
if (error.n_rows % outSize != 0)
|
||||
Log::Fatal << "Propagated error matrix has invalid dimension!" << std::endl;
|
||||
|
||||
const size_t nPoints = input.n_rows / inSize;
|
||||
const size_t nPoints = input.n_rows / this->inputDimensions[0];
|
||||
const size_t batchSize = input.n_cols;
|
||||
|
||||
const CubeType inputTemp(const_cast<MatType&>(input).memptr(), inSize,
|
||||
nPoints, batchSize, false, false);
|
||||
const CubeType inputTemp(const_cast<MatType&>(input).memptr(),
|
||||
this->inputDimensions[0], nPoints, batchSize, false, false);
|
||||
const CubeType errorTemp(const_cast<MatType&>(error).memptr(), outSize,
|
||||
nPoints, batchSize, false, false);
|
||||
|
||||
CubeType dW(outSize, inSize, batchSize);
|
||||
CubeType dW(outSize, this->inputDimensions[0], batchSize);
|
||||
for (size_t i = 0; i < batchSize; ++i)
|
||||
{
|
||||
// Shape of errorTemp : (outSize, nPoints, batchSize).
|
||||
@@ -202,8 +172,6 @@ void Linear3D<InputDataType, OutputDataType, RegularizerType>::Gradient(
|
||||
dW.slice(i) = errorTemp.slice(i) * inputTemp.slice(i).t();
|
||||
}
|
||||
|
||||
gradient.set_size(arma::size(weights));
|
||||
|
||||
gradient.submat(0, 0, weight.n_elem - 1, 0)
|
||||
= arma::vectorise(arma::sum(dW, 2));
|
||||
|
||||
@@ -213,19 +181,27 @@ void Linear3D<InputDataType, OutputDataType, RegularizerType>::Gradient(
|
||||
regularizer.Evaluate(weights, gradient);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void Linear3DType<
|
||||
MatType, RegularizerType
|
||||
>::ComputeOutputDimensions()
|
||||
{
|
||||
// The Linear3D layer shares weights for each row of the input, and
|
||||
// duplicates it across the columns. Thus, we only change the number of
|
||||
// rows.
|
||||
this->outputDimensions = this->inputDimensions;
|
||||
this->outputDimensions[0] = outSize;
|
||||
}
|
||||
|
||||
template<typename MatType, typename RegularizerType>
|
||||
template<typename Archive>
|
||||
void Linear3D<InputDataType, OutputDataType, RegularizerType>::serialize(
|
||||
void Linear3DType<MatType, RegularizerType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(inSize));
|
||||
ar(CEREAL_NVP(outSize));
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
// This is inefficient, but we have to allocate this memory so that
|
||||
// WeightSetVisitor gets the right size.
|
||||
if (cereal::is_loading<Archive>())
|
||||
weights.set_size(outSize * inSize + outSize, 1);
|
||||
ar(CEREAL_NVP(outSize));
|
||||
ar(CEREAL_NVP(regularizer));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -19,136 +19,141 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>::Linear() :
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearType<MatType, RegularizerType>::LinearType() :
|
||||
Layer<MatType>(),
|
||||
inSize(0),
|
||||
outSize(0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>::Linear(
|
||||
const size_t inSize,
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearType<MatType, RegularizerType>::LinearType(
|
||||
const size_t outSize,
|
||||
RegularizerType regularizer) :
|
||||
inSize(inSize),
|
||||
Layer<MatType>(),
|
||||
inSize(0), // This will be computed in ComputeOutputDimensions().
|
||||
outSize(outSize),
|
||||
regularizer(regularizer)
|
||||
{
|
||||
weights.set_size(WeightSize(), 1);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>::Linear(
|
||||
const Linear& layer) :
|
||||
// Copy constructor.
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearType<MatType, RegularizerType>::LinearType(const LinearType& layer) :
|
||||
Layer<MatType>(layer),
|
||||
inSize(layer.inSize),
|
||||
outSize(layer.outSize),
|
||||
weights(layer.weights),
|
||||
regularizer(layer.regularizer)
|
||||
{
|
||||
// Nothing to do here.
|
||||
// Nothing else to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>::Linear(
|
||||
Linear&& layer) :
|
||||
inSize(0),
|
||||
outSize(0),
|
||||
weights(std::move(layer.weights)),
|
||||
// Move constructor.
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearType<MatType, RegularizerType>::LinearType(LinearType&& layer) :
|
||||
Layer<MatType>(std::move(layer)),
|
||||
inSize(std::move(layer.inSize)),
|
||||
outSize(std::move(layer.outSize)),
|
||||
regularizer(std::move(layer.regularizer))
|
||||
{
|
||||
// Nothing to do here.
|
||||
// Nothing else to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>&
|
||||
Linear<InputDataType, OutputDataType, RegularizerType>::
|
||||
operator=(const Linear& layer)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearType<MatType, RegularizerType>&
|
||||
LinearType<MatType, RegularizerType>::operator=(const LinearType& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
if (&layer != this)
|
||||
{
|
||||
Layer<MatType>::operator=(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)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearType<MatType, RegularizerType>&
|
||||
LinearType<MatType, RegularizerType>::operator=(
|
||||
LinearType&& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
if (&layer != this)
|
||||
{
|
||||
inSize = layer.inSize;
|
||||
outSize = layer.outSize;
|
||||
weights = std::move(layer.weights);
|
||||
Layer<MatType>::operator=(std::move(layer));
|
||||
inSize = std::move(layer.inSize);
|
||||
outSize = std::move(layer.outSize);
|
||||
regularizer = std::move(layer.regularizer);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
void Linear<InputDataType, OutputDataType, RegularizerType>::Reset()
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void LinearType<MatType, RegularizerType>::SetWeights(
|
||||
typename MatType::elem_type* weightsPtr)
|
||||
{
|
||||
weight = arma::mat(weights.memptr(), outSize, inSize, false, false);
|
||||
bias = arma::mat(weights.memptr() + weight.n_elem,
|
||||
outSize, 1, false, false);
|
||||
MakeAlias(weights, weightsPtr, outSize * inSize + outSize, 1);
|
||||
MakeAlias(weight, weightsPtr, outSize, inSize);
|
||||
MakeAlias(bias, weightsPtr + weight.n_elem, outSize, 1);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename eT>
|
||||
void Linear<InputDataType, OutputDataType, RegularizerType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void LinearType<MatType, RegularizerType>::Forward(
|
||||
const MatType& input, MatType& output)
|
||||
{
|
||||
output = weight * input;
|
||||
output.each_col() += bias;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename eT>
|
||||
void Linear<InputDataType, OutputDataType, RegularizerType>::Backward(
|
||||
const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void LinearType<MatType, RegularizerType>::Backward(
|
||||
const MatType& /* input */, const MatType& gy, MatType& g)
|
||||
{
|
||||
g = weight.t() * gy;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename eT>
|
||||
void Linear<InputDataType, OutputDataType, RegularizerType>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void LinearType<MatType, RegularizerType>::Gradient(
|
||||
const MatType& input,
|
||||
const MatType& error,
|
||||
MatType& gradient)
|
||||
{
|
||||
gradient.submat(0, 0, weight.n_elem - 1, 0) = arma::vectorise(
|
||||
error * input.t());
|
||||
gradient.submat(weight.n_elem, 0, gradient.n_elem - 1, 0) =
|
||||
arma::sum(error, 1);
|
||||
|
||||
regularizer.Evaluate(weights, gradient);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void LinearType<MatType, RegularizerType>::ComputeOutputDimensions()
|
||||
{
|
||||
inSize = this->inputDimensions[0];
|
||||
for (size_t i = 1; i < this->inputDimensions.size(); ++i)
|
||||
inSize *= this->inputDimensions[i];
|
||||
this->outputDimensions = std::vector<size_t>(this->inputDimensions.size(),
|
||||
1);
|
||||
|
||||
// The Linear layer flattens its input.
|
||||
this->outputDimensions[0] = outSize;
|
||||
}
|
||||
|
||||
template<typename MatType, typename RegularizerType>
|
||||
template<typename Archive>
|
||||
void Linear<InputDataType, OutputDataType, RegularizerType>::serialize(
|
||||
void LinearType<MatType, RegularizerType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(inSize));
|
||||
ar(CEREAL_NVP(outSize));
|
||||
ar(CEREAL_NVP(weights));
|
||||
ar(CEREAL_NVP(regularizer));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include <mlpack/methods/ann/regularizer/no_regularizer.hpp>
|
||||
|
||||
#include "layer_types.hpp"
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
@@ -25,48 +25,50 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* Implementation of the LinearNoBias class. The LinearNoBias class represents a
|
||||
* single layer of a neural network.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
* @tparam RegularizerType Type of the regularizer to be used (Default no
|
||||
* regularizer).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat,
|
||||
template<
|
||||
typename MatType = arma::mat,
|
||||
typename RegularizerType = NoRegularizer
|
||||
>
|
||||
class LinearNoBias
|
||||
class LinearNoBiasType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
//! Create the LinearNoBias object.
|
||||
LinearNoBias();
|
||||
LinearNoBiasType();
|
||||
|
||||
/**
|
||||
* Create the LinearNoBias object using the specified number of units.
|
||||
*
|
||||
* @param inSize The number of input units.
|
||||
* @param outSize The number of output units.
|
||||
* @param regularizer The regularizer to use, optional.
|
||||
*/
|
||||
LinearNoBias(const size_t inSize,
|
||||
const size_t outSize,
|
||||
RegularizerType regularizer = RegularizerType());
|
||||
LinearNoBiasType(const size_t outSize,
|
||||
RegularizerType regularizer = RegularizerType());
|
||||
|
||||
//! Clone the LinearNoBiasType object. This handles polymorphism correctly.
|
||||
LinearNoBiasType* Clone() const { return new LinearNoBiasType(*this); }
|
||||
|
||||
//! Reset the layer parameter.
|
||||
void SetWeights(typename MatType::elem_type* weightsPtr);
|
||||
|
||||
//! Copy constructor.
|
||||
LinearNoBias(const LinearNoBias& layer);
|
||||
LinearNoBiasType(const LinearNoBiasType& layer);
|
||||
|
||||
//! Move constructor.
|
||||
LinearNoBias(LinearNoBias&&);
|
||||
LinearNoBiasType(LinearNoBiasType&&);
|
||||
|
||||
//! Copy assignment operator.
|
||||
LinearNoBias& operator=(const LinearNoBias& layer);
|
||||
LinearNoBiasType& operator=(const LinearNoBiasType& layer);
|
||||
|
||||
//! Move assignment operator.
|
||||
LinearNoBias& operator=(LinearNoBias&& layer);
|
||||
LinearNoBiasType& operator=(LinearNoBiasType&& layer);
|
||||
|
||||
/*
|
||||
* Reset the layer parameter.
|
||||
*/
|
||||
void Reset();
|
||||
//! Virtual destructor.
|
||||
virtual ~LinearNoBiasType() { }
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -75,8 +77,7 @@ class LinearNoBias
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
@@ -87,69 +88,33 @@ class LinearNoBias
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
void Backward(const MatType& /* input */,
|
||||
const MatType& gy,
|
||||
MatType& g);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
*
|
||||
* @param input The input parameter used for calculating the gradient.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient);
|
||||
void Gradient(const MatType& input,
|
||||
const MatType& error,
|
||||
MatType& gradient);
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
const MatType& Parameters() const { return weight; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
MatType& Parameters() { return weight; }
|
||||
|
||||
//! Get the input parameter.
|
||||
InputDataType const& InputParameter() const { return inputParameter; }
|
||||
//! Modify the input parameter.
|
||||
InputDataType& InputParameter() { return inputParameter; }
|
||||
//! Get the number of weights in the layer.
|
||||
size_t WeightSize() const { return inSize * outSize; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
//! Compute the output dimensions of the layer using `InputDimensions()`.
|
||||
void ComputeOutputDimensions();
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the input size.
|
||||
size_t InputSize() const { return inSize; }
|
||||
|
||||
//! Get the output size.
|
||||
size_t OutputSize() const { return outSize; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return gradient; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return gradient; }
|
||||
|
||||
//! Get the size of the weights.
|
||||
size_t WeightSize() const
|
||||
{
|
||||
return inSize * outSize;
|
||||
}
|
||||
|
||||
//! Get the shape of the input.
|
||||
size_t InputShape() const
|
||||
{
|
||||
return inSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the layer
|
||||
*/
|
||||
//! Serialize the layer.
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
@@ -160,27 +125,17 @@ class LinearNoBias
|
||||
//! Locally-stored number of output units.
|
||||
size_t outSize;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
|
||||
//! Locally-stored weight parameter.
|
||||
OutputDataType weight;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
|
||||
//! Locally-stored input parameter object.
|
||||
InputDataType inputParameter;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
MatType weight;
|
||||
|
||||
//! Locally-stored regularizer object.
|
||||
RegularizerType regularizer;
|
||||
}; // class LinearNoBias
|
||||
}; // class LinearNoBiasType
|
||||
|
||||
// Convenience typedefs.
|
||||
|
||||
// Standard Linear without bias layer using no regularization.
|
||||
typedef LinearNoBiasType<arma::mat, NoRegularizer> LinearNoBias;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -19,135 +19,136 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
LinearNoBias<InputDataType, OutputDataType, RegularizerType>::LinearNoBias() :
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearNoBiasType<MatType, RegularizerType>::LinearNoBiasType() :
|
||||
Layer<MatType>(),
|
||||
inSize(0),
|
||||
outSize(0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
LinearNoBias<InputDataType, OutputDataType, RegularizerType>::LinearNoBias(
|
||||
const size_t inSize,
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearNoBiasType<MatType, RegularizerType>::LinearNoBiasType(
|
||||
const size_t outSize,
|
||||
RegularizerType regularizer) :
|
||||
inSize(inSize),
|
||||
Layer<MatType>(),
|
||||
inSize(0), // This will be set by ComputeOutputDimensions().
|
||||
outSize(outSize),
|
||||
regularizer(regularizer)
|
||||
{
|
||||
weights.set_size(WeightSize(), 1);
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
LinearNoBias<InputDataType, OutputDataType, RegularizerType>::LinearNoBias(
|
||||
const LinearNoBias& layer) :
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearNoBiasType<MatType, RegularizerType>::LinearNoBiasType(
|
||||
const LinearNoBiasType& layer) :
|
||||
Layer<MatType>(layer),
|
||||
inSize(layer.inSize),
|
||||
outSize(layer.outSize),
|
||||
weights(layer.weights),
|
||||
regularizer(layer.regularizer)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
LinearNoBias<InputDataType, OutputDataType, RegularizerType>::LinearNoBias(
|
||||
LinearNoBias&& layer) :
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearNoBiasType<MatType, RegularizerType>::LinearNoBiasType(
|
||||
LinearNoBiasType&& layer) :
|
||||
Layer<MatType>(std::move(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>
|
||||
LinearNoBias<InputDataType, OutputDataType, RegularizerType>&
|
||||
LinearNoBias<InputDataType, OutputDataType, RegularizerType>::
|
||||
operator=(const LinearNoBias& layer)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearNoBiasType<MatType, RegularizerType>&
|
||||
LinearNoBiasType<MatType, RegularizerType>::operator=(
|
||||
const LinearNoBiasType& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
{
|
||||
Layer<MatType>::operator=(layer);
|
||||
inSize = layer.inSize;
|
||||
outSize = layer.outSize;
|
||||
weights = layer.weights;
|
||||
regularizer = layer.regularizer;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
LinearNoBias<InputDataType, OutputDataType, RegularizerType>&
|
||||
LinearNoBias<InputDataType, OutputDataType, RegularizerType>::
|
||||
operator=(LinearNoBias&& layer)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
LinearNoBiasType<MatType, RegularizerType>&
|
||||
LinearNoBiasType<MatType, RegularizerType>::operator=(
|
||||
LinearNoBiasType&& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
{
|
||||
inSize = layer.inSize;
|
||||
outSize = layer.outSize;
|
||||
weights = std::move(layer.weights);
|
||||
Layer<MatType>::operator=(std::move(layer));
|
||||
inSize = std::move(layer.inSize);
|
||||
outSize = std::move(layer.outSize);
|
||||
regularizer = std::move(layer.regularizer);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
void LinearNoBias<InputDataType, OutputDataType, RegularizerType>::Reset()
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void LinearNoBiasType<MatType, RegularizerType>::SetWeights(
|
||||
typename MatType::elem_type* weightsPtr)
|
||||
{
|
||||
weight = arma::mat(weights.memptr(), outSize, inSize, false, false);
|
||||
MakeAlias(weight, weightsPtr, outSize, inSize);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename eT>
|
||||
void LinearNoBias<InputDataType, OutputDataType, RegularizerType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void LinearNoBiasType<MatType, RegularizerType>::Forward(
|
||||
const MatType& input, MatType& output)
|
||||
{
|
||||
output = weight * input;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename eT>
|
||||
void LinearNoBias<InputDataType, OutputDataType, RegularizerType>::Backward(
|
||||
const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void LinearNoBiasType<MatType, RegularizerType>::Backward(
|
||||
const MatType& /* input */, const MatType& gy, MatType& g)
|
||||
{
|
||||
g = weight.t() * gy;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename eT>
|
||||
void LinearNoBias<InputDataType, OutputDataType, RegularizerType>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient)
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void LinearNoBiasType<MatType, RegularizerType>::Gradient(
|
||||
const MatType& input,
|
||||
const MatType& error,
|
||||
MatType& gradient)
|
||||
{
|
||||
gradient.submat(0, 0, weight.n_elem - 1, 0) = arma::vectorise(
|
||||
error * input.t());
|
||||
regularizer.Evaluate(weights, gradient);
|
||||
regularizer.Evaluate(weight, gradient);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename RegularizerType>
|
||||
template<typename MatType, typename RegularizerType>
|
||||
void LinearNoBiasType<MatType, RegularizerType>::ComputeOutputDimensions()
|
||||
{
|
||||
inSize = this->inputDimensions[0];
|
||||
for (size_t i = 1; i < this->inputDimensions.size(); ++i)
|
||||
inSize *= this->inputDimensions[i];
|
||||
|
||||
this->outputDimensions = std::vector<size_t>(this->inputDimensions.size(),
|
||||
1);
|
||||
|
||||
this->outputDimensions[0] = outSize;
|
||||
}
|
||||
|
||||
template<typename MatType, typename RegularizerType>
|
||||
template<typename Archive>
|
||||
void LinearNoBias<InputDataType, OutputDataType, RegularizerType>::serialize(
|
||||
void LinearNoBiasType<MatType, RegularizerType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(inSize));
|
||||
ar(CEREAL_NVP(outSize));
|
||||
|
||||
// This is inefficient, but necessary so that WeightSetVisitor sets the right
|
||||
// size.
|
||||
if (cereal::is_loading<Archive>())
|
||||
weights.set_size(outSize * inSize, 1);
|
||||
ar(CEREAL_NVP(regularizer));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
@@ -24,22 +26,32 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* (NegativeLogLikelihoodLayer), which expects that the input contains
|
||||
* log-probabilities for each class.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class LogSoftMax
|
||||
template <typename MatType = arma::mat>
|
||||
class LogSoftMaxType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create the LogSoftmax object.
|
||||
* Create the LogSoftmax layer.
|
||||
*/
|
||||
LogSoftMax();
|
||||
LogSoftMaxType();
|
||||
|
||||
//! Clone the LogSoftMaxType object. This handles polymorphism correctly.
|
||||
LogSoftMaxType* Clone() const { return new LogSoftMaxType(*this); }
|
||||
|
||||
// Virtual destructor.
|
||||
virtual ~LogSoftMaxType() { }
|
||||
|
||||
//! Copy the given LogSoftMaxType.
|
||||
LogSoftMaxType(const LogSoftMaxType& other);
|
||||
//! Take ownership of the given LogSoftMaxType.
|
||||
LogSoftMaxType(LogSoftMaxType&& other);
|
||||
//! Copy the given LogSoftMaxType.
|
||||
LogSoftMaxType& operator=(const LogSoftMaxType& other);
|
||||
//! Take ownership of the given LogSoftMaxType.
|
||||
LogSoftMaxType& operator=(LogSoftMaxType&& other);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -48,8 +60,7 @@ class LogSoftMax
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
@@ -60,34 +71,22 @@ class LogSoftMax
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
void Backward(const MatType& input, const MatType& gy, MatType& g);
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
InputDataType& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
InputDataType& Delta() { return delta; }
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& /* ar */, const uint32_t /* version */);
|
||||
void serialize(Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
private:
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
}; // class LogSoftmaxType
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
}; // class LogSoftmax
|
||||
// Convenience typedefs.
|
||||
|
||||
// Standard Linear layer using no regularization.
|
||||
typedef LogSoftMaxType<arma::mat> LogSoftMax;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -18,18 +18,54 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
LogSoftMax<InputDataType, OutputDataType>::LogSoftMax()
|
||||
template<typename MatType>
|
||||
LogSoftMaxType<MatType>::LogSoftMaxType()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
void LogSoftMax<InputDataType, OutputDataType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
template<typename MatType>
|
||||
LogSoftMaxType<MatType>::LogSoftMaxType(const LogSoftMaxType& other) :
|
||||
Layer<MatType>(other)
|
||||
{
|
||||
arma::mat maxInput = arma::repmat(arma::max(input), input.n_rows, 1);
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
LogSoftMaxType<MatType>::LogSoftMaxType(LogSoftMaxType&& other) :
|
||||
Layer<MatType>(std::move(other))
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
LogSoftMaxType<MatType>&
|
||||
LogSoftMaxType<MatType>::operator=(const LogSoftMaxType& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
Layer<MatType>::operator=(other);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
LogSoftMaxType<MatType>&
|
||||
LogSoftMaxType<MatType>::operator=(LogSoftMaxType&& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
Layer<MatType>::operator=(std::move(other));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void LogSoftMaxType<MatType>::Forward(const MatType& input, MatType& output)
|
||||
{
|
||||
MatType maxInput = arma::repmat(arma::max(input), input.n_rows, 1);
|
||||
output = (maxInput - input);
|
||||
|
||||
// Approximation of the base-e exponential function. The acuracy however is
|
||||
@@ -61,25 +97,15 @@ void LogSoftMax<InputDataType, OutputDataType>::Forward(
|
||||
output = input - maxInput;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void LogSoftMax<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
template<typename MatType>
|
||||
void LogSoftMaxType<MatType>::Backward(
|
||||
const MatType& input,
|
||||
const MatType& gy,
|
||||
MatType& g)
|
||||
{
|
||||
g = arma::exp(input) + gy;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename Archive>
|
||||
void LogSoftMax<InputDataType, OutputDataType>::serialize(
|
||||
Archive& /* ar */,
|
||||
const uint32_t /* version */)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include <limits>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
@@ -50,43 +52,43 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* \see FastLSTM for a faster LSTM version which combines the calculation of the
|
||||
* input, forget, output gates and hidden state in a single step.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class LSTM
|
||||
template<typename MatType = arma::mat>
|
||||
class LSTMType : public RecurrentLayer<MatType>
|
||||
{
|
||||
public:
|
||||
//! Create the LSTM object.
|
||||
LSTM();
|
||||
LSTMType();
|
||||
|
||||
/**
|
||||
* Create the LSTM layer object using the specified parameters.
|
||||
*
|
||||
* @param inSize The number of input units.
|
||||
* @param outSize The number of output units.
|
||||
* @param rho Maximum number of steps to backpropagate through time (BPTT).
|
||||
*/
|
||||
LSTM(const size_t inSize,
|
||||
const size_t outSize,
|
||||
const size_t rho = std::numeric_limits<size_t>::max());
|
||||
LSTMType(const size_t outSize);
|
||||
|
||||
//! Copy constructor.
|
||||
LSTM(const LSTM& layer);
|
||||
//! Clone the LSTMType object. This handles polymorphism correctly.
|
||||
LSTMType* Clone() const { return new LSTMType(*this); }
|
||||
|
||||
//! Move constructor.
|
||||
LSTM(LSTM&&);
|
||||
//! Copy the given LSTMType object.
|
||||
LSTMType(const LSTMType& other);
|
||||
//! Take ownership of the given LSTMType object's data.
|
||||
LSTMType(LSTMType&& other);
|
||||
//! Copy the given LSTMType object.
|
||||
LSTMType& operator=(const LSTMType& other);
|
||||
//! Take ownership of the given LSTMType object's data.
|
||||
LSTMType& operator=(LSTMType&& other);
|
||||
|
||||
//! Copy assignment operator.
|
||||
LSTM& operator=(const LSTM& layer);
|
||||
virtual ~LSTMType() { }
|
||||
|
||||
//! Move assignment operator.
|
||||
LSTM& operator=(LSTM&& layer);
|
||||
/**
|
||||
* Reset the layer parameter. The method is called to
|
||||
* assign the allocated memory to the internal learnable parameters.
|
||||
*/
|
||||
void SetWeights(typename MatType::elem_type* weightsPtr);
|
||||
|
||||
/**
|
||||
* Ordinary feed-forward pass of a neural network, evaluating the function
|
||||
@@ -95,23 +97,7 @@ class LSTM
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed-forward pass of a neural network, evaluating the function
|
||||
* f(x) by propagating the activity forward through f.
|
||||
*
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
* @param cellState Cell state of the LSTM.
|
||||
* @param useCellState Use the cellState passed in the LSTM cell.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void Forward(const InputType& input,
|
||||
OutputType& output,
|
||||
OutputType& cellState,
|
||||
bool useCellState = false);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
@@ -122,23 +108,7 @@ class LSTM
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename InputType, typename ErrorType, typename GradientType>
|
||||
void Backward(const InputType& input,
|
||||
const ErrorType& gy,
|
||||
GradientType& g);
|
||||
|
||||
/*
|
||||
* Reset the layer parameter.
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/*
|
||||
* Resets the cell to accept a new input. This breaks the BPTT chain starts a
|
||||
* new one.
|
||||
*
|
||||
* @param size The current maximum number of steps through time.
|
||||
*/
|
||||
void ResetCell(const size_t size);
|
||||
void Backward(const MatType& input, const MatType& gy, MatType& g);
|
||||
|
||||
/*
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
@@ -147,56 +117,44 @@ class LSTM
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename InputType, typename ErrorType, typename GradientType>
|
||||
void Gradient(const InputType& input,
|
||||
const ErrorType& error,
|
||||
GradientType& gradient);
|
||||
void Gradient(const MatType& input,
|
||||
const MatType& error,
|
||||
MatType& gradient);
|
||||
|
||||
//! Get the maximum number of steps to backpropagate through time (BPTT).
|
||||
size_t Rho() const { return rho; }
|
||||
//! Modify the maximum number of steps to backpropagate through time (BPTT).
|
||||
size_t& Rho() { return rho; }
|
||||
/**
|
||||
* Reset the recurrent state of the LSTM layer, and allocate enough space to
|
||||
* hold `bpttSteps` of previous passes with a batch size of `batchSize`.
|
||||
*
|
||||
* @param bpttSteps Number of steps of history to allocate space for.
|
||||
* @param batchSize Batch size to prepare for.
|
||||
*/
|
||||
void ClearRecurrentState(const size_t bpttSteps, const size_t batchSize);
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
const MatType& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
MatType& Parameters() { return weights; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return grad; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return grad; }
|
||||
|
||||
//! Get the number of input units.
|
||||
size_t InSize() const { return inSize; }
|
||||
|
||||
//! Get the number of output units.
|
||||
size_t OutSize() const { return outSize; }
|
||||
|
||||
//! Get the size of the weights.
|
||||
//! Get the total number of trainable parameters.
|
||||
size_t WeightSize() const
|
||||
{
|
||||
return (4 * outSize * inSize + 7 * outSize + 4 * outSize * outSize);
|
||||
}
|
||||
|
||||
//! Get the shape of the input.
|
||||
size_t InputShape() const
|
||||
//! Given a properly set InputDimensions(), compute the output dimensions.
|
||||
void ComputeOutputDimensions()
|
||||
{
|
||||
return inSize;
|
||||
inSize = std::accumulate(this->inputDimensions.begin(),
|
||||
this->inputDimensions.end(), 0);
|
||||
this->outputDimensions = std::vector<size_t>(this->inputDimensions.size(),
|
||||
1);
|
||||
|
||||
// The LSTM layer flattens its input.
|
||||
this->outputDimensions[0] = outSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the layer
|
||||
* Serialize the layer.
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
@@ -208,148 +166,111 @@ class LSTM
|
||||
//! Locally-stored number of output units.
|
||||
size_t outSize;
|
||||
|
||||
//! Number of steps to backpropagate through time (BPTT).
|
||||
size_t rho;
|
||||
|
||||
//! Locally-stored number of forward steps.
|
||||
size_t forwardStep;
|
||||
|
||||
//! Locally-stored number of backward steps.
|
||||
size_t backwardStep;
|
||||
|
||||
//! Locally-stored number of gradient steps.
|
||||
size_t gradientStep;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
|
||||
//! Locally-stored previous output.
|
||||
OutputDataType prevOutput;
|
||||
|
||||
//! Locally-stored batch size.
|
||||
size_t batchSize;
|
||||
|
||||
//! Current batch step, alias for batchSize - 1.
|
||||
size_t batchStep;
|
||||
|
||||
//! Current gradient step to keep track of the backpropagate through time
|
||||
//! step.
|
||||
size_t gradientStepIdx;
|
||||
|
||||
//! Locally-stored cell activation error.
|
||||
OutputDataType cellActivationError;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType grad;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
MatType weights;
|
||||
|
||||
//! Weights between the output and input gate.
|
||||
OutputDataType output2GateInputWeight;
|
||||
MatType output2GateInputWeight;
|
||||
|
||||
//! Weights between the input and gate.
|
||||
OutputDataType input2GateInputWeight;
|
||||
MatType input2GateInputWeight;
|
||||
|
||||
//! Bias between the input and input gate.
|
||||
OutputDataType input2GateInputBias;
|
||||
MatType input2GateInputBias;
|
||||
|
||||
//! Weights between the cell and input gate.
|
||||
OutputDataType cell2GateInputWeight;
|
||||
MatType cell2GateInputWeight;
|
||||
|
||||
//! Weights between the output and forget gate.
|
||||
OutputDataType output2GateForgetWeight;
|
||||
MatType output2GateForgetWeight;
|
||||
|
||||
//! Weights between the input and gate.
|
||||
OutputDataType input2GateForgetWeight;
|
||||
MatType input2GateForgetWeight;
|
||||
|
||||
//! Bias between the input and gate.
|
||||
OutputDataType input2GateForgetBias;
|
||||
MatType input2GateForgetBias;
|
||||
|
||||
//! Bias between the input and gate.
|
||||
OutputDataType cell2GateForgetWeight;
|
||||
MatType cell2GateForgetWeight;
|
||||
|
||||
//! Weights between the output and gate.
|
||||
OutputDataType output2GateOutputWeight;
|
||||
MatType output2GateOutputWeight;
|
||||
|
||||
//! Weights between the input and gate.
|
||||
OutputDataType input2GateOutputWeight;
|
||||
MatType input2GateOutputWeight;
|
||||
|
||||
//! Bias between the input and gate.
|
||||
OutputDataType input2GateOutputBias;
|
||||
MatType input2GateOutputBias;
|
||||
|
||||
//! Weights between cell and output gate.
|
||||
OutputDataType cell2GateOutputWeight;
|
||||
MatType cell2GateOutputWeight;
|
||||
|
||||
// Below here are recurrent state matrices.
|
||||
|
||||
//! Locally-stored input gate parameter.
|
||||
OutputDataType inputGate;
|
||||
MatType inputGate;
|
||||
|
||||
//! Locally-stored forget gate parameter.
|
||||
OutputDataType forgetGate;
|
||||
MatType forgetGate;
|
||||
|
||||
//! Locally-stored hidden layer parameter.
|
||||
OutputDataType hiddenLayer;
|
||||
MatType hiddenLayer;
|
||||
|
||||
//! Locally-stored output gate parameter.
|
||||
OutputDataType outputGate;
|
||||
|
||||
//! Locally-stored input gate activation.
|
||||
OutputDataType inputGateActivation;
|
||||
|
||||
//! Locally-stored forget gate activation.
|
||||
OutputDataType forgetGateActivation;
|
||||
|
||||
//! Locally-stored output gate activation.
|
||||
OutputDataType outputGateActivation;
|
||||
|
||||
//! Locally-stored hidden layer activation.
|
||||
OutputDataType hiddenLayerActivation;
|
||||
MatType outputGate;
|
||||
|
||||
//! Locally-stored input to hidden weight.
|
||||
OutputDataType input2HiddenWeight;
|
||||
MatType input2HiddenWeight;
|
||||
|
||||
//! Locally-stored input to hidden bias.
|
||||
OutputDataType input2HiddenBias;
|
||||
MatType input2HiddenBias;
|
||||
|
||||
//! Locally-stored output to hidden weight.
|
||||
OutputDataType output2HiddenWeight;
|
||||
MatType output2HiddenWeight;
|
||||
|
||||
//! Locally-stored cell parameter.
|
||||
OutputDataType cell;
|
||||
arma::Cube<typename MatType::elem_type> cell;
|
||||
|
||||
// These members store recurrent state.
|
||||
|
||||
//! Locally-stored input gate activation.
|
||||
arma::Cube<typename MatType::elem_type> inputGateActivation;
|
||||
|
||||
//! Locally-stored forget gate activation.
|
||||
arma::Cube<typename MatType::elem_type> forgetGateActivation;
|
||||
|
||||
//! Locally-stored output gate activation.
|
||||
arma::Cube<typename MatType::elem_type> outputGateActivation;
|
||||
|
||||
//! Locally-stored hidden layer activation.
|
||||
arma::Cube<typename MatType::elem_type> hiddenLayerActivation;
|
||||
|
||||
//! Locally-stored cell activation error.
|
||||
OutputDataType cellActivation;
|
||||
arma::Cube<typename MatType::elem_type> cellActivation;
|
||||
|
||||
//! Locally-stored forget gate error.
|
||||
OutputDataType forgetGateError;
|
||||
MatType forgetGateError;
|
||||
|
||||
//! Locally-stored output gate error.
|
||||
OutputDataType outputGateError;
|
||||
|
||||
//! Locally-stored previous error.
|
||||
OutputDataType prevError;
|
||||
MatType outputGateError;
|
||||
|
||||
//! Locally-stored output parameters.
|
||||
OutputDataType outParameter;
|
||||
arma::Cube<typename MatType::elem_type> outParameter;
|
||||
|
||||
//! Locally-stored input cell error parameter.
|
||||
OutputDataType inputCellError;
|
||||
MatType inputCellError;
|
||||
|
||||
//! Locally-stored input gate error.
|
||||
OutputDataType inputGateError;
|
||||
MatType inputGateError;
|
||||
|
||||
//! Locally-stored hidden layer error.
|
||||
OutputDataType hiddenError;
|
||||
MatType hiddenError;
|
||||
}; // class LSTMType
|
||||
|
||||
//! Locally-stored current rho size.
|
||||
size_t rhoSize;
|
||||
// Convenience typedefs.
|
||||
|
||||
//! Current backpropagate through time steps.
|
||||
size_t bpttSteps;
|
||||
}; // class LSTM
|
||||
// Standard LSTM layer.
|
||||
typedef LSTMType<arma::mat> LSTM;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -18,430 +18,296 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
LSTM<InputDataType, OutputDataType>::LSTM()
|
||||
template<typename MatType>
|
||||
LSTMType<MatType>::LSTMType() :
|
||||
RecurrentLayer<MatType>(),
|
||||
outSize(0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
LSTM<InputDataType, OutputDataType>::LSTM(
|
||||
const LSTM& layer) :
|
||||
inSize(layer.inSize),
|
||||
outSize(layer.outSize),
|
||||
rho(layer.rho),
|
||||
forwardStep(layer.forwardStep),
|
||||
backwardStep(layer.backwardStep),
|
||||
gradientStep(layer.gradientStep),
|
||||
weights(layer.weights),
|
||||
batchSize(layer.batchSize),
|
||||
batchStep(layer.batchStep),
|
||||
gradientStepIdx(layer.gradientStepIdx),
|
||||
rhoSize(layer.rho),
|
||||
bpttSteps(layer.bpttSteps)
|
||||
template<typename MatType>
|
||||
LSTMType<MatType>::LSTMType(const size_t outSize) :
|
||||
RecurrentLayer<MatType>(),
|
||||
outSize(outSize)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
LSTM<InputDataType, OutputDataType>::LSTM(
|
||||
LSTM&& layer) :
|
||||
inSize(std::move(layer.inSize)),
|
||||
outSize(std::move(layer.outSize)),
|
||||
rho(std::move(layer.rho)),
|
||||
forwardStep(std::move(layer.forwardStep)),
|
||||
backwardStep(std::move(layer.backwardStep)),
|
||||
gradientStep(std::move(layer.gradientStep)),
|
||||
weights(std::move(layer.weights)),
|
||||
batchSize(std::move(layer.batchSize)),
|
||||
batchStep(std::move(layer.batchStep)),
|
||||
gradientStepIdx(std::move(layer.gradientStepIdx)),
|
||||
rhoSize(std::move(layer.rho)),
|
||||
bpttSteps(std::move(layer.bpttSteps))
|
||||
template<typename MatType>
|
||||
LSTMType<MatType>::LSTMType(const LSTMType& layer) :
|
||||
RecurrentLayer<MatType>(layer)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType>
|
||||
LSTM<InputDataType, OutputDataType>&
|
||||
LSTM<InputDataType, OutputDataType> :: operator=(const LSTM& layer)
|
||||
template<typename MatType>
|
||||
LSTMType<MatType>::LSTMType(LSTMType&& layer) :
|
||||
RecurrentLayer<MatType>(std::move(layer))
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
LSTMType<MatType>& LSTMType<MatType>::operator=(const LSTMType& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
{
|
||||
inSize = layer.inSize;
|
||||
outSize = layer.outSize;
|
||||
rho = layer.rho;
|
||||
forwardStep = layer.forwardStep;
|
||||
backwardStep = layer.backwardStep;
|
||||
gradientStep = layer.gradientStep;
|
||||
weights = layer.weights;
|
||||
batchSize = layer.batchSize;
|
||||
batchStep = layer.batchStep;
|
||||
gradientStepIdx = layer.gradientStepIdx;
|
||||
grad = layer.grad;
|
||||
rhoSize = layer.rho;
|
||||
bpttSteps = layer.bpttSteps;
|
||||
RecurrentLayer<MatType>::operator=(layer);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType>
|
||||
LSTM<InputDataType, OutputDataType>&
|
||||
LSTM<InputDataType, OutputDataType> :: operator=(LSTM&& layer)
|
||||
template<typename MatType>
|
||||
LSTMType<MatType>& LSTMType<MatType>::operator=(LSTMType&& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
{
|
||||
inSize = std::move(layer.inSize);
|
||||
outSize = std::move(layer.outSize);
|
||||
rho = std::move(layer.rho);
|
||||
forwardStep = std::move(layer.forwardStep);
|
||||
backwardStep = std::move(layer.backwardStep);
|
||||
gradientStep = std::move(layer.gradientStep);
|
||||
weights = std::move(layer.weights);
|
||||
batchSize = std::move(layer.batchSize);
|
||||
batchStep = std::move(layer.batchStep);
|
||||
gradientStepIdx = std::move(layer.gradientStepIdx);
|
||||
grad = std::move(layer.grad);
|
||||
rhoSize = std::move(layer.rho);
|
||||
bpttSteps = std::move(layer.bpttSteps);
|
||||
RecurrentLayer<MatType>::operator=(std::move(layer));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType>
|
||||
LSTM<InputDataType, OutputDataType>::LSTM(
|
||||
const size_t inSize, const size_t outSize, const size_t rho) :
|
||||
inSize(inSize),
|
||||
outSize(outSize),
|
||||
rho(rho),
|
||||
forwardStep(0),
|
||||
backwardStep(0),
|
||||
gradientStep(0),
|
||||
batchSize(0),
|
||||
batchStep(0),
|
||||
gradientStepIdx(0),
|
||||
rhoSize(rho),
|
||||
bpttSteps(0)
|
||||
template<typename MatType>
|
||||
void LSTMType<MatType>::ClearRecurrentState(
|
||||
const size_t bpttSteps, const size_t batchSize)
|
||||
{
|
||||
weights.set_size(WeightSize(), 1);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
void LSTM<InputDataType, OutputDataType>::ResetCell(const size_t size)
|
||||
{
|
||||
if (size == std::numeric_limits<size_t>::max())
|
||||
return;
|
||||
|
||||
rhoSize = size;
|
||||
|
||||
if (batchSize == 0)
|
||||
return;
|
||||
|
||||
bpttSteps = std::min(rho, rhoSize);
|
||||
forwardStep = 0;
|
||||
gradientStepIdx = 0;
|
||||
backwardStep = batchSize * size - 1;
|
||||
gradientStep = batchSize * size - 1;
|
||||
|
||||
const size_t rhoBatchSize = size * batchSize;
|
||||
|
||||
// Make sure all of the different matrices we will use to hold parameters are
|
||||
// at least as large as we need.
|
||||
inputGate.set_size(outSize, rhoBatchSize);
|
||||
forgetGate.set_size(outSize, rhoBatchSize);
|
||||
hiddenLayer.set_size(outSize, rhoBatchSize);
|
||||
outputGate.set_size(outSize, rhoBatchSize);
|
||||
inputGate.set_size(outSize, batchSize);
|
||||
forgetGate.set_size(outSize, batchSize);
|
||||
hiddenLayer.set_size(outSize, batchSize);
|
||||
outputGate.set_size(outSize, batchSize);
|
||||
|
||||
inputGateActivation.set_size(outSize, rhoBatchSize);
|
||||
forgetGateActivation.set_size(outSize, rhoBatchSize);
|
||||
outputGateActivation.set_size(outSize, rhoBatchSize);
|
||||
hiddenLayerActivation.set_size(outSize, rhoBatchSize);
|
||||
inputGateActivation.set_size(outSize, batchSize, bpttSteps);
|
||||
forgetGateActivation.set_size(outSize, batchSize, bpttSteps);
|
||||
outputGateActivation.set_size(outSize, batchSize, bpttSteps);
|
||||
hiddenLayerActivation.set_size(outSize, batchSize, bpttSteps);
|
||||
|
||||
cellActivation.set_size(outSize, rhoBatchSize);
|
||||
prevError.set_size(4 * outSize, batchSize);
|
||||
cellActivation.set_size(outSize, batchSize, bpttSteps);
|
||||
outParameter.set_size(outSize, batchSize, bpttSteps);
|
||||
|
||||
// Now reset recurrent values to 0.
|
||||
cell.zeros(outSize, size * batchSize);
|
||||
outParameter.zeros(outSize, (size + 1) * batchSize);
|
||||
cell.zeros(outSize, batchSize, bpttSteps);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
void LSTM<InputDataType, OutputDataType>::Reset()
|
||||
template<typename MatType>
|
||||
void LSTMType<MatType>::SetWeights(
|
||||
typename MatType::elem_type* weightsPtr)
|
||||
{
|
||||
// Set the weight parameter for the output gate.
|
||||
input2GateOutputWeight = OutputDataType(weights.memptr(), outSize, inSize,
|
||||
false, false);
|
||||
input2GateOutputBias = OutputDataType(weights.memptr() +
|
||||
input2GateOutputWeight.n_elem, outSize, 1, false, false);
|
||||
size_t offset = input2GateOutputWeight.n_elem + input2GateOutputBias.n_elem;
|
||||
MakeAlias(input2GateOutputWeight, weightsPtr, outSize, inSize);
|
||||
size_t offset = input2GateOutputWeight.n_elem;
|
||||
MakeAlias(input2GateOutputBias, weightsPtr + offset, outSize, 1);
|
||||
offset += input2GateOutputBias.n_elem;
|
||||
|
||||
// Set the weight parameter for the forget gate.
|
||||
input2GateForgetWeight = OutputDataType(weights.memptr() + offset,
|
||||
outSize, inSize, false, false);
|
||||
input2GateForgetBias = OutputDataType(weights.memptr() +
|
||||
offset + input2GateForgetWeight.n_elem, outSize, 1, false, false);
|
||||
offset += input2GateForgetWeight.n_elem + input2GateForgetBias.n_elem;
|
||||
MakeAlias(input2GateForgetWeight, weightsPtr + offset, outSize, inSize);
|
||||
offset += input2GateForgetWeight.n_elem;
|
||||
MakeAlias(input2GateForgetBias, weightsPtr + offset, outSize, 1);
|
||||
offset += input2GateForgetBias.n_elem;
|
||||
|
||||
// Set the weight parameter for the input gate.
|
||||
input2GateInputWeight = OutputDataType(weights.memptr() +
|
||||
offset, outSize, inSize, false, false);
|
||||
input2GateInputBias = OutputDataType(weights.memptr() +
|
||||
offset + input2GateInputWeight.n_elem, outSize, 1, false, false);
|
||||
offset += input2GateInputWeight.n_elem + input2GateInputBias.n_elem;
|
||||
MakeAlias(input2GateInputWeight, weightsPtr + offset, outSize, inSize);
|
||||
offset += input2GateInputWeight.n_elem;
|
||||
MakeAlias(input2GateInputBias, weightsPtr + offset, outSize, 1);
|
||||
offset += input2GateInputBias.n_elem;
|
||||
|
||||
// Set the weight parameter for the hidden gate.
|
||||
input2HiddenWeight = OutputDataType(weights.memptr() +
|
||||
offset, outSize, inSize, false, false);
|
||||
input2HiddenBias = OutputDataType(weights.memptr() +
|
||||
offset + input2HiddenWeight.n_elem, outSize, 1, false, false);
|
||||
offset += input2HiddenWeight.n_elem + input2HiddenBias.n_elem;
|
||||
MakeAlias(input2HiddenWeight, weightsPtr + offset, outSize, inSize);
|
||||
offset += input2HiddenWeight.n_elem;
|
||||
MakeAlias(input2HiddenBias, weightsPtr + offset, outSize, 1);
|
||||
offset += input2HiddenBias.n_elem;
|
||||
|
||||
// Set the weight parameter for the output multiplication.
|
||||
output2GateOutputWeight = OutputDataType(weights.memptr() +
|
||||
offset, outSize, outSize, false, false);
|
||||
MakeAlias(output2GateOutputWeight, weightsPtr + offset, outSize, outSize);
|
||||
offset += output2GateOutputWeight.n_elem;
|
||||
|
||||
// Set the weight parameter for the output multiplication.
|
||||
output2GateForgetWeight = OutputDataType(weights.memptr() +
|
||||
offset, outSize, outSize, false, false);
|
||||
MakeAlias(output2GateForgetWeight, weightsPtr + offset, outSize, outSize);
|
||||
offset += output2GateForgetWeight.n_elem;
|
||||
|
||||
// Set the weight parameter for the input multiplication.
|
||||
output2GateInputWeight = OutputDataType(weights.memptr() +
|
||||
offset, outSize, outSize, false, false);
|
||||
MakeAlias(output2GateInputWeight, weightsPtr + offset, outSize, outSize);
|
||||
offset += output2GateInputWeight.n_elem;
|
||||
|
||||
// Set the weight parameter for the hidden multiplication.
|
||||
output2HiddenWeight = OutputDataType(weights.memptr() +
|
||||
offset, outSize, outSize, false, false);
|
||||
MakeAlias(output2HiddenWeight, weightsPtr + offset, outSize, outSize);
|
||||
offset += output2HiddenWeight.n_elem;
|
||||
|
||||
// Set the weight parameter for the cell multiplication.
|
||||
cell2GateOutputWeight = OutputDataType(weights.memptr() +
|
||||
offset, outSize, 1, false, false);
|
||||
MakeAlias(cell2GateOutputWeight, weightsPtr + offset, outSize, 1);
|
||||
offset += cell2GateOutputWeight.n_elem;
|
||||
|
||||
// Set the weight parameter for the cell - forget gate multiplication.
|
||||
cell2GateForgetWeight = OutputDataType(weights.memptr() +
|
||||
offset, outSize, 1, false, false);
|
||||
MakeAlias(cell2GateForgetWeight, weightsPtr + offset, outSize, 1);
|
||||
offset += cell2GateOutputWeight.n_elem;
|
||||
|
||||
// Set the weight parameter for the cell - input gate multiplication.
|
||||
cell2GateInputWeight = OutputDataType(weights.memptr() +
|
||||
offset, outSize, 1, false, false);
|
||||
MakeAlias(cell2GateInputWeight, weightsPtr + offset, outSize, 1);
|
||||
}
|
||||
|
||||
// Forward when cellState is not needed.
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
void LSTM<InputDataType, OutputDataType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
template<typename MatType>
|
||||
void LSTMType<MatType>::Forward(const MatType& input, MatType& output)
|
||||
{
|
||||
//! Locally-stored cellState.
|
||||
OutputType cellState;
|
||||
Forward(input, output, cellState, false);
|
||||
}
|
||||
// Convenience alias.
|
||||
const size_t batchSize = input.n_cols;
|
||||
|
||||
// Forward when cellState is needed overloaded LSTM::Forward().
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
void LSTM<InputDataType, OutputDataType>::Forward(const InputType& input,
|
||||
OutputType& output,
|
||||
OutputType& cellState,
|
||||
bool useCellState)
|
||||
{
|
||||
// Check if the batch size changed, the number of cols is defines the input
|
||||
// batch size.
|
||||
if (input.n_cols != batchSize)
|
||||
inputGate = input2GateInputWeight * input;
|
||||
if (this->HasPreviousStep())
|
||||
{
|
||||
batchSize = input.n_cols;
|
||||
batchStep = batchSize - 1;
|
||||
ResetCell(rhoSize);
|
||||
inputGate +=
|
||||
output2GateInputWeight * outParameter.slice(this->PreviousStep());
|
||||
}
|
||||
inputGate.each_col() += input2GateInputBias;
|
||||
|
||||
forgetGate = input2GateForgetWeight * input;
|
||||
if (this->HasPreviousStep())
|
||||
{
|
||||
forgetGate += output2GateForgetWeight * outParameter.slice(
|
||||
this->PreviousStep());
|
||||
}
|
||||
forgetGate.each_col() += input2GateForgetBias;
|
||||
|
||||
if (this->HasPreviousStep())
|
||||
{
|
||||
inputGate += arma::repmat(cell2GateInputWeight, 1, batchSize) %
|
||||
cell.slice(this->PreviousStep());
|
||||
|
||||
forgetGate += arma::repmat(cell2GateForgetWeight, 1, batchSize) %
|
||||
cell.slice(this->PreviousStep());
|
||||
}
|
||||
|
||||
inputGate.cols(forwardStep, forwardStep + batchStep) = input2GateInputWeight *
|
||||
input + output2GateInputWeight * outParameter.cols(forwardStep,
|
||||
forwardStep + batchStep);
|
||||
inputGate.cols(forwardStep, forwardStep + batchStep).each_col() +=
|
||||
input2GateInputBias;
|
||||
inputGateActivation.slice(this->CurrentStep()) =
|
||||
1.0 / (1.0 + arma::exp(-inputGate));
|
||||
forgetGateActivation.slice(this->CurrentStep()) =
|
||||
1.0 / (1.0 + arma::exp(-forgetGate));
|
||||
|
||||
forgetGate.cols(forwardStep, forwardStep + batchStep) = input2GateForgetWeight
|
||||
* input + output2GateForgetWeight * outParameter.cols(
|
||||
forwardStep, forwardStep + batchStep);
|
||||
forgetGate.cols(forwardStep, forwardStep + batchStep).each_col() +=
|
||||
input2GateForgetBias;
|
||||
|
||||
if (forwardStep > 0)
|
||||
hiddenLayer = input2HiddenWeight * input;
|
||||
if (this->HasPreviousStep())
|
||||
{
|
||||
if (useCellState)
|
||||
{
|
||||
if (!cellState.is_empty())
|
||||
{
|
||||
cell.cols(forwardStep - batchSize,
|
||||
forwardStep - batchSize + batchStep) = cellState;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Cell parameter is empty.");
|
||||
}
|
||||
}
|
||||
inputGate.cols(forwardStep, forwardStep + batchStep) +=
|
||||
arma::repmat(cell2GateInputWeight, 1, batchSize) %
|
||||
cell.cols(forwardStep - batchSize, forwardStep - batchSize + batchStep);
|
||||
|
||||
forgetGate.cols(forwardStep, forwardStep + batchStep) +=
|
||||
arma::repmat(cell2GateForgetWeight, 1, batchSize) %
|
||||
cell.cols(forwardStep - batchSize, forwardStep - batchSize + batchStep);
|
||||
hiddenLayer += output2HiddenWeight *
|
||||
outParameter.slice(this->PreviousStep());
|
||||
}
|
||||
hiddenLayer.each_col() += input2HiddenBias;
|
||||
|
||||
inputGateActivation.cols(forwardStep, forwardStep + batchStep) = 1.0 /
|
||||
(1 + arma::exp(-inputGate.cols(forwardStep, forwardStep + batchStep)));
|
||||
hiddenLayerActivation.slice(this->CurrentStep()) = arma::tanh(hiddenLayer);
|
||||
|
||||
forgetGateActivation.cols(forwardStep, forwardStep + batchStep) = 1.0 /
|
||||
(1 + arma::exp(-forgetGate.cols(forwardStep, forwardStep + batchStep)));
|
||||
|
||||
hiddenLayer.cols(forwardStep, forwardStep + batchStep) = input2HiddenWeight *
|
||||
input + output2HiddenWeight * outParameter.cols(
|
||||
forwardStep, forwardStep + batchStep);
|
||||
|
||||
hiddenLayer.cols(forwardStep, forwardStep + batchStep).each_col() +=
|
||||
input2HiddenBias;
|
||||
|
||||
hiddenLayerActivation.cols(forwardStep, forwardStep + batchStep) =
|
||||
arma::tanh(hiddenLayer.cols(forwardStep, forwardStep + batchStep));
|
||||
|
||||
if (forwardStep == 0)
|
||||
if (!this->HasPreviousStep())
|
||||
{
|
||||
cell.cols(forwardStep, forwardStep + batchStep) =
|
||||
inputGateActivation.cols(forwardStep, forwardStep + batchStep) %
|
||||
hiddenLayerActivation.cols(forwardStep, forwardStep + batchStep);
|
||||
cell.slice(this->CurrentStep()) =
|
||||
inputGateActivation.slice(this->CurrentStep()) %
|
||||
hiddenLayerActivation.slice(this->CurrentStep());
|
||||
}
|
||||
else
|
||||
{
|
||||
cell.cols(forwardStep, forwardStep + batchStep) =
|
||||
forgetGateActivation.cols(forwardStep, forwardStep + batchStep) %
|
||||
cell.cols(forwardStep - batchSize, forwardStep - batchSize + batchStep)
|
||||
+ inputGateActivation.cols(forwardStep, forwardStep + batchStep) %
|
||||
hiddenLayerActivation.cols(forwardStep, forwardStep + batchStep);
|
||||
cell.slice(this->CurrentStep()) =
|
||||
forgetGateActivation.slice(this->CurrentStep()) %
|
||||
cell.slice(this->PreviousStep()) +
|
||||
inputGateActivation.slice(this->CurrentStep()) %
|
||||
hiddenLayerActivation.slice(this->CurrentStep());
|
||||
}
|
||||
|
||||
outputGate.cols(forwardStep, forwardStep + batchStep) = input2GateOutputWeight
|
||||
* input + output2GateOutputWeight * outParameter.cols(
|
||||
forwardStep, forwardStep + batchStep) + cell.cols(forwardStep,
|
||||
forwardStep + batchStep).each_col() % cell2GateOutputWeight;
|
||||
|
||||
outputGate.cols(forwardStep, forwardStep + batchStep).each_col() +=
|
||||
input2GateOutputBias;
|
||||
|
||||
outputGateActivation.cols(forwardStep, forwardStep + batchStep) = 1.0 /
|
||||
(1 + arma::exp(-outputGate.cols(forwardStep, forwardStep + batchStep)));
|
||||
|
||||
cellActivation.cols(forwardStep, forwardStep + batchStep) =
|
||||
arma::tanh(cell.cols(forwardStep, forwardStep + batchStep));
|
||||
|
||||
outParameter.cols(forwardStep + batchSize,
|
||||
forwardStep + batchSize + batchStep) =
|
||||
cellActivation.cols(forwardStep, forwardStep + batchStep) %
|
||||
outputGateActivation.cols(forwardStep, forwardStep + batchStep);
|
||||
|
||||
output = OutputType(outParameter.memptr() +
|
||||
(forwardStep + batchSize) * outSize, outSize, batchSize, false, false);
|
||||
|
||||
cellState = OutputType(cell.memptr() +
|
||||
forwardStep * outSize, outSize, batchSize, false, false);
|
||||
|
||||
forwardStep += batchSize;
|
||||
if ((forwardStep / batchSize) == bpttSteps)
|
||||
outputGate = input2GateOutputWeight * input +
|
||||
cell.slice(this->CurrentStep()).each_col() % cell2GateOutputWeight;
|
||||
if (this->HasPreviousStep())
|
||||
{
|
||||
forwardStep = 0;
|
||||
outputGate +=
|
||||
output2GateOutputWeight * outParameter.slice(this->PreviousStep());
|
||||
}
|
||||
outputGate.each_col() += input2GateOutputBias;
|
||||
|
||||
outputGateActivation.slice(this->CurrentStep()) =
|
||||
1.0 / (1.0 + arma::exp(-outputGate));
|
||||
|
||||
cellActivation.slice(this->CurrentStep()) =
|
||||
arma::tanh(cell.slice(this->CurrentStep()));
|
||||
|
||||
// There's a bit of an issue here: we need to preserve the output for the next
|
||||
// time step, but we also need to set `output` to that. Unfortunately for now
|
||||
// we make a copy, but it's possible that we could instead use an alias here,
|
||||
// or have `outParameter` hold a collection of aliases.
|
||||
outParameter.slice(this->CurrentStep()) =
|
||||
cellActivation.slice(this->CurrentStep()) %
|
||||
outputGateActivation.slice(this->CurrentStep());
|
||||
|
||||
output = outParameter.slice(this->CurrentStep());
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename ErrorType, typename GradientType>
|
||||
void LSTM<InputDataType, OutputDataType>::Backward(
|
||||
const InputType& /* input */, const ErrorType& gy, GradientType& g)
|
||||
template<typename MatType>
|
||||
void LSTMType<MatType>::Backward(
|
||||
const MatType& /* input */, const MatType& gy, MatType& g)
|
||||
{
|
||||
ErrorType gyLocal;
|
||||
if (gradientStepIdx > 0)
|
||||
MatType gyLocal;
|
||||
if (this->HasPreviousStep())
|
||||
{
|
||||
gyLocal = gy + prevError;
|
||||
gyLocal = gy + output2GateOutputWeight.t() * outputGateError +
|
||||
output2GateForgetWeight.t() * forgetGateError +
|
||||
output2GateInputWeight.t() * inputGateError +
|
||||
output2HiddenWeight.t() * hiddenError;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make an alias.
|
||||
gyLocal = ErrorType(((ErrorType&) gy).memptr(), gy.n_rows, gy.n_cols, false,
|
||||
false);
|
||||
gyLocal = MatType(((MatType&) gy).memptr(), gy.n_rows, gy.n_cols,
|
||||
false, false);
|
||||
}
|
||||
|
||||
outputGateError =
|
||||
gyLocal % cellActivation.cols(backwardStep - batchStep, backwardStep) %
|
||||
(outputGateActivation.cols(backwardStep - batchStep, backwardStep) %
|
||||
(1.0 - outputGateActivation.cols(backwardStep - batchStep,
|
||||
backwardStep)));
|
||||
outputGateError = gyLocal % cellActivation.slice(this->CurrentStep()) %
|
||||
(outputGateActivation.slice(this->CurrentStep()) %
|
||||
(1.0 - outputGateActivation.slice(this->CurrentStep())));
|
||||
|
||||
OutputDataType cellError = gyLocal %
|
||||
outputGateActivation.cols(backwardStep - batchStep, backwardStep) %
|
||||
(1 - arma::pow(cellActivation.cols(backwardStep -
|
||||
batchStep, backwardStep), 2)) + outputGateError.each_col() %
|
||||
cell2GateOutputWeight;
|
||||
MatType cellError = gyLocal %
|
||||
outputGateActivation.slice(this->CurrentStep()) %
|
||||
(1 - arma::pow(cellActivation.slice(this->CurrentStep()), 2)) +
|
||||
outputGateError.each_col() % cell2GateOutputWeight;
|
||||
|
||||
if (gradientStepIdx > 0)
|
||||
if (this->HasPreviousStep())
|
||||
{
|
||||
cellError += inputCellError;
|
||||
}
|
||||
|
||||
if (backwardStep > batchStep)
|
||||
if (this->HasPreviousStep())
|
||||
{
|
||||
forgetGateError = cell.cols((backwardStep - batchSize) - batchStep,
|
||||
(backwardStep - batchSize)) % cellError % (forgetGateActivation.cols(
|
||||
backwardStep - batchStep, backwardStep) % (1.0 -
|
||||
forgetGateActivation.cols(backwardStep - batchStep, backwardStep)));
|
||||
forgetGateError = cell.slice(this->PreviousStep()) % cellError %
|
||||
(forgetGateActivation.slice(this->CurrentStep()) %
|
||||
(1.0 - forgetGateActivation.slice(this->CurrentStep())));
|
||||
}
|
||||
else
|
||||
{
|
||||
forgetGateError.zeros();
|
||||
forgetGateError.zeros(forgetGateActivation.n_rows,
|
||||
forgetGateActivation.n_cols);
|
||||
}
|
||||
|
||||
inputGateError = hiddenLayerActivation.cols(backwardStep - batchStep,
|
||||
backwardStep) % cellError %
|
||||
(inputGateActivation.cols(backwardStep - batchStep, backwardStep) %
|
||||
(1.0 - inputGateActivation.cols(backwardStep - batchStep, backwardStep)));
|
||||
inputGateError = hiddenLayerActivation.slice(this->CurrentStep()) %
|
||||
cellError % (inputGateActivation.slice(this->CurrentStep()) %
|
||||
(1.0 - inputGateActivation.slice(this->CurrentStep())));
|
||||
|
||||
hiddenError = inputGateActivation.cols(backwardStep - batchStep,
|
||||
backwardStep) % cellError % (1 - arma::pow(hiddenLayerActivation.cols(
|
||||
backwardStep - batchStep, backwardStep), 2));
|
||||
hiddenError = inputGateActivation.slice(this->CurrentStep()) % cellError %
|
||||
(1 - arma::pow(hiddenLayerActivation.slice(this->CurrentStep()), 2));
|
||||
|
||||
inputCellError = forgetGateActivation.cols(backwardStep - batchStep,
|
||||
backwardStep) % cellError + forgetGateError.each_col() %
|
||||
cell2GateForgetWeight + inputGateError.each_col() % cell2GateInputWeight;
|
||||
inputCellError = forgetGateActivation.slice(this->CurrentStep()) % cellError +
|
||||
forgetGateError.each_col() % cell2GateForgetWeight +
|
||||
inputGateError.each_col() % cell2GateInputWeight;
|
||||
|
||||
g = input2GateInputWeight.t() * inputGateError +
|
||||
input2HiddenWeight.t() * hiddenError +
|
||||
input2GateForgetWeight.t() * forgetGateError +
|
||||
input2GateOutputWeight.t() * outputGateError;
|
||||
|
||||
prevError = output2GateOutputWeight.t() * outputGateError +
|
||||
output2GateForgetWeight.t() * forgetGateError +
|
||||
output2GateInputWeight.t() * inputGateError +
|
||||
output2HiddenWeight.t() * hiddenError;
|
||||
|
||||
backwardStep -= batchSize;
|
||||
gradientStepIdx++;
|
||||
if (gradientStepIdx == bpttSteps)
|
||||
{
|
||||
backwardStep = bpttSteps - 1;
|
||||
gradientStepIdx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename ErrorType, typename GradientType>
|
||||
void LSTM<InputDataType, OutputDataType>::Gradient(
|
||||
const InputType& input,
|
||||
const ErrorType& /* error */,
|
||||
GradientType& gradient)
|
||||
template<typename MatType>
|
||||
void LSTMType<MatType>::Gradient(
|
||||
const MatType& input,
|
||||
const MatType& /* error */,
|
||||
MatType& gradient)
|
||||
{
|
||||
// This implementation depends on Gradient() being called just after
|
||||
// Backward(), which is something we can safely assume.
|
||||
|
||||
// Input2GateOutputWeight and input2GateOutputBias gradients.
|
||||
gradient.submat(0, 0, input2GateOutputWeight.n_elem - 1, 0) =
|
||||
arma::vectorise(outputGateError * input.t());
|
||||
@@ -450,7 +316,7 @@ void LSTM<InputDataType, OutputDataType>::Gradient(
|
||||
arma::sum(outputGateError, 1);
|
||||
size_t offset = input2GateOutputWeight.n_elem + input2GateOutputBias.n_elem;
|
||||
|
||||
// Input2GateForgetWeight and input2GateForgetBias gradients.
|
||||
// input2GateForgetWeight and input2GateForgetBias gradients.
|
||||
gradient.submat(offset, 0, offset + input2GateForgetWeight.n_elem - 1, 0) =
|
||||
arma::vectorise(forgetGateError * input.t());
|
||||
gradient.submat(offset + input2GateForgetWeight.n_elem, 0,
|
||||
@@ -458,7 +324,7 @@ void LSTM<InputDataType, OutputDataType>::Gradient(
|
||||
input2GateForgetBias.n_elem - 1, 0) = arma::sum(forgetGateError, 1);
|
||||
offset += input2GateForgetWeight.n_elem + input2GateForgetBias.n_elem;
|
||||
|
||||
// Input2GateInputWeight and input2GateInputBias gradients.
|
||||
// input2GateInputWeight and input2GateInputBias gradients.
|
||||
gradient.submat(offset, 0, offset + input2GateInputWeight.n_elem - 1, 0) =
|
||||
arma::vectorise(inputGateError * input.t());
|
||||
gradient.submat(offset + input2GateInputWeight.n_elem, 0,
|
||||
@@ -466,7 +332,7 @@ void LSTM<InputDataType, OutputDataType>::Gradient(
|
||||
input2GateInputBias.n_elem - 1, 0) = arma::sum(inputGateError, 1);
|
||||
offset += input2GateInputWeight.n_elem + input2GateInputBias.n_elem;
|
||||
|
||||
// Input2HiddenWeight and input2HiddenBias gradients.
|
||||
// input2HiddenWeight and input2HiddenBias gradients.
|
||||
gradient.submat(offset, 0, offset + input2HiddenWeight.n_elem - 1, 0) =
|
||||
arma::vectorise(hiddenError * input.t());
|
||||
gradient.submat(offset + input2HiddenWeight.n_elem, 0,
|
||||
@@ -474,48 +340,43 @@ void LSTM<InputDataType, OutputDataType>::Gradient(
|
||||
arma::sum(hiddenError, 1);
|
||||
offset += input2HiddenWeight.n_elem + input2HiddenBias.n_elem;
|
||||
|
||||
// Output2GateOutputWeight gradients.
|
||||
// output2GateOutputWeight gradients.
|
||||
gradient.submat(offset, 0, offset + output2GateOutputWeight.n_elem - 1, 0) =
|
||||
arma::vectorise(outputGateError *
|
||||
outParameter.cols(gradientStep - batchStep, gradientStep).t());
|
||||
outParameter.slice(this->CurrentStep()).t());
|
||||
offset += output2GateOutputWeight.n_elem;
|
||||
|
||||
// Output2GateForgetWeight gradients.
|
||||
// output2GateForgetWeight gradients.
|
||||
gradient.submat(offset, 0, offset + output2GateForgetWeight.n_elem - 1, 0) =
|
||||
arma::vectorise(forgetGateError *
|
||||
outParameter.cols(gradientStep - batchStep, gradientStep).t());
|
||||
outParameter.slice(this->CurrentStep()).t());
|
||||
offset += output2GateForgetWeight.n_elem;
|
||||
|
||||
// Output2GateInputWeight gradients.
|
||||
// output2GateInputWeight gradients.
|
||||
gradient.submat(offset, 0, offset + output2GateInputWeight.n_elem - 1, 0) =
|
||||
arma::vectorise(inputGateError *
|
||||
outParameter.cols(gradientStep - batchStep, gradientStep).t());
|
||||
outParameter.slice(this->CurrentStep()).t());
|
||||
offset += output2GateInputWeight.n_elem;
|
||||
|
||||
// Output2HiddenWeight gradients.
|
||||
// output2HiddenWeight gradients.
|
||||
gradient.submat(offset, 0, offset + output2HiddenWeight.n_elem - 1, 0) =
|
||||
arma::vectorise(hiddenError *
|
||||
outParameter.cols(gradientStep - batchStep, gradientStep).t());
|
||||
outParameter.slice(this->CurrentStep()).t());
|
||||
offset += output2HiddenWeight.n_elem;
|
||||
|
||||
// Cell2GateOutputWeight gradients.
|
||||
// cell2GateOutputWeight gradients.
|
||||
gradient.submat(offset, 0, offset + cell2GateOutputWeight.n_elem - 1, 0) =
|
||||
arma::sum(outputGateError %
|
||||
cell.cols(gradientStep - batchStep, gradientStep), 1);
|
||||
arma::sum(outputGateError % cell.slice(this->CurrentStep()), 1);
|
||||
offset += cell2GateOutputWeight.n_elem;
|
||||
|
||||
// Cell2GateForgetWeight and cell2GateInputWeight gradients.
|
||||
if (gradientStep > batchStep)
|
||||
// cell2GateForgetWeight and cell2GateInputWeight gradients.
|
||||
if (this->HasPreviousStep())
|
||||
{
|
||||
gradient.submat(offset, 0, offset + cell2GateForgetWeight.n_elem - 1, 0) =
|
||||
arma::sum(forgetGateError %
|
||||
cell.cols((gradientStep - batchSize) - batchStep,
|
||||
(gradientStep - batchSize)), 1);
|
||||
arma::sum(forgetGateError % cell.slice(this->PreviousStep()), 1);
|
||||
gradient.submat(offset + cell2GateForgetWeight.n_elem, 0, offset +
|
||||
cell2GateForgetWeight.n_elem + cell2GateInputWeight.n_elem - 1, 0) =
|
||||
arma::sum(inputGateError %
|
||||
cell.cols((gradientStep - batchSize) - batchStep,
|
||||
(gradientStep - batchSize)), 1);
|
||||
arma::sum(inputGateError % cell.slice(this->PreviousStep()), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -525,41 +386,32 @@ void LSTM<InputDataType, OutputDataType>::Gradient(
|
||||
cell2GateForgetWeight.n_elem +
|
||||
cell2GateInputWeight.n_elem - 1, 0).zeros();
|
||||
}
|
||||
|
||||
if (gradientStep == 0)
|
||||
{
|
||||
gradientStep = batchSize * bpttSteps - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
gradientStep -= batchSize;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename MatType>
|
||||
template<typename Archive>
|
||||
void LSTM<InputDataType, OutputDataType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
void LSTMType<MatType>::serialize(Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(weights));
|
||||
ar(cereal::base_class<RecurrentLayer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(inSize));
|
||||
ar(CEREAL_NVP(outSize));
|
||||
ar(CEREAL_NVP(rho));
|
||||
ar(CEREAL_NVP(bpttSteps));
|
||||
ar(CEREAL_NVP(batchSize));
|
||||
ar(CEREAL_NVP(batchStep));
|
||||
ar(CEREAL_NVP(forwardStep));
|
||||
ar(CEREAL_NVP(backwardStep));
|
||||
ar(CEREAL_NVP(gradientStep));
|
||||
ar(CEREAL_NVP(gradientStepIdx));
|
||||
ar(CEREAL_NVP(cell));
|
||||
ar(CEREAL_NVP(inputGateActivation));
|
||||
ar(CEREAL_NVP(forgetGateActivation));
|
||||
ar(CEREAL_NVP(outputGateActivation));
|
||||
ar(CEREAL_NVP(hiddenLayerActivation));
|
||||
ar(CEREAL_NVP(cellActivation));
|
||||
ar(CEREAL_NVP(prevError));
|
||||
ar(CEREAL_NVP(outParameter));
|
||||
|
||||
// Clear recurrent state if we are loading.
|
||||
if (Archive::is_loading::value)
|
||||
{
|
||||
inputGateActivation.clear();
|
||||
forgetGateActivation.clear();
|
||||
outputGateActivation.clear();
|
||||
hiddenLayerActivation.clear();
|
||||
cellActivation.clear();
|
||||
forgetGateError.clear();
|
||||
outputGateError.clear();
|
||||
outParameter.clear();
|
||||
inputCellError.clear();
|
||||
inputGateError.clear();
|
||||
hiddenError.clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
@@ -28,32 +30,39 @@ class MaxPoolingRule
|
||||
/*
|
||||
* Return the maximum value within the receptive block.
|
||||
*
|
||||
* @param input Input used to perform the pooling operation.
|
||||
* @param input Input used to perform the pooling operation. Could be an
|
||||
* Armadillo subview.
|
||||
*/
|
||||
template<typename MatType>
|
||||
size_t Pooling(const MatType& input)
|
||||
typename MatType::elem_type Pooling(const MatType& input)
|
||||
{
|
||||
return arma::as_scalar(arma::find(input.max() == input, 1));
|
||||
return arma::max(arma::vectorise(input));
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
std::tuple<size_t, typename MatType::elem_type> PoolingWithIndex(
|
||||
const MatType& input)
|
||||
{
|
||||
const typename MatType::elem_type maxVal =
|
||||
arma::max(arma::vectorise(input));
|
||||
const size_t index = arma::as_scalar(arma::find(input == maxVal, 1));
|
||||
|
||||
return std::tuple<size_t, typename MatType::elem_type>(index, maxVal);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of the MaxPooling layer.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class MaxPooling
|
||||
template<typename MatType = arma::mat>
|
||||
class MaxPoolingType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
//! Create the MaxPooling object.
|
||||
MaxPooling();
|
||||
MaxPoolingType();
|
||||
|
||||
/**
|
||||
* Create the MaxPooling object using the specified number of units.
|
||||
@@ -64,11 +73,25 @@ class MaxPooling
|
||||
* @param strideHeight Width of the stride operation.
|
||||
* @param floor Rounding operator (floor or ceil).
|
||||
*/
|
||||
MaxPooling(const size_t kernelWidth,
|
||||
const size_t kernelHeight,
|
||||
const size_t strideWidth = 1,
|
||||
const size_t strideHeight = 1,
|
||||
const bool floor = true);
|
||||
MaxPoolingType(const size_t kernelWidth,
|
||||
const size_t kernelHeight,
|
||||
const size_t strideWidth = 1,
|
||||
const size_t strideHeight = 1,
|
||||
const bool floor = true);
|
||||
|
||||
// Virtual destructor.
|
||||
virtual ~MaxPoolingType() { }
|
||||
|
||||
//! Copy the given MaxPoolingType.
|
||||
MaxPoolingType(const MaxPoolingType& other);
|
||||
//! Take ownership of the given MaxPoolingType.
|
||||
MaxPoolingType(MaxPoolingType&& other);
|
||||
//! Copy the given MaxPoolingType.
|
||||
MaxPoolingType& operator=(const MaxPoolingType& other);
|
||||
//! Take ownership of the given MaxPoolingType.
|
||||
MaxPoolingType& operator=(MaxPoolingType&& other);
|
||||
|
||||
MaxPoolingType* Clone() const { return new MaxPoolingType(*this); }
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -77,8 +100,7 @@ class MaxPooling
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, using 3rd-order tensors as
|
||||
@@ -89,79 +111,37 @@ class MaxPooling
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
|
||||
//! Get the output parameter.
|
||||
const OutputDataType& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
const OutputDataType& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the input width.
|
||||
size_t InputWidth() const { return inputWidth; }
|
||||
//! Modify the input width.
|
||||
size_t& InputWidth() { return inputWidth; }
|
||||
|
||||
//! Get the input height.
|
||||
size_t InputHeight() const { return inputHeight; }
|
||||
//! Modify the input height.
|
||||
size_t& InputHeight() { return inputHeight; }
|
||||
|
||||
//! Get the output width.
|
||||
size_t OutputWidth() const { return outputWidth; }
|
||||
//! Modify the output width.
|
||||
size_t& OutputWidth() { return outputWidth; }
|
||||
|
||||
//! Get the output height.
|
||||
size_t OutputHeight() const { return outputHeight; }
|
||||
//! Modify the output height.
|
||||
size_t& OutputHeight() { return outputHeight; }
|
||||
|
||||
//! Get the input size.
|
||||
size_t InputSize() const { return inSize; }
|
||||
|
||||
//! Get the output size.
|
||||
size_t OutputSize() const { return outSize; }
|
||||
void Backward(const MatType& /* input */,
|
||||
const MatType& gy,
|
||||
MatType& g);
|
||||
|
||||
//! Get the kernel width.
|
||||
size_t KernelWidth() const { return kernelWidth; }
|
||||
size_t const& KernelWidth() const { return kernelWidth; }
|
||||
//! Modify the kernel width.
|
||||
size_t& KernelWidth() { return kernelWidth; }
|
||||
|
||||
//! Get the kernel height.
|
||||
size_t KernelHeight() const { return kernelHeight; }
|
||||
size_t const& KernelHeight() const { return kernelHeight; }
|
||||
//! Modify the kernel height.
|
||||
size_t& KernelHeight() { return kernelHeight; }
|
||||
|
||||
//! Get the stride width.
|
||||
size_t StrideWidth() const { return strideWidth; }
|
||||
size_t const& StrideWidth() const { return strideWidth; }
|
||||
//! Modify the stride width.
|
||||
size_t& StrideWidth() { return strideWidth; }
|
||||
|
||||
//! Get the stride height.
|
||||
size_t StrideHeight() const { return strideHeight; }
|
||||
size_t const& StrideHeight() const { return strideHeight; }
|
||||
//! Modify the stride height.
|
||||
size_t& StrideHeight() { return strideHeight; }
|
||||
|
||||
//! Get the value of the rounding operation.
|
||||
bool Floor() const { return floor; }
|
||||
bool const& Floor() const { return floor; }
|
||||
//! Modify the value of the rounding operation.
|
||||
bool& Floor() { return floor; }
|
||||
|
||||
//! Get the value of the deterministic parameter.
|
||||
bool Deterministic() const { return deterministic; }
|
||||
//! Modify the value of the deterministic parameter.
|
||||
bool& Deterministic() { return deterministic; }
|
||||
|
||||
//! Get the size of the weights.
|
||||
size_t WeightSize() const { return 0; }
|
||||
//! Compute the size of the output given `InputDimensions()`.
|
||||
void ComputeOutputDimensions();
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
@@ -170,62 +150,94 @@ class MaxPooling
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
/**
|
||||
/**
|
||||
* Apply pooling to the input and store the results.
|
||||
*
|
||||
* @param input The input to be apply the pooling rule.
|
||||
* @param output The pooled result.
|
||||
* @param poolingIndices The pooled indices.
|
||||
*/
|
||||
template<typename eT>
|
||||
void PoolingOperation(const arma::Mat<eT>& input,
|
||||
arma::Mat<eT>& output,
|
||||
arma::Mat<eT>& poolingIndices)
|
||||
void PoolingOperation(
|
||||
const arma::Cube<typename MatType::elem_type>& input,
|
||||
arma::Cube<typename MatType::elem_type>& output,
|
||||
arma::Cube<size_t>& poolingIndices)
|
||||
{
|
||||
for (size_t j = 0, colidx = 0; j < output.n_cols;
|
||||
++j, colidx += strideHeight)
|
||||
// Iterate over all slices individually.
|
||||
for (size_t s = 0; s < input.n_slices; ++s)
|
||||
{
|
||||
for (size_t i = 0, rowidx = 0; i < output.n_rows;
|
||||
++i, rowidx += strideWidth)
|
||||
for (size_t j = 0, colidx = 0; j < output.n_cols;
|
||||
++j, colidx += strideHeight)
|
||||
{
|
||||
size_t rowEnd = rowidx + kernelWidth - 1;
|
||||
size_t colEnd = colidx + kernelHeight - 1;
|
||||
|
||||
if (rowEnd > input.n_rows - 1)
|
||||
rowEnd = input.n_rows - 1;
|
||||
if (colEnd > input.n_cols - 1)
|
||||
colEnd = input.n_cols - 1;
|
||||
|
||||
arma::mat subInput = input(
|
||||
arma::span(rowidx, rowEnd),
|
||||
arma::span(colidx, colEnd));
|
||||
|
||||
const size_t idx = pooling.Pooling(subInput);
|
||||
output(i, j) = subInput(idx);
|
||||
|
||||
if (!deterministic)
|
||||
for (size_t i = 0, rowidx = 0; i < output.n_rows;
|
||||
++i, rowidx += strideWidth)
|
||||
{
|
||||
arma::Mat<size_t> subIndices = indices(arma::span(rowidx, rowEnd),
|
||||
arma::span(colidx, colEnd));
|
||||
const std::tuple<size_t, typename MatType::elem_type> poolResult =
|
||||
pooling.PoolingWithIndex(input.slice(s).submat(
|
||||
rowidx,
|
||||
colidx,
|
||||
rowidx + kernelWidth - 1 - offset,
|
||||
colidx + kernelHeight - 1 - offset));
|
||||
|
||||
poolingIndices(i, j) = subIndices(idx);
|
||||
// Now map the returned pooling index, which corresponds to the
|
||||
// submatrix we gave, back to its position in the (linearized) input.
|
||||
const size_t poolIndex = std::get<0>(poolResult);
|
||||
const size_t poolingCol = poolIndex / (kernelWidth - offset);
|
||||
const size_t poolingRow = poolIndex % (kernelWidth - offset);
|
||||
const size_t unmappedPoolingIndex = (rowidx + poolingRow) +
|
||||
input.n_rows * (colidx + poolingCol) +
|
||||
input.n_rows * input.n_cols * s;
|
||||
|
||||
poolingIndices(i, j, s) = unmappedPoolingIndex;
|
||||
output(i, j, s) = std::get<1>(poolResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply unpooling to the input and store the results.
|
||||
* Apply pooling to all slices of the input and store the results, but not the
|
||||
* indices used.
|
||||
*
|
||||
* @param input The input to apply the pooling rule to.
|
||||
* @param output The pooled result.
|
||||
*/
|
||||
void PoolingOperation(
|
||||
const arma::Cube<typename MatType::elem_type>& input,
|
||||
arma::Cube<typename MatType::elem_type>& output)
|
||||
{
|
||||
// Iterate over all slices individually.
|
||||
for (size_t s = 0; s < input.n_slices; ++s)
|
||||
{
|
||||
for (size_t j = 0, colidx = 0; j < output.n_cols;
|
||||
++j, colidx += strideHeight)
|
||||
{
|
||||
for (size_t i = 0, rowidx = 0; i < output.n_rows;
|
||||
++i, rowidx += strideWidth)
|
||||
{
|
||||
output(i, j, s) = pooling.Pooling(input.slice(s).submat(
|
||||
rowidx,
|
||||
colidx,
|
||||
rowidx + kernelWidth - 1 - offset,
|
||||
colidx + kernelHeight - 1 - offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply unpooling to all slices of the input and store the results.
|
||||
*
|
||||
* @param error The backward error.
|
||||
* @param output The pooled result.
|
||||
* @param poolingIndices The pooled indices.
|
||||
* @param poolingIndices The pooled indices (from `PoolingOperation()`).
|
||||
*/
|
||||
template<typename eT>
|
||||
void Unpooling(const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& output,
|
||||
arma::Mat<eT>& poolingIndices)
|
||||
void UnpoolingOperation(
|
||||
const arma::Cube<typename MatType::elem_type>& error,
|
||||
arma::Cube<typename MatType::elem_type>& output,
|
||||
const arma::Cube<size_t>& poolingIndices)
|
||||
{
|
||||
output.zeros();
|
||||
|
||||
for (size_t i = 0; i < poolingIndices.n_elem; ++i)
|
||||
{
|
||||
output(poolingIndices(i)) += error(i);
|
||||
@@ -247,64 +259,22 @@ class MaxPooling
|
||||
//! Rounding operation used.
|
||||
bool floor;
|
||||
|
||||
//! Locally-stored number of input channels.
|
||||
size_t inSize;
|
||||
//! Locally-stored number of channels.
|
||||
size_t channels;
|
||||
|
||||
//! Locally-stored number of output channels.
|
||||
size_t outSize;
|
||||
|
||||
//! Locally-stored reset parameter used to initialize the module once.
|
||||
bool reset;
|
||||
|
||||
//! Locally-stored input width.
|
||||
size_t inputWidth;
|
||||
|
||||
//! Locally-stored input height.
|
||||
size_t inputHeight;
|
||||
|
||||
//! Locally-stored output width.
|
||||
size_t outputWidth;
|
||||
|
||||
//! Locally-stored output height.
|
||||
size_t outputHeight;
|
||||
|
||||
//! If true use maximum a posteriori during the forward pass.
|
||||
bool deterministic;
|
||||
|
||||
|
||||
//! Locally-stored number of input units.
|
||||
size_t batchSize;
|
||||
|
||||
//! Locally-stored output parameter.
|
||||
arma::cube outputTemp;
|
||||
|
||||
//! Locally-stored transformed input parameter.
|
||||
arma::cube inputTemp;
|
||||
|
||||
//! Locally-stored transformed output parameter.
|
||||
arma::cube gTemp;
|
||||
//! Locally-stored offset: indicates whether we take the first element or the
|
||||
//! second element when pooling. Computed by `ComputeOutputDimensions()`.
|
||||
size_t offset;
|
||||
|
||||
//! Locally-stored pooling strategy.
|
||||
MaxPoolingRule pooling;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
//! Locally-stored pooling indices.
|
||||
arma::Cube<size_t> poolingIndices;
|
||||
}; // class MaxPoolingType
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
|
||||
//! Locally-stored indices matrix parameter.
|
||||
arma::Mat<size_t> indices;
|
||||
|
||||
//! Locally-stored indices column parameter.
|
||||
arma::Col<size_t> indicesCol;
|
||||
|
||||
//! Locally-stored pooling indicies.
|
||||
std::vector<arma::cube> poolingIndices;
|
||||
}; // class MaxPooling
|
||||
// Standard MaxPooling layer.
|
||||
typedef MaxPoolingType<arma::mat> MaxPooling;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -19,141 +19,201 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
MaxPooling<InputDataType, OutputDataType>::MaxPooling()
|
||||
template<typename MatType>
|
||||
MaxPoolingType<MatType>::MaxPoolingType() :
|
||||
Layer<MatType>()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
MaxPooling<InputDataType, OutputDataType>::MaxPooling(
|
||||
template<typename MatType>
|
||||
MaxPoolingType<MatType>::MaxPoolingType(
|
||||
const size_t kernelWidth,
|
||||
const size_t kernelHeight,
|
||||
const size_t strideWidth,
|
||||
const size_t strideHeight,
|
||||
const bool floor) :
|
||||
Layer<MatType>(),
|
||||
kernelWidth(kernelWidth),
|
||||
kernelHeight(kernelHeight),
|
||||
strideWidth(strideWidth),
|
||||
strideHeight(strideHeight),
|
||||
floor(floor),
|
||||
inSize(0),
|
||||
outSize(0),
|
||||
reset(false),
|
||||
inputWidth(0),
|
||||
inputHeight(0),
|
||||
outputWidth(0),
|
||||
outputHeight(0),
|
||||
deterministic(false),
|
||||
batchSize(0)
|
||||
channels(0),
|
||||
offset(0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void MaxPooling<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
template<typename MatType>
|
||||
MaxPoolingType<MatType>::MaxPoolingType(
|
||||
const MaxPoolingType& other) :
|
||||
Layer<MatType>(other),
|
||||
kernelWidth(other.kernelWidth),
|
||||
kernelHeight(other.kernelHeight),
|
||||
strideWidth(other.strideWidth),
|
||||
strideHeight(other.strideHeight),
|
||||
floor(other.floor),
|
||||
channels(other.channels),
|
||||
offset(other.offset),
|
||||
pooling(other.pooling)
|
||||
{
|
||||
batchSize = input.n_cols;
|
||||
inSize = input.n_elem / (inputWidth * inputHeight * batchSize);
|
||||
inputTemp = arma::cube(const_cast<arma::Mat<eT>&>(input).memptr(),
|
||||
inputWidth, inputHeight, batchSize * inSize, false, false);
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
if (floor)
|
||||
template<typename MatType>
|
||||
MaxPoolingType<MatType>::MaxPoolingType(
|
||||
MaxPoolingType&& other) :
|
||||
Layer<MatType>(std::move(other)),
|
||||
kernelWidth(std::move(other.kernelWidth)),
|
||||
kernelHeight(std::move(other.kernelHeight)),
|
||||
strideWidth(std::move(other.strideWidth)),
|
||||
strideHeight(std::move(other.strideHeight)),
|
||||
floor(std::move(other.floor)),
|
||||
channels(std::move(other.channels)),
|
||||
offset(std::move(other.offset)),
|
||||
pooling(std::move(other.pooling))
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
MaxPoolingType<MatType>&
|
||||
MaxPoolingType<MatType>::operator=(const MaxPoolingType& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
outputWidth = std::floor((inputWidth -
|
||||
(double) kernelWidth) / (double) strideWidth + 1);
|
||||
outputHeight = std::floor((inputHeight -
|
||||
(double) kernelHeight) / (double) strideHeight + 1);
|
||||
Layer<MatType>::operator=(other);
|
||||
kernelWidth = other.kernelWidth;
|
||||
kernelHeight = other.kernelHeight;
|
||||
strideWidth = other.strideWidth;
|
||||
strideHeight = other.strideHeight;
|
||||
floor = other.floor;
|
||||
channels = other.channels;
|
||||
offset = other.offset;
|
||||
pooling = other.pooling;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
MaxPoolingType<MatType>&
|
||||
MaxPoolingType<MatType>::operator=(MaxPoolingType&& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
Layer<MatType>::operator=(std::move(other));
|
||||
kernelWidth = std::move(other.kernelWidth);
|
||||
kernelHeight = std::move(other.kernelHeight);
|
||||
strideWidth = std::move(other.strideWidth);
|
||||
strideHeight = std::move(other.strideHeight);
|
||||
floor = std::move(other.floor);
|
||||
channels = std::move(other.channels);
|
||||
offset = std::move(other.offset);
|
||||
pooling = std::move(other.pooling);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void MaxPoolingType<MatType>::Forward(const MatType& input, MatType& output)
|
||||
{
|
||||
arma::Cube<typename MatType::elem_type> inputTemp(
|
||||
const_cast<MatType&>(input).memptr(), this->inputDimensions[0],
|
||||
this->inputDimensions[1], input.n_cols * channels, false, false);
|
||||
|
||||
arma::Cube<typename MatType::elem_type> outputTemp(output.memptr(),
|
||||
this->outputDimensions[0], this->outputDimensions[1],
|
||||
input.n_cols * channels, false, true);
|
||||
|
||||
if (this->training)
|
||||
{
|
||||
// If we are training, we'll do a backwards pass, so we need to ensure that
|
||||
// we know what indices we used.
|
||||
poolingIndices.set_size(this->outputDimensions[0],
|
||||
this->outputDimensions[1], input.n_cols * channels);
|
||||
|
||||
PoolingOperation(inputTemp, outputTemp, poolingIndices);
|
||||
}
|
||||
else
|
||||
{
|
||||
outputWidth = std::ceil((inputWidth -
|
||||
(double) kernelWidth) / (double) strideWidth + 1);
|
||||
outputHeight = std::ceil((inputHeight -
|
||||
(double) kernelHeight) / (double) strideHeight + 1);
|
||||
PoolingOperation(inputTemp, outputTemp);
|
||||
}
|
||||
|
||||
outputTemp = arma::zeros<arma::Cube<eT> >(outputWidth, outputHeight,
|
||||
batchSize * inSize);
|
||||
|
||||
if (!deterministic)
|
||||
{
|
||||
poolingIndices.push_back(outputTemp);
|
||||
}
|
||||
|
||||
if (!reset)
|
||||
{
|
||||
size_t elements = inputWidth * inputHeight;
|
||||
indicesCol = arma::linspace<arma::Col<size_t> >(0, (elements - 1),
|
||||
elements);
|
||||
|
||||
indices = arma::Mat<size_t>(indicesCol.memptr(), inputWidth, inputHeight);
|
||||
|
||||
reset = true;
|
||||
}
|
||||
|
||||
for (size_t s = 0; s < inputTemp.n_slices; s++)
|
||||
{
|
||||
if (!deterministic)
|
||||
{
|
||||
PoolingOperation(inputTemp.slice(s), outputTemp.slice(s),
|
||||
poolingIndices.back().slice(s));
|
||||
}
|
||||
else
|
||||
{
|
||||
PoolingOperation(inputTemp.slice(s), outputTemp.slice(s),
|
||||
inputTemp.slice(s));
|
||||
}
|
||||
}
|
||||
|
||||
output = arma::Mat<eT>(outputTemp.memptr(), outputTemp.n_elem / batchSize,
|
||||
batchSize);
|
||||
|
||||
outputWidth = outputTemp.n_rows;
|
||||
outputHeight = outputTemp.n_cols;
|
||||
outSize = batchSize * inSize;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void MaxPooling<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
|
||||
template<typename MatType>
|
||||
void MaxPoolingType<MatType>::Backward(
|
||||
const MatType& input, const MatType& gy, MatType& g)
|
||||
{
|
||||
arma::cube mappedError = arma::cube(((arma::Mat<eT>&) gy).memptr(),
|
||||
outputWidth, outputHeight, outSize, false, false);
|
||||
arma::Cube<typename MatType::elem_type> mappedError =
|
||||
arma::Cube<typename MatType::elem_type>(((MatType&) gy).memptr(),
|
||||
this->outputDimensions[0], this->outputDimensions[1],
|
||||
channels * input.n_cols, false, false);
|
||||
|
||||
gTemp = arma::zeros<arma::cube>(inputTemp.n_rows,
|
||||
inputTemp.n_cols, inputTemp.n_slices);
|
||||
arma::Cube<typename MatType::elem_type> gTemp(g.memptr(),
|
||||
this->inputDimensions[0], this->inputDimensions[1],
|
||||
channels * input.n_cols, false, true);
|
||||
|
||||
for (size_t s = 0; s < mappedError.n_slices; s++)
|
||||
{
|
||||
Unpooling(mappedError.slice(s), gTemp.slice(s),
|
||||
poolingIndices.back().slice(s));
|
||||
}
|
||||
|
||||
poolingIndices.pop_back();
|
||||
|
||||
g = arma::mat(gTemp.memptr(), gTemp.n_elem / batchSize, batchSize);
|
||||
// There's no version of UnpoolingOperation without pooling indices, because
|
||||
// if we call `Backward()`, we know for sure we are training.
|
||||
UnpoolingOperation(mappedError, gTemp, poolingIndices);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename MatType>
|
||||
void MaxPoolingType<MatType>::ComputeOutputDimensions()
|
||||
{
|
||||
this->outputDimensions = this->inputDimensions;
|
||||
|
||||
// Compute the size of the output.
|
||||
if (floor)
|
||||
{
|
||||
this->outputDimensions[0] = std::floor((this->inputDimensions[0] -
|
||||
(double) kernelWidth) / (double) strideWidth + 1);
|
||||
this->outputDimensions[1] = std::floor((this->inputDimensions[1] -
|
||||
(double) kernelHeight) / (double) strideHeight + 1);
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->outputDimensions[0] = std::ceil((this->inputDimensions[0] -
|
||||
(double) kernelWidth) / (double) strideWidth + 1);
|
||||
this->outputDimensions[1] = std::ceil((this->inputDimensions[1] -
|
||||
(double) kernelHeight) / (double) strideHeight + 1);
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
// Higher dimensions are not modified.
|
||||
|
||||
// Cache input size and output size.
|
||||
channels = 1;
|
||||
for (size_t i = 2; i < this->inputDimensions.size(); ++i)
|
||||
channels *= this->inputDimensions[i];
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
template<typename Archive>
|
||||
void MaxPooling<InputDataType, OutputDataType>::serialize(
|
||||
void MaxPoolingType<MatType>::serialize(
|
||||
Archive& ar,
|
||||
const uint32_t /* version */)
|
||||
|
||||
{
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(kernelWidth));
|
||||
ar(CEREAL_NVP(kernelHeight));
|
||||
ar(CEREAL_NVP(strideWidth));
|
||||
ar(CEREAL_NVP(strideHeight));
|
||||
ar(CEREAL_NVP(batchSize));
|
||||
ar(CEREAL_NVP(channels));
|
||||
ar(CEREAL_NVP(floor));
|
||||
ar(CEREAL_NVP(inputWidth));
|
||||
ar(CEREAL_NVP(inputHeight));
|
||||
ar(CEREAL_NVP(outputWidth));
|
||||
ar(CEREAL_NVP(outputHeight));
|
||||
ar(CEREAL_NVP(offset));
|
||||
|
||||
if (Archive::is_loading::value)
|
||||
{
|
||||
// Clear any memory used by `poolingIndices`.
|
||||
poolingIndices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/mean_pooling_impl.hpp
|
||||
* @author Marcus Edel
|
||||
* @author Nilay Jain
|
||||
*
|
||||
* Implementation of the MeanPooling layer class.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_MEAN_POOLING_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_MEAN_POOLING_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "mean_pooling.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
MeanPooling<InputDataType, OutputDataType>::MeanPooling()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
MeanPooling<InputDataType, OutputDataType>::MeanPooling(
|
||||
const size_t kernelWidth,
|
||||
const size_t kernelHeight,
|
||||
const size_t strideWidth,
|
||||
const size_t strideHeight,
|
||||
const bool floor) :
|
||||
kernelWidth(kernelWidth),
|
||||
kernelHeight(kernelHeight),
|
||||
strideWidth(strideWidth),
|
||||
strideHeight(strideHeight),
|
||||
floor(floor),
|
||||
inSize(0),
|
||||
outSize(0),
|
||||
inputWidth(0),
|
||||
inputHeight(0),
|
||||
outputWidth(0),
|
||||
outputHeight(0),
|
||||
reset(false),
|
||||
deterministic(false),
|
||||
batchSize(0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void MeanPooling<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
{
|
||||
batchSize = input.n_cols;
|
||||
inSize = input.n_elem / (inputWidth * inputHeight * batchSize);
|
||||
inputTemp = arma::cube(const_cast<arma::Mat<eT>&>(input).memptr(),
|
||||
inputWidth, inputHeight, batchSize * inSize, false, false);
|
||||
|
||||
if (floor)
|
||||
{
|
||||
outputWidth = std::floor((inputWidth -
|
||||
(double) kernelWidth) / (double) strideWidth + 1);
|
||||
outputHeight = std::floor((inputHeight -
|
||||
(double) kernelHeight) / (double) strideHeight + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
outputWidth = std::ceil((inputWidth -
|
||||
(double) kernelWidth) / (double) strideWidth + 1);
|
||||
outputHeight = std::ceil((inputHeight -
|
||||
(double) kernelHeight) / (double) strideHeight + 1);
|
||||
}
|
||||
|
||||
outputTemp = arma::zeros<arma::Cube<eT> >(outputWidth, outputHeight,
|
||||
batchSize * inSize);
|
||||
|
||||
for (size_t s = 0; s < inputTemp.n_slices; s++)
|
||||
Pooling(inputTemp.slice(s), outputTemp.slice(s));
|
||||
|
||||
output = arma::Mat<eT>(outputTemp.memptr(), outputTemp.n_elem / batchSize,
|
||||
batchSize);
|
||||
|
||||
outputWidth = outputTemp.n_rows;
|
||||
outputHeight = outputTemp.n_cols;
|
||||
outSize = batchSize * inSize;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void MeanPooling<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
{
|
||||
arma::cube mappedError = arma::cube(((arma::Mat<eT>&) gy).memptr(),
|
||||
outputWidth, outputHeight, outSize, false, false);
|
||||
|
||||
gTemp = arma::zeros<arma::cube>(inputTemp.n_rows,
|
||||
inputTemp.n_cols, inputTemp.n_slices);
|
||||
|
||||
for (size_t s = 0; s < mappedError.n_slices; s++)
|
||||
{
|
||||
Unpooling(inputTemp.slice(s), mappedError.slice(s), gTemp.slice(s));
|
||||
}
|
||||
|
||||
g = arma::mat(gTemp.memptr(), gTemp.n_elem / batchSize, batchSize);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename Archive>
|
||||
void MeanPooling<InputDataType, OutputDataType>::serialize(
|
||||
Archive& ar,
|
||||
const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(kernelWidth));
|
||||
ar(CEREAL_NVP(kernelHeight));
|
||||
ar(CEREAL_NVP(strideWidth));
|
||||
ar(CEREAL_NVP(strideHeight));
|
||||
ar(CEREAL_NVP(batchSize));
|
||||
ar(CEREAL_NVP(floor));
|
||||
ar(CEREAL_NVP(inputWidth));
|
||||
ar(CEREAL_NVP(inputHeight));
|
||||
ar(CEREAL_NVP(outputWidth));
|
||||
ar(CEREAL_NVP(outputHeight));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -1,147 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/minibatch_discrimination_impl.hpp
|
||||
* @author Saksham Bansal
|
||||
*
|
||||
* Implementation of the MiniBatchDiscrimination layer class.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_MINIBATCH_DISCRIMINATION_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_MINIBATCH_DISCRIMINATION_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "minibatch_discrimination.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
MiniBatchDiscrimination<InputDataType, OutputDataType
|
||||
>::MiniBatchDiscrimination() :
|
||||
A(0),
|
||||
B(0),
|
||||
C(0),
|
||||
batchSize(0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType>
|
||||
MiniBatchDiscrimination<InputDataType, OutputDataType
|
||||
>::MiniBatchDiscrimination(
|
||||
const size_t inSize,
|
||||
const size_t outSize,
|
||||
const size_t features) :
|
||||
A(inSize),
|
||||
B(outSize - inSize),
|
||||
C(features),
|
||||
batchSize(0)
|
||||
{
|
||||
weights.set_size(A * B * C, 1);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
void MiniBatchDiscrimination<InputDataType, OutputDataType>::Reset()
|
||||
{
|
||||
weight = arma::mat(weights.memptr(), B * C, A, false, false);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void MiniBatchDiscrimination<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
{
|
||||
batchSize = input.n_cols;
|
||||
tempM = weight * input;
|
||||
M = arma::cube(tempM.memptr(), B, C, batchSize, false, false);
|
||||
distances.set_size(B, batchSize, batchSize);
|
||||
output.set_size(B, batchSize);
|
||||
|
||||
for (size_t i = 0; i < M.n_slices; ++i)
|
||||
{
|
||||
output.col(i).ones();
|
||||
for (size_t j = 0; j < M.n_slices; ++j)
|
||||
{
|
||||
if (j < i)
|
||||
{
|
||||
output.col(i) += distances.slice(j).col(i);
|
||||
}
|
||||
else if (i == j)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
distances.slice(i).col(j) =
|
||||
arma::exp(-arma::sum(abs(M.slice(i) - M.slice(j)), 1));
|
||||
output.col(i) += distances.slice(i).col(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output = join_cols(input, output); // (A + B) x batchSize
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void MiniBatchDiscrimination<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
|
||||
{
|
||||
g = gy.head_rows(A);
|
||||
arma::Mat<eT> gM = gy.tail_rows(B);
|
||||
deltaM.zeros(B, C, batchSize);
|
||||
|
||||
for (size_t i = 0; i < M.n_slices; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < M.n_slices; ++j)
|
||||
{
|
||||
if (i == j)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
arma::mat t = arma::sign(M.slice(i) - M.slice(j));
|
||||
t.each_col() %=
|
||||
distances.slice(std::min(i, j)).col(std::max(i, j)) % gM.col(i);
|
||||
deltaM.slice(i) -= t;
|
||||
deltaM.slice(j) += t;
|
||||
}
|
||||
}
|
||||
|
||||
deltaTemp = arma::mat(deltaM.memptr(), B * C, batchSize, false, false);
|
||||
g += weight.t() * deltaTemp;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void MiniBatchDiscrimination<InputDataType, OutputDataType>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& /* error */,
|
||||
arma::Mat<eT>& gradient)
|
||||
{
|
||||
gradient = arma::vectorise(deltaTemp * input.t());
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename Archive>
|
||||
void MiniBatchDiscrimination<InputDataType, OutputDataType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(A));
|
||||
ar(CEREAL_NVP(B));
|
||||
ar(CEREAL_NVP(C));
|
||||
|
||||
// This is inefficient, but we have to allocate this memory so that
|
||||
// WeightSetVisitor gets the right size.
|
||||
if (cereal::is_loading<Archive>())
|
||||
{
|
||||
weights.set_size(A * B * C, 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,252 @@
|
||||
/**
|
||||
* @file methods/ann/layer/multi_layer.hpp
|
||||
* @author Ryan Curtin
|
||||
*
|
||||
* Base class for neural network layers that are wrappers around other layers.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_MULTI_LAYER_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_MULTI_LAYER_HPP
|
||||
|
||||
#include "../make_alias.hpp"
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann {
|
||||
|
||||
/**
|
||||
* A "multi-layer" is a layer that is a wrapper around other layers. It passes
|
||||
* the input through all of its child layers sequentially, returning the output
|
||||
* from the last layer.
|
||||
*
|
||||
* It's likely not very useful to use this layer directly; instead, this layer
|
||||
* is meant as a base class for use by other layers that must store and use
|
||||
* multiple layers.
|
||||
*
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template<typename MatType>
|
||||
class MultiLayer : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create an empty MultiLayer that holds no layers of its own. Be sure to add
|
||||
* layers with Add() before using!
|
||||
*/
|
||||
MultiLayer();
|
||||
|
||||
//! Copy the given MultiLayer.
|
||||
MultiLayer(const MultiLayer& other);
|
||||
//! Take ownership of the layers of the given MultiLayer.
|
||||
MultiLayer(MultiLayer&& other);
|
||||
//! Copy the given MultiLayer.
|
||||
MultiLayer& operator=(const MultiLayer& other);
|
||||
//! Take ownership of the given MultiLayer.
|
||||
MultiLayer& operator=(MultiLayer&& other);
|
||||
|
||||
//! Virtual destructor: delete all held layers.
|
||||
virtual ~MultiLayer()
|
||||
{
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
delete network[i];
|
||||
}
|
||||
|
||||
//! Create a copy of the MultiLayer (this is safe for polymorphic use).
|
||||
virtual MultiLayer* Clone() const { return new MultiLayer(*this); }
|
||||
|
||||
/**
|
||||
* Perform a forward pass with the given input data. `output` is expected to
|
||||
* have the correct size (e.g. number of rows equal to `OutputSize()` of the
|
||||
* last held layer; number of columns equal to `input.n_cols`).
|
||||
*
|
||||
* @param input Input data to pass through the MultiLayer.
|
||||
* @param output Matrix to store output in.
|
||||
*/
|
||||
virtual void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Perform a forward pass with the given input data, but only on a subset of
|
||||
* the layers in the MultiLayer. `output` is expected to have the correct
|
||||
* size (e.g. number of rows equal to `OutputSize()` of the last layer to be
|
||||
* computed; number of columns equal to `input.n_cols`).
|
||||
*
|
||||
* @param input Input data to pass through the MultiLayer.
|
||||
* @param output Matrix to store output in.
|
||||
* @param start Index of first layer to pass data through.
|
||||
* @param end Index of last layer to pass data through.
|
||||
*/
|
||||
void Forward(const MatType& input,
|
||||
MatType& output,
|
||||
const size_t start,
|
||||
const size_t end);
|
||||
|
||||
/**
|
||||
* Perform a backward pass with the given data. `gy` is expected to be the
|
||||
* propagated error from the subsequent layer (or output), `input` is expected
|
||||
* to be the output from this layer when `Forward()` was called, and `g` will
|
||||
* store the propagated error from this layer (to be passed to the previous
|
||||
* layer as `gy`).
|
||||
*
|
||||
* It is expected that `g` has the correct size already (e.g., number of rows
|
||||
* equal to `OutputSize()` of the previous layer, and number of columns equal
|
||||
* to `input.n_cols`).
|
||||
*
|
||||
* This function is expected to be called for the same input data as
|
||||
* `Forward()` was just called for.
|
||||
*
|
||||
* @param input Output of Forward().
|
||||
* @param gy Propagated error from next layer.
|
||||
* @param g Matrix to store propagated error in for previous layer.
|
||||
*/
|
||||
virtual void Backward(const MatType& input,
|
||||
const MatType& gy,
|
||||
MatType& g);
|
||||
|
||||
/**
|
||||
* Compute the gradients of each layer.
|
||||
*
|
||||
* This function is expected to be called for the same input data as
|
||||
* `Forward()` and `Backward()` were just called for. That is, `input` here
|
||||
* should be the same data as `Forward()` was called with.
|
||||
*
|
||||
* `gradient` is expected to have the correct size already (e.g., number of
|
||||
* rows equal to 1, and number of columns equal to `WeightSize()`).
|
||||
*
|
||||
* @param input Original input data provided to Forward().
|
||||
* @param error Error as computed by `Backward()`.
|
||||
* @param gradient Matrix to store the gradients in.
|
||||
*/
|
||||
virtual void Gradient(const MatType& input,
|
||||
const MatType& error,
|
||||
MatType& gradient);
|
||||
|
||||
/**
|
||||
* Set the weights of the layer to use the memory given as `weightsPtr`.
|
||||
*/
|
||||
virtual void SetWeights(typename MatType::elem_type* weightsPtr);
|
||||
|
||||
/**
|
||||
* Return the number of weights in the MultiLayer. This is the sum of the
|
||||
* number of weights in each layer.
|
||||
*/
|
||||
virtual size_t WeightSize() const;
|
||||
|
||||
/**
|
||||
* Compute the output dimensions of the MultiLayer using `InputDimensions()`.
|
||||
* This computes the dimensions of each layer held by the MultiLayer, and the
|
||||
* output dimensions are set to the output dimensions of the last layer.
|
||||
*/
|
||||
virtual void ComputeOutputDimensions();
|
||||
|
||||
/**
|
||||
* Compute the loss that should be added to the objective.
|
||||
*/
|
||||
virtual double Loss() const;
|
||||
|
||||
/*
|
||||
* Add a new module to the model.
|
||||
*
|
||||
* @param args The layer parameter.
|
||||
*/
|
||||
template <typename LayerType, typename... Args>
|
||||
void Add(Args... args)
|
||||
{
|
||||
network.push_back(new LayerType(args...));
|
||||
layerOutputs.push_back(MatType());
|
||||
layerDeltas.push_back(MatType());
|
||||
layerGradients.push_back(MatType());
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new module to the model.
|
||||
*
|
||||
* @param layer The Layer to be added to the model.
|
||||
*/
|
||||
void Add(Layer<MatType>* layer)
|
||||
{
|
||||
network.push_back(layer);
|
||||
layerOutputs.push_back(MatType());
|
||||
layerDeltas.push_back(MatType());
|
||||
layerGradients.push_back(MatType());
|
||||
}
|
||||
|
||||
//! Get the network (series of layers) held by this MultiLayer.
|
||||
const std::vector<Layer<MatType>*> Network() const
|
||||
{
|
||||
return network;
|
||||
}
|
||||
//! Modify the network (series of layers) held by this MultiLayer. Be
|
||||
//! careful!
|
||||
std::vector<Layer<MatType>*>& Network() { return network; }
|
||||
|
||||
//! Serialize the MultiLayer.
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Initialize memory that will be used by each layer for the forward pass,
|
||||
* assuming that the input will have the given `batchSize`. When `Forward()`
|
||||
* is called, each internally-held layer will output its results into the
|
||||
* memory allocated by this function (this is the internal member
|
||||
* `layerOutputMatrix` and its aliases `layerOutputs`).
|
||||
*/
|
||||
void InitializeForwardPassMemory(const size_t batchSize);
|
||||
|
||||
/**
|
||||
* Initialize memory that will be used by each layer for the backwards pass,
|
||||
* assuming that the input will have the given `batchSize`. When `Backward()`
|
||||
* is called, each internally-held layer will output the results of its
|
||||
* backwards pass into the memory allocated by this function (this is the
|
||||
* internal member `layerDeltaMatrix` and its aliases `layerDeltas`).
|
||||
*/
|
||||
void InitializeBackwardPassMemory(const size_t batchSize);
|
||||
|
||||
/**
|
||||
* Initialize memory for the gradient pass. This sets the internal aliases
|
||||
* `layerGradients` appropriately using the memory from the given `gradient`,
|
||||
* such that each layer will output its gradient (via its `Gradient()` method)
|
||||
* into the appropriate member of `layerGradients`.
|
||||
*/
|
||||
void InitializeGradientPassMemory(MatType& gradient);
|
||||
|
||||
//! The internally-held network.
|
||||
std::vector<Layer<MatType>*> network;
|
||||
|
||||
// Total number of elements in the input, cached for convenience.
|
||||
size_t inSize;
|
||||
// Total number of input elements for *every* layer.
|
||||
size_t totalInputSize;
|
||||
// Total number of output elements for *every* layer.
|
||||
size_t totalOutputSize;
|
||||
|
||||
//! This matrix stores all of the outputs of each layer when Forward() is
|
||||
//! called. See `InitializeForwardPassMemory()`.
|
||||
MatType layerOutputMatrix;
|
||||
//! These are aliases of `layerOutputMatrix` for each layer.
|
||||
std::vector<MatType> layerOutputs;
|
||||
|
||||
//! This matrix stores all of the backwards pass results of each layer when
|
||||
//! Backward() is called. See `InitializeBackwardPassMemory()`.
|
||||
MatType layerDeltaMatrix;
|
||||
//! These are aliases of `layerDeltaMatrix` for each layer.
|
||||
std::vector<MatType> layerDeltas;
|
||||
|
||||
//! Gradient aliases for each layer. Note that this is *only* valid in the
|
||||
//! context of `Gradient()`! We have it as a class member to avoid
|
||||
//! reallocating the `MatType`s each call to `Gradient()`.
|
||||
std::vector<MatType> layerGradients;
|
||||
};
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
// Include implementation.
|
||||
#include "multi_layer_impl.hpp"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,414 @@
|
||||
/**
|
||||
* @file methods/ann/layer/multi_layer_impl.hpp
|
||||
* @author Ryan Curtin
|
||||
*
|
||||
* Implementation of the base class for neural network layers that are wrappers
|
||||
* around other layers.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_MULTI_LAYER_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_MULTI_LAYER_IMPL_HPP
|
||||
|
||||
#include "multi_layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann {
|
||||
|
||||
template<typename MatType>
|
||||
MultiLayer<MatType>::MultiLayer() :
|
||||
inSize(0),
|
||||
totalInputSize(0),
|
||||
totalOutputSize(0)
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
MultiLayer<MatType>::MultiLayer(const MultiLayer& other) :
|
||||
Layer<MatType>(other),
|
||||
inSize(other.inSize),
|
||||
totalInputSize(other.totalInputSize),
|
||||
totalOutputSize(other.totalOutputSize),
|
||||
layerOutputMatrix(other.layerOutputMatrix),
|
||||
layerDeltaMatrix(other.layerDeltaMatrix)
|
||||
{
|
||||
// Copy each layer.
|
||||
for (size_t i = 0; i < other.network.size(); ++i)
|
||||
network.push_back(other.network[i]->Clone());
|
||||
|
||||
// Ensure that the aliases for layers during passes have the right size.
|
||||
layerOutputs.resize(network.size(), MatType());
|
||||
layerDeltas.resize(network.size(), MatType());
|
||||
layerGradients.resize(network.size(), MatType());
|
||||
|
||||
// layerOutputs, layerDeltas, and layerGradients will be reset the next time
|
||||
// Forward(), Backward(), or Gradient() is called.
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
MultiLayer<MatType>::MultiLayer(MultiLayer&& other) :
|
||||
Layer<MatType>(other),
|
||||
network(std::move(other.network)),
|
||||
inSize(std::move(other.inSize)),
|
||||
totalInputSize(std::move(other.totalInputSize)),
|
||||
totalOutputSize(std::move(other.totalOutputSize)),
|
||||
layerOutputMatrix(std::move(other.layerOutputMatrix)),
|
||||
layerDeltaMatrix(std::move(other.layerDeltaMatrix))
|
||||
{
|
||||
// Ensure that the aliases for layers during passes have the right size.
|
||||
layerOutputs.resize(network.size(), MatType());
|
||||
layerDeltas.resize(network.size(), MatType());
|
||||
layerGradients.resize(network.size(), MatType());
|
||||
|
||||
// layerOutputs, layerDeltas, and layerGradients will be reset the next time
|
||||
// Forward(), Backward(), or Gradient() is called.
|
||||
|
||||
other.layerOutputs.clear();
|
||||
other.layerDeltas.clear();
|
||||
other.layerGradients.clear();
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
MultiLayer<MatType>& MultiLayer<MatType>::operator=(const MultiLayer& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
Layer<MatType>::operator=(other);
|
||||
|
||||
network.clear();
|
||||
layerOutputs.clear();
|
||||
layerDeltas.clear();
|
||||
layerGradients.clear();
|
||||
|
||||
inSize = other.inSize;
|
||||
totalInputSize = other.totalInputSize;
|
||||
totalOutputSize = other.totalOutputSize;
|
||||
|
||||
layerOutputMatrix = other.layerOutputMatrix;
|
||||
layerDeltaMatrix = other.layerDeltaMatrix;
|
||||
|
||||
for (size_t i = 0; i < other.network.size(); ++i)
|
||||
network.push_back(other.network[i]->Clone());
|
||||
|
||||
// Ensure that the aliases for layers during passes have the right size.
|
||||
layerOutputs.resize(network.size(), MatType());
|
||||
layerDeltas.resize(network.size(), MatType());
|
||||
layerGradients.resize(network.size(), MatType());
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
MultiLayer<MatType>& MultiLayer<MatType>::operator=(MultiLayer&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
Layer<MatType>::operator=(other);
|
||||
|
||||
layerOutputs.clear();
|
||||
layerDeltas.clear();
|
||||
layerGradients.clear();
|
||||
|
||||
inSize = std::move(other.inSize);
|
||||
totalInputSize = std::move(other.totalInputSize);
|
||||
totalOutputSize = std::move(other.totalOutputSize);
|
||||
|
||||
network = std::move(other.network);
|
||||
|
||||
layerOutputs.resize(network.size(), MatType());
|
||||
layerDeltas.resize(network.size(), MatType());
|
||||
layerGradients.resize(network.size(), MatType());
|
||||
|
||||
other.layerOutputs.clear();
|
||||
other.layerDeltas.clear();
|
||||
other.layerGradients.clear();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void MultiLayer<MatType>::Forward(
|
||||
const MatType& input, MatType& output)
|
||||
{
|
||||
Forward(input, output, 0, network.size() - 1);
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void MultiLayer<MatType>::Forward(
|
||||
const MatType& input,
|
||||
MatType& output,
|
||||
const size_t start,
|
||||
const size_t end)
|
||||
{
|
||||
// Make sure training/testing mode is set right in each layer.
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
network[i]->Training() = this->training;
|
||||
|
||||
// Note that we use `output` for the last layer; layerOutputs is only used for
|
||||
// intermediate values between layers.
|
||||
if ((end - start) > 0)
|
||||
{
|
||||
// Initialize memory for the forward pass (if needed).
|
||||
InitializeForwardPassMemory(input.n_cols);
|
||||
|
||||
network[start]->Forward(input, layerOutputs[start]);
|
||||
for (size_t i = start + 1; i < end; ++i)
|
||||
network[i]->Forward(layerOutputs[i - 1], layerOutputs[i]);
|
||||
network[end]->Forward(layerOutputs[end - 1], output);
|
||||
}
|
||||
else if ((end - start) == 0 && network.size() > 0)
|
||||
{
|
||||
network[start]->Forward(input, output);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Empty network?
|
||||
output = input;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void MultiLayer<MatType>::Backward(
|
||||
const MatType& input, const MatType& gy, MatType& g)
|
||||
{
|
||||
if (network.size() > 1)
|
||||
{
|
||||
// Initialize memory for the backward pass (if needed).
|
||||
InitializeBackwardPassMemory(input.n_cols);
|
||||
|
||||
network.back()->Backward(input, gy, layerDeltas.back());
|
||||
for (size_t i = network.size() - 2; i > 0; --i)
|
||||
network[i]->Backward(layerOutputs[i], layerDeltas[i + 1], layerDeltas[i]);
|
||||
network[0]->Backward(layerOutputs[0], layerDeltas[1], g);
|
||||
}
|
||||
else if (network.size() == 1)
|
||||
{
|
||||
network[0]->Backward(input, gy, g);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Empty network?
|
||||
g = input;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void MultiLayer<MatType>::Gradient(
|
||||
const MatType& input, const MatType& error, MatType& gradient)
|
||||
{
|
||||
// We assume gradient has the right size already.
|
||||
|
||||
// Pass gradients through each layer.
|
||||
if (network.size() > 1)
|
||||
{
|
||||
// Initialize memory for the gradient pass (if needed).
|
||||
InitializeGradientPassMemory(gradient);
|
||||
|
||||
network.front()->Gradient(input, layerDeltas[1], layerGradients.front());
|
||||
for (size_t i = 1; i < network.size() - 1; ++i)
|
||||
{
|
||||
network[i]->Gradient(layerOutputs[i - 1], layerDeltas[i + 1],
|
||||
layerGradients[i]);
|
||||
}
|
||||
network.back()->Gradient(layerOutputs[network.size() - 2], error,
|
||||
layerGradients.back());
|
||||
}
|
||||
else if (network.size() == 1)
|
||||
{
|
||||
network[0]->Gradient(input, error, gradient);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing to do if the network is empty... there is no gradient.
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void MultiLayer<MatType>::SetWeights(typename MatType::elem_type* weightsPtr)
|
||||
{
|
||||
size_t start = 0;
|
||||
const size_t totalWeightSize = WeightSize();
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
const size_t weightSize = network[i]->WeightSize();
|
||||
|
||||
// Sanity check: ensure we aren't passing memory past the end of the
|
||||
// parameters.
|
||||
Log::Assert(start + weightSize <= totalWeightSize,
|
||||
"FNN::SetLayerMemory(): parameter size does not match total layer "
|
||||
"weight size!");
|
||||
|
||||
network[i]->SetWeights(weightsPtr + start);
|
||||
start += weightSize;
|
||||
}
|
||||
|
||||
// Technically this check should be unnecessary, but there's nothing wrong
|
||||
// with a little paranoia...
|
||||
Log::Assert(start == totalWeightSize,
|
||||
"FNN::SetLayerMemory(): total layer weight size does not match parameter "
|
||||
"size!");
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
size_t MultiLayer<MatType>::WeightSize() const
|
||||
{
|
||||
// Sum the weights in each layer.
|
||||
size_t total = 0;
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
total += network[i]->WeightSize();
|
||||
return total;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void MultiLayer<MatType>::ComputeOutputDimensions()
|
||||
{
|
||||
inSize = 0;
|
||||
totalInputSize = 0;
|
||||
totalOutputSize = 0;
|
||||
|
||||
// Propagate the input dimensions forward to the output.
|
||||
network.front()->InputDimensions() = this->inputDimensions;
|
||||
inSize = this->inputDimensions[0];
|
||||
for (size_t i = 1; i < this->inputDimensions.size(); ++i)
|
||||
inSize *= this->inputDimensions[i];
|
||||
totalInputSize += inSize;
|
||||
|
||||
for (size_t i = 1; i < network.size(); ++i)
|
||||
{
|
||||
network[i]->InputDimensions() = network[i - 1]->OutputDimensions();
|
||||
size_t layerInputSize = network[i]->InputDimensions()[0];
|
||||
for (size_t j = 1; j < network[i]->InputDimensions().size(); ++j)
|
||||
layerInputSize *= network[i]->InputDimensions()[j];
|
||||
|
||||
totalInputSize += layerInputSize;
|
||||
totalOutputSize += layerInputSize;
|
||||
}
|
||||
|
||||
size_t lastLayerSize = network.back()->OutputDimensions()[0];
|
||||
for (size_t i = 1; i < network.back()->OutputDimensions().size(); ++i)
|
||||
lastLayerSize *= network.back()->OutputDimensions()[i];
|
||||
|
||||
totalOutputSize += lastLayerSize;
|
||||
this->outputDimensions = network.back()->OutputDimensions();
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
double MultiLayer<MatType>::Loss() const
|
||||
{
|
||||
double loss = 0.0;
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
loss += network[i]->Loss();
|
||||
|
||||
return loss;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
template<typename Archive>
|
||||
void MultiLayer<MatType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_VECTOR_POINTER(network));
|
||||
ar(CEREAL_NVP(inSize));
|
||||
ar(CEREAL_NVP(totalInputSize));
|
||||
ar(CEREAL_NVP(totalOutputSize));
|
||||
|
||||
if (Archive::is_loading::value)
|
||||
{
|
||||
layerOutputMatrix.clear();
|
||||
layerDeltaMatrix.clear();
|
||||
layerGradients.clear();
|
||||
layerOutputs.resize(network.size(), MatType());
|
||||
layerDeltas.resize(network.size(), MatType());
|
||||
layerGradients.resize(network.size(), MatType());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void MultiLayer<MatType>::InitializeForwardPassMemory(const size_t batchSize)
|
||||
{
|
||||
// We need to initialize memory to store the output of each layer's Forward()
|
||||
// call. We'll do this all in one matrix, but, the size of this matrix
|
||||
// depends on the batch size we are using for computation. We avoid resizing
|
||||
// layerOutputMatrix down, unless we only need 10% or less of it.
|
||||
if (batchSize * totalOutputSize > layerOutputMatrix.n_elem ||
|
||||
batchSize * totalOutputSize <
|
||||
std::floor(0.1 * layerOutputMatrix.n_elem))
|
||||
{
|
||||
// All outputs will be represented by one big block of memory.
|
||||
layerOutputMatrix = MatType(1, batchSize * totalOutputSize);
|
||||
}
|
||||
|
||||
// Now, create an alias to the right place for each layer. We assume that
|
||||
// layerOutputs is already sized correctly (this should be done by Add()).
|
||||
size_t start = 0;
|
||||
for (size_t i = 0; i < layerOutputs.size(); ++i)
|
||||
{
|
||||
const size_t layerOutputSize = network[i]->OutputSize();
|
||||
MakeAlias(layerOutputs[i], layerOutputMatrix.colptr(start),
|
||||
layerOutputSize, batchSize);
|
||||
start += batchSize * layerOutputSize;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void MultiLayer<MatType>::InitializeBackwardPassMemory(
|
||||
const size_t batchSize)
|
||||
{
|
||||
// We need to initialize memory to store the output of each layer's Backward()
|
||||
// call. We do this similarly to InitializeForwardPassMemory(), but we must
|
||||
// store a matrix to use as the delta for each layer.
|
||||
if (batchSize * totalInputSize > layerDeltaMatrix.n_elem ||
|
||||
batchSize * totalInputSize < std::floor(0.1 * layerDeltaMatrix.n_elem))
|
||||
{
|
||||
// All deltas will be represented by one big block of memory.
|
||||
layerDeltaMatrix = MatType(1, batchSize * totalInputSize);
|
||||
}
|
||||
|
||||
// Now, create an alias to the right place for each layer. We assume that
|
||||
// layerDeltas is already sized correctly (this should be done by Add()).
|
||||
size_t start = 0;
|
||||
for (size_t i = 0; i < layerDeltas.size(); ++i)
|
||||
{
|
||||
size_t layerInputSize = 1;
|
||||
if (i == 0)
|
||||
{
|
||||
for (size_t j = 0; j < this->inputDimensions.size(); ++j)
|
||||
layerInputSize *= this->inputDimensions[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
layerInputSize = network[i - 1]->OutputSize();
|
||||
}
|
||||
MakeAlias(layerDeltas[i], layerDeltaMatrix.colptr(start), layerInputSize,
|
||||
batchSize);
|
||||
start += batchSize * layerInputSize;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void MultiLayer<MatType>::InitializeGradientPassMemory(MatType& gradient)
|
||||
{
|
||||
// We need to initialize memory to store the gradients of each layer. To do
|
||||
// this, we need to know the weight size of each layer.
|
||||
size_t gradientStart = 0;
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
const size_t weightSize = network[i]->WeightSize();
|
||||
MakeAlias(layerGradients[i], gradient.memptr() + gradientStart,
|
||||
weightSize, 1);
|
||||
gradientStart += weightSize;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/multiply_constant_impl.hpp
|
||||
* @author Marcus Edel
|
||||
*
|
||||
* Implementation of the MultiplyConstantLayer class, which multiplies the
|
||||
* input by a (non-learnable) constant.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_MULTIPLY_CONSTANT_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_MULTIPLY_CONSTANT_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "multiply_constant.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
MultiplyConstant<InputDataType, OutputDataType>::MultiplyConstant(
|
||||
const double scalar) : scalar(scalar)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
MultiplyConstant<InputDataType, OutputDataType>::MultiplyConstant(
|
||||
const MultiplyConstant& layer) :
|
||||
scalar(layer.scalar)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
MultiplyConstant<InputDataType, OutputDataType>::MultiplyConstant(
|
||||
MultiplyConstant&& layer) :
|
||||
scalar(std::move(layer.scalar))
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
MultiplyConstant<InputDataType, OutputDataType>&
|
||||
MultiplyConstant<InputDataType, OutputDataType>::operator=(
|
||||
const MultiplyConstant& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
{
|
||||
scalar = layer.scalar;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
MultiplyConstant<InputDataType, OutputDataType>&
|
||||
MultiplyConstant<InputDataType, OutputDataType>::operator=(
|
||||
MultiplyConstant&& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
{
|
||||
scalar = std::move(layer.scalar);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
void MultiplyConstant<InputDataType, OutputDataType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
output = input * scalar;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename DataType>
|
||||
void MultiplyConstant<InputDataType, OutputDataType>::Backward(
|
||||
const DataType& /* input */, const DataType& gy, DataType& g)
|
||||
{
|
||||
g = gy * scalar;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename Archive>
|
||||
void MultiplyConstant<InputDataType, OutputDataType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(scalar));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -1,190 +0,0 @@
|
||||
/**
|
||||
* @file methods/ann/layer/multiply_merge_impl.hpp
|
||||
* @author Haritha Nair
|
||||
*
|
||||
* Definition of the MultiplyMerge module which multiplies the output of the
|
||||
* given modules element-wise.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_MULTIPLY_MERGE_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_MULTIPLY_MERGE_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "multiply_merge.hpp"
|
||||
|
||||
#include "../visitor/forward_visitor.hpp"
|
||||
#include "../visitor/backward_visitor.hpp"
|
||||
#include "../visitor/gradient_visitor.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::MultiplyMerge(
|
||||
const bool model, const bool run) :
|
||||
model(model), run(run), ownsLayer(!model)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::MultiplyMerge(
|
||||
const MultiplyMerge& layer) :
|
||||
model(layer.model),
|
||||
run(layer.run),
|
||||
ownsLayer(layer.ownsLayer),
|
||||
network(layer.network),
|
||||
weights(layer.weights)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::MultiplyMerge(
|
||||
MultiplyMerge&& layer) :
|
||||
model(std::move(layer.model)),
|
||||
run(std::move(layer.run)),
|
||||
ownsLayer(std::move(layer.ownsLayer)),
|
||||
network(std::move(layer.network)),
|
||||
weights(std::move(layer.weights))
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>&
|
||||
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::operator=(
|
||||
const MultiplyMerge& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
{
|
||||
model = layer.model;
|
||||
run = layer.run;
|
||||
ownsLayer = layer.ownsLayer;
|
||||
network = layer.network;
|
||||
weights = layer.weights;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>&
|
||||
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::operator=(
|
||||
MultiplyMerge&& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
{
|
||||
model = std::move(layer.model);
|
||||
run = std::move(layer.run);
|
||||
ownsLayer = std::move(layer.ownsLayer);
|
||||
network = std::move(layer.network);
|
||||
weights = std::move(layer.weights);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::~MultiplyMerge()
|
||||
{
|
||||
if (ownsLayer)
|
||||
{
|
||||
std::for_each(network.begin(), network.end(),
|
||||
boost::apply_visitor(deleteVisitor));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename InputType, typename OutputType>
|
||||
void MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
if (run)
|
||||
{
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
boost::apply_visitor(ForwardVisitor(input,
|
||||
boost::apply_visitor(outputParameterVisitor, network[i])),
|
||||
network[i]);
|
||||
}
|
||||
}
|
||||
|
||||
output = boost::apply_visitor(outputParameterVisitor, network.front());
|
||||
for (size_t i = 1; i < network.size(); ++i)
|
||||
{
|
||||
output %= boost::apply_visitor(outputParameterVisitor, network[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::Backward(
|
||||
const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
|
||||
{
|
||||
if (run)
|
||||
{
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
boost::apply_visitor(BackwardVisitor(boost::apply_visitor(
|
||||
outputParameterVisitor, network[i]), gy,
|
||||
boost::apply_visitor(deltaVisitor, network[i])), network[i]);
|
||||
}
|
||||
|
||||
g = boost::apply_visitor(deltaVisitor, network[0]);
|
||||
for (size_t i = 1; i < network.size(); ++i)
|
||||
{
|
||||
g += boost::apply_visitor(deltaVisitor, network[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
g = gy;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename eT>
|
||||
void MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& /* gradient */ )
|
||||
{
|
||||
if (run)
|
||||
{
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
boost::apply_visitor(GradientVisitor(input, error), network[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType,
|
||||
typename... CustomLayers>
|
||||
template<typename Archive>
|
||||
void MultiplyMerge<InputDataType, OutputDataType, CustomLayers...>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
// Be sure to clear other layers before loading.
|
||||
if (cereal::is_loading<Archive>())
|
||||
network.clear();
|
||||
|
||||
ar(CEREAL_VECTOR_VARIANT_POINTER(network));
|
||||
ar(CEREAL_NVP(model));
|
||||
ar(CEREAL_NVP(run));
|
||||
ar(CEREAL_NVP(ownsLayer));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
@@ -21,55 +23,42 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* Implementation of the NoisyLinear layer class. It represents a single
|
||||
* layer of a neural network, with parametric noise added to its weights.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam MatType Matrix representation to accept as input and use for
|
||||
* computation.
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class NoisyLinear
|
||||
template<typename MatType = arma::mat>
|
||||
class NoisyLinearType : public Layer<MatType>
|
||||
{
|
||||
public:
|
||||
//! Create the NoisyLinear object.
|
||||
NoisyLinear();
|
||||
|
||||
/**
|
||||
* Create the NoisyLinear layer object using the specified number of units.
|
||||
*
|
||||
* @param inSize The number of input units.
|
||||
* @param outSize The number of output units.
|
||||
*/
|
||||
NoisyLinear(const size_t inSize,
|
||||
const size_t outSize);
|
||||
NoisyLinearType(const size_t outSize = 0);
|
||||
|
||||
//! Copy constructor.
|
||||
NoisyLinear(const NoisyLinear&);
|
||||
//! Clone the NoisyLinearType object. This handles polymorphism correctly.
|
||||
NoisyLinearType* Clone() const { return new NoisyLinearType(*this); }
|
||||
|
||||
//! Move constructor.
|
||||
NoisyLinear(NoisyLinear&&);
|
||||
// Virtual destructor.
|
||||
virtual ~NoisyLinearType() { }
|
||||
|
||||
//! Operator= copy constructor.
|
||||
NoisyLinear& operator=(const NoisyLinear& layer);
|
||||
//! Copy the given NoisyLinear layer (but not weights).
|
||||
NoisyLinearType(const NoisyLinearType& other);
|
||||
//! Take ownership of the given NoisyLinear layer (but not weights).
|
||||
NoisyLinearType(NoisyLinearType&& other);
|
||||
//! Copy the given NoisyLinear layer (but not weights).
|
||||
NoisyLinearType& operator=(const NoisyLinearType& other);
|
||||
//! Take ownership of the given NoisyLinear layer (but not weights).
|
||||
NoisyLinearType& operator=(NoisyLinearType&& other);
|
||||
|
||||
//! Operator= move constructor.
|
||||
NoisyLinear& operator=(NoisyLinear&& layer);
|
||||
//! Reset the layer parameter.
|
||||
void SetWeights(typename MatType::elem_type* weightsPtr);
|
||||
|
||||
/*
|
||||
* Reset the layer parameter.
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/*
|
||||
* Reset the noise parameters(epsilons).
|
||||
*/
|
||||
//! Reset the noise parameters (epsilons).
|
||||
void ResetNoise();
|
||||
|
||||
/*
|
||||
* Reset the values of layer parameters (factorized gaussian noise).
|
||||
*/
|
||||
//! Reset the values of layer parameters (factorized gaussian noise).
|
||||
void ResetParameters();
|
||||
|
||||
/**
|
||||
@@ -79,8 +68,7 @@ class NoisyLinear
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const MatType& input, MatType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
@@ -91,117 +79,80 @@ class NoisyLinear
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
void Backward(const MatType& /* input */,
|
||||
const MatType& gy,
|
||||
MatType& g);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
*
|
||||
* @param input The input parameter used for calculating the gradient.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient);
|
||||
void Gradient(const MatType& input,
|
||||
const MatType& error,
|
||||
MatType& gradient);
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
MatType const& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
|
||||
//! Get the input parameter.
|
||||
InputDataType const& InputParameter() const { return inputParameter; }
|
||||
//! Modify the input parameter.
|
||||
InputDataType& InputParameter() { return inputParameter; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the input size.
|
||||
size_t InputSize() const { return inSize; }
|
||||
|
||||
//! Get the output size.
|
||||
size_t OutputSize() const { return outSize; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return gradient; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return gradient; }
|
||||
MatType& Parameters() { return weights; }
|
||||
|
||||
//! Get the shape of the input.
|
||||
size_t InputShape() const
|
||||
{
|
||||
return inSize;
|
||||
}
|
||||
|
||||
//! Modify the bias weights of the layer.
|
||||
arma::mat& Bias() { return bias; }
|
||||
MatType& Bias() { return bias; }
|
||||
|
||||
//! Get size of weights.
|
||||
//! Compute the number of parameters in the layer.
|
||||
size_t WeightSize() const { return (outSize * inSize + outSize) * 2; }
|
||||
/**
|
||||
* Serialize the layer
|
||||
*/
|
||||
|
||||
//! Compute the output dimensions of the layer given `InputDimensions()`.
|
||||
void ComputeOutputDimensions();
|
||||
|
||||
//! Serialize the layer.
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally-stored number of input units.
|
||||
size_t inSize;
|
||||
|
||||
//! Locally-stored number of output units.
|
||||
size_t outSize;
|
||||
|
||||
//! Locally stored number of input units.
|
||||
size_t inSize;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
MatType weights;
|
||||
|
||||
//! Locally-stored weight parameters.
|
||||
OutputDataType weight;
|
||||
MatType weight;
|
||||
|
||||
//! Locally-stored weight-mean parameters.
|
||||
OutputDataType weightMu;
|
||||
MatType weightMu;
|
||||
|
||||
//! Locally-stored weight-standard-deviation parameters.
|
||||
OutputDataType weightSigma;
|
||||
MatType weightSigma;
|
||||
|
||||
//! Locally-stored weight-epsilon parameters.
|
||||
OutputDataType weightEpsilon;
|
||||
MatType weightEpsilon;
|
||||
|
||||
//! Locally-stored bias parameters.
|
||||
OutputDataType bias;
|
||||
MatType bias;
|
||||
|
||||
//! Locally-stored bias-mean parameters.
|
||||
OutputDataType biasMu;
|
||||
MatType biasMu;
|
||||
|
||||
//! Locally-stored bias-standard-deviation parameters.
|
||||
OutputDataType biasSigma;
|
||||
MatType biasSigma;
|
||||
|
||||
//! Locally-stored bias-epsilon parameters.
|
||||
OutputDataType biasEpsilon;
|
||||
MatType biasEpsilon;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
}; // class NoisyLinearType
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
// Convenience typedefs.
|
||||
|
||||
//! Locally-stored input parameter object.
|
||||
InputDataType inputParameter;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
}; // class NoisyLinear
|
||||
// Standard noisy linear layer.
|
||||
typedef NoisyLinearType<arma::mat> NoisyLinear;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
@@ -18,107 +18,92 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
NoisyLinear<InputDataType, OutputDataType>::NoisyLinear() :
|
||||
inSize(0),
|
||||
outSize(0)
|
||||
template<typename MatType>
|
||||
NoisyLinearType<MatType>::NoisyLinearType(const size_t outSize) :
|
||||
Layer<MatType>(),
|
||||
outSize(outSize),
|
||||
inSize(0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
NoisyLinear<InputDataType, OutputDataType>::NoisyLinear(
|
||||
const NoisyLinear& layer) :
|
||||
inSize(layer.inSize),
|
||||
outSize(layer.outSize),
|
||||
weights(layer.weights)
|
||||
template<typename MatType>
|
||||
NoisyLinearType<MatType>::NoisyLinearType(const NoisyLinearType& other) :
|
||||
Layer<MatType>(other),
|
||||
outSize(other.outSize),
|
||||
inSize(other.inSize)
|
||||
{
|
||||
Reset();
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
NoisyLinear<InputDataType, OutputDataType>::NoisyLinear(
|
||||
const size_t inSize,
|
||||
const size_t outSize) :
|
||||
inSize(inSize),
|
||||
outSize(outSize)
|
||||
template<typename MatType>
|
||||
NoisyLinearType<MatType>::NoisyLinearType(NoisyLinearType&& other) :
|
||||
Layer<MatType>(std::move(other)),
|
||||
outSize(std::move(other.outSize)),
|
||||
inSize(std::move(other.inSize))
|
||||
{
|
||||
weights.set_size(WeightSize(), 1);
|
||||
weightEpsilon.set_size(outSize, inSize);
|
||||
biasEpsilon.set_size(outSize, 1);
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
NoisyLinear<InputDataType, OutputDataType>::NoisyLinear(
|
||||
NoisyLinear&& layer) :
|
||||
inSize(std::move(layer.inSize)),
|
||||
outSize(std::move(layer.outSize)),
|
||||
weights(std::move(layer.weights))
|
||||
template<typename MatType>
|
||||
NoisyLinearType<MatType>&
|
||||
NoisyLinearType<MatType>::operator=(const NoisyLinearType& other)
|
||||
{
|
||||
layer.inSize = 0;
|
||||
layer.outSize = 0;
|
||||
layer.weights = nullptr;
|
||||
Reset();
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
NoisyLinear<InputDataType, OutputDataType>&
|
||||
NoisyLinear<InputDataType, OutputDataType>::operator=(const NoisyLinear& layer)
|
||||
{
|
||||
if (this != &layer)
|
||||
if (&other != this)
|
||||
{
|
||||
inSize = layer.inSize;
|
||||
outSize = layer.outSize;
|
||||
weights = layer.weights;
|
||||
Reset();
|
||||
Layer<MatType>::operator=(other);
|
||||
outSize = other.outSize;
|
||||
inSize = other.inSize;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
NoisyLinear<InputDataType, OutputDataType>&
|
||||
NoisyLinear<InputDataType, OutputDataType>::operator=(NoisyLinear&& layer)
|
||||
template<typename MatType>
|
||||
NoisyLinearType<MatType>&
|
||||
NoisyLinearType<MatType>::operator=(NoisyLinearType&& other)
|
||||
{
|
||||
if (this != &layer)
|
||||
if (&other != this)
|
||||
{
|
||||
inSize = std::move(layer.inSize);
|
||||
layer.inSize = 0;
|
||||
outSize = std::move(layer.outSize);
|
||||
layer.outSize = 0;
|
||||
weights = std::move(layer.weights);
|
||||
layer.weights = nullptr;
|
||||
Reset();
|
||||
Layer<MatType>::operator=(std::move(other));
|
||||
outSize = std::move(other.outSize);
|
||||
inSize = std::move(other.inSize);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
void NoisyLinear<InputDataType, OutputDataType>::Reset()
|
||||
template<typename MatType>
|
||||
void NoisyLinearType<MatType>::SetWeights(
|
||||
typename MatType::elem_type* weightsPtr)
|
||||
{
|
||||
weightMu = arma::mat(weights.memptr(),
|
||||
outSize, inSize, false, false);
|
||||
biasMu = arma::mat(weights.memptr() + weightMu.n_elem,
|
||||
outSize, 1, false, false);
|
||||
weightSigma = arma::mat(weights.memptr() + weightMu.n_elem + biasMu.n_elem,
|
||||
outSize, inSize, false, false);
|
||||
biasSigma = arma::mat(weights.memptr() + weightMu.n_elem * 2 + biasMu.n_elem,
|
||||
outSize, 1, false, false);
|
||||
MakeAlias(weights, weightsPtr, 1, (outSize * inSize + outSize) * 2);
|
||||
|
||||
MakeAlias(weightMu, weightsPtr, outSize, inSize);
|
||||
MakeAlias(biasMu, weightsPtr + weightMu.n_elem, outSize, 1);
|
||||
MakeAlias(weightSigma, weightsPtr + weightMu.n_elem + biasMu.n_elem, outSize,
|
||||
inSize);
|
||||
MakeAlias(biasSigma, weightsPtr + weightMu.n_elem * 2 + biasMu.n_elem,
|
||||
outSize, 1);
|
||||
|
||||
this->ResetNoise();
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
void NoisyLinear<InputDataType, OutputDataType>::ResetNoise()
|
||||
template<typename MatType>
|
||||
void NoisyLinearType<MatType>::ResetNoise()
|
||||
{
|
||||
arma::mat epsilonIn = arma::randn<arma::mat>(inSize, 1);
|
||||
MatType epsilonIn = arma::randn<MatType>(inSize, 1);
|
||||
epsilonIn = arma::sign(epsilonIn) % arma::sqrt(arma::abs(epsilonIn));
|
||||
arma::mat epsilonOut = arma::randn<arma::mat>(outSize, 1);
|
||||
|
||||
MatType epsilonOut = arma::randn<MatType>(outSize, 1);
|
||||
epsilonOut = arma::sign(epsilonOut) % arma::sqrt(arma::abs(epsilonOut));
|
||||
|
||||
weightEpsilon = epsilonOut * epsilonIn.t();
|
||||
biasEpsilon = epsilonOut;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
void NoisyLinear<InputDataType, OutputDataType>::ResetParameters()
|
||||
template<typename MatType>
|
||||
void NoisyLinearType<MatType>::ResetParameters()
|
||||
{
|
||||
const double muRange = 1 / std::sqrt(inSize);
|
||||
weightMu.randu();
|
||||
@@ -129,10 +114,8 @@ void NoisyLinear<InputDataType, OutputDataType>::ResetParameters()
|
||||
biasSigma.fill(0.5 / std::sqrt(outSize));
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void NoisyLinear<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
template<typename MatType>
|
||||
void NoisyLinearType<MatType>::Forward(const MatType& input, MatType& output)
|
||||
{
|
||||
weight = weightMu + weightSigma % weightEpsilon;
|
||||
bias = biasMu + biasSigma % biasEpsilon;
|
||||
@@ -140,23 +123,19 @@ void NoisyLinear<InputDataType, OutputDataType>::Forward(
|
||||
output.each_col() += bias;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void NoisyLinear<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
|
||||
template<typename MatType>
|
||||
void NoisyLinearType<MatType>::Backward(
|
||||
const MatType& /* input */, const MatType& gy, MatType& g)
|
||||
{
|
||||
g = weight.t() * gy;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void NoisyLinear<InputDataType, OutputDataType>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient)
|
||||
template<typename MatType>
|
||||
void NoisyLinearType<MatType>::Gradient(
|
||||
const MatType& input, const MatType& error, MatType& gradient)
|
||||
{
|
||||
// Locally stored to prevent multiplication twice.
|
||||
arma::mat weightGrad = error * input.t();
|
||||
MatType weightGrad = error * input.t();
|
||||
|
||||
// Gradients for mu values.
|
||||
gradient.rows(0, weight.n_elem - 1) = arma::vectorise(weightGrad);
|
||||
@@ -170,18 +149,34 @@ void NoisyLinear<InputDataType, OutputDataType>::Gradient(
|
||||
= arma::sum(error, 1) % biasEpsilon;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename MatType>
|
||||
void NoisyLinearType<MatType>::ComputeOutputDimensions()
|
||||
{
|
||||
inSize = this->inputDimensions[0];
|
||||
for (size_t i = 1; i < this->inputDimensions.size(); ++i)
|
||||
inSize *= this->inputDimensions[i];
|
||||
|
||||
this->outputDimensions = std::vector<size_t>(this->inputDimensions.size(),
|
||||
1);
|
||||
|
||||
// The NoisyLinear layer flattens its output.
|
||||
this->outputDimensions[0] = outSize;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
template<typename Archive>
|
||||
void NoisyLinear<InputDataType, OutputDataType>::serialize(
|
||||
void NoisyLinearType<MatType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(inSize));
|
||||
ar(CEREAL_NVP(outSize));
|
||||
ar(cereal::base_class<Layer<MatType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(outSize));
|
||||
ar(CEREAL_NVP(inSize));
|
||||
|
||||
// This is inefficient, but we have to allocate this memory so that
|
||||
// WeightSetVisitor gets the right size.
|
||||
if (cereal::is_loading<Archive>())
|
||||
weights.set_size((outSize * inSize + outSize) * 2, 1);
|
||||
{
|
||||
ResetNoise();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
Layers in this directory were written with the old boost::visitor interface. In
|
||||
[#2777](https://github.com/mlpack/mlpack/pull/2777), we adapted each layer to
|
||||
use inheritance instead. However, time did not permit the adaptation of all
|
||||
layers, and so remaining layers that have not yet been adapted are in this
|
||||
directory.
|
||||
|
||||
The intention is that we will work our way through layers in this directory,
|
||||
updating them to the new interface and re-enabling tests for them in separate,
|
||||
follow-up PRs. If you'd like to help out, you are more than welcome to!
|
||||
+38
-52
@@ -13,7 +13,9 @@
|
||||
#define MLPACK_METHODS_ANN_LAYER_ADAPTIVE_MAX_POOLING_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include "layer_types.hpp"
|
||||
|
||||
#include "layer.hpp"
|
||||
#include "max_pooling.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
@@ -21,20 +23,17 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
/**
|
||||
* Implementation of the AdaptiveMaxPooling layer.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam InputType The type of the layer's inputs. The layer automatically
|
||||
* cast inputs to this type (Default: arma::mat).
|
||||
* @tparam OutputType The type of the layer's Outputs. The layer automatically
|
||||
* cast inputs to this type (Default: arma::mat).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class AdaptiveMaxPooling
|
||||
template <typename InputType = arma::mat, typename OutputType = arma::mat>
|
||||
class AdaptiveMaxPoolingType : public Layer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
//! Create the AdaptiveMaxPooling object.
|
||||
AdaptiveMaxPooling();
|
||||
AdaptiveMaxPoolingType();
|
||||
|
||||
/**
|
||||
* Create the AdaptiveMaxPooling object.
|
||||
@@ -42,15 +41,16 @@ class AdaptiveMaxPooling
|
||||
* @param outputWidth Width of the output.
|
||||
* @param outputHeight Height of the output.
|
||||
*/
|
||||
AdaptiveMaxPooling(const size_t outputWidth,
|
||||
const size_t outputHeight);
|
||||
AdaptiveMaxPoolingType(const size_t outputWidth,
|
||||
const size_t outputHeight);
|
||||
|
||||
/**
|
||||
* Create the AdaptiveMaxPooling object.
|
||||
*
|
||||
* @param outputShape A two-value tuple indicating width and height of the output.
|
||||
* @param outputShape A two-value tuple indicating width and height of the
|
||||
* output.
|
||||
*/
|
||||
AdaptiveMaxPooling(const std::tuple<size_t, size_t>& outputShape);
|
||||
AdaptiveMaxPoolingType(const std::tuple<size_t, size_t>& outputShape);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -59,8 +59,7 @@ class AdaptiveMaxPooling
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, using 3rd-order tensors as
|
||||
@@ -71,48 +70,30 @@ class AdaptiveMaxPooling
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
|
||||
//! Get the output parameter.
|
||||
const OutputDataType& OutputParameter() const
|
||||
{ return poolingLayer.OutputParameter(); }
|
||||
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return poolingLayer.OutputParameter(); }
|
||||
|
||||
//! Get the delta.
|
||||
const OutputDataType& Delta() const { return poolingLayer.Delta(); }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return poolingLayer.Delta(); }
|
||||
|
||||
//! Get the input width.
|
||||
size_t InputWidth() const { return poolingLayer.InputWidth(); }
|
||||
//! Modify the input width.
|
||||
size_t& InputWidth() { return poolingLayer.InputWidth(); }
|
||||
|
||||
//! Get the input height.
|
||||
size_t InputHeight() const { return poolingLayer.InputHeight(); }
|
||||
//! Modify the input height.
|
||||
size_t& InputHeight() { return poolingLayer.InputHeight(); }
|
||||
void Backward(const InputType& input,
|
||||
const OutputType& gy,
|
||||
OutputType& g);
|
||||
|
||||
//! Get the output width.
|
||||
size_t OutputWidth() const { return outputWidth; }
|
||||
size_t const& OutputWidth() const { return outputWidth; }
|
||||
//! Modify the output width.
|
||||
size_t& OutputWidth() { return outputWidth; }
|
||||
|
||||
//! Get the output height.
|
||||
size_t OutputHeight() const { return outputHeight; }
|
||||
size_t const& OutputHeight() const { return outputHeight; }
|
||||
//! Modify the output height.
|
||||
size_t& OutputHeight() { return outputHeight; }
|
||||
|
||||
//! Get the input size.
|
||||
size_t InputSize() const { return poolingLayer.InputSize(); }
|
||||
//! Get the number of trainable weights.
|
||||
size_t WeightSize() const { return 0; }
|
||||
|
||||
//! Get the output size.
|
||||
size_t OutputSize() const { return poolingLayer.OutputSize(); }
|
||||
const std::vector<size_t>& OutputDimensions() const
|
||||
{
|
||||
std::vector<size_t> result(this->inputDimensions.size(), 1);
|
||||
result[0] = outputWidth;
|
||||
result[1] = outputHeight;
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Get the size of the weights.
|
||||
size_t WeightSize() const { return 0; }
|
||||
@@ -127,7 +108,7 @@ class AdaptiveMaxPooling
|
||||
/**
|
||||
* Initialize Kernel Size and Stride for Adaptive Pooling.
|
||||
*/
|
||||
void IntializeAdaptivePadding()
|
||||
void InitializeAdaptivePadding()
|
||||
{
|
||||
poolingLayer.StrideWidth() = std::floor(poolingLayer.InputWidth() /
|
||||
outputWidth);
|
||||
@@ -150,7 +131,7 @@ class AdaptiveMaxPooling
|
||||
}
|
||||
|
||||
//! Locally stored MaxPooling Object.
|
||||
MaxPooling<InputDataType, OutputDataType> poolingLayer;
|
||||
MaxPoolingType<InputType, OutputType> poolingLayer;
|
||||
|
||||
//! Locally-stored output width.
|
||||
size_t outputWidth;
|
||||
@@ -160,7 +141,12 @@ class AdaptiveMaxPooling
|
||||
|
||||
//! Locally-stored reset parameter used to initialize the layer once.
|
||||
bool reset;
|
||||
}; // class AdaptiveMaxPooling
|
||||
}; // class AdaptiveMaxPoolingType
|
||||
|
||||
// Convenience typedefs.
|
||||
|
||||
// Standard Adaptive max pooling layer.
|
||||
typedef AdaptiveMaxPoolingType<arma::mat, arma::mat> AdaptiveMaxPooling;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
+21
-21
@@ -18,61 +18,61 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
AdaptiveMaxPooling<InputDataType, OutputDataType>::AdaptiveMaxPooling()
|
||||
template<typename InputType, typename OutputType>
|
||||
AdaptiveMaxPoolingType<InputType, OutputType>::AdaptiveMaxPoolingType()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType>
|
||||
AdaptiveMaxPooling<InputDataType, OutputDataType>::AdaptiveMaxPooling(
|
||||
template <typename InputType, typename OutputType>
|
||||
AdaptiveMaxPoolingType<InputType, OutputType>::AdaptiveMaxPoolingType(
|
||||
const size_t outputWidth,
|
||||
const size_t outputHeight) :
|
||||
AdaptiveMaxPooling(std::tuple<size_t, size_t>(outputWidth, outputHeight))
|
||||
AdaptiveMaxPoolingType(std::tuple<size_t, size_t>(outputWidth, outputHeight))
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType>
|
||||
AdaptiveMaxPooling<InputDataType, OutputDataType>::AdaptiveMaxPooling(
|
||||
template <typename InputType, typename OutputType>
|
||||
AdaptiveMaxPoolingType<InputType, OutputType>::AdaptiveMaxPoolingType(
|
||||
const std::tuple<size_t, size_t>& outputShape):
|
||||
outputWidth(std::get<0>(outputShape)),
|
||||
outputHeight(std::get<1>(outputShape)),
|
||||
reset(false)
|
||||
{
|
||||
poolingLayer = ann::MaxPooling<>(0, 0);
|
||||
poolingLayer = ann::MaxPoolingType<InputType, OutputType>(0, 0);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void AdaptiveMaxPooling<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
template<typename InputType, typename OutputType>
|
||||
void AdaptiveMaxPoolingType<InputType, OutputType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
if (!reset)
|
||||
{
|
||||
IntializeAdaptivePadding();
|
||||
InitializeAdaptivePadding();
|
||||
reset = true;
|
||||
}
|
||||
|
||||
poolingLayer.Forward(input, output);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void AdaptiveMaxPooling<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
template<typename InputType, typename OutputType>
|
||||
void AdaptiveMaxPoolingType<InputType, OutputType>::Backward(
|
||||
const InputType& input,
|
||||
const OutputType& gy,
|
||||
OutputType& g)
|
||||
{
|
||||
poolingLayer.Backward(input, gy, g);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
template<typename Archive>
|
||||
void AdaptiveMaxPooling<InputDataType, OutputDataType>::serialize(
|
||||
void AdaptiveMaxPoolingType<InputType, OutputType>::serialize(
|
||||
Archive& ar,
|
||||
const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<InputType, OutputType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(outputWidth));
|
||||
ar(CEREAL_NVP(outputHeight));
|
||||
ar(CEREAL_NVP(reset));
|
||||
+39
-52
@@ -1,3 +1,4 @@
|
||||
// Maybe
|
||||
/**
|
||||
* @file methods/ann/layer/adaptive_mean_pooling.hpp
|
||||
* @author Kartik Dutt
|
||||
@@ -14,7 +15,9 @@
|
||||
#define MLPACK_METHODS_ANN_LAYER_ADAPTIVE_MEAN_POOLING_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include "layer_types.hpp"
|
||||
|
||||
#include "layer.hpp"
|
||||
#include "mean_pooling.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
@@ -22,20 +25,17 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
/**
|
||||
* Implementation of the AdaptiveMeanPooling.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam InputType The type of the layer's inputs. The layer automatically
|
||||
* cast inputs to this type (Default: arma::mat).
|
||||
* @tparam OutputType The type of the layer's Outputs. The layer automatically
|
||||
* cast inputs to this type (Default: arma::mat).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class AdaptiveMeanPooling
|
||||
template <typename InputType = arma::mat, typename OutputType = arma::mat>
|
||||
class AdaptiveMeanPoolingType : public Layer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
//! Create the AdaptiveMeanPooling object.
|
||||
AdaptiveMeanPooling();
|
||||
AdaptiveMeanPoolingType();
|
||||
|
||||
/**
|
||||
* Create the AdaptiveMeanPooling object.
|
||||
@@ -43,15 +43,16 @@ class AdaptiveMeanPooling
|
||||
* @param outputWidth Width of the output.
|
||||
* @param outputHeight Height of the output.
|
||||
*/
|
||||
AdaptiveMeanPooling(const size_t outputWidth,
|
||||
const size_t outputHeight);
|
||||
AdaptiveMeanPoolingType(const size_t outputWidth,
|
||||
const size_t outputHeight);
|
||||
|
||||
/**
|
||||
* Create the AdaptiveMeanPooling object.
|
||||
*
|
||||
* @param outputShape A two-value tuple indicating width and height of the output.
|
||||
* @param outputShape A two-value tuple indicating width and height of the
|
||||
* output.
|
||||
*/
|
||||
AdaptiveMeanPooling(const std::tuple<size_t, size_t>& outputShape);
|
||||
AdaptiveMeanPoolingType(const std::tuple<size_t, size_t>& outputShape);
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -60,8 +61,7 @@ class AdaptiveMeanPooling
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, using 3rd-order tensors as
|
||||
@@ -72,48 +72,30 @@ class AdaptiveMeanPooling
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
|
||||
//! Get the output parameter.
|
||||
const OutputDataType& OutputParameter() const
|
||||
{ return poolingLayer.OutputParameter(); }
|
||||
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return poolingLayer.OutputParameter(); }
|
||||
|
||||
//! Get the delta.
|
||||
const OutputDataType& Delta() const { return poolingLayer.Delta(); }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return poolingLayer.Delta(); }
|
||||
|
||||
//! Get the input width.
|
||||
size_t InputWidth() const { return poolingLayer.InputWidth(); }
|
||||
//! Modify the input width.
|
||||
size_t& InputWidth() { return poolingLayer.InputWidth(); }
|
||||
|
||||
//! Get the input height.
|
||||
size_t InputHeight() const { return poolingLayer.InputHeight(); }
|
||||
//! Modify the input height.
|
||||
size_t& InputHeight() { return poolingLayer.InputHeight(); }
|
||||
void Backward(const InputType& input,
|
||||
const OutputType& gy,
|
||||
OutputType& g);
|
||||
|
||||
//! Get the output width.
|
||||
size_t OutputWidth() const { return outputWidth; }
|
||||
size_t const& OutputWidth() const { return outputWidth; }
|
||||
//! Modify the output width.
|
||||
size_t& OutputWidth() { return outputWidth; }
|
||||
|
||||
//! Get the output height.
|
||||
size_t OutputHeight() const { return outputHeight; }
|
||||
size_t const& OutputHeight() const { return outputHeight; }
|
||||
//! Modify the output height.
|
||||
size_t& OutputHeight() { return outputHeight; }
|
||||
|
||||
//! Get the input size.
|
||||
size_t InputSize() const { return poolingLayer.InputSize(); }
|
||||
//! Get the number of trainable weights.
|
||||
size_t WeightSize() const { return 0; }
|
||||
|
||||
//! Get the output size.
|
||||
size_t OutputSize() const { return poolingLayer.OutputSize(); }
|
||||
const std::vector<size_t>& OutputDimensions() const
|
||||
{
|
||||
std::vector<size_t> result(this->inputDimensions);
|
||||
result[0] = outputWidth;
|
||||
result[1] = outputHeight;
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Get the size of the weights.
|
||||
size_t WeightSize() const { return 0; }
|
||||
@@ -128,7 +110,7 @@ class AdaptiveMeanPooling
|
||||
/**
|
||||
* Initialize Kernel Size and Stride for Adaptive Pooling.
|
||||
*/
|
||||
void IntializeAdaptivePadding()
|
||||
void InitializeAdaptivePadding()
|
||||
{
|
||||
poolingLayer.StrideWidth() = std::floor(poolingLayer.InputWidth() /
|
||||
outputWidth);
|
||||
@@ -151,7 +133,7 @@ class AdaptiveMeanPooling
|
||||
}
|
||||
|
||||
//! Locally stored MeanPooling Object.
|
||||
MeanPooling<InputDataType, OutputDataType> poolingLayer;
|
||||
MeanPoolingType<InputType, OutputType> poolingLayer;
|
||||
|
||||
//! Locally-stored output width.
|
||||
size_t outputWidth;
|
||||
@@ -161,7 +143,12 @@ class AdaptiveMeanPooling
|
||||
|
||||
//! Locally-stored reset parameter used to initialize the layer once.
|
||||
bool reset;
|
||||
}; // class AdaptiveMeanPooling
|
||||
}; // class AdaptiveMeanPoolingType
|
||||
|
||||
// Convenience typedefs.
|
||||
|
||||
// Standard Adaptive mean pooling layer.
|
||||
typedef AdaptiveMeanPoolingType<arma::mat, arma::mat> AdaptiveMeanPooling;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
+21
-21
@@ -18,61 +18,61 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
AdaptiveMeanPooling<InputDataType, OutputDataType>::AdaptiveMeanPooling()
|
||||
template<typename InputType, typename OutputType>
|
||||
AdaptiveMeanPoolingType<InputType, OutputType>::AdaptiveMeanPoolingType()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType>
|
||||
AdaptiveMeanPooling<InputDataType, OutputDataType>::AdaptiveMeanPooling(
|
||||
template <typename InputType, typename OutputType>
|
||||
AdaptiveMeanPoolingType<InputType, OutputType>::AdaptiveMeanPoolingType(
|
||||
const size_t outputWidth,
|
||||
const size_t outputHeight) :
|
||||
AdaptiveMeanPooling(std::tuple<size_t, size_t>(outputWidth, outputHeight))
|
||||
AdaptiveMeanPoolingType(std::tuple<size_t, size_t>(outputWidth, outputHeight))
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType>
|
||||
AdaptiveMeanPooling<InputDataType, OutputDataType>::AdaptiveMeanPooling(
|
||||
template <typename InputType, typename OutputType>
|
||||
AdaptiveMeanPoolingType<InputType, OutputType>::AdaptiveMeanPoolingType(
|
||||
const std::tuple<size_t, size_t>& outputShape):
|
||||
outputWidth(std::get<0>(outputShape)),
|
||||
outputHeight(std::get<1>(outputShape)),
|
||||
reset(false)
|
||||
{
|
||||
poolingLayer = ann::MeanPooling<>(0, 0);
|
||||
poolingLayer = ann::MeanPoolingType<InputType, OutputType>(0, 0);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void AdaptiveMeanPooling<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
template<typename InputType, typename OutputType>
|
||||
void AdaptiveMeanPoolingType<InputType, OutputType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
if (!reset)
|
||||
{
|
||||
IntializeAdaptivePadding();
|
||||
InitializeAdaptivePadding();
|
||||
reset = true;
|
||||
}
|
||||
|
||||
poolingLayer.Forward(input, output);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void AdaptiveMeanPooling<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
template<typename InputType, typename OutputType>
|
||||
void AdaptiveMeanPoolingType<InputType, OutputType>::Backward(
|
||||
const InputType& input,
|
||||
const OutputType& gy,
|
||||
OutputType& g)
|
||||
{
|
||||
poolingLayer.Backward(input, gy, g);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
template<typename Archive>
|
||||
void AdaptiveMeanPooling<InputDataType, OutputDataType>::serialize(
|
||||
void AdaptiveMeanPoolingType<InputType, OutputType>::serialize(
|
||||
Archive& ar,
|
||||
const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<InputType, OutputType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(outputWidth));
|
||||
ar(CEREAL_NVP(outputHeight));
|
||||
ar(CEREAL_NVP(reset));
|
||||
+29
-109
@@ -1,3 +1,4 @@
|
||||
// Temporarily drop.
|
||||
/**
|
||||
* @file methods/ann/layer/add_merge.hpp
|
||||
* @author Marcus Edel
|
||||
@@ -15,10 +16,6 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "../visitor/delete_visitor.hpp"
|
||||
#include "../visitor/delta_visitor.hpp"
|
||||
#include "../visitor/output_parameter_visitor.hpp"
|
||||
|
||||
#include "layer_types.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
@@ -28,18 +25,17 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* Implementation of the AddMerge module class. The AddMerge class accumulates
|
||||
* the output of various modules.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* @tparam InputType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* @tparam OutputType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam CustomLayers Additional custom layers that can be added.
|
||||
*/
|
||||
template<
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat,
|
||||
typename... CustomLayers
|
||||
typename InputType = arma::mat,
|
||||
typename OutputType = arma::mat
|
||||
>
|
||||
class AddMerge
|
||||
class AddMerge : public MultiLayer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -48,7 +44,7 @@ class AddMerge
|
||||
* @param model Expose all the network modules.
|
||||
* @param run Call the Forward/Backward method before the output is merged.
|
||||
*/
|
||||
AddMerge(const bool model = false, const bool run = true);
|
||||
AddMerge(const bool run = true);
|
||||
|
||||
/**
|
||||
* Create the AddMerge object using the specified parameters.
|
||||
@@ -57,7 +53,7 @@ class AddMerge
|
||||
* @param run Call the Forward/Backward method before the output is merged.
|
||||
* @param ownsLayers Delete the layers when this is deallocated.
|
||||
*/
|
||||
AddMerge(const bool model, const bool run, const bool ownsLayers);
|
||||
AddMerge(const bool run, const bool ownsLayers);
|
||||
|
||||
//! Destructor to release allocated memory.
|
||||
~AddMerge();
|
||||
@@ -69,8 +65,7 @@ class AddMerge
|
||||
* @param * (input) Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void Forward(const InputType& /* input */, OutputType& output);
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
@@ -81,10 +76,9 @@ class AddMerge
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
void Backward(const InputType& /* input */,
|
||||
const OutputType& gy,
|
||||
OutputType& g);
|
||||
|
||||
/**
|
||||
* This is the overload of Backward() that runs only a specific layer with
|
||||
@@ -95,10 +89,9 @@ class AddMerge
|
||||
* @param g The calculated gradient.
|
||||
* @param index The index of the layer to run.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g,
|
||||
void Backward(const InputType& /* input */,
|
||||
const OutputType& gy,
|
||||
OutputType& g,
|
||||
const size_t index);
|
||||
|
||||
/*
|
||||
@@ -108,10 +101,9 @@ class AddMerge
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient);
|
||||
void Gradient(const InputType& input,
|
||||
const OutputType& error,
|
||||
OutputType& gradient);
|
||||
|
||||
/*
|
||||
* This is the overload of Gradient() that runs a specific layer with the
|
||||
@@ -122,63 +114,24 @@ class AddMerge
|
||||
* @param gradient The calculated gradient.
|
||||
* @param The index of the layer to run.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient,
|
||||
void Gradient(const InputType& input,
|
||||
const OutputType& error,
|
||||
OutputType& gradient,
|
||||
const size_t index);
|
||||
|
||||
/*
|
||||
* Add a new module to the model.
|
||||
*
|
||||
* @param args The layer parameter.
|
||||
*/
|
||||
template <class LayerType, class... Args>
|
||||
void Add(Args... args) { network.push_back(new LayerType(args...)); }
|
||||
|
||||
/*
|
||||
* Add a new module to the model.
|
||||
*
|
||||
* @param layer The Layer to be added to the model.
|
||||
*/
|
||||
void Add(LayerTypes<CustomLayers...> layer) { network.push_back(layer); }
|
||||
|
||||
//! Get the input parameter.
|
||||
InputDataType const& InputParameter() const { return inputParameter; }
|
||||
//! Modify the input parameter.
|
||||
InputDataType& InputParameter() { return inputParameter; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Return the model modules.
|
||||
std::vector<LayerTypes<CustomLayers...> >& Model()
|
||||
{
|
||||
if (model)
|
||||
{
|
||||
return network;
|
||||
}
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
|
||||
//! Get the value of run parameter.
|
||||
bool Run() const { return run; }
|
||||
//! Modify the value of run parameter.
|
||||
bool& Run() { return run; }
|
||||
|
||||
const std::vector<size_t>& OutputDimensions() const
|
||||
{
|
||||
// Propagate input size to child layers.
|
||||
for (size_t i = 0; i < this->network.size(); ++i)
|
||||
this->network[i]->InputDimensions() = this->inputDimensions;
|
||||
return this->network.back()->OutputDimensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
*/
|
||||
@@ -186,9 +139,6 @@ class AddMerge
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Parameter which indicates if the modules should be exposed.
|
||||
bool model;
|
||||
|
||||
//! Parameter which indicates if the Forward/Backward method should be called
|
||||
//! before merging the output.
|
||||
bool run;
|
||||
@@ -196,36 +146,6 @@ class AddMerge
|
||||
//! We need this to know whether we should delete the internally-held layers
|
||||
//! in the destructor.
|
||||
bool ownsLayers;
|
||||
|
||||
//! Locally-stored network modules.
|
||||
std::vector<LayerTypes<CustomLayers...> > network;
|
||||
|
||||
//! Locally-stored empty list of modules.
|
||||
std::vector<LayerTypes<CustomLayers...> > empty;
|
||||
|
||||
//! Locally-stored delete visitor module object.
|
||||
DeleteVisitor deleteVisitor;
|
||||
|
||||
//! Locally-stored output parameter visitor module object.
|
||||
OutputParameterVisitor outputParameterVisitor;
|
||||
|
||||
//! Locally-stored delta visitor module object.
|
||||
DeltaVisitor deltaVisitor;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
|
||||
//! Locally-stored input parameter object.
|
||||
InputDataType inputParameter;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
}; // class AddMerge
|
||||
|
||||
} // namespace ann
|
||||
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* @file methods/ann/layer/add_merge_impl.hpp
|
||||
* @author Marcus Edel
|
||||
*
|
||||
* Definition of the AddMerge module which accumulates the output of the given
|
||||
* modules.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_ADD_MERGE_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_ADD_MERGE_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "add_merge.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
AddMerge<InputType, OutputType>::AddMerge(
|
||||
const bool run) :
|
||||
run(run), ownsLayers(true)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
AddMerge<InputType, OutputType>::AddMerge(
|
||||
const bool run, const bool ownsLayers) :
|
||||
run(run), ownsLayers(ownsLayers)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
AddMerge<InputType, OutputType>::~AddMerge()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void AddMerge<InputType, OutputType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
this->InitializeForwardPassMemory();
|
||||
|
||||
if (run)
|
||||
{
|
||||
for (size_t i = 0; i < this->network.size(); ++i)
|
||||
{
|
||||
this->network[i]->Forward(input, this->layerOutputs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
output = this->layerOutputs.front();
|
||||
for (size_t i = 1; i < this->network.size(); ++i)
|
||||
{
|
||||
output += this->layerOutputs[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void AddMerge<InputType, OutputType>::Backward(
|
||||
const InputType& /* input */,
|
||||
const OutputType& gy,
|
||||
OutputType& g)
|
||||
{
|
||||
this->InitializeBackwardPassMemory();
|
||||
|
||||
if (run)
|
||||
{
|
||||
for (size_t i = 0; i < this->network.size(); ++i)
|
||||
{
|
||||
this->network[i]->Backward(this->layerOutputs[i], gy,
|
||||
this->layerDeltas[i]);
|
||||
}
|
||||
|
||||
g = this->layerDeltas[0];
|
||||
for (size_t i = 1; i < this->network.size(); ++i)
|
||||
{
|
||||
g += this->layerDeltas[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g = gy;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void AddMerge<InputType, OutputType>::Backward(
|
||||
const InputType& /* input */,
|
||||
const OutputType& gy,
|
||||
OutputType& g,
|
||||
const size_t index)
|
||||
{
|
||||
this->network[index]->Backward(this->layerOutputs[index], gy, g);
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void AddMerge<InputType, OutputType>::Gradient(
|
||||
const InputType& input,
|
||||
const OutputType& error,
|
||||
OutputType& gradient)
|
||||
{
|
||||
if (run)
|
||||
{
|
||||
size_t start = 0;
|
||||
for (size_t i = 0; i < this->network.size(); ++i)
|
||||
{
|
||||
this->network[i]->Gradient(input, error, OutputType(gradient.colptr(start),
|
||||
1, this->network[i]->WeightSize(), false, true));
|
||||
start += this->network[i]->WeightSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void AddMerge<InputType, OutputType>::Gradient(
|
||||
const InputType& input,
|
||||
const OutputType& error,
|
||||
OutputType& gradient,
|
||||
const size_t index)
|
||||
{
|
||||
this->network[index]->Gradient(input, error, gradient);
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
template<typename Archive>
|
||||
void AddMerge<InputType, OutputType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<MultiLayer<InputType, OutputType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(run));
|
||||
ar(CEREAL_NVP(ownsLayers));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
+48
-69
@@ -1,3 +1,4 @@
|
||||
// Temporarily drop.
|
||||
/**
|
||||
* @file methods/ann/layer/atrous_convolution.hpp
|
||||
* @author Aarush Gupta
|
||||
@@ -46,10 +47,10 @@ template <
|
||||
typename ForwardConvolutionRule = NaiveConvolution<ValidConvolution>,
|
||||
typename BackwardConvolutionRule = NaiveConvolution<FullConvolution>,
|
||||
typename GradientConvolutionRule = NaiveConvolution<ValidConvolution>,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
typename InputType = arma::mat,
|
||||
typename OutputType = arma::mat
|
||||
>
|
||||
class AtrousConvolution
|
||||
class AtrousConvolution : public Layer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
//! Create the AtrousConvolution object.
|
||||
@@ -139,8 +140,7 @@ class AtrousConvolution
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
@@ -151,10 +151,9 @@ class AtrousConvolution
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
void Backward(const InputType& /* input */,
|
||||
const OutputType& gy,
|
||||
OutputType& g);
|
||||
|
||||
/*
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
@@ -163,101 +162,90 @@ class AtrousConvolution
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient);
|
||||
void Gradient(const InputType& /* input */,
|
||||
const OutputType& error,
|
||||
OutputType& gradient);
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
OutputType const& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
OutputType& Parameters() { return weights; }
|
||||
|
||||
//! Get the weight of the layer.
|
||||
arma::cube const& Weight() const { return weight; }
|
||||
const arma::Cube<typename OutputType::elem_type>& Weight() const
|
||||
{
|
||||
return weight;
|
||||
}
|
||||
//! Modify the weight of the layer.
|
||||
arma::cube& Weight() { return weight; }
|
||||
arma::Cube<typename OutputType::elem_type>& Weight() { return weight; }
|
||||
|
||||
const std::vector<size_t>& OutputDimensions() const
|
||||
{
|
||||
std::vector<size_t> result(inputDimensions.size(), 0);
|
||||
result[0] = outputWidth;
|
||||
result[1] = outputHeight;
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Get the bias of the layer.
|
||||
arma::mat const& Bias() const { return bias; }
|
||||
const OutputType& Bias() const { return bias; }
|
||||
//! Modify the bias of the layer.
|
||||
arma::mat& Bias() { return bias; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return gradient; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return gradient; }
|
||||
OutputType& Bias() { return bias; }
|
||||
|
||||
//! Get the input width.
|
||||
size_t InputWidth() const { return inputWidth; }
|
||||
const size_t& InputWidth() const { return inputWidth; }
|
||||
//! Modify input the width.
|
||||
size_t& InputWidth() { return inputWidth; }
|
||||
|
||||
//! Get the input height.
|
||||
size_t InputHeight() const { return inputHeight; }
|
||||
const size_t& InputHeight() const { return inputHeight; }
|
||||
//! Modify the input height.
|
||||
size_t& InputHeight() { return inputHeight; }
|
||||
|
||||
//! Get the output width.
|
||||
size_t OutputWidth() const { return outputWidth; }
|
||||
const size_t& OutputWidth() const { return outputWidth; }
|
||||
//! Modify the output width.
|
||||
size_t& OutputWidth() { return outputWidth; }
|
||||
|
||||
//! Get the output height.
|
||||
size_t OutputHeight() const { return outputHeight; }
|
||||
const size_t& OutputHeight() const { return outputHeight; }
|
||||
//! Modify the output height.
|
||||
size_t& OutputHeight() { return outputHeight; }
|
||||
|
||||
//! Get the input size.
|
||||
size_t InputSize() const { return inSize; }
|
||||
|
||||
//! Get the output size.
|
||||
size_t OutputSize() const { return outSize; }
|
||||
|
||||
//! Get the kernel width.
|
||||
size_t KernelWidth() const { return kernelWidth; }
|
||||
const size_t& KernelWidth() const { return kernelWidth; }
|
||||
//! Modify the kernel width.
|
||||
size_t& KernelWidth() { return kernelWidth; }
|
||||
|
||||
//! Get the kernel height.
|
||||
size_t KernelHeight() const { return kernelHeight; }
|
||||
const size_t& KernelHeight() const { return kernelHeight; }
|
||||
//! Modify the kernel height.
|
||||
size_t& KernelHeight() { return kernelHeight; }
|
||||
|
||||
//! Get the stride width.
|
||||
size_t StrideWidth() const { return strideWidth; }
|
||||
const size_t& StrideWidth() const { return strideWidth; }
|
||||
//! Modify the stride width.
|
||||
size_t& StrideWidth() { return strideWidth; }
|
||||
|
||||
//! Get the stride height.
|
||||
size_t StrideHeight() const { return strideHeight; }
|
||||
const size_t& StrideHeight() const { return strideHeight; }
|
||||
//! Modify the stride height.
|
||||
size_t& StrideHeight() { return strideHeight; }
|
||||
|
||||
//! Get the dilation rate on the X axis.
|
||||
size_t DilationWidth() const { return dilationWidth; }
|
||||
const size_t& DilationWidth() const { return dilationWidth; }
|
||||
//! Modify the dilation rate on the X axis.
|
||||
size_t& DilationWidth() { return dilationWidth; }
|
||||
|
||||
//! Get the dilation rate on the Y axis.
|
||||
size_t DilationHeight() const { return dilationHeight; }
|
||||
const size_t& DilationHeight() const { return dilationHeight; }
|
||||
//! Modify the dilation rate on the Y axis.
|
||||
size_t& DilationHeight() { return dilationHeight; }
|
||||
|
||||
//! Get the internal Padding layer.
|
||||
ann::Padding<> const& Padding() const { return padding; }
|
||||
PaddingType<InputType, OutputType> const& Padding() const { return padding; }
|
||||
//! Modify the internal Padding layer.
|
||||
ann::Padding<>& Padding() { return padding; }
|
||||
PaddingType<InputType, OutputType>& Padding() { return padding; }
|
||||
|
||||
//! Get size of the weight matrix.
|
||||
size_t WeightSize() const
|
||||
@@ -358,13 +346,13 @@ class AtrousConvolution
|
||||
size_t strideHeight;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
OutputType weights;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
arma::cube weight;
|
||||
arma::Cube<typename OutputType::elem_type> weight;
|
||||
|
||||
//! Locally-stored bias term object.
|
||||
arma::mat bias;
|
||||
OutputType bias;
|
||||
|
||||
//! Locally-stored input width.
|
||||
size_t inputWidth;
|
||||
@@ -385,28 +373,19 @@ class AtrousConvolution
|
||||
size_t dilationHeight;
|
||||
|
||||
//! Locally-stored transformed output parameter.
|
||||
arma::cube outputTemp;
|
||||
arma::Cube<typename OutputType::elem_type> outputTemp;
|
||||
|
||||
//! Locally-stored transformed padded input parameter.
|
||||
arma::cube inputPaddedTemp;
|
||||
arma::Cube<typename OutputType::elem_type> inputPaddedTemp;
|
||||
|
||||
//! Locally-stored transformed error parameter.
|
||||
arma::cube gTemp;
|
||||
arma::Cube<typename OutputType::elem_type> gTemp;
|
||||
|
||||
//! Locally-stored transformed gradient parameter.
|
||||
arma::cube gradientTemp;
|
||||
arma::Cube<typename OutputType::elem_type> gradientTemp;
|
||||
|
||||
//! Locally-stored padding layer.
|
||||
ann::Padding<> padding;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
PaddingType<InputType, OutputType> padding;
|
||||
}; // class AtrousConvolution
|
||||
|
||||
} // namespace ann
|
||||
+73
-76
@@ -23,15 +23,15 @@ template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
AtrousConvolution<
|
||||
ForwardConvolutionRule,
|
||||
BackwardConvolutionRule,
|
||||
GradientConvolutionRule,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
InputType,
|
||||
OutputType
|
||||
>::AtrousConvolution()
|
||||
{
|
||||
// Nothing to do here.
|
||||
@@ -41,15 +41,15 @@ template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
AtrousConvolution<
|
||||
ForwardConvolutionRule,
|
||||
BackwardConvolutionRule,
|
||||
GradientConvolutionRule,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
InputType,
|
||||
OutputType
|
||||
>::AtrousConvolution(
|
||||
const size_t inSize,
|
||||
const size_t outSize,
|
||||
@@ -86,15 +86,15 @@ template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
AtrousConvolution<
|
||||
ForwardConvolutionRule,
|
||||
BackwardConvolutionRule,
|
||||
GradientConvolutionRule,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
InputType,
|
||||
OutputType
|
||||
>::AtrousConvolution(
|
||||
const size_t inSize,
|
||||
const size_t outSize,
|
||||
@@ -143,49 +143,49 @@ AtrousConvolution<
|
||||
InitializeSamePadding(padWLeft, padWRight, padHTop, padHBottom);
|
||||
}
|
||||
|
||||
padding = ann::Padding<>(padWLeft, padWRight, padHTop, padHBottom);
|
||||
padding = PaddingType<InputType, OutputType>(padWLeft, padWRight, padHTop,
|
||||
padHBottom);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
void AtrousConvolution<
|
||||
ForwardConvolutionRule,
|
||||
BackwardConvolutionRule,
|
||||
GradientConvolutionRule,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
>::Reset()
|
||||
InputType,
|
||||
OutputType
|
||||
>::ResetWeights(typename OutputType::elem_type* weightsPtr)
|
||||
{
|
||||
weight = arma::cube(weights.memptr(), kernelWidth, kernelHeight,
|
||||
outSize * inSize, false, false);
|
||||
bias = arma::mat(weights.memptr() + weight.n_elem,
|
||||
outSize, 1, false, false);
|
||||
weight = arma::Cube<typename OutputType::elem_type>(weightsPtr, kernelWidth,
|
||||
kernelHeight, outSize * inSize, false, true);
|
||||
bias = OutputType(weightsPtr + weight.n_elem, outSize, 1, false, true);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
template<typename eT>
|
||||
void AtrousConvolution<
|
||||
ForwardConvolutionRule,
|
||||
BackwardConvolutionRule,
|
||||
GradientConvolutionRule,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
>::Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
InputType,
|
||||
OutputType
|
||||
>::Forward(const InputType& input, OutputType& output)
|
||||
{
|
||||
batchSize = input.n_cols;
|
||||
arma::cube inputTemp(const_cast<arma::Mat<eT>&>(input).memptr(),
|
||||
inputWidth, inputHeight, inSize * batchSize, false, false);
|
||||
arma::Cube<typename InputType::elem_type> inputTemp(
|
||||
const_cast<InputType&>(input).memptr(), inputWidth, inputHeight, inSize *
|
||||
batchSize, false, false);
|
||||
|
||||
if (padding.PadWLeft() != 0 || padding.PadWRight() != 0 ||
|
||||
padding.PadHTop() != 0 || padding.PadHBottom() != 0)
|
||||
@@ -207,8 +207,8 @@ void AtrousConvolution<
|
||||
padding.PadHTop(), padding.PadHBottom(), dilationHeight);
|
||||
|
||||
output.set_size(wConv * hConv * outSize, batchSize);
|
||||
outputTemp = arma::Cube<eT>(output.memptr(), wConv, hConv,
|
||||
outSize * batchSize, false, false);
|
||||
outputTemp = arma::Cube<typename OutputType::elem_type>(output.memptr(),
|
||||
wConv, hConv, outSize * batchSize, false, false);
|
||||
outputTemp.zeros();
|
||||
|
||||
for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap <
|
||||
@@ -222,7 +222,7 @@ void AtrousConvolution<
|
||||
|
||||
for (size_t inMap = 0; inMap < inSize; inMap++, outMapIdx++)
|
||||
{
|
||||
arma::Mat<eT> convOutput;
|
||||
OutputType convOutput;
|
||||
|
||||
if (padding.PadWLeft() != 0 || padding.PadWRight() != 0 ||
|
||||
padding.PadHTop() != 0 || padding.PadHBottom() != 0)
|
||||
@@ -252,25 +252,24 @@ template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
template<typename eT>
|
||||
void AtrousConvolution<
|
||||
ForwardConvolutionRule,
|
||||
BackwardConvolutionRule,
|
||||
GradientConvolutionRule,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
>::Backward(
|
||||
const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
|
||||
InputType,
|
||||
OutputType
|
||||
>::Backward(const InputType& /* input */, const OutputType& gy, OutputType& g)
|
||||
{
|
||||
arma::cube mappedError(((arma::Mat<eT>&) gy).memptr(), outputWidth,
|
||||
outputHeight, outSize * batchSize, false, false);
|
||||
arma::Cube<typename OutputType::elem_type> mappedError(
|
||||
((OutputType&) gy).memptr(), outputWidth, outputHeight, outSize *
|
||||
batchSize, false, false);
|
||||
|
||||
g.set_size(inputWidth * inputHeight * inSize, batchSize);
|
||||
gTemp = arma::Cube<eT>(g.memptr(), inputWidth, inputHeight,
|
||||
inSize * batchSize, false, false);
|
||||
gTemp = arma::Cube<typename OutputType::elem_type>(g.memptr(), inputWidth,
|
||||
inputHeight, inSize * batchSize, false, false);
|
||||
gTemp.zeros();
|
||||
|
||||
for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap <
|
||||
@@ -284,7 +283,7 @@ void AtrousConvolution<
|
||||
|
||||
for (size_t inMap = 0; inMap < inSize; inMap++, outMapIdx++)
|
||||
{
|
||||
arma::Mat<eT> output, rotatedFilter;
|
||||
OutputType output, rotatedFilter;
|
||||
Rotate180(weight.slice(outMapIdx), rotatedFilter);
|
||||
|
||||
BackwardConvolutionRule::Convolution(mappedError.slice(outMap),
|
||||
@@ -311,29 +310,30 @@ template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
template<typename eT>
|
||||
void AtrousConvolution<
|
||||
ForwardConvolutionRule,
|
||||
BackwardConvolutionRule,
|
||||
GradientConvolutionRule,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
InputType,
|
||||
OutputType
|
||||
>::Gradient(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient)
|
||||
const InputType& input,
|
||||
const OutputType& error,
|
||||
OutputType& gradient)
|
||||
{
|
||||
arma::cube mappedError(((arma::Mat<eT>&) error).memptr(), outputWidth,
|
||||
outputHeight, outSize * batchSize, false, false);
|
||||
arma::cube inputTemp(const_cast<arma::Mat<eT>&>(input).memptr(),
|
||||
inputWidth, inputHeight, inSize * batchSize, false, false);
|
||||
arma::Cube<typename OutputType::elem_type> mappedError(
|
||||
((OutputType&) error).memptr(), outputWidth, outputHeight, outSize *
|
||||
batchSize, false, false);
|
||||
arma::Cube<typename InputType::elem_type> inputTemp(
|
||||
const_cast<InputType&>(input).memptr(), inputWidth, inputHeight,
|
||||
inSize * batchSize, false, false);
|
||||
|
||||
gradient.set_size(weights.n_elem, 1);
|
||||
gradientTemp = arma::Cube<eT>(gradient.memptr(), weight.n_rows,
|
||||
weight.n_cols, weight.n_slices, false, false);
|
||||
gradientTemp = arma::Cube<typename OutputType::elem_type>(gradient.memptr(),
|
||||
weight.n_rows, weight.n_cols, weight.n_slices, false, false);
|
||||
gradientTemp.zeros();
|
||||
|
||||
for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap <
|
||||
@@ -347,7 +347,7 @@ void AtrousConvolution<
|
||||
|
||||
for (size_t inMap = 0; inMap < inSize; inMap++, outMapIdx++)
|
||||
{
|
||||
arma::Mat<eT> inputSlice;
|
||||
InputType inputSlice;
|
||||
if (padding.PadWLeft() != 0 || padding.PadWRight() != 0 ||
|
||||
padding.PadHTop() != 0 || padding.PadHBottom() != 0)
|
||||
{
|
||||
@@ -358,9 +358,9 @@ void AtrousConvolution<
|
||||
inputSlice = inputTemp.slice(inMap + batchCount * inSize);
|
||||
}
|
||||
|
||||
arma::Mat<eT> deltaSlice = mappedError.slice(outMap);
|
||||
OutputType deltaSlice = mappedError.slice(outMap);
|
||||
|
||||
arma::Mat<eT> output;
|
||||
OutputType output;
|
||||
GradientConvolutionRule::Convolution(inputSlice, deltaSlice,
|
||||
output, strideWidth, strideHeight, 1, 1);
|
||||
|
||||
@@ -404,18 +404,20 @@ template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
template<typename Archive>
|
||||
void AtrousConvolution<
|
||||
ForwardConvolutionRule,
|
||||
BackwardConvolutionRule,
|
||||
GradientConvolutionRule,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
InputType,
|
||||
OutputType
|
||||
>::serialize(Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<InputType, OutputType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(inSize));
|
||||
ar(CEREAL_NVP(outSize));
|
||||
ar(CEREAL_NVP(batchSize));
|
||||
@@ -430,27 +432,22 @@ void AtrousConvolution<
|
||||
ar(CEREAL_NVP(dilationWidth));
|
||||
ar(CEREAL_NVP(dilationHeight));
|
||||
ar(CEREAL_NVP(padding));
|
||||
|
||||
if (cereal::is_loading<Archive>())
|
||||
{
|
||||
weights.set_size((outSize * inSize * kernelWidth * kernelHeight) + outSize,
|
||||
1);
|
||||
}
|
||||
ar(CEREAL_NVP(weights));
|
||||
}
|
||||
|
||||
template<
|
||||
typename ForwardConvolutionRule,
|
||||
typename BackwardConvolutionRule,
|
||||
typename GradientConvolutionRule,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
void AtrousConvolution<
|
||||
ForwardConvolutionRule,
|
||||
BackwardConvolutionRule,
|
||||
GradientConvolutionRule,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
InputType,
|
||||
OutputType
|
||||
>::InitializeSamePadding(size_t& padWLeft,
|
||||
size_t& padWRight,
|
||||
size_t& padHTop,
|
||||
+27
-65
@@ -50,10 +50,10 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* arma::sp_mat or arma::cube).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
typename InputType = arma::mat,
|
||||
typename OutputType = arma::mat
|
||||
>
|
||||
class BatchNorm
|
||||
class BatchNorm : public Layer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
//! Create the BatchNorm object.
|
||||
@@ -74,9 +74,9 @@ class BatchNorm
|
||||
const double momentum = 0.1);
|
||||
|
||||
/**
|
||||
* Reset the layer parameters
|
||||
* Reset the layer parameters.
|
||||
*/
|
||||
void Reset();
|
||||
void SetWeights(typename OutputType::elem_type* weightsPtr);
|
||||
|
||||
/**
|
||||
* Forward pass of the Batch Normalization layer. Transforms the input data
|
||||
@@ -86,8 +86,7 @@ class BatchNorm
|
||||
* @param input Input data for the layer
|
||||
* @param output Resulting output activations.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
* Backward pass through the layer.
|
||||
@@ -96,10 +95,9 @@ class BatchNorm
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g);
|
||||
void Backward(const InputType& input,
|
||||
const OutputType& gy,
|
||||
OutputType& g);
|
||||
|
||||
/**
|
||||
* Calculate the gradient using the output delta and the input activations.
|
||||
@@ -108,45 +106,24 @@ class BatchNorm
|
||||
* @param error The calculated error
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Gradient(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient);
|
||||
void Gradient(const InputType& input,
|
||||
const OutputType& error,
|
||||
OutputType& gradient);
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
const OutputType& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return gradient; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return gradient; }
|
||||
|
||||
//! Get the value of deterministic parameter.
|
||||
bool Deterministic() const { return deterministic; }
|
||||
//! Modify the value of deterministic parameter.
|
||||
bool& Deterministic() { return deterministic; }
|
||||
OutputType& Parameters() { return weights; }
|
||||
|
||||
//! Get the mean over the training data.
|
||||
OutputDataType const& TrainingMean() const { return runningMean; }
|
||||
const OutputType& TrainingMean() const { return runningMean; }
|
||||
//! Modify the mean over the training data.
|
||||
OutputDataType& TrainingMean() { return runningMean; }
|
||||
OutputType& TrainingMean() { return runningMean; }
|
||||
|
||||
//! Get the variance over the training data.
|
||||
OutputDataType const& TrainingVariance() const { return runningVariance; }
|
||||
const OutputType& TrainingVariance() const { return runningVariance; }
|
||||
//! Modify the variance over the training data.
|
||||
OutputDataType& TrainingVariance() { return runningVariance; }
|
||||
OutputType& TrainingVariance() { return runningVariance; }
|
||||
|
||||
//! Get the number of input units / channels.
|
||||
size_t InputSize() const { return size; }
|
||||
@@ -187,25 +164,19 @@ class BatchNorm
|
||||
bool loading;
|
||||
|
||||
//! Locally-stored scale parameter.
|
||||
OutputDataType gamma;
|
||||
OutputType gamma;
|
||||
|
||||
//! Locally-stored shift parameter.
|
||||
OutputDataType beta;
|
||||
OutputType beta;
|
||||
|
||||
//! Locally-stored mean object.
|
||||
OutputDataType mean;
|
||||
OutputType mean;
|
||||
|
||||
//! Locally-stored variance object.
|
||||
OutputDataType variance;
|
||||
OutputType variance;
|
||||
|
||||
//! Locally-stored parameters.
|
||||
OutputDataType weights;
|
||||
|
||||
/**
|
||||
* If true then mean and variance over the training set will be considered
|
||||
* instead of being calculated over the batch.
|
||||
*/
|
||||
bool deterministic;
|
||||
OutputType weights;
|
||||
|
||||
//! Locally-stored running mean/variance counter.
|
||||
size_t count;
|
||||
@@ -215,25 +186,16 @@ class BatchNorm
|
||||
double averageFactor;
|
||||
|
||||
//! Locally-stored mean object.
|
||||
OutputDataType runningMean;
|
||||
OutputType runningMean;
|
||||
|
||||
//! Locally-stored variance object.
|
||||
OutputDataType runningVariance;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType gradient;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
OutputType runningVariance;
|
||||
|
||||
//! Locally-stored normalized input.
|
||||
arma::cube normalized;
|
||||
arma::Cube<typename InputType::elem_type> normalized;
|
||||
|
||||
//! Locally-stored zero mean input.
|
||||
arma::cube inputMean;
|
||||
arma::Cube<typename InputType::elem_type> inputMean;
|
||||
}; // class BatchNorm
|
||||
|
||||
} // namespace ann
|
||||
+64
-58
@@ -21,22 +21,21 @@
|
||||
namespace mlpack {
|
||||
namespace ann { /** Artificial Neural Network. */
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
BatchNorm<InputDataType, OutputDataType>::BatchNorm() :
|
||||
template<typename InputType, typename OutputType>
|
||||
BatchNorm<InputType, OutputType>::BatchNorm() :
|
||||
size(0),
|
||||
eps(1e-8),
|
||||
average(true),
|
||||
momentum(0.0),
|
||||
loading(false),
|
||||
deterministic(false),
|
||||
count(0),
|
||||
averageFactor(0.0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template <typename InputDataType, typename OutputDataType>
|
||||
BatchNorm<InputDataType, OutputDataType>::BatchNorm(
|
||||
template <typename InputType, typename OutputType>
|
||||
BatchNorm<InputType, OutputType>::BatchNorm(
|
||||
const size_t size,
|
||||
const double eps,
|
||||
const bool average,
|
||||
@@ -46,7 +45,6 @@ BatchNorm<InputDataType, OutputDataType>::BatchNorm(
|
||||
average(average),
|
||||
momentum(momentum),
|
||||
loading(false),
|
||||
deterministic(false),
|
||||
count(0),
|
||||
averageFactor(0.0)
|
||||
{
|
||||
@@ -55,13 +53,14 @@ BatchNorm<InputDataType, OutputDataType>::BatchNorm(
|
||||
runningVariance.ones(size, 1);
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
void BatchNorm<InputDataType, OutputDataType>::Reset()
|
||||
template<typename InputType, typename OutputType>
|
||||
void BatchNorm<InputType, OutputType>::SetWeights(
|
||||
typename OutputType::elem_type* weightsPtr)
|
||||
{
|
||||
// Gamma acts as the scaling parameters for the normalized output.
|
||||
gamma = arma::mat(weights.memptr(), size, 1, false, false);
|
||||
gamma = OutputType(weightsPtr, size, 1, false, false);
|
||||
// Beta acts as the shifting parameters for the normalized output.
|
||||
beta = arma::mat(weights.memptr() + gamma.n_elem, size, 1, false, false);
|
||||
beta = OutputType(weightsPtr + gamma.n_elem, size, 1, false, false);
|
||||
|
||||
if (!loading)
|
||||
{
|
||||
@@ -69,18 +68,16 @@ void BatchNorm<InputDataType, OutputDataType>::Reset()
|
||||
beta.fill(0.0);
|
||||
}
|
||||
|
||||
deterministic = false;
|
||||
loading = false;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void BatchNorm<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input,
|
||||
arma::Mat<eT>& output)
|
||||
template<typename InputType, typename OutputType>
|
||||
void BatchNorm<InputType, OutputType>::Forward(
|
||||
const InputType& input,
|
||||
OutputType& output)
|
||||
{
|
||||
Log::Assert(input.n_rows % size == 0, "Input features must be divisible \
|
||||
by feature maps.");
|
||||
Log::Assert(input.n_rows % size == 0, "Input features must be divisible "
|
||||
"by feature maps.");
|
||||
|
||||
const size_t batchSize = input.n_cols;
|
||||
const size_t inputSize = input.n_rows / size;
|
||||
@@ -89,7 +86,7 @@ void BatchNorm<InputDataType, OutputDataType>::Forward(
|
||||
output.set_size(arma::size(input));
|
||||
|
||||
// We will calculate minibatch norm on each channel / feature map.
|
||||
if (!deterministic)
|
||||
if (this->training)
|
||||
{
|
||||
// Check only during training, batch-size can be one during inference.
|
||||
if (batchSize == 1 && inputSize == 1)
|
||||
@@ -101,12 +98,14 @@ void BatchNorm<InputDataType, OutputDataType>::Forward(
|
||||
|
||||
// Input corresponds to output from convolution layer.
|
||||
// Use a cube for simplicity.
|
||||
arma::cube inputTemp(const_cast<arma::Mat<eT>&>(input).memptr(),
|
||||
inputSize, size, batchSize, false, false);
|
||||
arma::Cube<typename InputType::elem_type> inputTemp(
|
||||
const_cast<InputType&>(input).memptr(), inputSize, size, batchSize,
|
||||
false, false);
|
||||
|
||||
// Initialize output to same size and values for convenience.
|
||||
arma::cube outputTemp(const_cast<arma::Mat<eT>&>(output).memptr(),
|
||||
inputSize, size, batchSize, false, false);
|
||||
arma::Cube<typename OutputType::elem_type> outputTemp(
|
||||
const_cast<OutputType&>(output).memptr(), inputSize, size, batchSize,
|
||||
false, false);
|
||||
outputTemp = inputTemp;
|
||||
|
||||
// Calculate mean and variance over all channels.
|
||||
@@ -152,8 +151,9 @@ void BatchNorm<InputDataType, OutputDataType>::Forward(
|
||||
{
|
||||
// Normalize the input and scale and shift the output.
|
||||
output = input;
|
||||
arma::cube outputTemp(const_cast<arma::Mat<eT>&>(output).memptr(),
|
||||
input.n_rows / size, size, batchSize, false, false);
|
||||
arma::Cube<typename OutputType::elem_type> outputTemp(
|
||||
const_cast<OutputType&>(output).memptr(), input.n_rows / size, size,
|
||||
batchSize, false, false);
|
||||
|
||||
outputTemp.each_slice() -= arma::repmat(runningMean.t(),
|
||||
input.n_rows / size, 1);
|
||||
@@ -166,28 +166,29 @@ void BatchNorm<InputDataType, OutputDataType>::Forward(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void BatchNorm<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& gy,
|
||||
arma::Mat<eT>& g)
|
||||
template<typename InputType, typename OutputType>
|
||||
void BatchNorm<InputType, OutputType>::Backward(
|
||||
const InputType& input,
|
||||
const OutputType& gy,
|
||||
OutputType& g)
|
||||
{
|
||||
const arma::mat stdInv = 1.0 / arma::sqrt(variance + eps);
|
||||
|
||||
g.set_size(arma::size(input));
|
||||
arma::cube gyTemp(const_cast<arma::Mat<eT>&>(gy).memptr(),
|
||||
input.n_rows / size, size, input.n_cols, false, false);
|
||||
arma::cube gTemp(const_cast<arma::Mat<eT>&>(g).memptr(),
|
||||
input.n_rows / size, size, input.n_cols, false, false);
|
||||
arma::Cube<typename OutputType::elem_type> gyTemp(
|
||||
const_cast<OutputType&>(gy).memptr(), input.n_rows / size, size,
|
||||
input.n_cols, false, false);
|
||||
arma::Cube<typename OutputType::elem_type> gTemp(
|
||||
const_cast<OutputType&>(g).memptr(), input.n_rows / size, size,
|
||||
input.n_cols, false, false);
|
||||
|
||||
// Step 1: dl / dxhat.
|
||||
arma::cube norm = gyTemp.each_slice() % arma::repmat(gamma.t(),
|
||||
input.n_rows / size, 1);
|
||||
arma::Cube<typename OutputType::elem_type> norm =
|
||||
gyTemp.each_slice() % arma::repmat(gamma.t(), input.n_rows / size, 1);
|
||||
|
||||
// Step 2: sum dl / dxhat * (x - mu) * -0.5 * stdInv^3.
|
||||
arma::mat temp = arma::sum(norm % inputMean, 2);
|
||||
arma::mat vars = temp % arma::repmat(arma::pow(stdInv, 3),
|
||||
OutputType temp = arma::sum(norm % inputMean, 2);
|
||||
OutputType vars = temp % arma::repmat(arma::pow(stdInv, 3),
|
||||
input.n_rows / size, 1) * -0.5;
|
||||
|
||||
// Step 3: dl / dxhat * 1 / stdInv + variance * 2 * (x - mu) / m +
|
||||
@@ -198,25 +199,25 @@ void BatchNorm<InputDataType, OutputDataType>::Backward(
|
||||
|
||||
// Step 4: sum (dl / dxhat * -1 / stdInv) + variance *
|
||||
// (sum -2 * (x - mu)) / m.
|
||||
arma::mat normTemp = arma::sum(norm.each_slice() %
|
||||
OutputType normTemp = arma::sum(norm.each_slice() %
|
||||
arma::repmat(-stdInv, input.n_rows / size, 1) , 2) /
|
||||
input.n_cols;
|
||||
gTemp.each_slice() += normTemp;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void BatchNorm<InputDataType, OutputDataType>::Gradient(
|
||||
const arma::Mat<eT>& /* input */,
|
||||
const arma::Mat<eT>& error,
|
||||
arma::Mat<eT>& gradient)
|
||||
template<typename InputType, typename OutputType>
|
||||
void BatchNorm<InputType, OutputType>::Gradient(
|
||||
const InputType& /* input */,
|
||||
const OutputType& error,
|
||||
OutputType& gradient)
|
||||
{
|
||||
gradient.set_size(size + size, 1);
|
||||
arma::cube errorTemp(const_cast<arma::Mat<eT>&>(error).memptr(),
|
||||
error.n_rows / size, size, error.n_cols, false, false);
|
||||
arma::Cube<typename OutputType::elem_type> errorTemp(
|
||||
const_cast<OutputType&>(error).memptr(), error.n_rows / size, size,
|
||||
error.n_cols, false, false);
|
||||
|
||||
// Step 5: dl / dy * xhat.
|
||||
arma::mat temp = arma::sum(arma::sum(normalized % errorTemp, 0), 2);
|
||||
OutputType temp = arma::sum(arma::sum(normalized % errorTemp, 0), 2);
|
||||
gradient.submat(0, 0, gamma.n_elem - 1, 0) = temp.t();
|
||||
|
||||
// Step 6: dl / dy.
|
||||
@@ -224,22 +225,27 @@ void BatchNorm<InputDataType, OutputDataType>::Gradient(
|
||||
gradient.submat(gamma.n_elem, 0, gradient.n_elem - 1, 0) = temp.t();
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
template<typename Archive>
|
||||
void BatchNorm<InputDataType, OutputDataType>::serialize(
|
||||
void BatchNorm<InputType, OutputType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<InputType, OutputType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(size));
|
||||
|
||||
if (cereal::is_loading<Archive>())
|
||||
{
|
||||
weights.set_size(size + size, 1);
|
||||
loading = true;
|
||||
}
|
||||
|
||||
ar(CEREAL_NVP(eps));
|
||||
ar(CEREAL_NVP(gamma));
|
||||
ar(CEREAL_NVP(beta));
|
||||
ar(CEREAL_NVP(weights));
|
||||
|
||||
if (Archive::is_loading::value)
|
||||
{
|
||||
// Gamma acts as the scaling parameters for the normalized output.
|
||||
gamma = arma::mat(weights.memptr(), size, 1, false, false);
|
||||
// Beta acts as the shifting parameters for the normalized output.
|
||||
beta = arma::mat(weights.memptr() + gamma.n_elem, size, 1, false, false);
|
||||
}
|
||||
|
||||
ar(CEREAL_NVP(count));
|
||||
ar(CEREAL_NVP(averageFactor));
|
||||
ar(CEREAL_NVP(momentum));
|
||||
+32
-64
@@ -1,3 +1,4 @@
|
||||
// Temporarily drop.
|
||||
/**
|
||||
* @file methods/ann/layer/bilinear_interpolation.hpp
|
||||
* @author Kris Singh
|
||||
@@ -27,35 +28,30 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* different known points in the grid. This way, we represent any arbitrary
|
||||
* point, present within the grid, as a function of those four points.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* @tparam InputType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* @tparam OutputType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
typename InputType = arma::mat,
|
||||
typename OutputType = arma::mat
|
||||
>
|
||||
class BilinearInterpolation
|
||||
class BilinearInterpolationType : public Layer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
//! Create the Bilinear Interpolation object.
|
||||
BilinearInterpolation();
|
||||
//! Create the BilinearInterpolationType object.
|
||||
BilinearInterpolationType();
|
||||
|
||||
/**
|
||||
* The constructor for the Bilinear Interpolation.
|
||||
* The constructor for the Bilinear Interpolation. The input size will be set
|
||||
* by the given input when the layer is used.
|
||||
*
|
||||
* @param inRowSize Number of input rows.
|
||||
* @param inColSize Number of input columns.
|
||||
* @param outRowSize Number of output rows.
|
||||
* @param outColSize Number of output columns.
|
||||
* @param depth Number of input slices.
|
||||
*/
|
||||
BilinearInterpolation(const size_t inRowSize,
|
||||
const size_t inColSize,
|
||||
const size_t outRowSize,
|
||||
const size_t outColSize,
|
||||
const size_t depth);
|
||||
BilinearInterpolationType(const size_t outRowSize,
|
||||
const size_t outColSize);
|
||||
|
||||
/**
|
||||
* Forward pass through the layer. The layer interpolates
|
||||
@@ -64,8 +60,7 @@ class BilinearInterpolation
|
||||
* @param input The input matrix.
|
||||
* @param output The resulting interpolated output matrix.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output);
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, calculating the function
|
||||
@@ -78,30 +73,22 @@ class BilinearInterpolation
|
||||
* @param gradient The computed backward gradient.
|
||||
* @param output The resulting down-sampled output.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& /*input*/,
|
||||
const arma::Mat<eT>& gradient,
|
||||
arma::Mat<eT>& output);
|
||||
void Backward(const InputType& /*input*/,
|
||||
const OutputType& gradient,
|
||||
OutputType& output);
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the row size of the input.
|
||||
size_t const& InRowSize() const { return inRowSize; }
|
||||
//! Modify the row size of the input.
|
||||
size_t& InRowSize() { return inRowSize; }
|
||||
|
||||
//! Get the column size of the input.
|
||||
size_t const& InColSize() const { return inColSize; }
|
||||
//! Modify the column size of the input.
|
||||
size_t& InColSize() { return inColSize; }
|
||||
const std::vector<size_t>& OutputDimensions() const
|
||||
{
|
||||
std::vector<size_t> result(this->inputDimensions.size(), 0);
|
||||
result[0] = outRowSize;
|
||||
result[1] = outColSize;
|
||||
if (result.size() > 2)
|
||||
{
|
||||
for (size_t i = 0; i < result.size(); ++i)
|
||||
result[i] = this->inputDimensions[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Get the row size of the output.
|
||||
size_t const& OutRowSize() const { return outRowSize; }
|
||||
@@ -113,17 +100,6 @@ class BilinearInterpolation
|
||||
//! Modify the column size of the output.
|
||||
size_t& OutColSize() { return outColSize; }
|
||||
|
||||
//! Get the depth of the input.
|
||||
size_t const& InDepth() const { return depth; }
|
||||
//! Modify the depth of the input.
|
||||
size_t& InDepth() { return depth; }
|
||||
|
||||
//! Get the shape of the input.
|
||||
size_t InputShape() const
|
||||
{
|
||||
return inRowSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
*/
|
||||
@@ -131,24 +107,16 @@ class BilinearInterpolation
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally stored row size of the input.
|
||||
size_t inRowSize;
|
||||
//! Locally stored column size of the input.
|
||||
size_t inColSize;
|
||||
//! Locally stored row size of the output.
|
||||
size_t outRowSize;
|
||||
|
||||
//! Locally stored column size of the input.
|
||||
size_t outColSize;
|
||||
//! Locally stored depth of the input.
|
||||
size_t depth;
|
||||
//! Locally stored number of input points.
|
||||
size_t batchSize;
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
}; // class BilinearInterpolation
|
||||
|
||||
// Standard BilinearInterpolation layer.
|
||||
typedef BilinearInterpolationType<arma::mat, arma::mat> BilinearInterpolation;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
+55
-72
@@ -19,69 +19,54 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
BilinearInterpolation<InputDataType, OutputDataType>::
|
||||
BilinearInterpolation():
|
||||
inRowSize(0),
|
||||
inColSize(0),
|
||||
template<typename InputType, typename OutputType>
|
||||
BilinearInterpolationType<InputType, OutputType>::
|
||||
BilinearInterpolationType():
|
||||
outRowSize(0),
|
||||
outColSize(0),
|
||||
depth(0),
|
||||
batchSize(0)
|
||||
outColSize(0)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
BilinearInterpolation<InputDataType, OutputDataType>::
|
||||
BilinearInterpolation(
|
||||
const size_t inRowSize,
|
||||
const size_t inColSize,
|
||||
const size_t outRowSize,
|
||||
const size_t outColSize,
|
||||
const size_t depth):
|
||||
inRowSize(inRowSize),
|
||||
inColSize(inColSize),
|
||||
template<typename InputType, typename OutputType>
|
||||
BilinearInterpolationType<InputType, OutputType>::
|
||||
BilinearInterpolationType(const size_t outRowSize,
|
||||
const size_t outColSize) :
|
||||
outRowSize(outRowSize),
|
||||
outColSize(outColSize),
|
||||
depth(depth),
|
||||
batchSize(0)
|
||||
outColSize(outColSize)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void BilinearInterpolation<InputDataType, OutputDataType>::Forward(
|
||||
const arma::Mat<eT>& input, arma::Mat<eT>& output)
|
||||
template<typename InputType, typename OutputType>
|
||||
void BilinearInterpolationType<InputType, OutputType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
batchSize = input.n_cols;
|
||||
if (output.is_empty())
|
||||
output.set_size(outRowSize * outColSize * depth, batchSize);
|
||||
else
|
||||
{
|
||||
assert(output.n_rows == outRowSize * outColSize * depth);
|
||||
assert(output.n_cols == batchSize);
|
||||
}
|
||||
const size_t batchSize = input.n_cols;
|
||||
const size_t depth = this->inputDimensions.size() <= 2 ? 1 :
|
||||
std::accumulate(this->inputDimensions.begin() + 2, this->inputDimensions.end(), 0);
|
||||
|
||||
assert(inRowSize >= 2);
|
||||
assert(inColSize >= 2);
|
||||
assert(output.n_rows == outRowSize * outColSize * depth);
|
||||
assert(output.n_cols == batchSize);
|
||||
|
||||
arma::cube inputAsCube(const_cast<arma::Mat<eT>&>(input).memptr(),
|
||||
inRowSize, inColSize, depth * batchSize, false, false);
|
||||
arma::cube outputAsCube(output.memptr(), outRowSize, outColSize,
|
||||
depth * batchSize, false, true);
|
||||
assert(this->inputDimensions[0] >= 2);
|
||||
assert(this->inputDimensions[1] >= 2);
|
||||
|
||||
double scaleRow = (double) inRowSize / (double) outRowSize;
|
||||
double scaleCol = (double) inColSize / (double) outColSize;
|
||||
arma::Cube<typename InputType::elem_type> inputAsCube(
|
||||
const_cast<InputType&>(input).memptr(), this->inputDimensions[0],
|
||||
this->inputDimensions[1], depth * batchSize, false, false);
|
||||
arma::Cube<typename OutputType::elem_type> outputAsCube(
|
||||
output.memptr(), outRowSize, outColSize, depth * batchSize, false, true);
|
||||
|
||||
double scaleRow = (double) this->inputDimensions[0] / (double) outRowSize;
|
||||
double scaleCol = (double) this->inputDimensions[1] / (double) outColSize;
|
||||
|
||||
arma::mat22 coeffs;
|
||||
for (size_t i = 0; i < outRowSize; ++i)
|
||||
{
|
||||
size_t rOrigin = (size_t) std::floor(i * scaleRow);
|
||||
if (rOrigin > inRowSize - 2)
|
||||
rOrigin = inRowSize - 2;
|
||||
if (rOrigin > this->inputDimensions[0] - 2)
|
||||
rOrigin = this->inputDimensions[0] - 2;
|
||||
|
||||
// Scaled distance of the interpolated point from the topmost row.
|
||||
double deltaR = i * scaleRow - rOrigin;
|
||||
@@ -91,8 +76,8 @@ void BilinearInterpolation<InputDataType, OutputDataType>::Forward(
|
||||
{
|
||||
// Scaled distance of the interpolated point from the leftmost column.
|
||||
size_t cOrigin = (size_t) std::floor(j * scaleCol);
|
||||
if (cOrigin > inColSize - 2)
|
||||
cOrigin = inColSize - 2;
|
||||
if (cOrigin > this->inputDimensions[1] - 2)
|
||||
cOrigin = this->inputDimensions[1] - 2;
|
||||
|
||||
double deltaC = j * scaleCol - cOrigin;
|
||||
if (deltaC > 1)
|
||||
@@ -111,28 +96,27 @@ void BilinearInterpolation<InputDataType, OutputDataType>::Forward(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename eT>
|
||||
void BilinearInterpolation<InputDataType, OutputDataType>::Backward(
|
||||
const arma::Mat<eT>& /*input*/,
|
||||
const arma::Mat<eT>& gradient,
|
||||
arma::Mat<eT>& output)
|
||||
template<typename InputType, typename OutputType>
|
||||
void BilinearInterpolationType<InputType, OutputType>::Backward(
|
||||
const InputType& /*input*/,
|
||||
const OutputType& gradient,
|
||||
OutputType& output)
|
||||
{
|
||||
if (output.is_empty())
|
||||
output.set_size(inRowSize * inColSize * depth, batchSize);
|
||||
else
|
||||
{
|
||||
assert(output.n_rows == inRowSize * inColSize * depth);
|
||||
assert(output.n_cols == batchSize);
|
||||
}
|
||||
const size_t batchSize = output.n_cols;
|
||||
const size_t depth = this->inputDimensions.size() <= 2 ? 1 :
|
||||
std::accumulate(this->inputDimensions.begin() + 2, this->inputDimensions.end(), 0);
|
||||
|
||||
assert(output.n_rows == this->inputDimensions[0] * this->inputDimensions[1] * depth);
|
||||
|
||||
assert(outRowSize >= 2);
|
||||
assert(outColSize >= 2);
|
||||
|
||||
arma::cube gradientAsCube(((arma::Mat<eT>&) gradient).memptr(), outRowSize,
|
||||
outColSize, depth * batchSize, false, false);
|
||||
arma::cube outputAsCube(output.memptr(), inRowSize, inColSize,
|
||||
depth * batchSize, false, true);
|
||||
arma::Cube<typename OutputType::elem_type> gradientAsCube(
|
||||
((OutputType&) gradient).memptr(), outRowSize, outColSize, depth *
|
||||
batchSize, false, false);
|
||||
arma::Cube<typename OutputType::elem_type> outputAsCube(
|
||||
output.memptr(), this->inputDimensions[0], this->inputDimensions[1], depth * batchSize,
|
||||
false, true);
|
||||
|
||||
if (gradient.n_elem == output.n_elem)
|
||||
{
|
||||
@@ -140,17 +124,17 @@ void BilinearInterpolation<InputDataType, OutputDataType>::Backward(
|
||||
}
|
||||
else
|
||||
{
|
||||
double scaleRow = (double)(outRowSize) / inRowSize;
|
||||
double scaleCol = (double)(outColSize) / inColSize;
|
||||
double scaleRow = (double)(outRowSize) / this->inputDimensions[0];
|
||||
double scaleCol = (double)(outColSize) / this->inputDimensions[1];
|
||||
|
||||
arma::mat22 coeffs;
|
||||
for (size_t i = 0; i < inRowSize; ++i)
|
||||
for (size_t i = 0; i < this->inputDimensions[0]; ++i)
|
||||
{
|
||||
size_t rOrigin = (size_t) std::floor(i * scaleRow);
|
||||
if (rOrigin > outRowSize - 2)
|
||||
rOrigin = outRowSize - 2;
|
||||
double deltaR = i * scaleRow - rOrigin;
|
||||
for (size_t j = 0; j < inColSize; ++j)
|
||||
for (size_t j = 0; j < this->inputDimensions[1]; ++j)
|
||||
{
|
||||
size_t cOrigin = (size_t) std::floor(j * scaleCol);
|
||||
|
||||
@@ -173,16 +157,15 @@ void BilinearInterpolation<InputDataType, OutputDataType>::Backward(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
template<typename Archive>
|
||||
void BilinearInterpolation<InputDataType, OutputDataType>::serialize(
|
||||
void BilinearInterpolationType<InputType, OutputType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(inRowSize));
|
||||
ar(CEREAL_NVP(inColSize));
|
||||
ar(cereal::base_class<Layer<InputType, OutputType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(outRowSize));
|
||||
ar(CEREAL_NVP(outColSize));
|
||||
ar(CEREAL_NVP(depth));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
+21
-39
@@ -14,10 +14,12 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
/**
|
||||
*
|
||||
* A concatenated ReLU has two outputs, one ReLU and one negative ReLU,
|
||||
* concatenated together. In other words, for positive x it produces [x, 0],
|
||||
* and for negative x it produces [0, x]. Because it has two outputs,
|
||||
@@ -38,22 +40,21 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam InputType The type of the layer's inputs. The layer automatically
|
||||
* cast inputs to this type (Default: arma::mat).
|
||||
* @tparam OutputType The type of the computation which also causes the output
|
||||
* to also be in this type. The type also allows the computation and weight
|
||||
* type to differ from the input type (Default: arma::mat).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class CReLU
|
||||
template<typename InputType = arma::mat, typename OutputType = arma::mat>
|
||||
class CReLUType : public Layer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create the CReLU object.
|
||||
*/
|
||||
CReLU();
|
||||
//! Create the CReLU object.
|
||||
CReLUType();
|
||||
|
||||
//! Clone the CReLUType object. This handles polymorphism correctly.
|
||||
CReLUType* Clone() const { return new CReLUType(*this); }
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -63,7 +64,6 @@ class CReLU
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
@@ -75,35 +75,17 @@ class CReLU
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename DataType>
|
||||
void Backward(const DataType& input, const DataType& gy, DataType& g);
|
||||
void Backward(const InputType& input, const OutputType& gy, OutputType& g);
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get size of weights.
|
||||
size_t WeightSize() const { return 0; }
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
*/
|
||||
//! Serialize the layer.
|
||||
template<typename Archive>
|
||||
void serialize(Archive& /* ar */, const uint32_t /* version */);
|
||||
}; // class CReLUType
|
||||
|
||||
private:
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
// Convenience typedefs.
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
}; // class CReLU
|
||||
// Standard CReLU layer.
|
||||
typedef CReLUType<arma::mat, arma::mat> CReLU;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
+11
-14
@@ -18,39 +18,36 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
CReLU<InputDataType, OutputDataType>::CReLU()
|
||||
template<typename InputType, typename OutputType>
|
||||
CReLUType<InputType, OutputType>::CReLUType()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
void CReLU<InputDataType, OutputDataType>::Forward(
|
||||
void CReLUType<InputType, OutputType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
output = arma::join_cols(arma::max(input, 0.0 * input), arma::max(
|
||||
(-1 * input), 0.0 * input));
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename DataType>
|
||||
void CReLU<InputDataType, OutputDataType>::Backward(
|
||||
const DataType& input, const DataType& gy, DataType& g)
|
||||
template<typename InputType, typename OutputType>
|
||||
void CReLUType<InputType, OutputType>::Backward(
|
||||
const InputType& input, const OutputType& gy, OutputType& g)
|
||||
{
|
||||
DataType temp;
|
||||
temp = gy % (input >= 0.0);
|
||||
OutputType temp = gy % (input >= 0.0);
|
||||
g = temp.rows(0, (input.n_rows / 2 - 1)) - temp.rows(input.n_rows / 2,
|
||||
(input.n_rows - 1));
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
template<typename Archive>
|
||||
void CReLU<InputDataType, OutputDataType>::serialize(
|
||||
Archive& /* ar */,
|
||||
void CReLUType<InputType, OutputType>::serialize(
|
||||
Archive& ar,
|
||||
const uint32_t /* version */)
|
||||
{
|
||||
// Nothing to do here.
|
||||
ar(cereal::base_class<Layer<InputType, OutputType>>(this));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
+22
-45
@@ -25,6 +25,8 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
@@ -46,18 +48,16 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* \right.
|
||||
* @f}
|
||||
*
|
||||
* In the deterministic mode, there is no computation of the derivative.
|
||||
* When not in training mode, there is no computation of the derivative.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam InputType The type of the layer's inputs. The layer automatically
|
||||
* cast inputs to this type (Default: arma::mat).
|
||||
* @tparam OutputType The type of the computation which also causes the output
|
||||
* to also be in this type. The type also allows the computation and weight
|
||||
* type to differ from the input type (Default: arma::mat).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class CELU
|
||||
template<typename InputType = arma::mat, typename OutputType = arma::mat>
|
||||
class CELUType : public Layer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -67,7 +67,10 @@ class CELU
|
||||
*
|
||||
* @param alpha Scale parameter for the negative factor (default = 1.0).
|
||||
*/
|
||||
CELU(const double alpha = 1.0);
|
||||
CELUType(const double alpha = 1.0);
|
||||
|
||||
//! Clone the CELUType object. This handles polymorphism correctly.
|
||||
CELUType* Clone() const { return new CELUType(*this); }
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -76,7 +79,6 @@ class CELU
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
@@ -88,54 +90,29 @@ class CELU
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename DataType>
|
||||
void Backward(const DataType& input, const DataType& gy, DataType& g);
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
void Backward(const InputType& input, const OutputType& gy, OutputType& g);
|
||||
|
||||
//! Get the non zero gradient.
|
||||
double const& Alpha() const { return alpha; }
|
||||
//! Modify the non zero gradient.
|
||||
double& Alpha() { return alpha; }
|
||||
|
||||
//! Get the value of deterministic parameter.
|
||||
bool Deterministic() const { return deterministic; }
|
||||
//! Modify the value of deterministic parameter.
|
||||
bool& Deterministic() { return deterministic; }
|
||||
|
||||
//! Get size of weights.
|
||||
size_t WeightSize() { return 0; }
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
*/
|
||||
//! Serialize the layer.
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
|
||||
//! Locally stored first derivative of the activation function.
|
||||
arma::mat derivative;
|
||||
OutputType derivative;
|
||||
|
||||
//! CELU Hyperparameter (alpha > 0).
|
||||
double alpha;
|
||||
}; // class CELUType
|
||||
|
||||
//! If true the derivative computation is disabled, see notes above.
|
||||
bool deterministic;
|
||||
}; // class CELU
|
||||
// Convenience typedefs.
|
||||
|
||||
// Standard CELU layer.
|
||||
typedef CELUType<arma::mat, arma::mat> CELU;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
+16
-15
@@ -18,10 +18,9 @@
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
CELU<InputDataType, OutputDataType>::CELU(const double alpha) :
|
||||
alpha(alpha),
|
||||
deterministic(false)
|
||||
template<typename InputType, typename OutputType>
|
||||
CELUType<InputType, OutputType>::CELUType(const double alpha) :
|
||||
alpha(alpha)
|
||||
{
|
||||
if (alpha == 0)
|
||||
{
|
||||
@@ -30,19 +29,18 @@ CELU<InputDataType, OutputDataType>::CELU(const double alpha) :
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
void CELU<InputDataType, OutputDataType>::Forward(
|
||||
void CELUType<InputType, OutputType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
output = arma::ones<OutputDataType>(arma::size(input));
|
||||
output = arma::ones<OutputType>(arma::size(input));
|
||||
for (size_t i = 0; i < input.n_elem; ++i)
|
||||
{
|
||||
output(i) = (input(i) >= 0) ? input(i) : alpha *
|
||||
(std::exp(input(i) / alpha) - 1);
|
||||
(std::exp(input(i) / alpha) - 1);
|
||||
}
|
||||
|
||||
if (!deterministic)
|
||||
if (this->training)
|
||||
{
|
||||
derivative.set_size(arma::size(input));
|
||||
for (size_t i = 0; i < input.n_elem; ++i)
|
||||
@@ -53,21 +51,24 @@ void CELU<InputDataType, OutputDataType>::Forward(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename DataType>
|
||||
void CELU<InputDataType, OutputDataType>::Backward(
|
||||
const DataType& /* input */, const DataType& gy, DataType& g)
|
||||
template<typename InputType, typename OutputType>
|
||||
void CELUType<InputType, OutputType>::Backward(
|
||||
const InputType& /* input */, const OutputType& gy, OutputType& g)
|
||||
{
|
||||
g = gy % derivative;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
template<typename Archive>
|
||||
void CELU<InputDataType, OutputDataType>::serialize(
|
||||
void CELUType<InputType, OutputType>::serialize(
|
||||
Archive& ar,
|
||||
const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<InputType, OutputType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(alpha));
|
||||
if (Archive::is_loading::value)
|
||||
derivative.clear();
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* @file methods/ann/layer/concat.hpp
|
||||
* @author Marcus Edel
|
||||
* @author Mehul Kumar Nirala
|
||||
*
|
||||
* Definition of the Concat class, which acts as a concatenation container.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_CONCAT_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_CONCAT_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
/**
|
||||
* Implementation of the Concat class. The Concat class works as a
|
||||
* feed-forward fully connected network container which plugs various layers
|
||||
* together.
|
||||
*
|
||||
* @tparam InputType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
*/
|
||||
template <
|
||||
typename InputType = arma::mat,
|
||||
typename OutputType = arma::mat
|
||||
>
|
||||
class ConcatType : public MultiLayer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create the Concat object using the specified parameters.
|
||||
*
|
||||
* @param run Call the Forward/Backward method before the output is merged.
|
||||
*/
|
||||
ConcatType(const bool run = true);
|
||||
|
||||
/**
|
||||
* Create the Concat object, specifying a particular axis on which the layer
|
||||
* outputs should be concatenated.
|
||||
*
|
||||
* @param axis Concat axis.
|
||||
* @param run Call the Forward/Backward method before the output is merged.
|
||||
*/
|
||||
ConcatType(const size_t axis, const bool run = true);
|
||||
|
||||
/**
|
||||
* Destroy the layers held by the model.
|
||||
*/
|
||||
~ConcatType();
|
||||
|
||||
//! Clone the ConcatType object. This handles polymorphism correctly.
|
||||
ConcatType* Clone() const { return new ConcatType(*this); }
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
* f(x) by propagating the activity forward through f.
|
||||
*
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network, using 3rd-order tensors as
|
||||
* input, calculating the function f(x) by propagating x backwards through f.
|
||||
* Using the results from the feed forward pass.
|
||||
*
|
||||
* @param * (input) The propagated input activation.
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
void Backward(const InputType& /* input */,
|
||||
const OutputType& gy,
|
||||
OutputType& g);
|
||||
|
||||
/**
|
||||
* This is the overload of Backward() that runs only a specific layer with
|
||||
* the given input.
|
||||
*
|
||||
* @param * (input) The propagated input activation.
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
* @param index The index of the layer to run.
|
||||
*/
|
||||
void Backward(const InputType& /* input */,
|
||||
const OutputType& gy,
|
||||
OutputType& g,
|
||||
const size_t index);
|
||||
|
||||
/**
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
*
|
||||
* @param input The input parameter used for calculating the gradient.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
void Gradient(const InputType& /* input */,
|
||||
const OutputType& error,
|
||||
OutputType& /* gradient */);
|
||||
|
||||
/**
|
||||
* This is the overload of Gradient() that runs a specific layer with the
|
||||
* given input.
|
||||
*
|
||||
* @param input The input parameter used for calculating the gradient.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
* @param The index of the layer to run.
|
||||
*/
|
||||
void Gradient(const InputType& input,
|
||||
const OutputType& error,
|
||||
OutputType& gradient,
|
||||
const size_t index);
|
||||
|
||||
//! Get the value of run parameter.
|
||||
bool Run() const { return run; }
|
||||
//! Modify the value of run parameter.
|
||||
bool& Run() { return run; }
|
||||
|
||||
//! Get the axis of concatenation.
|
||||
const size_t& ConcatAxis() const { return axis; }
|
||||
|
||||
//! Get the size of the weight matrix.
|
||||
size_t WeightSize() const { return 0; }
|
||||
|
||||
void ComputeOutputDimensions()
|
||||
{
|
||||
// The input is sent to every layer.
|
||||
for (size_t i = 0; i < network.size(); ++i)
|
||||
{
|
||||
network[i]->InputDimensions() = this->inputDimensions;
|
||||
network[i]->ComputeOutputDimensions();
|
||||
}
|
||||
|
||||
// If the user did not specify an axis, we will use the last one.
|
||||
// Otherwise, we must sanity check to ensure that the axis we are
|
||||
// concatenating along is valid.
|
||||
if (!useAxis)
|
||||
{
|
||||
axis = this->inputDimensions.size() - 1;
|
||||
}
|
||||
else if (axis >= this->inputDimensions.size())
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Concat::ComputeOutputDimensions(): cannot concatenate outputs "
|
||||
<< "along axis " << axis << " when input only has "
|
||||
<< this->inputDimensions.size() << " axes!";
|
||||
throw std::invalid_argument(oss.str());
|
||||
}
|
||||
|
||||
// Now, we concatenate the output along a specific axis.
|
||||
this->outputDimensions = std::vector<size_t>(this->inputDimensions.size(),
|
||||
0);
|
||||
for (size_t i = 0; i < this->inputDimensions.size(); ++i)
|
||||
{
|
||||
if (i == axis)
|
||||
{
|
||||
// Accumulate output size along this axis for each layer output.
|
||||
for (size_t n = 0; n < this->network.size(); ++n)
|
||||
{
|
||||
this->outputDimensions[i] += this->network[n]->OutputDimensions()[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure that the output size is the same along this axis.
|
||||
const size_t axisDim = this->network[0]->OutputDimensions()[i];
|
||||
for (size_t n = 1; n < this->network.size(); ++n)
|
||||
{
|
||||
const size_t axisDim2 = this->network[n]->OutputDimensions()[i];
|
||||
if (axisDim != axisDim2)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Concat::ComputeOutputDimensions(): cannot concatenate "
|
||||
<< "outputs along axis " << axis << "; held layer " << n
|
||||
<< " has output size " << axisDim2 << " along axis " << i
|
||||
<< ", but the first held layer has output size " << axisDim
|
||||
<< "! All layers must have identical output size in any "
|
||||
<< "axis other than the concatenated axis.";
|
||||
throw std::invalid_argument(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
this->outputDimensions[i] = axisDim;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the layer
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Parameter which indicates the axis of concatenation.
|
||||
size_t axis;
|
||||
|
||||
//! Parameter which indicates whether to use the axis of concatenation.
|
||||
bool useAxis;
|
||||
}; // class ConcatType.
|
||||
|
||||
// Standard Concat layer.
|
||||
typedef ConcatType<arma::mat, arma::mat> Concat;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
// Include implementation.
|
||||
#include "concat_impl.hpp"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* @file methods/ann/layer/concat_impl.hpp
|
||||
* @author Marcus Edel
|
||||
* @author Mehul Kumar Nirala
|
||||
*
|
||||
* Implementation of the Concat class, which acts as a concatenation contain.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_CONCAT_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_CONCAT_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "concat.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
ConcatType<InputType, OutputType>::ConcatType(
|
||||
const bool run) :
|
||||
axis(0),
|
||||
useAxis(false)
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
ConcatType<InputType, OutputType>::ConcatType(
|
||||
const size_t axis,
|
||||
const bool run) :
|
||||
axis(axis),
|
||||
useAxis(true)
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
ConcatType<InputType, OutputType>::~ConcatType()
|
||||
{
|
||||
// Clear memory.
|
||||
for (size_t i = 0; i < this->network.size(); ++i)
|
||||
delete this->network[i];
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void ConcatType<InputType, OutputType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
this->InitializeForwardPassMemory();
|
||||
|
||||
// Pass the input through all the layers in the network.
|
||||
for (size_t i = 0; i < this->network.size(); ++i)
|
||||
{
|
||||
this->network[i]->Forward(input, this->layerOutputs[i]);
|
||||
}
|
||||
|
||||
// Now concatenate the outputs along the correct axis.
|
||||
// We can actually use Armadillo to do this for us---we will treat the axis of
|
||||
// interest as "columns", any axes that come before the axis of interest as
|
||||
// 'flattened slices', and any axes that come after the axis of interest as
|
||||
// 'flattened rows'. As a result, we will only have to do join_cols() to
|
||||
// produce the right result.
|
||||
//
|
||||
// Note that we will have one "extra" axis in addition to
|
||||
// this->outputDimensions.size(); that is the batch size (represented as the
|
||||
// number of columns in `input`).
|
||||
|
||||
size_t slices = (axis == 0) ? input.n_cols :
|
||||
std::accumulate(this->outputDimensions.begin(),
|
||||
this->outputDimensions.begin() + axis, 0) + input.n_cols;
|
||||
size_t rows = (axis == this->outputDimensions.size() - 1) ? 1 :
|
||||
std::accumulate(this->outputDimensions.begin() + axis + 1,
|
||||
this->outputDimensions.end(), 0);
|
||||
|
||||
std::vector<arma::Cube<typename OutputType::elem_type>> layerOutputAliases;
|
||||
for (size_t i = 0; i < this->layerOutputs.size(); ++i)
|
||||
{
|
||||
layerOutputAliases.emplace_back(arma::Cube<typename OutputType::elem_type>(
|
||||
this->layerOutputs[i].memptr(), rows,
|
||||
this->network[i]->OutputDimensions()[axis], slices, false, true);
|
||||
}
|
||||
|
||||
arma::Cube<typename OutputType::elem_type> output(output.memptr(), rows,
|
||||
this->outputDimensions[axis], slices, false, true);
|
||||
|
||||
// Now get the columns from each output.
|
||||
size_t startCol = 0;
|
||||
for (size_t i = 0; i < layerOutputAliases.size(); ++i)
|
||||
{
|
||||
const size_t cols = layerOutputAliases[i].n_cols;
|
||||
output.cols(startCol, startCol + cols - 1) = layerOutputAliases[i];
|
||||
startCol += cols;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void ConcatType<InputType, OutputType>::Backward(
|
||||
const InputType& /* input */, const OutputType& gy, OutputType& g)
|
||||
{
|
||||
this->InitializeBackwardPassMemory();
|
||||
|
||||
// Just like the forward pass, we can treat our inputs as a cube, but here we
|
||||
// have to distribute the correct parts of `gy` to the layers.
|
||||
|
||||
size_t slices = (axis == 0) ? gy.n_cols :
|
||||
std::accumulate(this->outputDimensions.begin(),
|
||||
this->outputDimensions.begin() + axis, 0) + gy.n_cols;
|
||||
size_t rows = (axis == this->outputDimensions.size() - 1) ? 1 :
|
||||
std::accumulate(this->outputDimensions.begin() + axis + 1,
|
||||
this->outputDimensions.end(), 0);
|
||||
|
||||
arma::Cube<typename OutputType::elem_type> gyTmp(gy.memptr(), rows,
|
||||
this->outputDimensions[axis], slices, false, true);
|
||||
|
||||
size_t startCol = 0;
|
||||
for (size_t i = 0; i < this->network.size(); ++i)
|
||||
{
|
||||
const size_t cols = this->network[i]->OutputDimensions()[axis];
|
||||
// TODO: is delta size correct?
|
||||
// TODO: no copy!
|
||||
OutputType delta = gyTmp.cols(startCol, startCol + cols - 1);
|
||||
// TODO: consider batch size correctly
|
||||
delta.reshape( ... );
|
||||
this->network[i]->Backward(this->layerOutputs[i], delta,
|
||||
this->layerDeltas[i]);
|
||||
|
||||
startCol += cols;
|
||||
}
|
||||
|
||||
g = this->layerDeltas[0];
|
||||
for (size_t i = 1; i < this->network.size(); ++i)
|
||||
{
|
||||
g += this->layerDeltas[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void ConcatType<InputType, OutputType>::Backward(
|
||||
const InputType& /* input */,
|
||||
const OutputType& gy,
|
||||
OutputType& g,
|
||||
const size_t index)
|
||||
{
|
||||
// We only intend to perform a backward pass on one layer.
|
||||
// Thus, we need to extract the parts of gy that correspond to the desired
|
||||
// layer (specified by `index`).
|
||||
|
||||
size_t slices = (axis == 0) ? gy.n_cols :
|
||||
std::accumulate(this->outputDimensions.begin(),
|
||||
this->outputDimensions.begin() + axis, 0) + gy.n_cols;
|
||||
size_t rows = (axis == this->outputDimensions.size() - 1) ? 1 :
|
||||
std::accumulate(this->outputDimensions.begin() + axis + 1,
|
||||
this->outputDimensions.end(), 0);
|
||||
|
||||
arma::Cube<typename OutputType::elem_type> gyTmp(gy.memptr(), rows,
|
||||
this->outputDimensions[axis], slices, false, true);
|
||||
|
||||
size_t startCol = 0;
|
||||
for (size_t i = 0; i < index; ++i)
|
||||
{
|
||||
startCol += this->network[i]->OutputDimensions()[axis];
|
||||
}
|
||||
|
||||
// TODO: no copy!
|
||||
const size_t cols = this->network[index]->OutputDimensions()[axis];
|
||||
OutputType delta = gyTmp.cols(startCol, startCol + cols - 1);
|
||||
delta.reshape( ... );
|
||||
|
||||
this->network[index]->Backward(this->layerOutputs[index], delta, g);
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void ConcatType<InputType, OutputType>::Gradient(
|
||||
const InputType& input,
|
||||
const OutputType& error,
|
||||
OutputType& gradient)
|
||||
{
|
||||
// Just like the forward pass, we can treat our inputs as a cube, but here we
|
||||
// have to distribute the correct parts of `gy` to the layers.
|
||||
|
||||
size_t slices = (axis == 0) ? input.n_cols :
|
||||
std::accumulate(this->outputDimensions.begin(),
|
||||
this->outputDimensions.begin() + axis, 0) + input.n_cols;
|
||||
size_t rows = (axis == this->outputDimensions.size() - 1) ? 1 :
|
||||
std::accumulate(this->outputDimensions.begin() + axis + 1,
|
||||
this->outputDimensions.end(), 0);
|
||||
|
||||
arma::Cube<typename OutputType::elem_type> errorTmp(error.memptr(), rows,
|
||||
this->outputDimensions[axis], slices, false, true);
|
||||
|
||||
size_t startCol = 0;
|
||||
size_t startParam = 0;
|
||||
for (size_t i = 0; i < this->network.size(); ++i)
|
||||
{
|
||||
const size_t cols = this->network[i]->OutputDimensions()[axis];
|
||||
const size_t params = this->network[i]->WeightSize();
|
||||
|
||||
OutputType err = errorTmp.cols(startCol, startCol + cols - 1);
|
||||
err.reshape(input.n_cols, err.n_elem / input.n_cols);
|
||||
// TODO: what about layerGradients?
|
||||
OutputType gradientAlias(gradient.colptr(startParam, 1, params, false,
|
||||
true);
|
||||
this->network[i]->Gradient(input, err, gradientAlias);
|
||||
|
||||
startCol += cols;
|
||||
startParam += params;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: adapt
|
||||
template<typename InputType, typename OutputType>
|
||||
void ConcatType<InputType, OutputType>::Gradient(
|
||||
const InputType& input,
|
||||
const OutputType& error,
|
||||
OutputType& gradient,
|
||||
const size_t index)
|
||||
{
|
||||
// Just like the forward pass, we can treat our inputs as a cube, but here we
|
||||
// have to distribute the correct parts of `gy` to the layers.
|
||||
|
||||
size_t slices = (axis == 0) ? input.n_cols :
|
||||
std::accumulate(this->outputDimensions.begin(),
|
||||
this->outputDimensions.begin() + axis, 0) + input.n_cols;
|
||||
size_t rows = (axis == this->outputDimensions.size() - 1) ? 1 :
|
||||
std::accumulate(this->outputDimensions.begin() + axis + 1,
|
||||
this->outputDimensions.end(), 0);
|
||||
|
||||
arma::Cube<typename OutputType::elem_type> errorTmp(error.memptr(), rows,
|
||||
this->outputDimensions[axis], slices, false, true);
|
||||
|
||||
size_t startCol = 0;
|
||||
size_t startParam = 0;
|
||||
for (size_t i = 0; i < index; ++i)
|
||||
{
|
||||
startCol += this->network[i]->OutputDimensions()[axis];
|
||||
startParam += this->network[i]->WeightSize();
|
||||
}
|
||||
|
||||
const size_t cols = this->network[index]->OutputDimensions()[axis];
|
||||
const size_t params = this->network[index]->WeightSize();
|
||||
|
||||
// TODO: no copy!
|
||||
OutputType err = errorTmp.cols(startCol, startCol + cols - 1);
|
||||
err.reshape(input.n_cols, err.n_elem / input.n_cols);
|
||||
OutputType gradientAlias(gradient.memptr(), 1, params, false, true);
|
||||
this->network[index]->Gradient(input, err, gradientAlias);
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
template<typename Archive>
|
||||
void ConcatType<InputType, OutputType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<MultiLayer<InputType, OutputType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(axis));
|
||||
ar(CEREAL_NVP(useAxis));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
+15
-30
@@ -24,17 +24,17 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* feed-forward fully connected network container which plugs performance layers
|
||||
* together.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* @tparam InputType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* @tparam OutputType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
*/
|
||||
template <
|
||||
typename OutputLayerType = NegativeLogLikelihood<>,
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
typename InputType = arma::mat,
|
||||
typename OutputType = arma::mat
|
||||
>
|
||||
class ConcatPerformance
|
||||
class ConcatPerformance : public Layer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -43,8 +43,7 @@ class ConcatPerformance
|
||||
* @param inSize The number of inputs.
|
||||
* @param outputLayer Output layer used to evaluate the network.
|
||||
*/
|
||||
ConcatPerformance(const size_t inSize = 0,
|
||||
OutputLayerType&& outputLayer = OutputLayerType());
|
||||
ConcatPerformance(OutputLayerType&& outputLayer = OutputLayerType());
|
||||
|
||||
/*
|
||||
* Computes the Negative log likelihood.
|
||||
@@ -52,8 +51,7 @@ class ConcatPerformance
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename eT>
|
||||
double Forward(const arma::Mat<eT>& input, arma::Mat<eT>& target);
|
||||
void Forward(const InputType& input, OutputType& target);
|
||||
|
||||
/**
|
||||
* Ordinary feed backward pass of a neural network. The negative log
|
||||
@@ -66,42 +64,29 @@ class ConcatPerformance
|
||||
* between 1 and the number of classes.
|
||||
* @param output The calculated error.
|
||||
*/
|
||||
template<typename eT>
|
||||
void Backward(const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& target,
|
||||
arma::Mat<eT>& output);
|
||||
void Backward(const InputType& input,
|
||||
const OutputType& target,
|
||||
OutputType& output);
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType& OutputParameter() const { return outputParameter; }
|
||||
OutputType& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
OutputType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType& Delta() const { return delta; }
|
||||
OutputType& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the number of inputs.
|
||||
size_t InSize() const { return inSize; }
|
||||
OutputType& Delta() { return delta; }
|
||||
|
||||
/**
|
||||
* Serialize the layer
|
||||
* Serialize the layer.
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& /* ar */, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally-stored number of inputs.
|
||||
size_t inSize;
|
||||
|
||||
//! Instantiated outputlayer used to evaluate the network.
|
||||
OutputLayerType outputLayer;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
}; // class ConcatPerformance
|
||||
|
||||
} // namespace ann
|
||||
+35
-34
@@ -20,15 +20,14 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<
|
||||
typename OutputLayerType,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
ConcatPerformance<
|
||||
OutputLayerType,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
>::ConcatPerformance(const size_t inSize, OutputLayerType&& outputLayer) :
|
||||
inSize(inSize),
|
||||
InputType,
|
||||
OutputType
|
||||
>::ConcatPerformance(OutputLayerType&& outputLayer) :
|
||||
outputLayer(std::move(outputLayer))
|
||||
{
|
||||
// Nothing to do here.
|
||||
@@ -36,51 +35,51 @@ ConcatPerformance<
|
||||
|
||||
template<
|
||||
typename OutputLayerType,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
template<typename eT>
|
||||
double ConcatPerformance<
|
||||
void ConcatPerformance<
|
||||
OutputLayerType,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
>::Forward(const arma::Mat<eT>& input, arma::Mat<eT>& target)
|
||||
InputType,
|
||||
OutputType
|
||||
>::Forward(const InputType& input, OutputType& target)
|
||||
{
|
||||
const size_t elements = input.n_elem / inSize;
|
||||
const size_t elements = input.n_elem / inputDimensions[0];
|
||||
|
||||
double output = 0;
|
||||
for (size_t i = 0; i < input.n_elem; i+= elements)
|
||||
for (size_t i = 0; i < input.n_elem; i += elements)
|
||||
{
|
||||
arma::mat subInput = input.submat(i, 0, i + elements - 1, 0);
|
||||
InputType subInput = input.submat(i, 0, i + elements - 1, 0);
|
||||
output += outputLayer.Forward(subInput, target);
|
||||
}
|
||||
|
||||
return output;
|
||||
// TODO: what to do with output?
|
||||
//return output;
|
||||
return;
|
||||
}
|
||||
|
||||
template<
|
||||
typename OutputLayerType,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
template<typename eT>
|
||||
void ConcatPerformance<
|
||||
OutputLayerType,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
InputType,
|
||||
OutputType
|
||||
>::Backward(
|
||||
const arma::Mat<eT>& input,
|
||||
const arma::Mat<eT>& target,
|
||||
arma::Mat<eT>& output)
|
||||
const InputType& input,
|
||||
const OutputType& target,
|
||||
OutputType& output)
|
||||
{
|
||||
const size_t elements = input.n_elem / inSize;
|
||||
const size_t elements = input.n_elem / inputDimensions[0];
|
||||
|
||||
arma::mat subInput = input.submat(0, 0, elements - 1, 0);
|
||||
arma::mat subOutput;
|
||||
InputType subInput = input.submat(0, 0, elements - 1, 0);
|
||||
OutputType subOutput;
|
||||
|
||||
outputLayer.Backward(subInput, target, subOutput);
|
||||
|
||||
output = arma::zeros(subOutput.n_elem, inSize);
|
||||
output = arma::zeros(subOutput.n_elem, inputDimensions[0]);
|
||||
output.col(0) = subOutput;
|
||||
|
||||
for (size_t i = elements, j = 0; i < input.n_elem; i+= elements, ++j)
|
||||
@@ -94,17 +93,19 @@ void ConcatPerformance<
|
||||
|
||||
template<
|
||||
typename OutputLayerType,
|
||||
typename InputDataType,
|
||||
typename OutputDataType
|
||||
typename InputType,
|
||||
typename OutputType
|
||||
>
|
||||
template<typename Archive>
|
||||
void ConcatPerformance<
|
||||
OutputLayerType,
|
||||
InputDataType,
|
||||
OutputDataType
|
||||
InputType,
|
||||
OutputType
|
||||
>::serialize(Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(CEREAL_NVP(inSize));
|
||||
ar(cereal::base_class<Layer<InputType, OutputType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(outputLayer));
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
+40
-42
@@ -15,6 +15,8 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
@@ -22,18 +24,21 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* Implementation of the constant layer. The constant layer outputs a given
|
||||
* constant value given any input value.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam InputType The type of the layer's inputs. The layer automatically
|
||||
* cast inputs to this type (Default: arma::mat).
|
||||
* @tparam OutputType The type of the computation which also causes the output
|
||||
* to also be in this type. The type also allows the computation and weight
|
||||
* type to differ from the input type (Default: arma::mat).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class Constant
|
||||
template<typename InputType = arma::mat, typename OutputType = arma::mat>
|
||||
class ConstantType : public Layer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create an empty Constant layer.
|
||||
*/
|
||||
ConstantType();
|
||||
|
||||
/**
|
||||
* Create the Constant object that outputs a given constant scalar value
|
||||
* given any input value.
|
||||
@@ -41,7 +46,19 @@ class Constant
|
||||
* @param outSize The number of output units.
|
||||
* @param scalar The constant value used to create the constant output.
|
||||
*/
|
||||
Constant(const size_t outSize = 0, const double scalar = 0.0);
|
||||
ConstantType(const size_t outSize, const double scalar = 0);
|
||||
|
||||
//! Copy another ConstantType.
|
||||
ConstantType(const ConstantType& layer);
|
||||
//! Take ownership of another ConstantType.
|
||||
ConstantType(ConstantType&& layer);
|
||||
//! Copy another ConstantType.
|
||||
ConstantType& operator=(const ConstantType& layer);
|
||||
//! Take ownership of another ConstantType.
|
||||
ConstantType& operator=(ConstantType&& layer);
|
||||
|
||||
//! Clone the ConstantType object. This handles polymorphism correctly.
|
||||
ConstantType* Clone() const { return new ConstantType(*this); }
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network. The forward pass fills the
|
||||
@@ -50,7 +67,6 @@ class Constant
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
@@ -61,52 +77,34 @@ class Constant
|
||||
* @param * (gy) The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename DataType>
|
||||
void Backward(const DataType& /* input */,
|
||||
const DataType& /* gy */,
|
||||
DataType& g);
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
void Backward(const InputType& /* input */,
|
||||
const OutputType& /* gy */,
|
||||
OutputType& g);
|
||||
|
||||
//! Get the output size.
|
||||
size_t OutSize() const { return outSize; }
|
||||
|
||||
//! Get the size of the weights.
|
||||
size_t WeightSize() const
|
||||
const std::vector<size_t>& OutputDimensions() const
|
||||
{
|
||||
return 0;
|
||||
std::vector<size_t> result(this->inputDimensions.size(), 0);
|
||||
result[0] = outSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the layer.
|
||||
*/
|
||||
//! Serialize the layer.
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally-stored number of input units.
|
||||
size_t inSize;
|
||||
|
||||
//! Locally-stored number of output units.
|
||||
size_t outSize;
|
||||
|
||||
//! Locally-stored constant output matrix.
|
||||
OutputDataType constantOutput;
|
||||
OutputType constantOutput;
|
||||
}; // class ConstantType
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
// Convenience typedefs.
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
}; // class ConstantLayer
|
||||
// Standard HardShrink layer.
|
||||
typedef ConstantType<arma::mat, arma::mat> Constant;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file methods/ann/layer/constant_impl.hpp
|
||||
* @author Marcus Edel
|
||||
*
|
||||
* Implementation of the Constant class, which outputs a constant value given
|
||||
* any input.
|
||||
*
|
||||
* 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 MLPACK_METHODS_ANN_LAYER_CONSTANT_IMPL_HPP
|
||||
#define MLPACK_METHODS_ANN_LAYER_CONSTANT_IMPL_HPP
|
||||
|
||||
// In case it hasn't yet been included.
|
||||
#include "constant.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
ConstantType<InputType, OutputType>::ConstantType() :
|
||||
outSize(0)
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
ConstantType<InputType, OutputType>::ConstantType(
|
||||
const size_t outSize,
|
||||
const double scalar) :
|
||||
outSize(outSize)
|
||||
{
|
||||
constantOutput = OutputType(outSize, 1);
|
||||
constantOutput.fill(scalar);
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
ConstantType<InputType, OutputType>::ConstantType(
|
||||
const ConstantType<InputType, OutputType>& other) :
|
||||
outSize(other.outSize),
|
||||
constantOutput(other.constantOutput)
|
||||
{
|
||||
// Nothing else to do.
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
ConstantType<InputType, OutputType>::ConstantType(
|
||||
ConstantType<InputType, OutputType>&& other) :
|
||||
outSize(other.outSize),
|
||||
constantOutput(std::move(other.constantOutput))
|
||||
{
|
||||
other.outSize = 1;
|
||||
other.constantOutput = OutputType(other.outSize, 1);
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
ConstantType<InputType, OutputType>&
|
||||
ConstantType<InputType, OutputType>::operator=(
|
||||
const ConstantType<InputType, OutputType>& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
outSize = other.outSize;
|
||||
constantOutput = other.constantOutput;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
ConstantType<InputType, OutputType>&
|
||||
ConstantType<InputType, OutputType>::operator=(
|
||||
ConstantType<InputType, OutputType>&& other)
|
||||
{
|
||||
if (this != *other)
|
||||
{
|
||||
outSize = other.outSize;
|
||||
constantOutput = std::move(other.constantOutput);
|
||||
|
||||
other.outSize = 1;
|
||||
other.constantOutput = OutputType(other.outSize, 1);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void ConstantType<InputType, OutputType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
output = constantOutput;
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void ConstantType<InputType, OutputType>::Backward(
|
||||
const InputType& /* input */, const OutputType& /* gy */, OutputType& g)
|
||||
{
|
||||
g.zeros();
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
template<typename Archive>
|
||||
void ConstantType<InputType, OutputType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<InputType, OutputType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(constantOutput));
|
||||
if (Archive::is_loading::value)
|
||||
outSize = constantOutput.n_elem;
|
||||
}
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
+27
-49
@@ -6,9 +6,9 @@
|
||||
* Definition of the ELU activation function as described by Djork-Arne Clevert,
|
||||
* Thomas Unterthiner and Sepp Hochreiter.
|
||||
*
|
||||
* Definition of the SELU function as introduced by
|
||||
* Klambauer et. al. in Self Neural Networks. The SELU activation
|
||||
* function keeps the mean and variance of the input invariant.
|
||||
* Definition of the SELU function as introduced by Klambauer et. al. in Self
|
||||
* Neural Networks. The SELU activation function keeps the mean and variance of
|
||||
* the input invariant.
|
||||
*
|
||||
* In short, SELU = lambda * ELU, with 'alpha' and 'lambda' fixed for
|
||||
* normalized inputs.
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
@@ -61,7 +63,6 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* The SELU activation function is defined by
|
||||
*
|
||||
* @f{eqnarray*}{
|
||||
@@ -92,23 +93,19 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* In the deterministic mode, there is no computation of the derivative.
|
||||
* In testing mode, there is no computation of the derivative.
|
||||
*
|
||||
* @note During training deterministic should be set to false and during
|
||||
* testing/inference deterministic should be set to true.
|
||||
* @note Make sure to use SELU activation function with normalized inputs and
|
||||
* weights initialized with Lecun Normal Initialization.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam InputType The type of the layer's inputs. The layer automatically
|
||||
* cast inputs to this type (Default: arma::mat).
|
||||
* @tparam OutputType The type of the computation which also causes the output
|
||||
* to also be in this type. The type also allows the computation and weight
|
||||
* type to differ from the input type (Default: arma::mat).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
>
|
||||
class ELU
|
||||
template <typename InputType = arma::mat, typename OutputType = arma::mat>
|
||||
class ELUType : public Layer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -116,7 +113,7 @@ class ELU
|
||||
*
|
||||
* NOTE: Use this constructor for SELU activation function.
|
||||
*/
|
||||
ELU();
|
||||
ELUType();
|
||||
|
||||
/**
|
||||
* Create the ELU object using the specified parameter. The non zero
|
||||
@@ -126,8 +123,10 @@ class ELU
|
||||
* @note Use this constructor for ELU activation function.
|
||||
* @param alpha Scale parameter for the negative factor.
|
||||
*/
|
||||
ELU(const double alpha);
|
||||
ELUType(const double alpha);
|
||||
|
||||
//! Clone the ELUType object. This handles polymorphism correctly.
|
||||
ELUType* Clone() const { return new ELUType(*this); }
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
* f(x) by propagating the activity forward through f.
|
||||
@@ -135,7 +134,6 @@ class ELU
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
@@ -147,29 +145,13 @@ class ELU
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename DataType>
|
||||
void Backward(const DataType& input, const DataType& gy, DataType& g);
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
void Backward(const InputType& input, const OutputType& gy, OutputType& g);
|
||||
|
||||
//! Get the non zero gradient.
|
||||
double const& Alpha() const { return alpha; }
|
||||
//! Modify the non zero gradient.
|
||||
double& Alpha() { return alpha; }
|
||||
|
||||
//! Get the value of deterministic parameter.
|
||||
bool Deterministic() const { return deterministic; }
|
||||
//! Modify the value of deterministic parameter.
|
||||
bool& Deterministic() { return deterministic; }
|
||||
|
||||
//! Get the lambda parameter.
|
||||
double const& Lambda() const { return lambda; }
|
||||
|
||||
@@ -180,31 +162,27 @@ class ELU
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
|
||||
private:
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
|
||||
//! Locally stored first derivative of the activation function.
|
||||
arma::mat derivative;
|
||||
OutputType derivative;
|
||||
|
||||
//! ELU Hyperparameter (0 < alpha)
|
||||
//! SELU parameter fixed to 1.6732632423543774 for normalized inputs.
|
||||
double alpha;
|
||||
|
||||
//! Lambda Parameter used for multiplication of ELU function.
|
||||
//! Lambda parameter used for multiplication of ELU function.
|
||||
//! For ELU activation function, lambda = 1.
|
||||
//! For SELU activation function, lambda = 1.0507009873554802 for normalized
|
||||
//! inputs.
|
||||
double lambda;
|
||||
}; // class ELUType
|
||||
|
||||
//! If true the derivative computation is disabled, see notes above.
|
||||
bool deterministic;
|
||||
}; // class ELU
|
||||
// Convenience typedefs.
|
||||
|
||||
// Template alias for SELU using ELU class.
|
||||
using SELU = ELU<arma::mat, arma::mat>;
|
||||
// Standard flexible ReLU layer.
|
||||
typedef ELUType<arma::mat, arma::mat> ELU;
|
||||
|
||||
// Standard ELU layer.
|
||||
typedef ELUType<arma::mat, arma::mat> SELU;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
+35
-42
@@ -26,66 +26,59 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
|
||||
// This constructor is called for SELU activation function. The values of
|
||||
// alpha and lambda are constant for normalized inputs.
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
ELU<InputDataType, OutputDataType>::ELU() :
|
||||
alpha(1.6732632423543774),
|
||||
lambda(1.0507009873554802),
|
||||
deterministic(false)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
// This constructor is called for ELU activation function. The value of lambda
|
||||
// is fixed and equal to 1. 'alpha' is a hyperparameter.
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
ELU<InputDataType, OutputDataType>::ELU(const double alpha) :
|
||||
alpha(alpha),
|
||||
lambda(1),
|
||||
deterministic(false)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
void ELU<InputDataType, OutputDataType>::Forward(
|
||||
ELUType<InputType, OutputType>::ELUType() :
|
||||
alpha(1.6732632423543774),
|
||||
lambda(1.0507009873554802)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
// This constructor is called for ELU activation function. The value of lambda
|
||||
// is fixed and equal to 1. 'alpha' is a hyperparameter.
|
||||
template<typename InputType, typename OutputType>
|
||||
ELUType<InputType, OutputType>::ELUType(const double alpha) :
|
||||
alpha(alpha),
|
||||
lambda(1)
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
template<typename InputType, typename OutputType>
|
||||
void ELUType<InputType, OutputType>::Forward(
|
||||
const InputType& input, OutputType& output)
|
||||
{
|
||||
output = arma::ones<OutputDataType>(arma::size(input));
|
||||
output.ones();
|
||||
for (size_t i = 0; i < input.n_elem; ++i)
|
||||
{
|
||||
if (input(i) < DBL_MAX)
|
||||
{
|
||||
output(i) = (input(i) > 0) ? lambda * input(i) : lambda *
|
||||
alpha * (std::exp(input(i)) - 1);
|
||||
output(i) = (input(i) > 0) ? lambda * input(i) : lambda * alpha *
|
||||
(std::exp(input(i)) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!deterministic)
|
||||
{
|
||||
derivative.set_size(arma::size(input));
|
||||
for (size_t i = 0; i < input.n_elem; ++i)
|
||||
{
|
||||
derivative(i) = (input(i) > 0) ? lambda : output(i) +
|
||||
lambda * alpha;
|
||||
}
|
||||
}
|
||||
if (!deterministic)
|
||||
{
|
||||
for (size_t i = 0; i < input.n_elem; ++i)
|
||||
derivative(i) = (input(i) > 0) ? lambda : output(i) + lambda * alpha;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename DataType>
|
||||
void ELU<InputDataType, OutputDataType>::Backward(
|
||||
const DataType& /* input */, const DataType& gy, DataType& g)
|
||||
template<typename InputType, typename OutputType>
|
||||
void ELUType<InputType, OutputType>::Backward(
|
||||
const InputType& /* input */, const OutputType& gy, OutputType& g)
|
||||
{
|
||||
g = gy % derivative;
|
||||
}
|
||||
|
||||
template<typename InputDataType, typename OutputDataType>
|
||||
template<typename InputType, typename OutputType>
|
||||
template<typename Archive>
|
||||
void ELU<InputDataType, OutputDataType>::serialize(
|
||||
Archive& ar,
|
||||
const uint32_t /* version */)
|
||||
void ELUType<InputType, OutputType>::serialize(
|
||||
Archive& ar, const uint32_t /* version */)
|
||||
{
|
||||
ar(cereal::base_class<Layer<InputType, OutputType>>(this));
|
||||
|
||||
ar(CEREAL_NVP(alpha));
|
||||
ar(CEREAL_NVP(lambda));
|
||||
}
|
||||
+57
-76
@@ -1,3 +1,4 @@
|
||||
// Temporarily drop.
|
||||
/**
|
||||
* @file methods/ann/layer/fast_lstm.hpp
|
||||
* @author Marcus Edel
|
||||
@@ -15,6 +16,7 @@
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include <limits>
|
||||
#include "layer.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace ann /** Artificial Neural Network. */ {
|
||||
@@ -54,36 +56,36 @@ namespace ann /** Artificial Neural Network. */ {
|
||||
*
|
||||
* \see LSTM for a standard implementation of the LSTM layer.
|
||||
*
|
||||
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
|
||||
* @tparam InputType Type of the input data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
|
||||
* @tparam OutputType Type of the output data (arma::colvec, arma::mat,
|
||||
* arma::sp_mat or arma::cube).
|
||||
*/
|
||||
template <
|
||||
typename InputDataType = arma::mat,
|
||||
typename OutputDataType = arma::mat
|
||||
typename InputType = arma::mat,
|
||||
typename OutputType = arma::mat
|
||||
>
|
||||
class FastLSTM
|
||||
class FastLSTMType : public Layer<InputType, OutputType>
|
||||
{
|
||||
public:
|
||||
// Convenience typedefs.
|
||||
typedef typename InputDataType::elem_type InputElemType;
|
||||
typedef typename OutputDataType::elem_type ElemType;
|
||||
typedef typename InputType::elem_type InputET;
|
||||
typedef typename OutputType::elem_type OutputET;
|
||||
|
||||
//! Create the Fast LSTM object.
|
||||
FastLSTM();
|
||||
//! Create the FastLSTMType object.
|
||||
FastLSTMType();
|
||||
|
||||
//! Copy Constructor
|
||||
FastLSTM(const FastLSTM& layer);
|
||||
FastLSTMType(const FastLSTMType& layer);
|
||||
|
||||
//! Move Constructor
|
||||
FastLSTM(FastLSTM&& layer);
|
||||
FastLSTMType(FastLSTMType&& layer);
|
||||
|
||||
//! Copy assignment operator
|
||||
FastLSTM& operator=(const FastLSTM& layer);
|
||||
FastLSTMType& operator=(const FastLSTMType& layer);
|
||||
|
||||
//! Move assignment operator
|
||||
FastLSTM& operator=(FastLSTM&& layer);
|
||||
FastLSTMType& operator=(FastLSTMType&& layer);
|
||||
|
||||
/**
|
||||
* Create the Fast LSTM layer object using the specified parameters.
|
||||
@@ -92,9 +94,12 @@ class FastLSTM
|
||||
* @param outSize The number of output units.
|
||||
* @param rho Maximum number of steps to backpropagate through time (BPTT).
|
||||
*/
|
||||
FastLSTM(const size_t inSize,
|
||||
const size_t outSize,
|
||||
const size_t rho = std::numeric_limits<size_t>::max());
|
||||
FastLSTMType(const size_t inSize,
|
||||
const size_t outSize,
|
||||
const size_t rho = std::numeric_limits<size_t>::max());
|
||||
|
||||
//! Clone the FastLSTMType object. This handles polymorphism correctly.
|
||||
FastLSTMType* Clone() const { return new FastLSTMType(*this); }
|
||||
|
||||
/**
|
||||
* Ordinary feed forward pass of a neural network, evaluating the function
|
||||
@@ -103,7 +108,6 @@ class FastLSTM
|
||||
* @param input Input data used for evaluating the specified function.
|
||||
* @param output Resulting output activation.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void Forward(const InputType& input, OutputType& output);
|
||||
|
||||
/**
|
||||
@@ -115,17 +119,16 @@ class FastLSTM
|
||||
* @param gy The backpropagated error.
|
||||
* @param g The calculated gradient.
|
||||
*/
|
||||
template<typename InputType, typename ErrorType, typename GradientType>
|
||||
void Backward(const InputType& input,
|
||||
const ErrorType& gy,
|
||||
GradientType& g);
|
||||
const OutputType& gy,
|
||||
OutputType& g);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Reset the layer parameter.
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/*
|
||||
/**
|
||||
* Resets the cell to accept a new input. This breaks the BPTT chain starts a
|
||||
* new one.
|
||||
*
|
||||
@@ -133,17 +136,16 @@ class FastLSTM
|
||||
*/
|
||||
void ResetCell(const size_t size);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Calculate the gradient using the output delta and the input activation.
|
||||
*
|
||||
* @param input The input parameter used for calculating the gradient.
|
||||
* @param error The calculated error.
|
||||
* @param gradient The calculated gradient.
|
||||
*/
|
||||
template<typename InputType, typename ErrorType, typename GradientType>
|
||||
void Gradient(const InputType& input,
|
||||
const ErrorType& error,
|
||||
GradientType& gradient);
|
||||
const OutputType& error,
|
||||
OutputType& gradient);
|
||||
|
||||
//! Get the maximum number of steps to backpropagate through time (BPTT).
|
||||
size_t Rho() const { return rho; }
|
||||
@@ -151,24 +153,9 @@ class FastLSTM
|
||||
size_t& Rho() { return rho; }
|
||||
|
||||
//! Get the parameters.
|
||||
OutputDataType const& Parameters() const { return weights; }
|
||||
OutputType const& Parameters() const { return weights; }
|
||||
//! Modify the parameters.
|
||||
OutputDataType& Parameters() { return weights; }
|
||||
|
||||
//! Get the output parameter.
|
||||
OutputDataType const& OutputParameter() const { return outputParameter; }
|
||||
//! Modify the output parameter.
|
||||
OutputDataType& OutputParameter() { return outputParameter; }
|
||||
|
||||
//! Get the delta.
|
||||
OutputDataType const& Delta() const { return delta; }
|
||||
//! Modify the delta.
|
||||
OutputDataType& Delta() { return delta; }
|
||||
|
||||
//! Get the gradient.
|
||||
OutputDataType const& Gradient() const { return grad; }
|
||||
//! Modify the gradient.
|
||||
OutputDataType& Gradient() { return grad; }
|
||||
OutputType& Parameters() { return weights; }
|
||||
|
||||
//! Get the number of input units.
|
||||
size_t InSize() const { return inSize; }
|
||||
@@ -182,14 +169,15 @@ class FastLSTM
|
||||
return 4 * outSize * inSize + 4 * outSize + 4 * outSize * outSize;
|
||||
}
|
||||
|
||||
//! Get the shape of the input.
|
||||
size_t InputShape() const
|
||||
const std::vector<size_t> OutputDimensions() const
|
||||
{
|
||||
return inSize;
|
||||
std::vector<size_t> result(inputDimensions.size(), 0);
|
||||
result[0] = outSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the layer
|
||||
* Serialize the layer.
|
||||
*/
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar, const uint32_t /* version */);
|
||||
@@ -201,7 +189,6 @@ class FastLSTM
|
||||
* @param input The input data.
|
||||
* @param sigmoid The matrix to store the sigmoid approximation into.
|
||||
*/
|
||||
template<typename InputType, typename OutputType>
|
||||
void FastSigmoid(const InputType& input, OutputType& sigmoids)
|
||||
{
|
||||
for (size_t i = 0; i < input.n_elem; ++i)
|
||||
@@ -214,10 +201,10 @@ class FastLSTM
|
||||
* @param data The given data sample for the sigmoid approximation.
|
||||
* @tparam The sigmoid approximation.
|
||||
*/
|
||||
ElemType FastSigmoid(const InputElemType data)
|
||||
OutputET FastSigmoid(const InputET data)
|
||||
{
|
||||
ElemType x = 0.5 * data;
|
||||
ElemType z;
|
||||
OutputET x = 0.5 * data;
|
||||
OutputET z;
|
||||
if (x >= 0)
|
||||
{
|
||||
if (x < 1.7)
|
||||
@@ -229,7 +216,7 @@ class FastLSTM
|
||||
}
|
||||
else
|
||||
{
|
||||
ElemType xx = -x;
|
||||
OutputET xx = -x;
|
||||
if (xx < 1.7)
|
||||
z = -(1.5 * xx / (1 + xx));
|
||||
else if (xx < 3)
|
||||
@@ -260,10 +247,10 @@ class FastLSTM
|
||||
size_t gradientStep;
|
||||
|
||||
//! Locally-stored weight object.
|
||||
OutputDataType weights;
|
||||
OutputType weights;
|
||||
|
||||
//! Locally-stored previous output.
|
||||
OutputDataType prevOutput;
|
||||
OutputType prevOutput;
|
||||
|
||||
//! Locally-stored batch size.
|
||||
size_t batchSize;
|
||||
@@ -276,56 +263,50 @@ class FastLSTM
|
||||
size_t gradientStepIdx;
|
||||
|
||||
//! Locally-stored cell activation error.
|
||||
OutputDataType cellActivationError;
|
||||
|
||||
//! Locally-stored delta object.
|
||||
OutputDataType delta;
|
||||
|
||||
//! Locally-stored gradient object.
|
||||
OutputDataType grad;
|
||||
OutputType cellActivationError;
|
||||
|
||||
//! Locally-stored output parameter object.
|
||||
OutputDataType outputParameter;
|
||||
OutputType outputParameter;
|
||||
|
||||
//! Weights between the output and gate.
|
||||
OutputDataType output2GateWeight;
|
||||
OutputType output2GateWeight;
|
||||
|
||||
//! Weights between the input and gate.
|
||||
OutputDataType input2GateWeight;
|
||||
OutputType input2GateWeight;
|
||||
|
||||
//! Bias between the input and gate.
|
||||
OutputDataType input2GateBias;
|
||||
OutputType input2GateBias;
|
||||
|
||||
//! Locally-stored gate parameter.
|
||||
OutputDataType gate;
|
||||
OutputType gate;
|
||||
|
||||
//! Locally-stored gate activation.
|
||||
OutputDataType gateActivation;
|
||||
OutputType gateActivation;
|
||||
|
||||
//! Locally-stored state activation.
|
||||
OutputDataType stateActivation;
|
||||
OutputType stateActivation;
|
||||
|
||||
//! Locally-stored cell parameter.
|
||||
OutputDataType cell;
|
||||
OutputType cell;
|
||||
|
||||
//! Locally-stored cell activation error.
|
||||
OutputDataType cellActivation;
|
||||
OutputType cellActivation;
|
||||
|
||||
//! Locally-stored foget gate error.
|
||||
OutputDataType forgetGateError;
|
||||
OutputType forgetGateError;
|
||||
|
||||
//! Locally-stored previous error.
|
||||
OutputDataType prevError;
|
||||
|
||||
//! Locally-stored output parameters.
|
||||
OutputDataType outParameter;
|
||||
OutputType prevError;
|
||||
|
||||
//! Locally-stored current rho size.
|
||||
size_t rhoSize;
|
||||
|
||||
//! Current backpropagate through time steps.
|
||||
size_t bpttSteps;
|
||||
}; // class FastLSTM
|
||||
}; // class FastLSTMType.
|
||||
|
||||
// Standard FastLSTM layer.
|
||||
typedef FastLSTMType<arma::mat, arma::mat> FastLSTM;
|
||||
|
||||
} // namespace ann
|
||||
} // namespace mlpack
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user