Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Эффективные методы решения задач кинематики и динамики робота-станка параллельной структуры

..pdf
Скачиваний:
3
Добавлен:
20.11.2023
Размер:
7.84 Mб
Скачать

4.4. Применение НС для решения прямой задачи кинематики (ПЗК) 131

Далее проведем экспериментальную проверку решения ПЗК для трипода и гексапода на базе НС прямого распространения. Будем рассматривать влияние структуры и сложности НС, а также количе­ ства тренировочных примеров на точность решения и время обучения сети. В экспериментах использовалась программная реализация НС,

описание которой приведено

выше, а полный код программы на языке

C + + приведен в приложении

1 .

Данные для обучения и тестирования HC, включающие длины штанг и соответствующие им координаты рабочего инструмента, были получены посредствам решения обратной задачи кинематики, полу­ ченной в аналитическом виде (2.7-2.9 и 2.16-2.21). Таким образом, решения ПЗК каким-либо другим методом не требовалось. На вход обученной сети подавались тестовые значения длин штанг, на выходе получали декартовы координаты. В качестве варьируемых параметров выступали: количество точек тренировочного набора, изменяемое от 60 для 8000, число скрытых слоев, и число нейронов, составляющих скрытый слой. Ч исло нейронов принималось равным 10 и 60.

 

Количество нейронов

 

 

---------

64 эл.в выборке

-----

4096

элементов

— —

729 элементов

.-----

8000

элементов

Р ис. 4.6. Зависим ость ош ибки обучения от числа нейронов в скрытом слое

5 *

132 Гл. 4, Управление движением робота-станка на основе нейронных,,.

Как результат, был построен ряд зависимостей отображающих связь, числа нейронов, количества тренировочных точек с ошибкой по положению и времени обучения (рис. 4.5-4.8). Время затрачиваемое на обучение, сильно зависит от конфигурации используемого компью­ тера: частоты и разрядности процессора, объема оперативной памяти, поэтому на разных компьютерах будет наблюдаться разный результат.

На рис. 4.7 представлено семейство кривых, каждая из которых по­ лучена при количестве числа нейронов скрытого слоя для разного чис­ ла точек тренировочной выборки (60, 700, 1100, 8000). Из графиков видно, что при достаточном количестве примеров ошибка незначитель­ но уменьшается с увеличением числа нейронов в скрытом слое. Возрас­ тание ошибки на графиках соответствующих числу точек выборки 60 и 700 объясняется недостаточным их количеством. Таким образом, мож­ но сделать вывод о том, что количество точек тренировочного набора должно превышать количество связей в НС в не менее чем в пять раз.

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

О1000 2000 3000 4000 5000 6000 7000 8000

Количество тренировочных точек

10 нейронов

— -----

60 нейронов

— 10нейронов(2 слоя) — -----60 нейронов(2 слоя)

Рис. 4.7. Зависим ость времени обучения от объема выборки

4.4. Применение НС для решения прямой задачи кинематики (ПЗК) 133

---------

64 эл.в выборке

.............

4096 элементов

---------

729 элементов

---------

8000 элементов

Рис. 4.8. Зависимость времени обучения от числа нейронов в скрытом слое

увеличении количества нейронов в сети, величина ошибки изменя­ ется мало, а время обучения сети, напротив значительно возрастает (рис. 4.8). Поэтому, выбирая структуру НС, следует ограничиться небольшим числом нейронов скрытого слоя.

Для увеличения точности обучения можно создавать цепочку уз­ лов из так называемых корректирующих НС. Данная сеть будет обу­ чаться на величинах ошибок, полученных при расхождении между результатами работы основной НС и истинными значениями. При этом корректирующая НС не привязана к конкретному диапазону измене­ ния длин штанг, а определяется лишь границами разброса ошибок, полученных в результате работы первой НС. Принцип работы такой цепочки НС сводится к следующему. На вход первой НС подаются значения длин штанг, на выходе получаем приближенное решение ПЗК. Далее полученные приближенные значения подаются на вход корректирующей сети и на выходе получаем более точное решение.

В таблице 4.1. приведены сравнительные характеристики рабо­ ты НС разной структуры. Как видно, применение корректирующих НС

134Гл. 4. Управление движением робота-станка на основе нейронных,,.

Та б л и ц а 4.1. Оценка точности решения ПЗК с помощью НС

Структура НС

Характеристики

Время

Ошибка

обучения НС, с

обучения НС

 

 

НС с одним

20 нейронов, 8000

20,045

0,07984

скрытым слоем

точек

 

 

Многослойная НС

3 слоя, 20 нейронов,

