diff --git a/Xenith/core.cpp b/Xenith/core.cpp index 02b71fb..7d198e6 100644 --- a/Xenith/core.cpp +++ b/Xenith/core.cpp @@ -2,19 +2,6 @@ #include #include -#define USE_PARALLEL // Закомментируйте, чтобы отключить параллелизм -#define MAX_THREADS 0 // Укажите число ядер (0 — использовать все доступные) - -#ifdef USE_PARALLEL -#include -#define OMP_PARALLEL _Pragma("omp parallel for") -#define OMP_SET_THREADS() { if (MAX_THREADS > 0) omp_set_num_threads(MAX_THREADS); } -#else -#define OMP_PARALLEL -#define OMP_SET_THREADS() -#endif - - NeuralNetwork::NeuralNetwork(LayerStructure_t layers[], int count) : numLayers(count) { for (int i = 0; i < count; i++) sizes.push_back(layers[i].size); for (int i = 0; i < count - 1; i++) { @@ -32,32 +19,18 @@ NeuralNetwork::NeuralNetwork(LayerStructure_t layers[], int count) : numLayers(c } std::vector NeuralNetwork::feedForward(const std::vector& input) { - OMP_SET_THREADS(); // Применяем лимит ядер - outputs.clear(); outputs.push_back(input); std::vector curr = input; for (int i = 0; i < numLayers - 1; i++) { - // Заранее готовим вектор нужного размера для текущего слоя - std::vector next(sizes[i + 1]); - - // Распараллеливаем расчет каждого нейрона в слое - OMP_PARALLEL - for (int j = 0; j < sizes[i + 1]; j++) { - double sum = biases[i][j]; - - // Внутренний цикл обычно оставляем последовательным, - // так как создание потоков здесь даст больше тормозов, чем пользы - for (int k = 0; k < (int)curr.size(); k++) { - sum += curr[k] * weights[i][j][k]; - } - - // Сигмоида. Теперь пишем по индексу j — это безопасно для потоков - next[j] = 1.0 / (1.0 + exp(-sum)); - } - + std::vector next; + for (int j = 0; j < sizes[i+1]; j++) { + double sum = biases[i][j]; + for (int k = 0; k < (int)curr.size(); k++) sum += curr[k] * weights[i][j][k]; + next.push_back(1.0 / (1.0 + exp(-sum))); + } curr = next; outputs.push_back(curr); } @@ -66,53 +39,30 @@ std::vector NeuralNetwork::feedForward(const std::vector& input) double NeuralNetwork::train(const std::vector& input, const std::vector& target, double lr) { - // 0. Устанавливаем количество потоков (если включено в define) - OMP_SET_THREADS(); - - // 1. Прямой проход (получаем предсказание) std::vector pred = feedForward(input); std::vector> errors(numLayers); errors[numLayers - 1].resize(sizes[numLayers - 1]); double totalErr = 0; - - // 2. Вычисление ошибки на выходном слое - for (int i = 0; i < sizes[numLayers - 1]; i++) { + for (int i = 0; i < sizes[numLayers-1]; i++) { double e = target[i] - pred[i]; - // Производная функции активации (сигмоиды): pred * (1 - pred) - errors[numLayers - 1][i] = e * pred[i] * (1.0 - pred[i]); + errors[numLayers-1][i] = e * pred[i] * (1.0 - pred[i]); totalErr += e * e; } - - // 3. Обратное распространение ошибки (Backpropagation) по скрытым слоям for (int i = numLayers - 2; i > 0; i--) { errors[i].resize(sizes[i]); - - // Параллелим вычисления для каждого нейрона в слое - OMP_PARALLEL - for (int j = 0; j < sizes[i]; j++) { - double e = 0; - for (int k = 0; k < sizes[i + 1]; k++) { - e += errors[i + 1][k] * weights[i][k][j]; - } - // outputs[i][j] — это сохраненный результат активации этого нейрона из feedForward - errors[i][j] = e * outputs[i][j] * (1.0 - outputs[i][j]); - } + for (int j = 0; j < sizes[i]; j++) { + double e = 0; + for (int k = 0; k < sizes[i+1]; k++) e += errors[i+1][k] * weights[i][k][j]; + errors[i][j] = e * outputs[i][j] * (1.0 - outputs[i][j]); + } } - - // 4. Обновление весов и смещений (Biases) for (int i = 0; i < numLayers - 1; i++) { - - // Параллелим обновление весов следующего слоя - OMP_PARALLEL - for (int j = 0; j < sizes[i + 1]; j++) { - for (int k = 0; k < sizes[i]; k++) { - // Градиентный спуск: прибавляем (lr * ошибка * входной сигнал) - weights[i][j][k] += lr * errors[i + 1][j] * outputs[i][k]; - } - biases[i][j] += lr * errors[i + 1][j]; - } + for (int j = 0; j < sizes[i+1]; j++) { + for (int k = 0; k < sizes[i]; k++) weights[i][j][k] += lr * errors[i+1][j] * outputs[i][k]; + biases[i][j] += lr * errors[i+1][j]; + } } return totalErr;