dist(-10.0f, 10.0f);
67 |
68 | float x = dist(rng);
69 |
70 | int lastPercent = -1;
71 | for (int i = 0; i < c_numSteps; ++i)
72 | {
73 | float derivative = FDerivative(x);
74 |
75 | int percent = int(100.0f * float(i) / float(c_numSteps - 1));
76 | if (percent != lastPercent)
77 | {
78 | printf("%3i%%: x = %0.2f, y = %0.2f, y' = %0.2f\n", percent, x, F(x), derivative);
79 | lastPercent = percent;
80 | }
81 |
82 | x -= derivative * c_gradientStepSize;
83 | }
84 |
85 | return 0;
86 | }
87 |
--------------------------------------------------------------------------------
/Exercises/4_Backprop/Exercise Set 4 - Instructions.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/electronicarts/cpp-ml-intro/682222d9993d122749723b54d8d6064d6117288a/Exercises/4_Backprop/Exercise Set 4 - Instructions.docx
--------------------------------------------------------------------------------
/Exercises/4_Backprop/Exercise Set 4 - Solutions.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/electronicarts/cpp-ml-intro/682222d9993d122749723b54d8d6064d6117288a/Exercises/4_Backprop/Exercise Set 4 - Solutions.docx
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2023 Electronic Arts Inc. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4 |
5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
7 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
8 | 4. EA’s marks or logos, including SEED logos, are distributed with this software solely for demonstration purposes and may not be displayed or shared other than as part of a redistribution of this software, provided they are redistributed without modification. No other rights are provided for the use of these marks and logos, other than for their intended demonstration purposes.
9 |
10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11 |
--------------------------------------------------------------------------------
/Machina Presentation 2023 - ML Intro For Game Devs.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/electronicarts/cpp-ml-intro/682222d9993d122749723b54d8d6064d6117288a/Machina Presentation 2023 - ML Intro For Game Devs.pptx
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CPPMLBasics
2 |
3 | The code repo to go with the blog posts and YouTube video:
4 | 1. Blog Part I: https://www.ea.com/seed/news/machine-learning-game-devs-part-1
5 | 2. Blog Part II: https://www.ea.com/seed/news/machine-learning-game-devs-part-2
6 | 3. Blog Part III: https://www.ea.com/seed/news/machine-learning-game-devs-part-3
7 | 4. All 3 parts in one video: https://www.youtube.com/watch?v=sTAqWRsEiy0
8 |
9 | The `Data` folder contains the mnist hand drawn digits in their source format. Executing the `Training` project will extract those images into pngs.
10 |
11 | The `Demo` folder contains the C++ DX12 demo which allows you to draw numbers, and have the neural network run on the GPU to try and classify what number you drew.
12 |
13 | The `Training` folder contains the C++ code to train the neural network on the mnist data.
14 |
15 | The `Exercises` folder contains the exercises that go along with the article.
16 |
17 | ## Authors
18 |
19 | 
20 | Search for Extraordinary Experiences Division (SEED) - Electronic Arts
http://seed.ea.com
21 | We are a cross-disciplinary team within EA Worldwide Studios.
22 | Our mission is to explore, build and help define the future of interactive entertainment.
23 |
24 | This code accompanies articles written by Alan Wolfe (blog.demofox.org)
25 |
--------------------------------------------------------------------------------
/Training/DataSet.h:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////
2 | // Machine Learning Introduction For Game Developers //
3 | // Copyright (c) 2023 Electronic Arts Inc. All rights reserved. //
4 | ///////////////////////////////////////////////////////////////////////////////
5 |
6 | #pragma once
7 |
8 | #include
9 | #include
10 | #include "Settings.h"
11 | #include
12 |
13 | struct DataItem
14 | {
15 | int label;
16 | float image[c_imageDims * c_imageDims + 1]; // We have an extra 1.0 value for the input layer bias term
17 | };
18 |
19 | typedef std::vector DataSet;
20 |
21 | void ExtractMNISTData(DataSet& trainingData, DataSet& testingData);
--------------------------------------------------------------------------------
/Training/GetGradient_BackProp.cpp:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////
2 | // Machine Learning Introduction For Game Developers //
3 | // Copyright (c) 2023 Electronic Arts Inc. All rights reserved. //
4 | ///////////////////////////////////////////////////////////////////////////////
5 |
6 | #include "Settings.h"
7 | #include "DataSet.h"
8 |
9 | std::span GetGradient_Backprop(TNeuralNetwork& neuralNet, const DataItem& dataItem)
10 | {
11 | return neuralNet.ForwardPassAndBackprop(dataItem.image, dataItem.label);
12 | }
--------------------------------------------------------------------------------
/Training/GetGradient_DualNumbers.cpp:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////
2 | // Machine Learning Introduction For Game Developers //
3 | // Copyright (c) 2023 Electronic Arts Inc. All rights reserved. //
4 | ///////////////////////////////////////////////////////////////////////////////
5 |
6 | #include "Settings.h"
7 | #include "DataSet.h"
8 |
9 | std::span GetGradient_DualNumbers(TNeuralNetwork& neuralNet, const DataItem& dataItem)
10 | {
11 | static std::vector gradient(TNeuralNetwork::c_numWeights);
12 |
13 | // Evaluate it and get the cost as a dual number
14 | DualNumber cost = neuralNet.EvaluateOneHotCost(dataItem.image, dataItem.label);
15 |
16 | // extract the gradient
17 | for (int i = 0; i < gradient.size(); ++i)
18 | gradient[i] = -cost.GetDualValue(i);
19 |
20 | return std::span{ gradient.data(), TNeuralNetwork::c_numWeights };
21 | }
22 |
--------------------------------------------------------------------------------
/Training/Settings.h:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////
2 | // Machine Learning Introduction For Game Developers //
3 | // Copyright (c) 2023 Electronic Arts Inc. All rights reserved. //
4 | ///////////////////////////////////////////////////////////////////////////////
5 |
6 | #pragma once
7 |
8 | #include "NN.h"
9 |
10 | #define TRAIN_FORWARD_DIFF() false
11 | #define TRAIN_CENTRAL_DIFF() false
12 | #define TRAIN_DUAL_NUMBERS() false
13 | #define TRAIN_BACKPROP() true
14 |
15 | #define DETERMINISTIC() false
16 | #define MULTI_THREADED() true
17 |
18 | static const size_t c_imageDims = 28;
19 |
20 | const size_t c_trainingEpochs = 30; // How many times we go through all of the training data.
21 | const size_t c_miniBatchSize = 10; // How many items of the training data we should train against, at a time.
22 | const float c_learningRate = 3.0f; // How fast should we travel down the gradient.
23 |
24 | const float c_finiteDifferencesEpsilon = 0.01f; // The epsilon used in finite differences
25 | const size_t c_finiteDifferencesThreadSize = 100; // How many weights should each thread handle when doing finite differences?
26 |
27 | // Our neural network has:
28 | // * 784 input neurons. 1 input neuron for each pixel.
29 | // * 30 hidden neurons. To help find how to match input to output.
30 | // * 10 output neurons. To specify the digit 0 to 9.
31 | using TNeuralNetwork = NeuralNetwork;
32 |
33 | struct DataItem;
34 |
35 | std::span GetGradient_FiniteDifferences_Central(TNeuralNetwork& neuralNet, const DataItem& dataItem);
36 | std::span GetGradient_FiniteDifferences_Forward(TNeuralNetwork& neuralNet, const DataItem& dataItem);
37 | std::span GetGradient_DualNumbers(TNeuralNetwork& neuralNet, const DataItem& dataItem);
38 | std::span GetGradient_Backprop(TNeuralNetwork& neuralNet, const DataItem& dataItem);
--------------------------------------------------------------------------------
/Training/StackPoolAllocator.h:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////
2 | // Machine Learning Introduction For Game Developers //
3 | // Copyright (c) 2023 Electronic Arts Inc. All rights reserved. //
4 | ///////////////////////////////////////////////////////////////////////////////
5 |
6 | #pragma once
7 |
8 | #include
9 | #include
10 |
11 | // A stack allocator that is also strongly typed
12 |
13 | template
14 | class StackPoolAllocator
15 | {
16 | public:
17 | StackPoolAllocator(size_t maxCount)
18 | {
19 | // Max size must be set in advance to not make pointers invalid while this is in use.
20 | m_storage.resize(maxCount);
21 | }
22 |
23 | inline void Reset()
24 | {
25 | m_nextFree = 0;
26 | }
27 |
28 | template
29 | inline std::span Allocate()
30 | {
31 | // Allocate space
32 | T* ret = &m_storage[m_nextFree];
33 | m_nextFree += COUNT;
34 |
35 | // nullptr when we run out of space.
36 | if (m_nextFree > m_storage.size())
37 | return std::span{ (T*)nullptr, COUNT };
38 |
39 | // Make the values clean
40 | auto retSpan = std::span{ ret, COUNT };
41 |
42 | if (INITIALIZE)
43 | {
44 | T dflt = {};
45 | std::fill(retSpan.begin(), retSpan.end(), dflt);
46 | }
47 |
48 | // Return the data
49 | return retSpan;
50 | }
51 |
52 | inline std::span Allocate(size_t count, bool initialize)
53 | {
54 | // Allocate space
55 | T* ret = &m_storage[m_nextFree];
56 | m_nextFree += count;
57 |
58 | // nullptr when we run out of space.
59 | if (m_nextFree > m_storage.size())
60 | return std::span{ (T*)nullptr, 0 };
61 |
62 | // Make the values clean
63 | auto retSpan = std::span{ ret, count };
64 | if (initialize)
65 | {
66 | T dflt = {};
67 | std::fill(retSpan.begin(), retSpan.end(), dflt);
68 | }
69 |
70 | // Return the data
71 | return retSpan;
72 | }
73 |
74 | private:
75 | size_t m_nextFree = 0;
76 | std::vector m_storage;
77 | };
78 |
--------------------------------------------------------------------------------
/Training/Training.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | stb
15 |
16 |
17 | stb
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | {a315bce1-e785-4bc7-b167-040582fe7f98}
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Training/Training.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Training/out/Backprop_Accuracy.csv:
--------------------------------------------------------------------------------
1 | "Epoch","Backprop"
2 | "1","91.459999"
3 | "2","92.830002"
4 | "3","92.820000"
5 | "4","94.120003"
6 | "5","94.190002"
7 | "6","94.550003"
8 | "7","94.900002"
9 | "8","94.510002"
10 | "9","94.769997"
11 | "10","94.940002"
12 | "11","95.070000"
13 | "12","95.199997"
14 | "13","95.180000"
15 | "14","95.349998"
16 | "15","95.389999"
17 | "16","95.239998"
18 | "17","95.559998"
19 | "18","95.250000"
20 | "19","95.400002"
21 | "20","95.410004"
22 | "21","95.419998"
23 | "22","95.180000"
24 | "23","95.519997"
25 | "24","95.230003"
26 | "25","95.440002"
27 | "26","95.449997"
28 | "27","95.730003"
29 | "28","95.430000"
30 | "29","95.610001"
31 | "30","95.540001"
32 |
--------------------------------------------------------------------------------
/Training/out/Backprop_Weights.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/electronicarts/cpp-ml-intro/682222d9993d122749723b54d8d6064d6117288a/Training/out/Backprop_Weights.bin
--------------------------------------------------------------------------------
/logo/SEED.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/electronicarts/cpp-ml-intro/682222d9993d122749723b54d8d6064d6117288a/logo/SEED.jpg
--------------------------------------------------------------------------------