Нейронная сеть с нуля — часть 1 | GPTMain News

Полностью подключенная нейронная сеть

Давайте создадим библиотеку нейронной сети с нуля. Я имею в виду, почему бы и нет? Вы можете сказать: Пфф… Большое дело.. С Python и Numpy это всего лишь вопрос часов. Что, если я скажу вам, что буду использовать C++. Нет, я шучу. Я собираюсь использовать С.

Причина этого в том, что я хочу обучить свою сеть на GPU, а GPU не понимают ни Python, ни даже C++. Я планирую использовать OpenCL вместе с C++ для создания полнофункциональной библиотеки для создания собственной нейронной сети и ее обучения. И чтобы немного оживить его, почему бы не реализовать свёрточную нейронную сеть вместо простой, скучной полносвязной НС. Но обо всем по порядку.

Давайте не будем сразу углубляться в код ядра графического процессора. Сначала мы должны построить скелет нашей библиотеки.

OpenCL::initialize_OpenCL();

std::vector<std::vector<float> > inputs, targets;

std::vector<std::vector<float> > testinputs;

std::vector<float> testtargets;

ConvNN m_nn;

std::vector<int> netVec;

netVec = { 1024,10 };

m_nn.createFullyConnectedNN(netVec, 1, 32);

m_nn.trainFCNN(inputs, targets, testinputs, testtargets, 50000);

m_nn.trainingAccuracy(testinputs, testtargets, 2000, 1);

Хорошо, это обычный процесс каждого конвейера машинного обучения с той разницей, что вместо функций Sklearn или Tensorflow здесь у нас есть C++. Вполне достижение! Верно?

Все идет нормально. У нас есть базовая версия нашего программного обеспечения. Теперь пришло время разработать фактическую структуру нейронной сети. Базовым объектом любой NN является узел, и множество узлов, сложенных вместе, образуют слой. Вот оно:

Узел и слой

typedef struct Node {

int numberOfWeights;

float weights[1200];

float output;

float delta;

}Node;

typedef struct Layer {

int numOfNodes;

Node nodes[1200];

}Layer;

Так как это простой C, мы не можем использовать std::vector и нам нужен простой C, потому что приведенный выше код будет скомпилирован и выполнен реальным GPU. Но мы приближаемся к этому. Обратите внимание, что лучше, чем массив с предопределенной длиной, каждый раз выделять необходимое пространство в памяти, но это в другой раз.

Мы создаем наши базовые структуры для узла и слоя, поэтому пришло время запрограммировать настоящую сеть, которая представляет собой просто набор слоев.

Нейронная сеть

h_netVec = newNetVec;

Layer *inputLayer = layer(h_netVec[0], 0);

h_layers.push_back(*inputLayer);

for (unsigned int i = 1; i <h_netVec.size(); i++)

{

Layer *hidlayer = layer(h_netVec[i], h_netVec[i - 1]);

h_layers.push_back(*hidlayer);

}

Вот оно. Наша простая нейронная сеть написана на C++. По сути, это не более чем вектор слоев, где каждый слой является вектором узлов. Вы можете подумать, что наша работа здесь сделана. Ха-ха! Мы даже не близки. Мы должны обучать нашу сеть на реальных данных. Это время, когда OpenCL вступает в игру.

Графический процессор не может получить доступ к этим векторам, поэтому мы должны преобразовать их в другую структуру, называемую буфером, базовым элементом OpenCL. Но логика точно такая же, как и раньше.

Буферы OpenCL

d_InputBuffer = cl::Buffer(OpenCL::clcontext, CL_MEM_READ_WRITE, sizeof(float)*inpdim*inpdim);

tempbuf = cl::Buffer(OpenCL::clcontext, CL_MEM_READ_WRITE, sizeof(Node)*h_layers[0].numOfNodes);

(OpenCL::clqueue).enqueueWriteBuffer(tempbuf,CL_TRUE,0,sizeof(Node)*h_layers[0].numOfNodes,h_layers[0].nodes);

d_layersBuffers.push_back(tempbuf);

for (int i = 1; i<h_layers.size(); i++) {

tempbuf = cl::Buffer(OpenCL::clcontext, CL_MEM_READ_WRITE, sizeof(Node)*h_layers[i].numOfNodes);

(OpenCL::clqueue).enqueueWriteBuffer(tempbuf, CL_TRUE,0, sizeof(Node)*h_layers[i].numOfNodes, h_layers[i].nodes);

d_layersBuffers.push_back(tempbuf);

}

Не запутайтесь во всех этих “cl::”, “clqueue” и “context”. Это вещи OpenCL. Логика остается неосязаемой.