124,325

0,04805

8000 точек

 

 

 

Корректирующая НС

20 нейронов, 3 корр.

102,034

0,00102

 

сети, 8000 точек

 

 

является наиболее оптимальным вариантом, т. к. по сравнению с много­ слойной дает выигрыш и по величине ошибки, и по времени обучения. При этом следует заметить, что скорость прямого прохода по сети с корректирующей структурой будет также выше. Это объясняется тем, что каждая из сетей (основная и корректирующая) являются однослойными и по структуре являются более простыми, чем одна многослойная сеть.

Приложение 1

135

Приложение 1

la y e r.h

#ifndef ____ LAYER_H___

#define ____ LAYER_H___

#include <vector> #include <algorithm> #include <cmath> #include <fstream> #include <cstdlib> #include <iostream> #include "log.h"

typedef

flo a t

real;

 

 

 

 

 

 

 

Pointer;

 

 

typedef

s td ::v e c to r < r e a l> ::ite ra to r

 

 

class

Matrix:

public

std ::v ecto r< real>

{

 

 

 

p riv ate:

 

 

row,

col;

 

 

 

 

 

 

 

 

 

 

 

 

size _ t

 

 

 

 

 

 

 

 

 

 

 

public:

 

 

 

 

 

 

 

col(O)

{}

 

 

 

 

 

 

 

M atrix():row (0),

 

row(r),

co l(c ),

 

 

M atrix(size_t

r,

 

size _ t

c):

 

 

Matrix(const

Matrix

&m):

 

 

std::vector< real> (r*c) {}

 

std::vector<real>(m )

{

 

 

 

row = m.getRow();

 

 

 

 

 

 

 

 

}

 

col

= m.getCol();

 

 

 

 

 

 

 

 

 

 

getRow()

const

{

return

row;

}

 

 

 

size _ t

 

 

 

size _ t

getCol()

const

{

return

col;

}

 

 

 

void

se tS iz e (siz e _ t

r,

size _ t

c)

{

 

 

 

 

 

 

row

=

r;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

col

=

c;

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

resiz e (r* c);

 

 

 

 

 

 

 

 

 

 

 

& operator()(size_t

i , size _ t

j)

{

return

 

 

re a l

}

 

re a l

o p e ra to r()(size _ t

 

 

 

(* th is)[i* c o l+ j];

 

i , size _ t

j)

const { return

 

void

p rin t(std ::o stre a m

&out)

(* th is)[i* c o l+ j];

}

};

const;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

class

Layer

{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

protected:

*pNext,

*pPrev;

 

 

 

 

 

 

 

 

 

Layer

 

 

 

 

 

 

 

 

 

in t row,

col;

sdvig,

la stE rro r;

 

 

 

 

 

Matrix

weight,

 

 

 

 

 

Pointer

input,

erro r;

 

 

errorBuf;

 

 

 

std ::v ecto r< real>

inputBuf,

 

 

 

re a l

BETTA,

&NU;

 

in t

c);

 

 

 

 

 

 

 

 

void

i n i t ( i n t

r,

 

 

l./(l+exp(-x*BETTA)); }

 

re a l

func(real

x)

{

return

public:

 

 

 

r,

in t

 

c,

real

&nu):

row(r),

c o l(c ),

BETTA(l),

 

Layer(int

 

 

 

 

 

 

 

 

 

 

 

 

 

 

NU(nu), pNext(O),

pPrev(O) {

136

 

Приложение 1

 

}

init(r, C ) ;

 

 

 

 

 

void randorn{);

 

 

void

load{std::ifstrearn &in)

 

void

front();

= 0;

 

virtual void back()

std::vector<real

void

listOf(std::vector<real * > &W

void

zero();

* > & S ,

size_t pos);

 

 

void

setNext(Layer

*n);

 

void

setPrev(Layer

*p);

 

Layer *next() { return pNext; } Layer *prev() { return pPrev; }

void setIn(Pointer p) { input = p; }

void setOut(Pointer p) { error = p; } Pointer getIn() { return inputBuf.begin(); }

Pointer getOut() { return errorBuf.begin(); }

void setBetta(real b) { BETTA = b; } real getBetta() { return BETTA; }

void print(int num = 1, std::ostream &out = std::cout);

};

class StartLayer: public Layer { public:

StartLayer(int r, int C , real &nu): Layer(r, C , void back();

};

class {\it MidlLayer}: public Layer { public:

MidlLayer(int r, int C , real &nu): Layer(r, C , void back();

};

nu) {}

nu) {}

struct Mem

{

 

sizeOut;

int

sizeIn,

Pointer

in;

 

Pointer out;

int out): sizeln(in), sizeOut(out) {}

Mem(int

in,

};

 

 

 

class Memory { private:

int sizeIn, sizeOut, count; std::vector<real> data;

public:

Memory():sizeIn(0), sizeOut(O), count(0) {} void setIn(int in) { sizeIn = in; }

void setOut(int out) { sizeOut = out; }

 

 

 

 

 

Приложение 1

 

 

 

 

137

Mem

operator[]{int

i);

}

 

 

 

 

 

int

size()

{ return

count;

 

 

 

 

 

void read(char *name, int start, int end);

 

};

 

 

 

 

 

 

 

 

 

 

 

 

 

 

class {\it NeroNet}

{

 

 

 

 

 

 

 

 

 

private:

 

 

 

 

 

arch;

 

 

 

 

 

 

 

std::vector<int>

 

sdvig;

 

 

 

std::vector<real

*> weight,

 

 

 

std::vector<real>

koef;

 

 

 

 

 

 

 

Pointer error;

 

 

 

 

 

 

 

 

 

 

real

sumError;

 

 

 

 

 

 

 

 

 

 

Layer

*begin,

*end;

 

 

 

 

 

 

 

 

Memory

distr;

 

 

 

 

 

 

 

 

 

 

 

real

NU;

 

 

 

 

 

 

 

 

 

 

 

 

void createLayers();

 

 

 

 

 

 

 

void

front(Mem mem);

 

}

 

 

 

 

void

zero()

{ begin->zero();

 

 

 

 

public:

 

 

 

*name);

 

 

 

 

 

 

 

NeroNet(char

 

 

 

 

 

end(O)

{

NeroNet(std::vector<int> &v): begin(O),

 

 

arch

= v;

 

 

 

 

 

 

 

 

 

 

}

 

createLayers();

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

\sim NeroNet();

 

 

 

 

 

}

 

 

 

 

void print()

{ begin->print();

 

 

to)

 

void loadData(char

*name,

int

from, int

to);}

