手把手使用 C++ 构建多层神经网络(深度神经网络)
第一步:实现矩阵和相关运算(也可以使用 Eigen 库)
以下实现较为轻量,且可读性高、满足神经网络基本操作,定义了一些示例函数。后期可使用 CPU 指令集或 GPU、TPU 加速或使用 NPU 加速替代。
#include <iostream>
#include <vector>
using VECTOR = std::vector<double>;
class MATRIX : public std::vector<VECTOR> {
public:
MATRIX() { }
MATRIX(int n, int m) { resize(n, VECTOR(m, 0)); }
inline std::size_t rows() const noexcept {
return size();
}
inline std::size_t cols() const noexcept {
if (empty()) return 0;
return (*this)[0].size();
}
MATRIX operator + (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] += other;
}
}
return res;
}
MATRIX operator + (MATRIX other) const {
if (rows() != other.rows() || cols() != other.cols()) {
throw std::runtime_error("(MATRIX) operator + Error: rows() != other.rows() || cols() != other.cols()");
}
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] += other[i][j];
}
}
return res;
}
MATRIX operator - (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] -= other;
}
}
return res;
}
MATRIX operator - (MATRIX other) const {
if (rows() != other.rows() || cols() != other.cols()) {
throw std::runtime_error("(MATRIX) operator - Error: rows() != other.rows() || cols() != other.cols()");
}
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] -= other[i][j];
}
}
return res;
}
MATRIX operator * (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] *= other;
}
}
return res;
}
MATRIX operator * (MATRIX other) const {
if (cols() != other.rows()) {
throw std::runtime_error("(MATRIX) operator * Error: cols() != other.rows()");
}
MATRIX res(rows(), other.cols());
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
for (int k = 0; k < cols(); ++k) {
res[i][j] += (*this)[i][k] * other[k][j];
}
}
}
return res;
}
MATRIX operator / (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] /= other;
}
}
return res;
}
static MATRIX Hadamard_Static(MATRIX a, MATRIX b) {
if (a.rows() != b.rows() || a.cols() != b.cols()) {
throw std::runtime_error("(MATRIX) Hadamard Error: a.rows() != b.rows() || a.cols() != b.cols()");
}
MATRIX res = a;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] *= b[i][j];
}
}
return res;
}
static void EXAMPLE_ADD1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a + b;
std::cout << "(a + b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_ADD2() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto add = a + b;
std::cout << "(a + b)'s size: " << add.rows() << " " << add.cols() << std::endl;
for (int i = 0; i < add.rows(); ++i) {
for (int j = 0; j < add.cols(); ++j) {
std::cout << add[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_SUB1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a + b;
std::cout << "(a - b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_SUB2() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto add = a - b;
std::cout << "(a - b)'s size: " << add.rows() << " " << add.cols() << std::endl;
for (int i = 0; i < add.rows(); ++i) {
for (int j = 0; j < add.cols(); ++j) {
std::cout << add[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_MULTI1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a * b;
std::cout << "(a * b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_MULTI2() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto multi = a * b;
std::cout << "(ab)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_DEVIDE1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a / b;
std::cout << "(a / b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_HADAMARD1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto add = Hadamard_Static(a, b);
std::cout << "Hadamard(a, b)'s size: " << add.rows() << " " << add.cols() << std::endl;
for (int i = 0; i < add.rows(); ++i) {
for (int j = 0; j < add.cols(); ++j) {
std::cout << add[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
};
constexpr auto Hadamard = MATRIX::Hadamard_Static;
int main() {
MATRIX::EXAMPLE_HADAMARD1();
return 0;
}
第二步:激活函数的定义
以下实现补充了常见、流行的激活函数(2024 年)的定义,并允许用户自行定义激活函数。自定义方法:std::pair<std::function<double(double)>, std::function<double(double)>>。
#include <iostream>
#include <vector>
#include <cmath>
#include <functional>
#include <utility>
using VECTOR = std::vector<double>;
class MATRIX : public std::vector<VECTOR> {
public:
MATRIX() { }
MATRIX(int n, int m) { resize(n, VECTOR(m, 0)); }
inline std::size_t rows() const noexcept {
return size();
}
inline std::size_t cols() const noexcept {
if (empty()) return 0;
return (*this)[0].size();
}
MATRIX operator + (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] += other;
}
}
return res;
}
MATRIX operator + (MATRIX other) const {
if (rows() != other.rows() || cols() != other.cols()) {
throw std::runtime_error("(MATRIX) operator + Error: rows() != other.rows() || cols() != other.cols()");
}
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] += other[i][j];
}
}
return res;
}
MATRIX operator - (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] -= other;
}
}
return res;
}
MATRIX operator - (MATRIX other) const {
if (rows() != other.rows() || cols() != other.cols()) {
throw std::runtime_error("(MATRIX) operator - Error: rows() != other.rows() || cols() != other.cols()");
}
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] -= other[i][j];
}
}
return res;
}
MATRIX operator * (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] *= other;
}
}
return res;
}
MATRIX operator * (MATRIX other) const {
if (cols() != other.rows()) {
throw std::runtime_error("(MATRIX) operator * Error: cols() != other.rows()");
}
MATRIX res(rows(), other.cols());
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
for (int k = 0; k < cols(); ++k) {
res[i][j] += (*this)[i][k] * other[k][j];
}
}
}
return res;
}
MATRIX operator / (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] /= other;
}
}
return res;
}
static MATRIX Hadamard_Static(MATRIX a, MATRIX b) {
if (a.rows() != b.rows() || a.cols() != b.cols()) {
throw std::runtime_error("(MATRIX) Hadamard Error: a.rows() != b.rows() || a.cols() != b.cols()");
}
MATRIX res = a;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] *= b[i][j];
}
}
return res;
}
static void EXAMPLE_ADD1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a + b;
std::cout << "(a + b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_ADD2() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto add = a + b;
std::cout << "(a + b)'s size: " << add.rows() << " " << add.cols() << std::endl;
for (int i = 0; i < add.rows(); ++i) {
for (int j = 0; j < add.cols(); ++j) {
std::cout << add[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_SUB1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a + b;
std::cout << "(a - b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_SUB2() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto add = a - b;
std::cout << "(a - b)'s size: " << add.rows() << " " << add.cols() << std::endl;
for (int i = 0; i < add.rows(); ++i) {
for (int j = 0; j < add.cols(); ++j) {
std::cout << add[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_MULTI1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a * b;
std::cout << "(a * b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_MULTI2() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto multi = a * b;
std::cout << "(ab)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_DEVIDE1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a / b;
std::cout << "(a / b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_HADAMARD1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto add = Hadamard_Static(a, b);
std::cout << "Hadamard(a, b)'s size: " << add.rows() << " " << add.cols() << std::endl;
for (int i = 0; i < add.rows(); ++i) {
for (int j = 0; j < add.cols(); ++j) {
std::cout << add[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
};
constexpr auto Hadamard = MATRIX::Hadamard_Static;
using ActivationFunction = std::pair<std::function<double(double)>, std::function<double(double)>>;
ActivationFunction Sigmoid = {(std::function<double(double)>)[](double x) -> double {
return 1 / (1 + exp(-x));
}, (std::function<double(double)>)[](double x) -> double {
double SigmoidValue = 1 / (1 + exp(-x));
return SigmoidValue * (1 - SigmoidValue);
}};
ActivationFunction ReLU = {(std::function<double(double)>)[](double x) -> double {
return std::max((double)0.0, x);
}, (std::function<double(double)>)[](double x) -> double {
return x > 0 ? (double)1.0 : (double)0.0;
}};
int main() {
double x;
std::cin >> x;
std::cout << "Sigmoid(" << x << ") = " << Sigmoid.first(x) << std::endl;
std::cout << "Sigmoid'(" << x << ") = " << Sigmoid.second(x) << std::endl;
std::cout << "ReLU(" << x << ") = " << ReLU.first(x) << std::endl;
std::cout << "ReLU'(" << x << ") = " << ReLU.second(x) << std::endl;
return 0;
}
第三步:神经网络类的定义
#include <iostream>
#include <vector>
#include <cmath>
#include <functional>
#include <utility>
#include <random>
#include <ctime>
using VECTOR = std::vector<double>;
class MATRIX : public std::vector<VECTOR> {
public:
MATRIX() { }
MATRIX(int n, int m) { resize(n, VECTOR(m, 0)); }
inline std::size_t rows() const noexcept {
return size();
}
inline std::size_t cols() const noexcept {
if (empty()) return 0;
return (*this)[0].size();
}
MATRIX operator + (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] += other;
}
}
return res;
}
MATRIX operator + (MATRIX other) const {
if (rows() != other.rows() || cols() != other.cols()) {
throw std::runtime_error("(MATRIX) operator + Error: rows() != other.rows() || cols() != other.cols()");
}
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] += other[i][j];
}
}
return res;
}
MATRIX operator - (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] -= other;
}
}
return res;
}
MATRIX operator - (MATRIX other) const {
if (rows() != other.rows() || cols() != other.cols()) {
throw std::runtime_error("(MATRIX) operator - Error: rows() != other.rows() || cols() != other.cols()");
}
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] -= other[i][j];
}
}
return res;
}
MATRIX operator * (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] *= other;
}
}
return res;
}
MATRIX operator * (MATRIX other) const {
if (cols() != other.rows()) {
throw std::runtime_error("(MATRIX) operator * Error: cols() != other.rows()");
}
MATRIX res(rows(), other.cols());
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
for (int k = 0; k < cols(); ++k) {
res[i][j] += (*this)[i][k] * other[k][j];
}
}
}
return res;
}
MATRIX operator / (double other) const noexcept {
MATRIX res = *this;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] /= other;
}
}
return res;
}
static MATRIX Hadamard_Static(MATRIX a, MATRIX b) {
if (a.rows() != b.rows() || a.cols() != b.cols()) {
throw std::runtime_error("(MATRIX) Hadamard Error: a.rows() != b.rows() || a.cols() != b.cols()");
}
MATRIX res = a;
for (int i = 0; i < res.rows(); ++i) {
for (int j = 0; j < res.cols(); ++j) {
res[i][j] *= b[i][j];
}
}
return res;
}
static void EXAMPLE_ADD1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a + b;
std::cout << "(a + b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_ADD2() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto add = a + b;
std::cout << "(a + b)'s size: " << add.rows() << " " << add.cols() << std::endl;
for (int i = 0; i < add.rows(); ++i) {
for (int j = 0; j < add.cols(); ++j) {
std::cout << add[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_SUB1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a + b;
std::cout << "(a - b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_SUB2() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto add = a - b;
std::cout << "(a - b)'s size: " << add.rows() << " " << add.cols() << std::endl;
for (int i = 0; i < add.rows(); ++i) {
for (int j = 0; j < add.cols(); ++j) {
std::cout << add[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_MULTI1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a * b;
std::cout << "(a * b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_MULTI2() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto multi = a * b;
std::cout << "(ab)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_DEVIDE1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "Value b: ";
double b;
std::cin >> b;
std::cout << std::endl;
auto multi = a / b;
std::cout << "(a / b)'s size: " << multi.rows() << " " << multi.cols() << std::endl;
for (int i = 0; i < multi.rows(); ++i) {
for (int j = 0; j < multi.cols(); ++j) {
std::cout << multi[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
static void EXAMPLE_HADAMARD1() {
std::cout << "MATRIX a's size: ";
int n, m;
std::cin >> n >> m;
std::cout << std::endl;
MATRIX a(n, m);
std::cout << "MATRIX b's size: ";
std::cin >> n >> m;
std::cout << std::endl;
MATRIX b(n, m);
std::cout << "MATRIX a:" << std::endl;
for (int i = 0; i < a.rows(); ++i) {
for (int j = 0; j < a.cols(); ++j) {
std::cin >> a[i][j];
}
}
std::cout << "MATRIX b:" << std::endl;
for (int i = 0; i < b.rows(); ++i) {
for (int j = 0; j < b.cols(); ++j) {
std::cin >> b[i][j];
}
}
auto add = Hadamard_Static(a, b);
std::cout << "Hadamard(a, b)'s size: " << add.rows() << " " << add.cols() << std::endl;
for (int i = 0; i < add.rows(); ++i) {
for (int j = 0; j < add.cols(); ++j) {
std::cout << add[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
};
constexpr auto Hadamard = MATRIX::Hadamard_Static;
using ActivationFunction = std::pair<std::function<double(double)>, std::function<double(double)>>;
ActivationFunction Sigmoid = {(std::function<double(double)>)[](double x) -> double {
return 1 / (1 + exp(-x));
}, (std::function<double(double)>)[](double x) -> double {
double SigmoidValue = 1 / (1 + exp(-x));
return SigmoidValue * (1 - SigmoidValue);
}};
ActivationFunction ReLU = {(std::function<double(double)>)[](double x) -> double {
return std::max((double)0.0, x);
}, (std::function<double(double)>)[](double x) -> double {
return x > 0 ? (double)1.0 : (double)0.0;
}};
class NeuralNetwork {
public:
int layersN;
std::vector<std::size_t> layersNodes;
std::vector<ActivationFunction> layersActivationFunctions;
std::vector<MATRIX> weights, biases;
NeuralNetwork() { }
NeuralNetwork(std::vector<std::size_t> _layersNodes, std::vector<ActivationFunction> _layersActivationFunctions = {}) {
layersN = _layersNodes.size();
layersNodes = _layersNodes;
layersNodes.shrink_to_fit();
layersActivationFunctions.resize(layersN);
layersActivationFunctions.shrink_to_fit();
if (_layersActivationFunctions.empty()) [[unlikely]] {
for (int i = 1; i < layersN; ++i) {
layersActivationFunctions[i] = ReLU;
}
} else [[likely]] {
for (int i = 1; i < layersN; ++i) {
layersActivationFunctions[i] = _layersActivationFunctions[i - 1];
}
}
weights.resize(layersN);
for (int i = 1; i < weights.size(); ++i) {
auto& weight = weights[i];
weight = MATRIX(layersNodes[i], layersNodes[i - 1]);
}
biases.resize(layersN);
for (int i = 1; i < weights.size(); ++i) {
auto& biase = biases[i];
biase = MATRIX(layersNodes[i], 1);
}
}
std::vector<MATRIX> FeedForward(std::vector<MATRIX> inputs) const {
std::vector<MATRIX> outputs;
for (auto& input : inputs) {
MATRIX output = input;
for (int i = 1; i < layersN; ++i) {
output = weights[i] * output + biases[i];
for (int j = 0; j < output.rows(); ++j) {
output[j][0] = layersActivationFunctions[i].first(output[j][0]);
}
}
outputs.push_back(output);
}
return outputs;
}
std::vector<MATRIX> operator()(std::vector<MATRIX> input) const {
return FeedForward(input);
}
};
int main() {
NeuralNetwork NN({1, 100, 50, 2}, {ReLU, ReLU, Sigmoid});
srand(time(0));
for (int i = 1; i < 4; ++i) {
for (int j = 0; j < NN.weights[i].rows(); ++j) {
for (int k = 0; k < NN.weights[i].cols(); ++k) {
NN.weights[i][j][k] = rand() % 10 - 5;
}
}
for (int j = 0; j < NN.biases[i].rows(); ++j) {
NN.biases[i][j][0] = rand() % 10 - 5;
}
}
std::vector<MATRIX> inputs;
std::cout << "Enter the number of inputs: ";
int t;
std::cin >> t;
for (int i = 1; i <= t; ++i) {
MATRIX input(1, 1);
std::cout << std::endl << "input " << i << ": " << std::endl;
std::cin >> input[0][0];
inputs.push_back(input);
}
std::cout << std::endl << "------" << std::endl;
std::vector<MATRIX> outputs = NN(inputs);
for (auto& output : outputs) {
for (int i = 0; i < output.rows(); ++i) {
std::cout << output[i][0] << std::endl;
}
std::cout << std::endl;
}
return 0;
}