Source browser

examples/neural_checks.hpp

Read the complete file below or download its original bytes. Line numbers provide stable links to a declaration or processing step.

File fingerprint
1/** @file neural_checks.hpp
2 * @brief Training, inference and numerical validation shared by the ANN/CNN applications.
3 */
4#ifndef SHDR_EXAMPLES_NEURAL_CHECKS_HPP // Open this include guard or optional feature branch.
5#define SHDR_EXAMPLES_NEURAL_CHECKS_HPP // Define SHDR_EXAMPLES_NEURAL_CHECKS_HPP for the declarations that follow.
6#include "runner.hpp" // Include runner.hpp declarations.
7#include "neural_support.hpp" // Include neural_support.hpp declarations.
8
9namespace shdr_examples { // Group these helpers within their namespace.
10
11/** @brief Run complete model checks on the selected backend, including every parameter. */
12inline int binary_example_main(int argc, char** argv, bool cnn) { // Implement binary example main for the operations below.
13    try { // Run the operation while retaining the error handling below.
14        runner run(argc, argv); // Construct run with these initial values.
15        binary_network model(cnn); // Construct model with these initial values.
16        check_binary_gradients(model); // Apply check binary gradients to these arguments.
17        const float* cpu_gradients = // Set cpu gradients from this expression.
18            static_cast<const shdr::buffer<float>&>(model.gradients).data(); // Apply data to these arguments.
19        const std::vector<float> expected_gradient(cpu_gradients, // Declare expected gradient with the parameters continued below.
20                                                   cpu_gradients + model.gradients.size()); // Apply size to these arguments.
21        if (run.gpu()) { // Check this condition before entering the following branch.
22            run.run(model.gradient_pipeline()); // Execute the configured pipeline on the requested backend.
23            const float* gpu_gradients = // Set gpu gradients from this expression.
24                static_cast<const shdr::buffer<float>&>(model.gradients).data(); // Apply data to these arguments.
25            for (std::size_t i = 0; i < expected_gradient.size(); ++i) // Iterate over i for this calculation.
26                require_close( // Check the computed value against the independent reference.
27                    gpu_gradients[i], expected_gradient[i], "neural CPU/GPU gradient", 0.0002f); // Continue the expression using gpu gradients, i, expected gradient.
28        } // End this block.
29        run.run(model.evaluation_pipeline()); // Execute the configured pipeline on the requested backend.
30        const float initial_loss = static_cast<const shdr::buffer<float>&>(model.loss).data()[0]; // Use a constant buffer view so GPU writes synchronize before host reads.
31        const unsigned steps = cnn ? 180u : 160u; // Set steps from this expression.
32        for (unsigned step = 0; step < steps; ++step) // Iterate over step for this calculation.
33            run.run(model.training_pipeline()); // Execute the configured pipeline on the requested backend.
34        run.run(model.evaluation_pipeline()); // Execute the configured pipeline on the requested backend.
35        const float final_loss = static_cast<const shdr::buffer<float>&>(model.loss).data()[0]; // Use a constant buffer view so GPU writes synchronize before host reads.
36        const shdr::buffer<float>& parameter_buffer = model.parameters; // Use a constant buffer view so GPU writes synchronize before host reads.
37        const std::vector<double> weights(parameter_buffer.data(), // Declare weights with the parameters continued below.
38                                          parameter_buffer.data() + parameter_buffer.size()); // Apply data to these arguments.
39        const float* probabilities = // Set probabilities from this expression.
40            static_cast<const shdr::buffer<float>&>(model.predictions).data(); // Apply data to these arguments.
41        const float* labels = static_cast<const shdr::buffer<float>&>(model.targets).data(); // Use a constant buffer view so GPU writes synchronize before host reads.
42        unsigned correct = 0; // Set correct from this expression.
43        for (unsigned sample = 0; sample < model.batch_count(); ++sample) { // Iterate over sample for this calculation.
44            require_close(probabilities[sample], // Check the computed value against the independent reference.
45                          float(binary_reference_probability(model, weights, sample)), // Apply float to these arguments.
46                          "neural inference oracle", // Provide this text argument for the operation above.
47                          0.0002f); // Complete this expression or declaration.
48            if ((probabilities[sample] >= 0.5f) == (labels[sample] >= 0.5f)) // Check this condition before entering the following branch.
49                ++correct; // Continue the expression using correct.
50        } // End this block.
51        if (!(final_loss < initial_loss * 0.8f) || correct < model.batch_count() * 9u / 10u) // Check this condition before entering the following branch.
52            throw shdr::error( // Report this failed operation.
53                "neural training did not reduce loss and learn the seeded classification task"); // Provide this text argument for the operation above.
54        if (run.gpu()) { // Check this condition before entering the following branch.
55            binary_network cpu(cnn); // Construct cpu with these initial values.
56            for (unsigned step = 0; step < steps; ++step) // Iterate over step for this calculation.
57                cpu.training_pipeline().run(); // Execute the configured pipeline on the requested backend.
58            cpu.prediction_pipeline().run(); // Execute the configured pipeline on the requested backend.
59            const float* cpu_weights = // Set cpu weights from this expression.
60                static_cast<const shdr::buffer<float>&>(cpu.parameters).data(); // Apply data to these arguments.
61            const float* cpu_probabilities = // Set cpu probabilities from this expression.
62                static_cast<const shdr::buffer<float>&>(cpu.predictions).data(); // Apply data to these arguments.
63            for (unsigned parameter = 0; parameter < model.parameter_count(); ++parameter) // Iterate over parameter for this calculation.
64                require_close(float(weights[parameter]), // Check the computed value against the independent reference.
65                              cpu_weights[parameter], // Continue the expression using cpu weights, parameter.
66                              "neural trained CPU/GPU weights", // Provide this text argument for the operation above.
67                              0.002f); // Complete this expression or declaration.
68            for (unsigned sample = 0; sample < model.batch_count(); ++sample) // Iterate over sample for this calculation.
69                require_close(probabilities[sample], // Check the computed value against the independent reference.
70                              cpu_probabilities[sample], // Continue the expression using cpu probabilities, sample.
71                              "neural trained CPU/GPU predictions", // Provide this text argument for the operation above.
72                              0.002f); // Complete this expression or declaration.
73        } // End this block.
74        std::cout << (cnn ? "CNN" : "ANN") << ": " << model.parameter_count() // Write this part of the example result or diagnostic.
75                  << " parameters trained for " << steps << " steps, loss " << initial_loss // Write this part of the example result or diagnostic.
76                  << " -> " << final_loss << ", accuracy " << correct << '/' << model.batch_count() // Write this part of the example result or diagnostic.
77                  << "; analytic gradients and inference verified\n"; // Write this part of the example result or diagnostic.
78        return 0; // Report successful completion.
79    } // End this block.
80#ifdef SHDR_HAVE_EGL // Enable this branch when its feature macro is defined.
81    catch (const context_unavailable& e) { // Handle the indicated exception from the preceding operation.
82        std::cerr << "SKIP: " << e.what() << '\n'; // Write this part of the example result or diagnostic.
83        return 77; // Report an unavailable optional GPU backend.
84    } // End this block.
85#endif // Finish this conditional compilation branch.
86    catch (const std::exception& e) { // Handle the indicated exception from the preceding operation.
87        std::cerr << e.what() << '\n'; // Write this part of the example result or diagnostic.
88        return 1; // Report a failed check or operation.
89    } // End this block.
90} // End this block.
91} // namespace shdr_examples
92#endif // Finish this conditional compilation branch.