real

frontBack();

 

{distr.read(name, from,

 

 

 

 

 

 

 

 

 

real

front();

 

 

 

 

 

 

 

 

 

 

 

void

saveOld();

 

 

 

 

 

 

 

 

 

 

void

loadOld();

 

 

 

}

 

 

 

 

 

 

real

getNu()

{ return NU;

 

 

 

 

 

 

real

&setNu()

{ return NU;

}

 

 

}

 

 

real

getError()

{ return sumError;

 

 

std::vector<real

*>

&getWeight()

{ return weight; }

std::vector<real

*>

&getSdvig()

{ return

sdvig;

}

};

 

 

 

 

 

 

 

 

 

 

 

 

 

 

externstd::ostream

&operator<<(std::ostream&

Mem &mem);

 

 

 

 

 

 

 

 

 

 

out,

const

extern std::ostream &operator<<(std::ostream &out, Matrix &m); extern std::ostream &operator<<(std::ostream &out,

std::vector<real> &m);

#endif

layer.epp

#include layer.h using namespace std;

void Matrix::print(ostream &out) const {

138

Приложение 1

for{size_t i=0; i<row; ++i) { for{size_t j=0; j<col; ++j)

out<<(*this)[i*col+j]<<'\backslash t'; if (i != row-l)out<<endl;

}

}

void Layer::init(int r, int c) { r++;

weight.setSize(r, c); weight.assign(r*c, 0); sdvig.setSize(r, c); sdvig.assign(r*c, 0); lastError.resize(r*c); inputBuf.resize(c); errorBuf.resize(c);

}

void Layer::front() {

for(int i=0; i<weight.getCol(); ++i) { real tmp = weight(0, i);

Pointer it = input;

for(int j=l; j < weight.getRow(); ++it, ++j) tmp +=(*it)*weight(j, i);

inputBuf[i] = func(tmp);

}

DEBUG(endl<<input: <<endl<<inputBuf); Layer *point = next();

if (point) point->front();

}

void Layer::listOf(vector<real *> &w, vector<real * > & S , size_t pos) {

for(size_t i=0; i<weight.getRow(); ++i) for(size_t j=0; j<weight.getCol(); ++j) {

w[pos] = &weight(i, j); s[pos++] = &sdvig(i, j);

}

Layer *point = next();

if (point) point->listOf(w, s, pos);

}

void Layer::zero() { sdvig.assign((row+l)*col, 0); Layer *point = next();

if (point) point->zero();

}

void Layer::setNext(Layer *n) { pNext = n;

}

void Layer::setPrev(Layer *p) { pPrev = p;

 

 

 

Приложение 1

139

}

if (р)

(input = p->getln{); error = p->getOut{);}

 

 

 

 

 

 

void Layer::print(int

num, std::ostream &out) (

 

out«Sloy <<num<<std::endl;

 

 

weight.print(out);

 

 

 

out<<std::endl;

 

 

 

 

 

Layer *point = next();

 

 

}

if (point) point->print(num+l, out);

 

 

 

 

 

 

 

void

StartLayer::baok()

(

 

(

 

for(size_t i = 0;

i<errorBuf.size(); ++i)

 

errorBuf[i] = inputBuf[i]*(l-inputBuf[i])*errorBuf[i];

 

real adjust

= NU*errorBuf[i];

 

 

sdvig(0,i)

= sdvig(0,i) + adjust;

 

 

}

itln =

input;

 

 

 

Pointer

 

 

 

for(size_t i=l; i<weight.getRow(); ++i, ++itln) (

 

for(size_t j=0; j<weight.getCol(); ++j) (

 

 

real

adjust

= NU*errorBuf[j]*(*itIn);

 

}

sdvig(i,j)

= sdvig(i,j) + adjust;

 

 

 

 

 

 

 

}

 

 

 

 

 

 

DEBUG(endl<<sigma: <<endl<<errorBuf);

 

}

DEBUG(endl<<sdvid: <<endl<<sdvig);

 

 

 

 

 

 

 

void

(\it MidlLayer}::baok()

(

(

 

for(size_t i = 0;

i<errorBuf.size(); ++i)

 

errorBuf[i] = inputBuf[i]*(l-inputBuf[i])*errorBuf[i];

 

real adjust

= NU*errorBuf[i];

 

 

sdvig(0,i)

= sdvig(0,i) + adjust;

 

 

}

itErr = error;

 

 

 

Pointer

 

 

 

Pointer

itIn =

input;

 

 

 

for(int i=l; i<weight.getRow(); ++i, ++itErr, ++itIn) (

 

real tmp

=

0;

 

 

 

for(int j=0; j<weight.getCol(); ++j) (

 

 

real

adjust

= NU*errorBuf[j]*(*itIn);

 

 

sdvig(i,j) = sdvig(i,j) + adjust;

 

}

tmp

+= errorBuf[j]*weight(i,

j);

 

 

= tmp;

 

 

 

(*itErr)

 

 

 

}

 

 

 

 

 

Layer *point = prev(); point->baok();

DEBUG(endl<<sigma: <<endl<<errorBuf); DEBUG(endl<<sdvid: <<endl<<sdvig);

}

Mem Memory::operator[](int i) (

if (i>=count $\vert \vert $ i<0) ERROR(Out of range);

140

Приложение 1

Mem mem(sizeIn,

sizeOut);

mem.in = data.begin()+i*(sizeIn+sizeOut);

mem.out = data.begin() + i*(sizeIn+sizeOut) + sizeIn; return mem;

}

void Memory::read(ohar *name, int start, int end) { int C ;

data.clear(); count = 0;

ifstream file(name); file>>c;

if (c<end) ERROR(Out of range in file «name); real tmp;

for(int k=0; k<start; ++k) {

for(int i=0; i<sizeIn; ++i) file>>tmp; for(int i=0; i<sizeOut; ++i) file>>tmp;

}

for(int k=start; k<end; ++k) { for(int i=0; i<sizeIn; ++i) {

file>>tmp; data.push_back(tmp);

}

for(int i=0; i<sizeOut; ++i) { file>>tmp; data.push_back(tmp);

}

count++;

}

}

void {\it NeroNet}::createLayers() { Layer *prev, *curr;

size_t ratioCount = 0;

size_t count = arch.size() - 1;

if (Icount) ERROR(Incorrect arch nero net);

end = begin = prev = new StartLayer(arch[0], arch[1], NU); ratioCount = (arch[0]+1)*arch[1];

if (count == 1) return; for(size_t i=1; i<count-1; ++i) {

ratioCount += (arch[i]+1)*arch[i+1];

curr = new {\it MidlLayer}(arch[i], arch[i+1], NU); curr->setPrev(prev);

prev->setNext(curr); prev = curr;

}

ratioCount += (arch[count-1] + 1)*arch[count];

end = new {\it MidlLayer}(arch[count-1], arch[count], NU); end->setPrev(prev);

prev->setNext(end); distr.setIn(arch[0]); distr.setOut(arch[count]); error = end->getOut(); weight.resize(ratioCount); sdvig.resize(ratioCount);