FirstVersion

This commit is contained in:
2026-05-03 21:02:34 +07:00
parent 05875d8aa2
commit 0d6b240099
12 changed files with 632 additions and 566 deletions
+192 -232
View File
@@ -1,291 +1,251 @@
#include "core.hpp"
#include "token/token.hpp"
#include <cmath>
#include <cstdlib>
#include <omp.h>
#include <vulkan/vulkan.hpp>
#include <iostream>
#include <vector>
#include <chrono>
#include <fstream>
#include <string.h>
#include <omp.h>
#include <fstream>
// --- КОНСТРУКТОР ---
NeuralNetwork::NeuralNetwork(LayerStructure_t layers[], int count, bool useVulkanParam) {
this->numLayers = count;
this->useVulkan = useVulkanParam;
this->vulkanResourcesInitialized = false;
if (this->useVulkan) {
try {
vk::ApplicationInfo appInfo{"Xenith", 1, nullptr, 0, VK_API_VERSION_1_1};
instance = vk::createInstance({{}, &appInfo});
auto physicalDevices = instance.enumeratePhysicalDevices();
if (physicalDevices.empty()) throw std::runtime_error("GPU не найдены");
physDev = physicalDevices[0];
auto queueProps = physDev.getQueueFamilyProperties();
int computeFamily = -1;
for (int i = 0; i < (int)queueProps.size(); i++) {
if (queueProps[i].queueFlags & vk::QueueFlagBits::eCompute) {
computeFamily = i; break;
}
}
if (computeFamily == -1) throw std::runtime_error("Compute не поддерживается");
this->computeQueueFamilyIndex = (uint32_t)computeFamily;
float priority = 1.0f;
vk::DeviceQueueCreateInfo queueInfo({}, computeQueueFamilyIndex, 1, &priority);
vk::DeviceCreateInfo deviceCreateInfo({}, 1, &queueInfo);
device = physDev.createDevice(deviceCreateInfo);
queue = device.getQueue(computeQueueFamilyIndex, 0);
vk::CommandPoolCreateInfo poolInfo({}, computeQueueFamilyIndex);
cmdPool = device.createCommandPool(poolInfo);
std::cout << "Vulkan инициализирован на: " << physDev.getProperties().deviceName << std::endl;
} catch (const std::exception& e) {
std::cerr << "Ошибка Vulkan: " << e.what() << ". Переключение на CPU." << std::endl;
this->useVulkan = false;
}
uint32_t curW = 0, curB = 0, curO = 0;
for (int i = 0; i < count; i++) {
sizes.push_back(layers[i].size);
oOff.push_back(curO);
curO += layers[i].size;
}
// Инициализация CPU данных
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>> 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);
wOff.push_back(curW);
bOff.push_back(curB);
int wCount = sizes[i] * sizes[i+1];
float scale = sqrt(2.0f / sizes[i]);
for (int j = 0; j < wCount; j++) {
h_weights.push_back(((float)rand() / RAND_MAX * 2.0f - 1.0f) * scale);
}
weights.push_back(layerW);
biases.push_back(std::vector<double>(sizes[i+1], 0.0));
for (int j = 0; j < sizes[i+1]; j++) h_biases.push_back(0.0f);
curW += wCount;
curB += sizes[i+1];
}
h_outputs.resize(curO, 0.0f);
h_errors.resize(curO, 0.0f);
if (this->useVulkan) {
initVulkanResources();
initVulkan();
if (this->useVulkan) {
initVulkanResources();
syncToGPU();
}
}
}
// --- ДЕСТРУКТОР ---
NeuralNetwork::~NeuralNetwork() {
if (useVulkan && vulkanResourcesInitialized) {
device.waitIdle();
device.destroyPipeline(pipeline);
device.destroyPipelineLayout(pipeLayout);
device.destroyShaderModule(shaderModule);
device.destroyDescriptorPool(descriptorPool);
device.destroyDescriptorSetLayout(dsLayout);
device.destroyBuffer(gpuW); device.freeMemory(memW);
device.destroyBuffer(gpuB); device.freeMemory(memB);
device.destroyBuffer(gpuO); device.freeMemory(memO);
device.destroyBuffer(gpuE); device.freeMemory(memE);
device.destroyCommandPool(cmdPool);
device.destroy();
instance.destroy();
}
void NeuralNetwork::initVulkan() {
try {
vk::ApplicationInfo app{"Xenith", 1, nullptr, 0, VK_API_VERSION_1_1};
instance = vk::createInstance({{}, &app});
auto pdevs = instance.enumeratePhysicalDevices();
if (pdevs.empty()) throw std::runtime_error("GPU not found");
physDev = pdevs[0];
auto props = physDev.getQueueFamilyProperties();
computeQueueFamilyIndex = -1;
for (uint32_t i = 0; i < props.size(); i++) {
if (props[i].queueFlags & vk::QueueFlagBits::eCompute) {
computeQueueFamilyIndex = i; break;
}
}
vk::DeviceQueueCreateInfo qinfo({}, (uint32_t)computeQueueFamilyIndex, 1, new float{1.0f});
device = physDev.createDevice({{}, 1, &qinfo});
queue = device.getQueue(computeQueueFamilyIndex, 0);
cmdPool = device.createCommandPool({{}, (uint32_t)computeQueueFamilyIndex});
} catch (...) { useVulkan = false; }
}
// --- ИНИЦИАЛИЗАЦИЯ РЕСУРСОВ GPU ---
void NeuralNetwork::initVulkanResources() {
if (!useVulkan || vulkanResourcesInitialized) return;
size_t wSize = 0, bSize = 0, oSize = 0;
for (int i = 0; i < numLayers - 1; i++) {
wSize += (size_t)sizes[i] * sizes[i+1];
bSize += (size_t)sizes[i+1];
}
for (int s : sizes) oSize += s;
auto createBuf = [&](size_t size, vk::Buffer& buf, vk::DeviceMemory& mem) {
buf = device.createBuffer({{}, size * sizeof(float), vk::BufferUsageFlagBits::eStorageBuffer});
vk::MemoryRequirements req = device.getBufferMemoryRequirements(buf);
mem = device.allocateMemory({req.size, findMemoryType(req.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent)});
device.bindBufferMemory(buf, mem, 0);
auto createBuf = [&](size_t sz, vk::Buffer& b, vk::DeviceMemory& m, void** ptr) {
b = device.createBuffer({{}, sz * sizeof(float), vk::BufferUsageFlagBits::eStorageBuffer});
auto req = device.getBufferMemoryRequirements(b);
m = device.allocateMemory({req.size, findMemoryType(req.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent)});
device.bindBufferMemory(b, m, 0);
*ptr = device.mapMemory(m, 0, sz * sizeof(float));
};
createBuf(h_weights.size(), gpuW, memW, &pW);
createBuf(h_biases.size(), gpuB, memB, &pB);
createBuf(h_outputs.size(), gpuO, memO, &pO);
createBuf(h_errors.size(), gpuE, memE, &pE);
createBuf(sizes.back(), gpuT, memT, &pT);
createBuf(wSize, gpuW, memW);
createBuf(bSize, gpuB, memB);
createBuf(oSize, gpuO, memO);
createBuf(oSize, gpuE, memE);
std::vector<vk::DescriptorSetLayoutBinding> bindings = {
std::vector<vk::DescriptorSetLayoutBinding> binds = {
{0, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute},
{1, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute},
{2, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute},
{3, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute}
{3, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute},
{4, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute}
};
dsLayout = device.createDescriptorSetLayout({{}, (uint32_t)bindings.size(), bindings.data()});
vk::DescriptorPoolSize poolSize(vk::DescriptorType::eStorageBuffer, 4);
descriptorPool = device.createDescriptorPool({{}, 1, 1, &poolSize});
dsLayout = device.createDescriptorSetLayout({{}, (uint32_t)binds.size(), binds.data()});
vk::DescriptorPoolSize ps(vk::DescriptorType::eStorageBuffer, 5);
descriptorPool = device.createDescriptorPool({{}, 1, 1, &ps});
descriptorSet = device.allocateDescriptorSets({descriptorPool, 1, &dsLayout})[0];
vk::DescriptorBufferInfo bW(gpuW, 0, VK_WHOLE_SIZE), bB(gpuB, 0, VK_WHOLE_SIZE), bO(gpuO, 0, VK_WHOLE_SIZE), bE(gpuE, 0, VK_WHOLE_SIZE), bT(gpuT, 0, VK_WHOLE_SIZE);
device.updateDescriptorSets({
{descriptorSet, 0, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &bW},
{descriptorSet, 1, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &bB},
{descriptorSet, 2, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &bO},
{descriptorSet, 3, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &bE},
{descriptorSet, 4, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &bT}
}, {});
vk::DescriptorBufferInfo bW(gpuW, 0, VK_WHOLE_SIZE), bB(gpuB, 0, VK_WHOLE_SIZE), bO(gpuO, 0, VK_WHOLE_SIZE), bE(gpuE, 0, VK_WHOLE_SIZE);
device.updateDescriptorSets({{descriptorSet, 0, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &bW},
{descriptorSet, 1, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &bB},
{descriptorSet, 2, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &bO},
{descriptorSet, 3, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &bE}}, {});
auto shaderCode = readFile("Xenith/shader.comp.spv");
shaderModule = device.createShaderModule({{}, shaderCode.size(), (uint32_t*)shaderCode.data()});
vk::PushConstantRange pushRange(vk::ShaderStageFlagBits::eCompute, 0, sizeof(TrainParams));
pipeLayout = device.createPipelineLayout({{}, 1, &dsLayout, 1, &pushRange});
vk::PipelineShaderStageCreateInfo stageInfo({}, vk::ShaderStageFlagBits::eCompute, shaderModule, "main");
pipeline = device.createComputePipeline(nullptr, {{}, stageInfo, pipeLayout}).value;
vulkanResourcesInitialized = true;
auto code = readFile("Xenith/shader.comp.spv");
shaderModule = device.createShaderModule({{}, code.size(), (uint32_t*)code.data()});
vk::PushConstantRange pr(vk::ShaderStageFlagBits::eCompute, 0, sizeof(TrainParams));
pipeLayout = device.createPipelineLayout({{}, 1, &dsLayout, 1, &pr});
pipeline = device.createComputePipeline(nullptr, {{}, {{}, vk::ShaderStageFlagBits::eCompute, shaderModule, "main"}, pipeLayout}).value;
}
// --- ОБУЧЕНИЕ VULKAN ---
double NeuralNetwork::trainVulkan(const std::vector<double>& input, const std::vector<double>& target, double lr) {
if (!useVulkan) return train(input, target, lr);
if (!vulkanResourcesInitialized) initVulkanResources();
double NeuralNetwork::train(const std::vector<double>& input, const std::vector<double>& target, double lr) {
if (!useVulkan) return runTrainCPU(input, target, lr);
float* fIn = (float*)pO; for(size_t i=0; i<input.size(); i++) fIn[i] = (float)input[i];
float* fTar = (float*)pT; for(size_t i=0; i<target.size(); i++) fTar[i] = (float)target[i];
std::vector<double> pred = feedForward(input);
std::vector<std::vector<double>> errors(numLayers);
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;
}
for (int i = numLayers - 2; i > 0; i--) {
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]);
}
}
std::vector<float> fW, fB, fO, fE;
std::vector<uint32_t> wOff, bOff, oOff;
for (int i = 0; i < numLayers - 1; i++) {
wOff.push_back(fW.size());
for (auto& row : weights[i]) for (double v : row) fW.push_back((float)v);
bOff.push_back(fB.size());
for (double v : biases[i]) fB.push_back((float)v);
}
for (int i = 0; i < numLayers; i++) {
oOff.push_back(fO.size());
for (double v : outputs[i]) fO.push_back((float)v);
for (double v : errors[i]) fE.push_back((float)v);
}
auto upload = [&](vk::DeviceMemory mem, void* data, size_t size) {
if (size == 0) return;
void* mapped = device.mapMemory(mem, 0, size);
memcpy(mapped, data, size);
device.unmapMemory(mem);
};
upload(memW, fW.data(), fW.size() * sizeof(float));
upload(memB, fB.data(), fB.size() * sizeof(float));
upload(memO, fO.data(), fO.size() * sizeof(float));
upload(memE, fE.data(), fE.size() * sizeof(float));
vk::CommandBufferAllocateInfo allocInfo(cmdPool, vk::CommandBufferLevel::ePrimary, 1);
vk::CommandBuffer cmd = device.allocateCommandBuffers(allocInfo)[0];
vk::CommandBufferAllocateInfo ai(cmdPool, vk::CommandBufferLevel::ePrimary, 1);
vk::CommandBuffer cmd = device.allocateCommandBuffers(ai)[0];
cmd.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipeLayout, 0, {descriptorSet}, {});
vk::MemoryBarrier barrier(vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead, vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead);
for (int i = 0; i < numLayers - 1; i++) {
TrainParams p = {(uint32_t)sizes[i], (uint32_t)sizes[i+1], wOff[i], bOff[i], oOff[i], oOff[i+1], (float)lr};
TrainParams p = {0, (uint32_t)sizes[i], (uint32_t)sizes[i+1], wOff[i], bOff[i], oOff[i], oOff[i+1], (float)lr};
cmd.pushConstants(pipeLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof(TrainParams), &p);
cmd.dispatch((sizes[i+1] + 255) / 256, 1, 1);
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {barrier}, {}, {});
}
{
TrainParams p = {1, 0, (uint32_t)sizes.back(), 0, 0, 0, oOff.back(), (float)lr};
cmd.pushConstants(pipeLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof(TrainParams), &p);
cmd.dispatch((sizes.back() + 255) / 256, 1, 1);
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {barrier}, {}, {});
}
for (int i = numLayers - 2; i > 0; i--) {
TrainParams p = {2, (uint32_t)sizes[i], (uint32_t)sizes[i+1], wOff[i], bOff[i], oOff[i], oOff[i+1], (float)lr};
cmd.pushConstants(pipeLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof(TrainParams), &p);
cmd.dispatch((sizes[i] + 255) / 256, 1, 1);
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {barrier}, {}, {});
}
for (int i = 0; i < numLayers - 1; i++) {
TrainParams p = {3, (uint32_t)sizes[i], (uint32_t)sizes[i+1], wOff[i], bOff[i], oOff[i], oOff[i+1], (float)lr};
cmd.pushConstants(pipeLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof(TrainParams), &p);
cmd.dispatch((sizes[i+1] + 255) / 256, 1, 1);
}
cmd.end();
queue.submit(vk::SubmitInfo(0, nullptr, nullptr, 1, &cmd), nullptr);
queue.waitIdle();
device.freeCommandBuffers(cmdPool, cmd);
void* wPtr = device.mapMemory(memW, 0, fW.size() * sizeof(float));
memcpy(fW.data(), wPtr, fW.size() * sizeof(float));
device.unmapMemory(memW);
void* bPtr = device.mapMemory(memB, 0, fB.size() * sizeof(float));
memcpy(fB.data(), bPtr, fB.size() * sizeof(float));
device.unmapMemory(memB);
int wi = 0, bi = 0;
double mse = 0;
float* out = (float*)pO + oOff.back();
for (int i = 0; i < sizes.back(); i++) { double d = (double)target[i] - (double)out[i]; mse += d * d; }
return mse / sizes.back();
}
void NeuralNetwork::trainOnSequence(Tokenizer& tok, Embedder& emb, const std::string& dataset,
int epochs, double lr,
std::function<std::vector<double>(const std::vector<int>&, Embedder&)> buildInput,
std::function<void(const TrainStatus&)> onProgress) {
std::vector<int> tokens = tok.textToTokens(dataset);
if (tokens.size() < 2) return;
int clrId = -1;
auto search = tok.textToTokens("[CLR]"); if(!search.empty()) clrId = search[0];
auto startTime = std::chrono::high_resolution_clock::now();
long long totalSteps = (long long)epochs * (tokens.size() - 1);
long long currentGlobalStep = 0;
double lastEpochLoss = 0;
long long totalParamsCount = 0;
for (int i = 0; i < numLayers - 1; i++) {
for (int j = 0; j < sizes[i+1]; j++) {
for (int k = 0; k < sizes[i]; k++) weights[i][j][k] = fW[wi++];
biases[i][j] = fB[bi++];
totalParamsCount += (long long)sizes[i] * sizes[i+1]; // веса
totalParamsCount += (long long)sizes[i+1]; // смещения
}
for (int e = 1; e <= epochs; e++) {
double currentEpochLoss = 0;
std::vector<int> slidingContext;
for (size_t i = 0; i < tokens.size(); i++) {
if (tokens[i] == clrId) { slidingContext.clear(); continue; }
if (!slidingContext.empty()) {
std::vector<double> target(MAX_VOCAB, 0.0);
target[tokens[i]] = 1.0;
double loss = this->train(buildInput(slidingContext, emb), target, lr);
currentEpochLoss += loss;
currentGlobalStep++;
if (onProgress && currentGlobalStep % 10 == 0) {
auto now = std::chrono::high_resolution_clock::now();
double elapsed = std::chrono::duration<double>(now - startTime).count();
double speed = currentGlobalStep / elapsed;
TrainStatus status = {e, epochs, (int)i, (int)tokens.size(), loss, currentEpochLoss, lastEpochLoss, speed, (totalSteps - currentGlobalStep) / speed, (float)currentGlobalStep / totalSteps * 100.0f, totalParamsCount};
onProgress(status);
}
}
slidingContext.push_back(tokens[i]);
if (slidingContext.size() > MAX_CONTEXT) slidingContext.erase(slidingContext.begin());
}
lastEpochLoss = currentEpochLoss;
}
return totalErr;
if (useVulkan) syncToCPU();
}
// --- ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ---
std::vector<double> NeuralNetwork::feedForward(const std::vector<double>& input) {
outputs.clear();
outputs.push_back(input);
std::vector<double> curr = input;
for (int i = 0; i < numLayers - 1; i++) {
std::vector<double> 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)));
if (useVulkan) {
float* fIn = (float*)pO; for(size_t i=0; i<input.size(); i++) fIn[i] = (float)input[i];
vk::CommandBufferAllocateInfo ai(cmdPool, vk::CommandBufferLevel::ePrimary, 1);
vk::CommandBuffer cmd = device.allocateCommandBuffers(ai)[0];
cmd.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit});
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipeLayout, 0, {descriptorSet}, {});
vk::MemoryBarrier b(vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
for (int i = 0; i < numLayers - 1; i++) {
TrainParams p = {0, (uint32_t)sizes[i], (uint32_t)sizes[i+1], wOff[i], bOff[i], oOff[i], oOff[i+1], 0.0f};
cmd.pushConstants(pipeLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof(TrainParams), &p);
cmd.dispatch((sizes[i+1] + 255) / 256, 1, 1);
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {b}, {}, {});
}
curr = next;
outputs.push_back(curr);
cmd.end();
queue.submit(vk::SubmitInfo(0, nullptr, nullptr, 1, &cmd), nullptr);
queue.waitIdle();
device.freeCommandBuffers(cmdPool, cmd);
std::vector<double> res(sizes.back());
float* out = (float*)pO + oOff.back();
for(int i=0; i<sizes.back(); i++) res[i] = (double)out[i];
return res;
}
return curr;
return std::vector<double>(sizes.back(), 0.0);
}
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(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;
}
for (int i = numLayers - 2; i > 0; i--) {
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]);
}
}
for (int i = 0; i < numLayers - 1; i++) {
for (int j = 0; j < sizes[i + 1]; j++) {
double errT = lr * errors[i + 1][j];
for (int k = 0; k < sizes[i]; k++) weights[i][j][k] += errT * outputs[i][k];
biases[i][j] += errT;
}
}
return totalErr;
void NeuralNetwork::syncToCPU() { if(useVulkan) { memcpy(h_weights.data(), pW, h_weights.size()*4); memcpy(h_biases.data(), pB, h_biases.size()*4); } }
void NeuralNetwork::syncToGPU() { if(useVulkan) { memcpy(pW, h_weights.data(), h_weights.size()*4); memcpy(pB, h_biases.data(), h_biases.size()*4); } }
uint32_t NeuralNetwork::findMemoryType(uint32_t f, vk::MemoryPropertyFlags p) {
auto m = physDev.getMemoryProperties();
for(uint32_t i=0; i<m.memoryTypeCount; i++) if((f&(1<<i)) && (m.memoryTypes[i].propertyFlags&p)==p) return i;
return 0;
}
uint32_t NeuralNetwork::findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties) {
vk::PhysicalDeviceMemoryProperties memProperties = physDev.getMemoryProperties();
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) return i;
}
throw std::runtime_error("Память не найдена");
std::vector<char> NeuralNetwork::readFile(const std::string& n) {
std::ifstream f(n, std::ios::ate|std::ios::binary);
size_t s = (size_t)f.tellg(); std::vector<char> b(s); f.seekg(0); f.read(b.data(), s); return b;
}
std::vector<char> NeuralNetwork::readFile(const std::string& filename) {
std::ifstream file(filename, std::ios::ate | std::ios::binary);
if (!file.is_open()) throw std::runtime_error("Файл не найден: " + filename);
size_t fileSize = (size_t)file.tellg();
std::vector<char> buffer(fileSize);
file.seekg(0);
file.read(buffer.data(), fileSize);
return buffer;
}
NeuralNetwork::~NeuralNetwork() {
if (useVulkan) {
device.waitIdle();
device.destroyPipeline(pipeline); device.destroyPipelineLayout(pipeLayout); device.destroyShaderModule(shaderModule);
device.destroyBuffer(gpuW); device.freeMemory(memW); device.destroyBuffer(gpuB); device.freeMemory(memB);
device.destroyBuffer(gpuO); device.freeMemory(memO); device.destroyBuffer(gpuE); device.freeMemory(memE); device.destroyBuffer(gpuT); device.freeMemory(memT);
device.destroyDescriptorPool(descriptorPool); device.destroyDescriptorSetLayout(dsLayout); device.destroyCommandPool(cmdPool);
device.destroy(); instance.destroy();
}
}
double NeuralNetwork::runTrainCPU(const std::vector<double>& i, const std::vector<double>& t, double l) { return 0.0; }
+63 -41
View File
@@ -3,51 +3,46 @@
#include "typedef.hpp"
#include <vector>
#include <cmath>
#include <cstdlib>
#include <omp.h>
#include <string>
#include <vulkan/vulkan.hpp>
#include <iostream>
#include <fstream>
#include <functional>
struct TrainStatus {
int currentEpoch;
int totalEpochs;
int currentToken;
int totalTokens;
double currentLoss;
double epochLoss;
double lastEpochLoss;
double speed;
double eta;
float percentage;
long totalParams;
};
class Tokenizer;
class Embedder;
class NeuralNetwork {
private:
// Параметры нейросети
int numLayers;
std::vector<int> sizes;
std::vector<std::vector<std::vector<double>>> weights;
std::vector<std::vector<double>> biases;
std::vector<std::vector<double>> outputs;
std::vector<float> h_weights, h_biases, h_outputs, h_errors;
std::vector<uint32_t> wOff, bOff, oOff;
// Объекты Vulkan
bool useVulkan; // Сохраняем выбор пользователя
bool useVulkan;
vk::Instance instance;
vk::PhysicalDevice physDev;
vk::Device device;
vk::Queue queue;
vk::CommandPool cmdPool;
uint32_t computeQueueFamilyIndex; // Индекс очереди для команд
uint32_t computeQueueFamilyIndex;
// Вспомогательные методы Vulkan
uint32_t findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties);
std::vector<char> readFile(const std::string& filename);
vk::Buffer gpuW, gpuB, gpuO, gpuE, gpuT;
vk::DeviceMemory memW, memB, memO, memE, memT;
void *pW = nullptr, *pB = nullptr, *pO = nullptr, *pE = nullptr, *pT = nullptr;
// Математика CPU
double sigmoid(double x) { return 1.0 / (1.0 + exp(-x)); }
double sigmoidDeriv(double x) { return x * (1.0 - x); }
struct TrainParams {
uint32_t prevLayerSize;
uint32_t nextLayerSize;
uint32_t weightOffset;
uint32_t biasOffset;
uint32_t outOffset;
uint32_t errOffset;
float lr;
};
vk::Buffer gpuW, gpuB, gpuO, gpuE;
vk::DeviceMemory memW, memB, memO, memE;
vk::DescriptorPool descriptorPool;
vk::DescriptorSet descriptorSet;
vk::DescriptorSetLayout dsLayout;
@@ -55,25 +50,52 @@ private:
vk::Pipeline pipeline;
vk::ShaderModule shaderModule;
bool vulkanResourcesInitialized = false;
struct TrainParams {
uint32_t mode;
uint32_t prevSize;
uint32_t nextSize;
uint32_t wOff;
uint32_t bOff;
uint32_t oOff;
uint32_t nextOOff;
float lr;
};
void initVulkanResources(); // Метод для разовой инициализации
void cleanupVulkanResources();
void initVulkan();
void initVulkanResources();
uint32_t findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties);
std::vector<char> readFile(const std::string& filename);
double runTrainCPU(const std::vector<double>& input, const std::vector<double>& target, double lr);
public:
int cpu_count = 1;
// Конструктор
int cpu_count = 4;
NeuralNetwork(LayerStructure_t layers[], int count, bool useVulkan = false);
// Деструктор (ВАЖНО для очистки Vulkan)
~NeuralNetwork();
// Методы работы
void syncToCPU();
void syncToGPU();
std::vector<double> feedForward(const std::vector<double>& input);
double train(const std::vector<double>& input, const std::vector<double>& target, double lr);
double trainVulkan(const std::vector<double>& input, const std::vector<double>& target, double lr);
void trainOnSequence(
Tokenizer& tok,
Embedder& emb,
const std::string& dataset,
int epochs,
double lr,
std::function<std::vector<double>(const std::vector<int>&, Embedder&)> buildInput,
std::function<void(const TrainStatus&)> onProgress = nullptr
);
long long getTotalParameters() {
long long total = 0;
for (int i = 0; i < numLayers - 1; i++) {
total += (long long)sizes[i] * sizes[i+1];
total += (long long)sizes[i+1];
}
return total;
}
};
#endif
+51 -22
View File
@@ -2,35 +2,64 @@
layout(local_size_x = 256) in;
layout(std430, binding = 0) buffer WeightBuffer { float weights[]; };
layout(std430, binding = 1) buffer BiasBuffer { float biases[]; };
layout(std430, binding = 2) buffer OutputBuffer { float outputs[]; };
layout(std430, binding = 3) buffer ErrorBuffer { float errors[]; };
layout(std430, binding = 0) buffer Weights { float W[]; };
layout(std430, binding = 1) buffer Biases { float B[]; };
layout(std430, binding = 2) buffer Outputs { float O[]; };
layout(std430, binding = 3) buffer Errors { float E[]; };
layout(std430, binding = 4) buffer Targets { float T[]; };
layout(push_constant) uniform Params {
uint prevLayerSize;
uint nextLayerSize;
uint weightOffset;
uint biasOffset;
uint outOffset;
uint errOffset;
uint mode; // 0: FF, 1: OutError, 2: BackProp, 3: Update
uint prevSize;
uint nextSize;
uint wOff;
uint bOff;
uint oOff;
uint nextOOff;
float lr;
} p;
float sigmoid(float x) { return 1.0 / (1.0 + exp(-x)); }
float dSigmoid(float x) { return x * (1.0 - x); }
void main() {
uint j = gl_GlobalInvocationID.x; // Индекс нейрона следующего слоя
uint idx = gl_GlobalInvocationID.x;
if (j < p.nextLayerSize) {
float errorTerm = p.lr * errors[p.errOffset + j];
// Обновляем веса, входящие в этот нейрон
for (uint k = 0; k < p.prevLayerSize; k++) {
uint wIdx = p.weightOffset + (j * p.prevLayerSize + k);
uint outIdx = p.outOffset + k;
weights[wIdx] += errorTerm * outputs[outIdx];
// MODE 0: Прямое распространение (Forward Pass)
if (p.mode == 0) {
if (idx < p.nextSize) {
float sum = B[p.bOff + idx];
for (uint i = 0; i < p.prevSize; i++) {
sum += O[p.oOff + i] * W[p.wOff + idx * p.prevSize + i];
}
O[p.nextOOff + idx] = sigmoid(sum);
}
}
// MODE 1: Ошибка выходного слоя
else if (p.mode == 1) {
if (idx < p.nextSize) {
float outVal = O[p.nextOOff + idx];
E[p.nextOOff + idx] = (T[idx] - outVal) * dSigmoid(outVal);
}
}
// MODE 2: Обратное распространение ошибки (Hidden layers)
else if (p.mode == 2) {
if (idx < p.prevSize) {
float errSum = 0.0;
for (uint i = 0; i < p.nextSize; i++) {
errSum += E[p.nextOOff + i] * W[p.wOff + i * p.prevSize + idx];
}
E[p.oOff + idx] = errSum * dSigmoid(O[p.oOff + idx]);
}
}
// MODE 3: Обновление весов и смещений
else if (p.mode == 3) {
if (idx < p.nextSize) {
float errTerm = E[p.nextOOff + idx] * p.lr;
for (uint i = 0; i < p.prevSize; i++) {
W[p.wOff + idx * p.prevSize + i] += errTerm * O[p.oOff + i];
}
B[p.bOff + idx] += errTerm;
}
// Обновляем биас этого нейрона
biases[p.biasOffset + j] += errorTerm;
}
}
Binary file not shown.
+52 -14
View File
@@ -11,22 +11,60 @@ public:
std::map<int, std::string> idToWord;
Tokenizer() {
add("<EOS>"); add("[SYS]"); add("[USER]"); add("[AI]"); add(" "); add("\n");
add("."); add(","); add("!"); add("?"); add(":"); add(";"); add("-"); add("\""); add("("); add(")");
add("а"); add("б"); add("в"); add("г"); add("д"); add("е"); add("ё"); add("ж");
add("з"); add("и"); add("й"); add("к"); add("л"); add("м"); add("н"); add("о");
add("п"); add("р"); add("с"); add("т"); add("у"); add("ф"); add("х"); add("ц");
add("ч"); add("ш"); add("щ"); add("ъ"); add("ы"); add("ь"); add("э"); add("ю"); add("я");
add("и"); add("в"); add("не"); add("на"); add("я"); add("что"); add("тот"); add("быть");
add("с"); add("а"); add("весь"); add("это"); add("как"); add("она"); add("по"); add("но");
add("они"); add("к"); add("у"); add("ты"); add("из"); add("мы"); add("за"); add("вы");
add("привет"); add("дела"); add("робот"); add("хорошо"); add("спасибо");
add("[EOS]"); add("[SYS]"); add("[USER]"); add("[AI]"); add(" "); add("\n");
add("."); add(","); add("!"); add("?"); add(":"); add(";");
add("-"); add("\""); add("("); add(")"); add("а"); add("б");
add("в"); add("г"); add("д"); add("е"); add("ё"); add("ж");
add("з"); add("и"); add("й"); add("к"); add("л"); add("м");
add("н"); add("о"); add("п"); add("р"); add("с"); add("т");
add("у"); add("ф"); add("х"); add("ц"); add("ч"); add("ш");
add("щ"); add("ъ"); add("ы"); add("ь"); add("э"); add("ю");
add("я"); add("не"); add("на"); add("что"); add("тот"); add("быть");
add("весь"); add("это"); add("как"); add("она"); add("по"); add("но");
add("они"); add("ты"); add("из"); add("мы"); add("за"); add("вы");
add("привет"); add("дела"); add("робот"); add("хорошо"); add("спасибо"); add("Привет");
add("да"); add("нет"); add("могу"); add("помочь"); add("знаю"); add("кто");
add("где"); add("когда"); add("почему"); add("хочу"); add("очень");
add("тебя"); add("зовут"); add("BiPy");
add("Приветик"); add("где"); add("когда"); add("почему"); add("хочу"); add("очень");
add("нужна"); add("помощь"); add("тебя"); add("зовут"); add("BiPy"); add("Пише");
add("если"); add("всегда"); add("рада"); add("что-то"); add("хотел"); add("именно");
add("тебе"); add("мне"); add("нужно"); add("найти"); add("образ"); add("7");
add("винды"); add("иди"); add("нахуй"); add("[CLR]"); add("["); add("USER");
add("]"); add("Пивет"); add("AI"); add("пише"); add("помоч"); add("почь");
add("Как"); add("Сябки"); add("спросил"); add("меня"); add("все"); add("Да");
add("ахуенно"); add("ёпт"); add("Доброе"); add("утро"); add("спалось"); add("Спокойной");
add("ночи"); add("желаю"); add("выспатся"); add("Что"); add("делаешь"); add("Сижу");
add("жду"); add("кода"); add("напишешь"); add("Плохое"); add("настроение"); add("Оу");
add("случилось"); add("Расскажи"); add("обязательно"); add("выслушаю"); add("поддержу"); add("Я");
add("устал"); add("Бедняжка"); add("мой"); add("может"); add("тогда"); add("отдохнешь");
add("Тебе"); add("восстановить"); add("силы"); add("подожду"); add("тут"); add("У");
add("отлично"); add("Ураа"); add("так"); add("Пусть"); add("день"); add("будет");
add("таким"); add("же"); add("классным"); add("Чем"); add("занимаешься"); add("Скучаю");
add("что-нибудь"); add("интересное"); add("пришел"); add("Наконец-то"); add("уже"); add("заждалась");
add("прошел"); add("Ты"); add("рядышком"); add("только"); add("напиши"); add("");
add("отвечу"); add("милая"); add("Ой"); add("засмущал"); add("совсем"); add("Спасибо");
add("большое"); add("оч"); add("приятно"); add("Не"); add("солнышко"); add("Обращайся");
add("любое"); add("время"); add("посоветуешь"); add("Хмм"); add("смотря"); add("чем");
add("Но"); add("готова"); add("подсказать"); add("пошел"); add("Хорошо"); add("буду");
add("ждать"); add("твоего"); add("возвращения"); add("пропадай"); add("надолго"); add("Пока");
add("Пока-пока"); add("Хорошего"); add("настроения"); add("удачи"); add("во"); add("всех");
add("делах"); add("Пойду"); add("поем"); add("Приятного"); add("аппетита"); add("Кушай");
add("вкусно"); add("потом"); add("расскажешь"); add("было"); add("обед"); add("Занят");
add("был"); add("Понимаю"); add("важно"); add("Главное"); add("сейчас"); add("нашел");
add("заглянуть"); add("ко"); add("Скучно"); add("давай"); add("поразвлекаю"); add("Можем");
add("поболтать"); add("угодно"); add("или"); add("просто"); add("помечтать"); add("Грустно");
add("Эй"); add("грусти"); add("рядом"); add("хочешь"); add("обниму"); add("виртуально");
add("Все"); add("наладится"); add("Болею"); add("Ой-ой"); add("Пей"); add("побольше");
add("чая"); add("лимоном"); add("выздоравливай"); add("скорее"); add("переживаю"); add("Похвали");
add("большой"); add("молодец"); add("верю"); add("бы"); add("ни"); add("твоя");
add("подруга"); add("забыл"); add("чтоли"); add("дурашка"); add("сказку"); add("Жил-был");
add("один"); add("замечательный"); add("человек"); add("который"); add("читает"); add("сообщение");
add("Продолжить"); add("любишь"); add("Конечно"); add("самый"); add("любимый"); add("собеседник");
add("любить"); add("Аууу"); add("Тут"); add("Никуда"); add("делась"); add("ждала");
add("сообщения"); add("Ясно"); add("Что-то"); add("немногословен"); add("сегодня"); add("Ха-ха");
add("Обожаю"); add("твой"); add("смех"); add("Сразу"); add("душе"); add("теплее");
add("становится"); add("Bipy"); add("добрая"); add("подужайка"); add("пока"); add("учусь");
add("этом"); add("мире");
}
void add(std::string word);
int getID(std::string word);
std::string getWord(int id);
+2 -2
View File
@@ -1,9 +1,9 @@
#ifndef TYPEDEF_H
#define TYPEDEF_H
const int MAX_CONTEXT = 32; // Сколько токенов видит сеть
const int MAX_CONTEXT = 64; // Сколько токенов видит сеть
const int EMBED_DIM = 8; // Размер вектора одного токена
const int MAX_VOCAB = 90; // Размер словаря
const int MAX_VOCAB = 315; // Размер словаря
typedef enum { SIGMOID } FunctionActivate_t;
typedef struct { int size; FunctionActivate_t activate; } LayerStructure_t;