Прежде чем мы погрузимся в захватывающую часть, мы должны сделать еще одну вещь. Мы должны определить ядра OpenCL. Ядра — это фактический код, который выполняется графическим процессором. Всего нам нужно 3 ядра:

  • Один для прямого распространения
  • Один для обратного распространения в выходном слое
  • Один для отсталых в скрытом слое

ядро

compoutKern = cl::Kernel(OpenCL::clprogram, "compout");

backpropoutKern = cl::Kernel(OpenCL::clprogram, "backpropout");

bakckprophidKern = cl::Kernel(OpenCL::clprogram, "backprophid");

Ты угадал. Настала очередь GPU. Я не буду вдаваться в подробности о том, как работает OpenCL и как GPU обрабатывает данные, но кое-что нужно помнить:

  1. Графические процессоры имеют много ядер, поэтому они подходят для распараллеливания.
  2. Мы считаем, что каждое ядро ​​запускает код для одного узла слоя.
  3. Когда вычисления слоя завершены, мы переходим к следующему слою и так далее.

Обратное распространение

Имейте это в виду, теперь мы можем легко понять следующий фрагмент:

kernel void compout( global Node* nodes,global Node * prevnodes,int softflag)

{

const int n = get_global_size(0);

const int i = get_global_id(0);

float t = 0;

for ( int j = 0; j < nodes[i].numberOfWeights; j++)

t += nodes[i].weights[j] * prevnodes[j].output;

t+=0.1;

nodes[i].output =sigmoid(t);

}

А для обратного распространения имеем:

kernel void backprophid(global Node* nodes,global Node * prevnodes,global Node *nextnodes,int nextnumNodes,float a)

{

const int n = get_global_size(0);

const int i = get_global_id(0);

float delta = 0;

for (int j = 0; j !=nextnumNodes; j++)

delta += nextnodes[j].delta * nextnodes[j].weights[i];

delta *= devsigmoid(nodes[i].output);break;

nodes[i].delta = delta;

for (int j = 0; j != nodes[i].numberOfWeights; j++)

nodes[i].weights[j] -= a*delta*prevnodes[j].output;

}

kernel void backpropout(global Node* nodes,global Node * prevnodes,global float* targets,float a,int softflag )

{

const int n = get_global_size(0);

const int i = get_global_id(0);

float delta=0;

delta = (nodes[i].output-targets[i])*devsigmoid(nodes[i].output);

for (int j = 0; j !=nodes[i].numberOfWeights; j++)

nodes[i].weights[j] -= a*delta*prevnodes[j].output;

nodes[i].delta=delta;

}

Если вы чувствуете себя потерянным, позвольте мне напомнить вам уравнения для алгоритма обратного распространения:


Уравнения

Теперь все имеет смысл, верно?

Ну вот и все. Все, что нам нужно сделать, это загрузить наши данные и запустить ядра. Я не знаю, поняли ли вы это, но мы закончили. Мы просто создаем нашу сеть Neura полностью с нуля и обучаем ее работе с GPU.

Для получения полного кода посетите мой репозиторий github: библиотека нейронных сетей.

В следующей части мы расширим библиотеку, включив в нее сверточные нейронные сети. Следите за обновлениями…

Книга «Глубокое обучение в производстве» 📖

Узнайте, как создавать, обучать, развертывать, масштабировать и поддерживать модели глубокого обучения. Изучите инфраструктуру машинного обучения и MLOps на практических примерах.

Узнать больше

* Раскрытие информации: Обратите внимание, что некоторые из приведенных выше ссылок могут быть партнерскими ссылками, и мы без дополнительных затрат для вас получим комиссию, если вы решите совершить покупку после перехода по ссылке.

Последние статьи

Related articles

ОСТАВЬТЕ ОТВЕТ

Пожалуйста, введите ваш комментарий!
пожалуйста, введите ваше имя здесь

hentai lou nicehentai.com ahegeo hentai pron v bigztube.mobi kannada school girl sex videos sxsi com pornoko.net indian porn xnxx.com سكس.جماعي pornigh.com سكس لوسي bangali sex in kompoz2.com ganapa kannada movie songs
سكس مع المعلمة matureporni.com سكس كس مفتوح desi clip.com foxporns.info girls sexy pictures хентай манга hentaitale.net hentai zombie girl little sister doujin justhentaiporn.com kasumi tendo hentai افلام جيانا مايكلز gratisfucktube.com foto sex
desi gay porn vedio momyporn.mobi nepali x video مدام شرموطه freetube18x.com ايناس الدغيدي سكس tony tony chopper hentai hentaimangaz.com naruto new hentai manga الكس والزبر pornarabic.net احلى بزاز ميلفاية arabgrid.net فلم\سكس