Смотрите, Алекс. Я тут левой задней решил в Делфи вашу задачку о неподвижном короле ( у вас на почте архив с кодом). В виде эндшпильной таблицы как у Налимова. Это первый шаг для решения нашей задачи. Покрутите его у себя и давайте сформулируем чему мы хотим на основе этого решения научить нашу будущую нейросеть. Варианты есть
1. Классификатор (выиграно-не выиграно)
2. Более сложная задачка на регрессию - оценка позиции. Чем ближе к мату (если поза выиграна) тем больше ее оценка. Ну или ничья, если ничья.
Я посмотрел.
Не могли бы вы разложить по полочкам этот метод.
Мне интересно.
Но самому разобраться в вашем коде для меня сложно.
А, что касается "чему мы хотим на основе этого решения научить нашу будущую нейросеть", то мне бы хотелось так - "2. Более сложная задачка на регрессию - оценка позиции. Чем ближе к мату (если поза выиграна) тем больше ее оценка. Ну или ничья, если ничья."
Это стандартный алгоритм ретроанализа, когда эндшпиль оценивается от матовых позиций назад к самым длинным по продолжительности игры. Там же если отбросить из программы все примитивы (генератор ходов - проверки на легальность) сам ретроалгоритм у меня вроде отсилы 100 строчек кода занимает.
Состоит из 3 частей :
1. Формируем массивы с нашим эндшпилем. Их 2 : с ходом белых и ходом черных. Тут простые таблички 64 на 64 по числу клеток которые у нас могут занимать ферзь и черный король (белый же не двигается и фиксирован). На этом этапе мы просматриваем все позиции эндшпиля и выбрасываем из дальнейшего рассмотрения (помечаем специальными метками) следующие классы позиций
а) невозможные (короли не могут атаковать друг друга, ферзь при своем ходе не может уже атаковать черного короля и все фигурки должны на разных клетках стоять).
б) маты и паты (черный король при своем ходе не имеет легальных ходов)
в) "битую ничью" когда черный король может своим ходом сьесть незащищенного белого ферзя.
Все остальные позиции получают метку 0 - еще неранжированные.
2. "позиция назад с ходом белых". В каждой еще неранжированной позиции с ходом белых мы генерируем ходы белого ферзя. Если хоть один из них ведет в позицию с ходом черных где тем мат, то помечаем такую позицию меткой "позиция 1-го ранга" (мат в 1 полуход) и в следующих итерациях не рассматриваем.
3. "позиция назад с ходом черных". В каждой еще неранжированной позиции с ходом черных мы генерируем ходы черного короля. Если все из них ведут в ранее найденные позиции 1 ранга с выигрышем белых в 1 полуход , значит черные не могут избежать проигрыша и такую позицию мы помечаем меткой "позиция 2 ранга" (мат в 2 полухода).
Далее в цикле повторяем пп2 и пп3 пока на какой-то итерации не закончится процесс появления новых ранжированных позиций. Все, обрываем - эндшпиль проанализирован. Все оставшиеся неранжированные позиции - ничейные, а те кто получили меточку - позиции с кратчайшим выигрышем белых в указанное количество полуходов.
Как бы все . Брудно с Ландау в 1969 не то, чтобы нетленку космического масштаба сделали.
Я вам там для удобства все в процедурках оформил, подставляйте любую клетку белого короля и смотрите статистику. При короле на с3 оказывается что неранжированных позиций после отработки алгоритма не остается (нет ничейных - везед выигрыш белых) и максимальный ранг при этом у некоторых позиций (там я вывожу сколько их в каждом ранге) оказывается равным 46. То есть мат в 46 полуходов. Те самые 23 полных хода, что в книжках написано. Ради интереса посмотрите что при остальных положениях белого короля (интересны только поля с1 с2 с3 с4 и симметричные).
Ну и пример там в конце для вас как опрашивать эти таблицы. Если вдруг захотите цепочки ходов из любой позиции строить на будущее.
"то мне бы хотелось так - "2. Более сложная задачка на регрессию - оценка позиции. Чем ближе к мату (если поза выиграна) тем больше ее оценка. Ну или ничья, если ничья.""
Ну тогда перекурим, вы разберетесь с анатомией нейросети на примере циферок и пойдем дальше. Там уже немного
Сегодня добавил этот алгоритм в GUI для наглядности и понимания.
User ходит за черного короля, а комп с помощью "эндшпильной таблицы" его матует.
Круто прикоснуться к знаниям, которыми делятся умные люди, такие как booot76.
Немного поколдую с этим алгоритмом и нужно переходить к нейросетям
Хорошо мат ставит . Чтобы еще перед своим ходом в отдельно окне видеть все возможные свои ходы с оценкой - можно было бы пройти по всей максимальной ветке. Так-то не угадаешь сильнейшую защиту.
Если будет потом интересно то после нейросетей можем остановиться чуть подробнее на алгоритме эндшпильных таблиц. Можем генератор шахматных эндшпильных таблиц собственный поднять типа как у налимова или syzygy. В разных метриках.Учебный конечно. Без его фанатизма с индексной схемой и сжатием данных. Но даже с минимумом оптимизационных трюков 5-фигурку как нечего делать поднять можем. А то и на беспешечные 6 замахнуться.
После разбора задачи о неприкосновенном короле с помощью "эндшпильной таблицы", интересно узнать, как подойти к этой задаче с помощью нейросети в виде -
"2. Более сложная задачка на регрессию - оценка позиции. Чем ближе к мату (если поза выиграна) тем больше ее оценка. Ну или ничья, если ничья."
Но в каком формате получить информацию об тонкостях нейросетей?
Может быть в таком.
Сначала немного теории от уважаемого booot76. (в свете поставленой выше задачи)
Потом, какая то самостоятельная практическая работа, и если возникают вопросы в свете этой работы, а они неизбежно возникнут.
Получаем ответы от лектора
Или есть более эффективный метод освоения материала?
Переходим от таблицы к нейросетям. Что сразу сказать : решение табличное - математически истинное. На уровне правил игры. Ничего более точного не существует и в принципе не может существовать. А решения в виде нейросетей (любые) - по определению вероятностные. Неточные. Но , зато, обладающие другими очень важными преимуществами. Всегда нужно понимать возможности инструмента, прежде чем с помощью него чего-то решить.
Что собой представляет решение задачи инструментарием нейронных сетей в общем:
1.Подготавливаем обучающую выборку, с помощью которой мы хотим неросеть научить чему-то полезному с по возможности минимальной погрешностью.
2. Разрабатываем архитектуру нейросети специально под тип нашей решаемой задачи.
3. Обучаем.
4. Замеряем.
5. Возвращаемся на пункт 1 для следующей итерации.
Теперь по нашей учебной задачи про неподвижного короля:
Обучающая выборка у нас может быть шикарная - мы уже получили истинные оценки каждой позиции эндшпиля. Уже на уровне сбора данных у нас нет методологической ошибки - только сеть после обучения свою привнесет. Так как у нас используется несколько сред разработки, то нам нужен переход из одной в другую . Лучше всего - на уровне файлика. Который Делфи после отработки оставит после себя, а питон (где будем сеть учить) подхватит и обработает. После обучения сети нужен будет переход обратно (обученную нейросеть со всеми потрохами как-то переместить в Делфи), но об этом потом .
Нам нужно определиться : хотим ли мы обучить сетку для каждого отдельного положения белого короля или для всех его положений на доске сразу. Второй вариант наверное предпочтительнее. Типа решаем обобщенную задачу. Тогда в моем алгоритме надо в цикле проанализировать все положения белого короля, а вывод позиций сделать общим - в единый файл.
Формат файла лучше всего текстовый (питон умеет многое в плане обработки текстов и это все прямо из коробки существует и очень вкусно для программиста). Содержимое - минимально простое : текстовые строки, где каждая строка есть данные об одной позиции. Через пробел : белый король, белый ферзь, черный король, оценка из таблицы как есть. Положения фигур - сразу в диапазоне 0..63. Для нашей задачи , наверное, нам будет лучше всего брать только позиции с ходом черных. Будущая нейросеть при оценке позиции за белых будет делать минимальный перебор на 1 полуход : сгенерирует все ходы белого ферзя, полученные позиции с ходом черных оценит нейросеткой и выберет из них лучший.
Теперь относительно теории нейросети. У нас конкретная задача на регрессию : на вход принять позицию, на выходе дать оценку в диапазоне от 0 до 1, где мы уже интерпретируем эту оценку либо как ничья (около 0) либо выигрыш и тем ближе к мату чем оценка ближе к 1.
Входные данные для сети предлагаю попробовать самые простые, похожие на которые в принципе используются и в реальных шахматных движках. У нас есть 3 фигуры на доске, каждая из которых может стоять на любой клетке от 0 до 63. Значит наш входной блок данных имеет размер 3*64=192. Где первые 64 значения - для белого короля, вторые - для белого ферзя, третьи - для черного короля. Кодируем самым простым образом "1" будет на той позиции где стоит фигура. От 0-вой до 63-ей в своем блоке. То есть : каждая позиция это блок данных длиной 192 где 3 значения - "1", а все остальные - 0.
Значения для обучения можем закодировать так : если позиция ничейна (ничья, пат или "битая ничья") то 0, если выиграна, то для матовых позиций - 1, а для остальных рангов что-то типа 1-(Rang/100). Где чем ближе к мату ранг тем ближе к 1 будет значение.
Саму архитектуру нейросетки выберем максимально похожую на ту, что используется в движках : 3 Dense слоя по формуле 256-16-1. В качестве активационной функции для всех нейронов всех слоев возьмем сигмоид. Он дает красивую кривую значений от 0 до 1.
Оптимизатор - ADAM, лоссфункция - попробуем стандартную для задач на регрессию - mse (среднеквадратичные отклонения).
Вот закодируете все на стороне питона - можем посмотреть что получится при обучении . Начните с файла.
Формат файла лучше всего текстовый (питон умеет многое в плане обработки текстов и это все прямо из коробки существует и очень вкусно для программиста). Содержимое - минимально простое : текстовые строки, где каждая строка есть данные об одной позиции. Через пробел : белый король, белый ферзь, черный король, оценка из таблицы как есть. Положения фигур - сразу в диапазоне 0..63.
Это не самый быстрый вариант, как кажется. Но это я так
Для учебных целей неважно.
Конечно. Самым быстрым вариантом (который я использую для своего движка) это создать в Делфи длл-ку, которая в несколько потоков будет обрабатывать текстовый файл, заливая данные прямо в питоновские структуры памяти. Но это уже на уровне высшего пилотажа. Ладно мне - я миллиарды позиций прогоняю в процессе обучения в несколько эпох и не могу сразу все их в памяти держать - не хватает ее, поэтому по частям обрабатываю все время. Там любое ускорения - хлебушек. А у нас тут учебная задачка на пару сотен тысяч строк обучающей выборки, которые питон один раз обработает и потом уже все в памяти будет подаваться на нейросеть. Не критично вообще. А вот руками пощупать что мы там подаем - полезно будет.
текстовые строки, где каждая строка есть данные об одной позиции. Через пробел : белый король, белый ферзь, черный король, оценка из таблицы как есть. Положения фигур - сразу в диапазоне 0..63..
Для нашей задачи , наверное, нам будет лучше всего брать только позиции с ходом черных.
Набросал пробный код (точнее вставил к код от booot76 немного кода)
Просто для теста, пока что для одного положения белого короля - с3
Warning: Spoiler![ Click to expand ][ Click to hide ]
program king;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,Vcl.Forms;
const
num_directions=8;
maxmoves=35;
dir : array[1..num_directions] of integer=(1,-1,9,-9,10,-10,11,-11);
Broken=255;
Mate=254;
Stalemate=253;
DeadDraw=252;
type
tmovelist = array[0..maxmoves] of integer;
tboard = array[0..99] of integer;
var
w,b : array[0..63,0..63] of byte;
sbase:string='';
sprint:string='';
procedure WriteToFile(s:string;flag:Integer);
var
F: TextFile;
begin
try //uses Forms
AssignFile(F,ExtractFilePath(Application.ExeName)+'\test.txt');
case flag of
0:Rewrite(F);
1:begin
Append(F);
end;
end;
Write(F,s);
finally
CloseFile(F);
end;
end;
Function isAttackedbyKing(Sq:integer;kingsq:integer; var Board:Tboard):boolean;
var
i,x:integer;
begin
result:=false;
if (board[sq]<0) and (board[kingsq]<0) then exit;
x:=kingsq-sq;
for i:=1 to num_directions do
if (x=dir[i]) then
begin
result:=True;
exit;
end;
end;
Function isAttackedbyQueen(Sq:integer;queensq:integer; mykingsq:integer;var Board:Tboard):boolean;
var
i,x:integer;
begin
result:=false;
if (board[sq]<0) and (board[mykingsq]<0) or (board[queensq]<0) then exit;
for i:=1 to num_directions do
begin
x:=queensq+dir[i];
while (board[x]>=0) and (x<>mykingsq) do
begin
if x=sq then
begin
result:=true;
exit;
end;
x:=x+dir[i];
end;
end;
end;
Procedure GenBkingMoves(wk,wq,bk:integer;var board:Tboard;var Mlist:Tmovelist);
var
i,cnt,sq : integer;
begin
cnt:=0;
for i:=1 to num_directions do
begin
sq:=bk+dir[i];
if (board[sq]>=0) and (not isAttackedbyKing(sq,wk,board)) and (not isAttackedbyQueen(sq,wq,wk,board)) then
begin
inc(cnt);
Mlist[cnt]:=sq;
end;
end;
Mlist[0]:=cnt;
end;
Procedure GenWqueenMoves(wk,wq,bk:integer;var board:Tboard;var Mlist:Tmovelist);
var
i,cnt,sq : integer;
begin
cnt:=0;
for i:=1 to num_directions do
begin
sq:=wq+dir[i];
while (board[sq]>=0) and (sq<>wk) do
begin
inc(cnt);
Mlist[cnt]:=sq;
sq:=sq+dir[i];
end;
end;
Mlist[0]:=cnt;
end;
procedure AnalyzeSq(wkingsq:integer;var board:Tboard);
label l1;
var
mlist:Tmovelist;
wq,bk,newwq,newbk,Rang,tofind,i,total : integer;
check,fl : boolean;
swq,sbk,soutq,soutk:string;
x,y,posfig:integer;
begin
WriteToFile('',0);
for wq:=11 to 88 do
for bk:=11 to 88 do
if (board[wq]>=0) and (board[bk]>=0) then
begin
w[board[wq],board[bk]]:=0;
b[board[wq],board[bk]]:=0;
check:=false;
if (wq=wkingsq) or (bk=wkingsq) or (wq=bk) or (isAttackedbyKing(wkingsq,bk,board)) then
begin
w[board[wq],board[bk]]:=broken;
b[board[wq],board[bk]]:=broken;
continue;
end;
if isAttackedbyQueen(bk,wq,wkingsq,board) then
begin
w[board[wq],board[bk]]:=broken;
check:=true;
end;
if isAttackedbyKing(wq,bk,board) and (not isAttackedbyKing(wq,wkingsq,board))
then b[board[wq],board[bk]]:=DeadDraw else
begin
GenBkingMoves(wkingsq,wq,bk,board,mlist);
if Mlist[0]=0 then
begin
if check
then b[board[wq],board[bk]]:=Mate
else b[board[wq],board[bk]]:=Stalemate
end;
end;
end;
Rang:=1;ToFind:=Mate;
// WQ
while true do
begin
total:=0;
for wq:=11 to 88 do
for bk:=11 to 88 do
if (board[wq]>=0) and (board[bk]>=0) and (w[board[wq],board[bk]]=0) then
begin
GenWqueenMoves(wkingsq,wq,bk,board,mlist);
for i:=1 to Mlist[0] do
begin
newwq:=Mlist[i];
if (b[board[newwq],board[bk]]=tofind) then
begin
w[board[wq],board[bk]]:=rang;
inc(total);
break;
end;
end;
end;
writeln('Rang(',rang,') - ',total,' pos.');
// BK
inc(rang);
total:=0;
swq:='';sbk:='';sprint:='';
for wq:=11 to 88 do begin
for bk:=11 to 88 do
if (board[wq]>=0) and (board[bk]>=0) and (b[board[wq],board[bk]]=0) then
begin
GenBkingMoves(wkingsq,wq,bk,board,mlist);
fl:=false;
for i:=1 to Mlist[0] do
begin
newbk:=Mlist[i];
if (w[board[wq],board[newbk]]=0) then
begin
fl:=true;
break;
end;
end;
if not fl then
begin
inc(total);
b[board[wq],board[bk]]:=rang;
//ферзь
x:=wq mod 10;//остаток
y:=wq div 10;
posfig:=x*y;
soutq:=soutq+sbase;
Insert('1',soutq,posfig);
Delete(soutq,65,1);
soutq:=soutq+' ';
//черный король
x:=bk mod 10;//остаток
y:=bk div 10;
posfig:=x*y;
soutk:=soutk+sbase;
Insert('1',soutk,posfig);
Delete(soutk,65,1);
soutk:=soutk+' '+IntToStr(rang)+' '+#13#10;
//if pos('1',soutq)=0 then soutq:=soutk+'----'+#13#10;
//if pos('1',soutk)=0 then soutk:=soutk+'----'+#13#10;
sprint:=sprint+soutq+soutk;
soutq:='';soutk:='';
end;
end;
end;//for
writeln('Rang(',rang,') - ',total,' pos.');
WriteToFile(sprint,1);
if total=0 then break;
tofind:=rang;
inc(rang);
end;
total:=0;
rang:=0;
// Stat.
for wq:=0 to 63 do
for bk:=0 to 63 do
begin
if w[wq,bk]<DeadDraw then inc(total);
if w[wq,bk]=0 then inc(rang);
end;
writeln(rang*100/total:6:2,'% Draws');
end;
var
i,j,cnt,wq,bk:integer;
board : tboard;
// _________________________________________ НАЧАЛО ТУТ __________________________
begin
// создаем в памяти проверочную доску по технологии MAILBOX
for i:=0 to 99 do
board[i]:=-1;
cnt:=-1;
for i:=1 to 8 do
for j:=1 to 8 do
begin
inc(cnt);
board[i+j*10]:=cnt;
sbase:=sbase+'0';
end;
//Insert('1',sbase,1);
//writeln(sbase+' strlen='+IntToStr(length(sbase)));
// Здесь подставляем поле для неподвижного белого короля для последующего анализа (11=а1, 12=b1, 33=c3 36=c6 88=h8)
Analyzesq(33,board);
// Тут можем делать пробинг любой позиции после анализа (задаем положения ферзя и черного короля)
// Варианты : 255- невозможная, 254 уже мат на доске ход черных, 253 - пат на доске ход черных, 252 битая ничья ход черных и они забирают незащищенного ферзя, 0 - ничья, остальное - количество полуходов до мата
wq:=74;
bk:=88;
writeln('If white move : ',w[board[wq],board[bk]]);
writeln('If black move : ',b[board[wq],board[bk]]);
readln;
end.
Возник вопрос:
А нужны ли нам заведомо ничейные позиции (при белом короле на желтых клетках)
Пример учебный поэтому интересно посмотреть как сетка справится с заведомо ничейными положениями и вообще как она разберется в задаче.
Кстати у меня вся кодировка полей в диапазон [0..63] уже зашита в проверочную доску при инициализации. board[sq]. Но я бы вывод в файл делал бы уже после отработки всей процедуры Analyze когда эндшпиль посчитан полностью чтобы еще в одном простом цикле сразу все данные залить в файлик и перейти к следующей клетке белого короля.
Что-то типа такого :
for wq:=11 to 88 do
for bk:=11 to 88 do
if (board[wq]>=0) and (board[bk]>=0) and (b[board[wq],board[bk]]<>Broken) then
begin
string:=inttostr(board[wkingsq])+' '+inttostr(board[wq])+' '+inttostr(board[bk]) + ' ' + inttostr(b[board[wq],board[bk]]);
сохраняем в файл
end;
вся кодировка полей в диапазон [0..63] уже зашита в проверочную доску при инициализации. board[sq].
Сразу не сообразил
Конечно же уже все готово.
В бинарный вид Питон будет переводить?
Если да, то данные для обучения готовы, если Делфи будет переводить в бинарный вид, то в принципе тоже готовы.
Нужно переходить к Питону?
Warning: Spoiler![ Click to expand ][ Click to hide ]
WriteToFile('',0);
for i:=11 to 88 do
// Здесь подставляем поле для неподвижного белого короля для последующего анализа (11=а1, 12=b1, 33=c3 36=c6 88=h8)
Analyzesq(i,board);
writeln('END');
readln;
Warning: Spoiler![ Click to expand ][ Click to hide ]
...
for wq:=11 to 88 do
for bk:=11 to 88 do
if (board[wq]>=0) and (board[bk]>=0) and (b[board[wq],board[bk]]<>Broken) then
begin
str:=inttostr(board[wkingsq])+' '+inttostr(board[wq])+' '+inttostr(board[bk]) + ' ' + inttostr(b[board[wq],board[bk]])+#13#10;
WriteToFile(str,1);
end;
total:=0;
rang:=0;
// Stat.
В питоне лучше переводить. Все равно нам на вход нейросети нужно будет потом массивы входных данных в формате numpy подавать, а в Делфи это делать замысловато.
А да - в цикле неподвижного короля обязательно надо проверять чтобы он за пределы доски не уходил.
Warning: Spoiler![ Click to expand ][ Click to hide ]
# Function to convert decimal to binary
# using built-in python function
def decimalToBinary(n):
# Converting decimal to binary
# and removing the prefix(0b)
return bin(n).replace("0b", "")
with open('/content/sample_data/training_data.txt', 'r') as f:
data = f.read()
lines = data.splitlines()
lines1=[]
s=''
for i in range(0,len(lines)):
s=''
for j in range(0,len(lines[i])):
if (lines[i][j] == ' '):
lines1.append(s)
s=''
continue
s=s+lines[i][j]
lines1.append(s)
print(len(lines))
print(lines)
print(len(lines1) / 4)
print(lines1)
print(lines1[0]+lines1[1]+lines1[2]+lines1[3])
print(lines1[len(lines1)-4]+lines1[len(lines1)-3]+lines1[len(lines1)-2]+lines1[len(lines1)-1])
Warning: Spoiler![ Click to expand ][ Click to hide ]
Нужно же будет принять данные от Делфи
PS
Можно проще
Warning: Spoiler![ Click to expand ][ Click to hide ]
with open('/content/sample_data/training_data.txt', 'r') as f:
data = f.read()
lines1 = data.split()
print(len(lines1) / 4)
print(lines1)
print(lines1[0]+lines1[1]+lines1[2]+lines1[3])
print(lines1[len(lines1)-4]+lines1[len(lines1)-3]+lines1[len(lines1)-2]+lines1[len(lines1)-1])
Я предпочитаю обрабатывать по одной строке в цикле типа :
while True:
line=f.readline()
if not line:
f.close()
break
тут разбиваем строку на подстроки и убираем разделяющие пробелы
mylist=line.split()
далее не мудрствуя лукаво просто переводим подстроки в целые числа (чем они в Делфи и являлись)
wk=int(mylist[0])
wq=int(mylist[1])
bk=int(mylist[2])
res=int(mylist[3])
Ну и далее бы писал прямо в массив numpy по полученным координатам уже единички. Предварительно, конечно, сразу надо создать 2 массива (Х Y) наших входных данных и меток. Массив входных данных имеет размерность [количество строк в файле, 192] массив меток просто массив размерностью [количество строк в файле,]
Создавать массивы надо сразу заполненные нулями (чтобы потом осталось единички где надо расставить в одном массиве и дать число от 0 до 1 во втором).
Все - данные для нейросети будут готовы. Эти массивы потом сразу же в model.fit и скармливать там где надо Х и Y.
Статья толковая, монументальная. Как лобзиком в скале средневековый замок выпилить. Полезная, безусловно, но изучать ее надо долго и обстоятельно. Пока же, чтобы вы до уровня метро в нее не закопались , просто подготовим 2 массива и на основе керас-примера про распознавание цифр смастерим сетку. Подготовьте пока эти 2 массива и перепрверьте их, чтобы в них не было ошибок. Просто глазами просмотрите чем они заполнены , чтобы в каждой строке массива данных было именно 3 единички и не более, а в массиве меток - число именно от 0 до 1.
Warning: Spoiler![ Click to expand ][ Click to hide ]
import numpy as np
x = np.zeros((223944, 192))
x.dtype='byte'
y = np.zeros(223944)
f = open('/content/drive/MyDrive/Colab Notebooks/training_data.txt', 'r')
i = -1
while True:
lines=f.readline()
if not lines:
f.close()
break
mylist=lines.split()
wk=int(mylist[0])
wq=int(mylist[1])
bk=int(mylist[2])
i = i + 1
x[i][wk] = 1
x[i][wq+64] = 1
x[i][bk+128] = 1
res=int(mylist[3])
# 1-(Rang/100)
# res = 255 - невозможная,
# 254 уже мат на доске ход черных,
# 253 - пат на доске ход черных,
# 252 битая ничья ход черных и они забирают незащищенного ферзя,
# 0 - ничья, остальное - количество полуходов до мата
y[i] = 1 - (res/100)
if (res == 252) or (res == 253):
y[i] = 0
if (res == 254):
y[i] = 1
#test
s = ''
z = 0
n = 56196 # line n+1=56197
for j in range(0,193):
if (j==64) or (j==128):
#visual separator
s=s+' '
s=s + str(x[n][j])
if x[n][j]==1:
z = z + 1
#print(i)
print(n)
print('x =',s)
print('sum (1) =',z)
#print(x.dtype)
print('y =',y[n])
Warning: Spoiler![ Click to expand ][ Click to hide ]
56196
x = 0000000000000000000000000000000000000000000000000000000001000000 0000000000000000000000000000000000000000000000000000000000000010 00000000000000000000000000000000000000000000000000000000000001000
sum (1) = 3
y = 0.0
Warning: Spoiler![ Click to expand ][ Click to hide ]
В каком виде нам нужно получить результат обучения?
Выглядит все рабочим! Результат обучения обычно всегда нам нужен в виде сохраненной модели в которой мы понимаем итоговоые параметры точности и лосс-функции.
Warning: Spoiler![ Click to expand ][ Click to hide ]
import tensorflow as tf
import keras
import numpy as np
from keras.layers import Dense, Flatten
from keras.models import Sequential
print('tensorflow:' + tf.__version__)
print('keras:' + keras.__version__)
print('numpy:' + np.__version__)
x = np.zeros((223944, 192))
x.dtype='byte'
y = np.zeros(223944)
f = open('/content/drive/MyDrive/Colab Notebooks/training_data.txt', 'r')
i = -1
while True:
lines=f.readline()
if not lines:
f.close()
break
mylist=lines.split()
wk=int(mylist[0])
wq=int(mylist[1])
bk=int(mylist[2])
i = i + 1
x[i][wk] = 1
x[i][wq+64] = 1
x[i][bk+128] = 1
res=int(mylist[3])
# 1-(Rang/100)
# res = 255 - невозможная,
# 254 уже мат на доске ход черных,
# 253 - пат на доске ход черных,
# 252 битая ничья ход черных и они забирают незащищенного ферзя,
# 0 - ничья, остальное - количество полуходов до мата
y[i] = 1 - (res/100)
if (res == 252) or (res == 253):
y[i] = 0
if (res == 254):
y[i] = 1
# архитектуру нейросетки выберем максимально похожую на ту, что используется в движках :
# 3 Dense слоя по формуле 256-16-1. В качестве активационной функции для всех нейронов всех слоев возьмем сигмоид.
x_train = x
y_train = y
model = Sequential()
model.add(Dense(256, activation='sigmoid', input_shape=(x_train[0].shape)))
model.add(Dense(16, activation='sigmoid'))
model.add(Dense(1, activation='sigmoid'))
model.add(Flatten())
#Оптимизатор - ADAM, лоссфункция - попробуем стандартную для задач на регрессию - mse (среднеквадратичные отклонения)
model.compile(loss='mse',
optimizer='adam',
metrics=['accuracy'])
model.fit(x_train, y_train, epochs=50 )
Не уверен, что правильно ...
Warning: Spoiler![ Click to expand ][ Click to hide ]
Сообщение «UserWarning: Do not pass an input_shape / input_dim argument to a layer» появляется при использовании последовательных моделей в Keras.
Причина ошибки — в последовательных моделях не нужно указывать размер входного слоя или его форму. Размер входа определяется автоматически, когда модель подгоняют под данные.
Чтобы исправить предупреждение, при построении последовательной модели нужно использовать объект Input, который определяет форму входа.
Пример кода, который решает проблему:
model = models.Sequential()
model.add(layers.Input(shape=(x_train.shape,))) # Указываем форму входа
model.add(layers.Dense(10, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
результат
Warning: Spoiler![ Click to expand ][ Click to hide ]
1. Вот это - убираем вообще model.add(Flatten())
Этот слой нужен в цифрах чтобы двумерные по своей сути картинки в пикселях 28х28 преобразовать в одномерный массив. Нам это не нужно у нас и так 192 столбца без признаков иных измерений.
2. метрику возьмите вместо accuracy - mae. Первая это точность "угадывания" в моделях на распознавание. Типа сколько правильно была угадана 1 (а не 0) там где правильно именно 1. Для задач на регрессию нам нужно что-то поскучнее. Поэтому вторая метрика - средняя арифметическая общей суммарной ошибки. Чем она к 0 ближе тем наша сеть точнее.
А так... шутки шутками лосс функция стабильно уменьшается. Сеть беспрерывно учится. Гулять так гулять - поставьте 100 эпох. Или даже 200. В нашем случае мы не боимся переобучения - иных данных чем мы уже в сеть для обучения подаем в системе нет и не будет.
Но... я так и не понял - после исправления ошибки размерности входного слоя сколько у вас в сухом остатке слоев и нейронов в сети осталось? Если только два слоя (10 и 1), то, как бы "маловато будет" и "командир, добавить бы надо" .