edit chatbot and core
This commit is contained in:
+37
-56
@@ -1,82 +1,63 @@
|
||||
#include "core.h"
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
NeuralNetwork::NeuralNetwork(LayerStructure_t layers[], int count) {
|
||||
numLayers = count;
|
||||
for (int i = 0; i < count; i++) {
|
||||
layerSizes.push_back(layers[i].size);
|
||||
}
|
||||
|
||||
// Инициализация весов случайными числами
|
||||
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++) {
|
||||
std::vector<std::vector<double>> layerWeights;
|
||||
for (int j = 0; j < layerSizes[i+1]; j++) {
|
||||
std::vector<double> nodeWeights;
|
||||
for (int k = 0; k < layerSizes[i]; k++) {
|
||||
nodeWeights.push_back(((double)rand() / RAND_MAX) * 2 - 1);
|
||||
}
|
||||
layerWeights.push_back(nodeWeights);
|
||||
std::vector<std::vector<double>> layerW;
|
||||
double scale = sqrt(2.0 / sizes[i]);
|
||||
for (int j = 0; j < sizes[i+1]; j++) {
|
||||
std::vector<double> nodeW;
|
||||
for (int k = 0; k < sizes[i]; k++)
|
||||
nodeW.push_back(((double)rand()/RAND_MAX * 2 - 1) * scale);
|
||||
layerW.push_back(nodeW);
|
||||
}
|
||||
weights.push_back(layerWeights);
|
||||
|
||||
std::vector<double> layerBiases;
|
||||
for (int j = 0; j < layerSizes[i+1]; j++) {
|
||||
layerBiases.push_back(((double)rand() / RAND_MAX) * 2 - 1);
|
||||
}
|
||||
biases.push_back(layerBiases);
|
||||
weights.push_back(layerW);
|
||||
biases.push_back(std::vector<double>(sizes[i+1], 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<double> NeuralNetwork::feedForward(std::vector<double> input) {
|
||||
std::vector<double> NeuralNetwork::feedForward(const std::vector<double>& input) {
|
||||
outputs.clear();
|
||||
outputs.push_back(input);
|
||||
|
||||
std::vector<double> current = input;
|
||||
std::vector<double> curr = input;
|
||||
for (int i = 0; i < numLayers - 1; i++) {
|
||||
std::vector<double> next;
|
||||
for (int j = 0; j < layerSizes[i+1]; j++) {
|
||||
for (int j = 0; j < sizes[i+1]; j++) {
|
||||
double sum = biases[i][j];
|
||||
for (int k = 0; k < layerSizes[i]; k++) {
|
||||
sum += current[k] * weights[i][j][k];
|
||||
}
|
||||
next.push_back(sigmoid(sum));
|
||||
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)));
|
||||
}
|
||||
current = next;
|
||||
outputs.push_back(current);
|
||||
curr = next;
|
||||
outputs.push_back(curr);
|
||||
}
|
||||
return current;
|
||||
return curr;
|
||||
}
|
||||
|
||||
void NeuralNetwork::train(std::vector<double> input, std::vector<double> target, double lr) {
|
||||
// 1. Прямой проход
|
||||
feedForward(input);
|
||||
|
||||
// 2. Вычисление ошибок для выходного слоя
|
||||
double NeuralNetwork::train(const std::vector<double>& input, const std::vector<double>& target, double lr) {
|
||||
std::vector<double> pred = feedForward(input);
|
||||
std::vector<std::vector<double>> errors(numLayers);
|
||||
errors[numLayers - 1].resize(layerSizes[numLayers - 1]);
|
||||
for (int i = 0; i < layerSizes[numLayers - 1]; i++) {
|
||||
double output = outputs[numLayers - 1][i];
|
||||
errors[numLayers - 1][i] = (target[i] - output) * sigmoidDerivative(output);
|
||||
errors[numLayers-1].resize(sizes[numLayers-1]);
|
||||
double totalErr = 0;
|
||||
for (int i = 0; i < sizes[numLayers-1]; i++) {
|
||||
double e = target[i] - pred[i];
|
||||
errors[numLayers-1][i] = e * pred[i] * (1.0 - pred[i]);
|
||||
totalErr += e * e;
|
||||
}
|
||||
|
||||
// 3. Обратное распространение ошибки на скрытые слои
|
||||
for (int i = numLayers - 2; i > 0; i--) {
|
||||
errors[i].resize(layerSizes[i]);
|
||||
for (int j = 0; j < layerSizes[i]; j++) {
|
||||
double error = 0.0;
|
||||
for (int k = 0; k < layerSizes[i+1]; k++) {
|
||||
error += errors[i+1][k] * weights[i][k][j];
|
||||
}
|
||||
errors[i][j] = error * sigmoidDerivative(outputs[i][j]);
|
||||
errors[i].resize(sizes[i]);
|
||||
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. Обновление весов и смещений
|
||||
for (int i = 0; i < numLayers - 1; i++) {
|
||||
for (int j = 0; j < layerSizes[i+1]; j++) {
|
||||
for (int k = 0; k < layerSizes[i]; k++) {
|
||||
weights[i][j][k] += lr * errors[i+1][j] * outputs[i][k];
|
||||
}
|
||||
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;
|
||||
}
|
||||
+7
-10
@@ -4,25 +4,22 @@
|
||||
#include "typedef.h"
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
class NeuralNetwork {
|
||||
private:
|
||||
int numLayers;
|
||||
std::vector<int> layerSizes;
|
||||
std::vector<std::vector<std::vector<double>>> weights; // weights[layer][to_node][from_node]
|
||||
std::vector<std::vector<double>> biases; // biases[layer][node]
|
||||
std::vector<std::vector<double>> outputs; // Храним выходы слоев для backprop
|
||||
std::vector<int> sizes;
|
||||
std::vector<std::vector<std::vector<double>>> weights;
|
||||
std::vector<std::vector<double>> biases;
|
||||
std::vector<std::vector<double>> outputs;
|
||||
|
||||
double sigmoid(double x) { return 1.0 / (1.0 + exp(-x)); }
|
||||
double sigmoidDerivative(double x) { return x * (1.0 - x); }
|
||||
double sigmoidDeriv(double x) { return x * (1.0 - x); }
|
||||
|
||||
public:
|
||||
NeuralNetwork(LayerStructure_t layers[], int count);
|
||||
|
||||
std::vector<double> feedForward(std::vector<double> input);
|
||||
void train(std::vector<double> input, std::vector<double> target, double learningRate);
|
||||
std::vector<double> feedForward(const std::vector<double>& input);
|
||||
double train(const std::vector<double>& input, const std::vector<double>& target, double lr);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "token.h"
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
void Tokenizer::add(std::string word) {
|
||||
int id = wordToId.size();
|
||||
wordToId[word] = id;
|
||||
idToWord[id] = word;
|
||||
}
|
||||
|
||||
std::string Tokenizer::getWord(int id) {
|
||||
return idToWord.count(id) ? idToWord[id] : "";
|
||||
}
|
||||
|
||||
std::vector<int> Tokenizer::textToTokens(const std::string& text) {
|
||||
std::vector<int> tokens;
|
||||
size_t pos = 0;
|
||||
while (pos < text.length()) {
|
||||
int longestId = -1; size_t longestLen = 0;
|
||||
for (auto const& [word, id] : wordToId) {
|
||||
if (text.compare(pos, word.length(), word) == 0) {
|
||||
if (word.length() > longestLen) {
|
||||
longestLen = word.length(); longestId = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (longestId != -1) {
|
||||
tokens.push_back(longestId);
|
||||
pos += longestLen;
|
||||
} else pos++;
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
Embedder::Embedder(int vSize, int dim) {
|
||||
std::mt19937 gen(42);
|
||||
std::uniform_real_distribution<double> dist(-1.0, 1.0);
|
||||
matrix.resize(vSize, std::vector<double>(dim));
|
||||
for(int i=0; i<vSize; i++)
|
||||
for(int j=0; j<dim; j++) matrix[i][j] = dist(gen);
|
||||
}
|
||||
|
||||
std::vector<double> Embedder::get(int id) {
|
||||
if (id >= 0 && id < (int)matrix.size()) return matrix[id];
|
||||
return std::vector<double>(matrix[0].size(), 0.0);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef TOKEN_H
|
||||
#define TOKEN_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
class Tokenizer {
|
||||
public:
|
||||
std::map<std::string, int> wordToId;
|
||||
std::map<int, std::string> idToWord;
|
||||
|
||||
Tokenizer() {
|
||||
add("<EOS>"); // 0
|
||||
add("[SYS]"); // 1
|
||||
add("[USER]"); // 2
|
||||
add("[AI]"); // 3
|
||||
add(" "); // 4
|
||||
add("\n"); // 5
|
||||
add("привет"); // 6
|
||||
add("как"); // 7
|
||||
add("дела"); // 8
|
||||
add("?"); // 9
|
||||
add("я"); // 10
|
||||
add("робот"); // 11
|
||||
add("хорошо"); // 12
|
||||
}
|
||||
|
||||
void add(std::string word);
|
||||
int getID(std::string word);
|
||||
std::string getWord(int id);
|
||||
std::vector<int> textToTokens(const std::string& text);
|
||||
};
|
||||
|
||||
class Embedder {
|
||||
public:
|
||||
std::vector<std::vector<double>> matrix;
|
||||
Embedder(int vSize, int dim);
|
||||
std::vector<double> get(int id);
|
||||
};
|
||||
|
||||
#endif
|
||||
+5
-9
@@ -1,15 +1,11 @@
|
||||
#ifndef TYPEDEF_H
|
||||
#define TYPEDEF_H
|
||||
|
||||
#include <vector>
|
||||
const int MAX_CONTEXT = 4; // Сколько токенов видит сеть
|
||||
const int EMBED_DIM = 4; // Размер вектора одного токена
|
||||
const int MAX_VOCAB = 13; // Размер словаря
|
||||
|
||||
typedef enum {
|
||||
SIGMOID
|
||||
} FunctionActivate_t;
|
||||
|
||||
typedef struct {
|
||||
int size;
|
||||
FunctionActivate_t activate;
|
||||
} LayerStructure_t;
|
||||
typedef enum { SIGMOID } FunctionActivate_t;
|
||||
typedef struct { int size; FunctionActivate_t activate; } LayerStructure_t;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user