目的
tangnano9kにNNを実装できるようにしロボコンにおける活用方法を探す
使用するもの
TnagNano9k
GOWIN IDE
cで重みを作る
今回は学習はpc上で行い推論のみをFPGAで行う
ホップフィールドネットワーク
今回は最も古典的なNNであるホップフィールドネットワークを使う
5*5で表されたD J M Cを識別するものから始める
https://github.com/imaoca/neuroC/blob/main/neuro.c
から持ってきたこいつを試す(今後もここからプログラムリストを引用する)
#include <stdio.h>
int links[25*25];
int D[25]={
1, 1, 1, 1,-1,
-1, 1,-1,-1, 1,
-1, 1,-1,-1, 1,
-1, 1,-1,-1, 1,
-1, 1, 1, 1,-1
};
int J[25]={
1, 1, 1, 1, 1,
-1,-1,-1, 1,-1,
-1,-1,-1, 1,-1,
1,-1,-1, 1,-1,
1, 1, 1,-1,-1
};
int C[25]={
-1, 1, 1, 1, 1,
1,-1,-1,-1,-1,
1,-1,-1,-1,-1,
1,-1,-1,-1,-1,
-1, 1, 1, 1, 1
};
int M[25]={ 1,-1,-1,-1, 1,
1, 1,-1, 1, 1,
1,-1, 1,-1, 1,
1,-1,-1,-1, 1,
1,-1,-1,-1, 1};
void show(int p[]){
int i,j;
for (i=0;i<5;i++){
for(j=0;j<5;j++)
if (p[i*5+j]>0) putchar('#');
else
putchar(' ');
putchar('\n');
}
putchar('\n');
}
void learn2(void){
int i,j;
for (i=0;i<25;i++)
for(j=0;j<25;j++)
links[i*25+j]=
((D[i]==D[j])?1:-1)+
((J[i]==J[j])?1:-1)+
((C[i]==C[j])?1:-1)+
((M[i]==M[j])?1:-1);
}
void hopfield(int inp[], int lin[]){
int sum,i,j;
for (i=0;i<25;i++){
sum = 0;
for(j=0;j<25;j++)sum=sum+(inp[j])*(lin[i*25+j]);
inp[i]=(sum>=0)?1:-1;
}
}
void main(void){
int input[25]={
-1, 1,-1, 1, 1,
-1,-1,-1, 1,-1,
-1,-1,-1, 1,-1,
-1,-1,-1, 1,-1,
-1, 1, 1,-1,-1
};
learn2();
printf("example\n");
show(input);
printf("recognition\n");
hopfield(input,links);
show(input);
}
結果
重みを出す
学習でだした重みを見ます
#include <stdio.h>
int links[25*25];
int D[25]={
1, 1, 1, 1,-1,
-1, 1,-1,-1, 1,
-1, 1,-1,-1, 1,
-1, 1,-1,-1, 1,
-1, 1, 1, 1,-1
};
int J[25]={
1, 1, 1, 1, 1,
-1,-1,-1, 1,-1,
-1,-1,-1, 1,-1,
1,-1,-1, 1,-1,
1, 1, 1,-1,-1
};
int C[25]={
-1, 1, 1, 1, 1,
1,-1,-1,-1,-1,
1,-1,-1,-1,-1,
1,-1,-1,-1,-1,
-1, 1, 1, 1, 1
};
int M[25]={ 1,-1,-1,-1, 1,
1, 1,-1, 1, 1,
1,-1, 1,-1, 1,
1,-1,-1,-1, 1,
1,-1,-1,-1, 1};
void learn2(void){
int i,j;
for (i=0;i<25;i++)
for(j=0;j<25;j++)
links[i*25+j]=links[i*25+j]+((D[i]==D[j])?1:-1)+((J[i]==J[j])?1:-1)+((C[i]==C[j])?1:-1)+((M[i]==M[j])?1:-1);
}
void listlinks(void){
for (int i = 0; i < 625; i++) {
int val = links[i]; // 整数としてそのまま出力
printf("%d\n", val);
}
}
int main(void){
learn2();
listlinks();
}
結果
Cで推論だけする
さっき出力した重みを使い推論のみを行う
#include <stdio.h>
// 学習済みの重み行列(links)を直接定義
int links[25*25] = {
4, 0, 0, 0, 0, -2, 2, -2, 2, 2, -2, 0, 0, 0, 2, 0, 0, -2, 0, 2, 2, 0, 0, -2, -2, 0, 4, 4, 4, 0, -2, -2, -2, -2, -2, -2, 0, -4, 0, -2, 0, 0, -2, 0, -2, -2, 4, 4, 2, -2, 0, 4, 4, 4, 0, -2, -2, -2, -2, -2, -2, 0, -4, 0, -2, 0, 0, -2, 0, -2, -2, 4, 4, 2, -2, 0, 4, 4, 4, 0, -2, -2, -2, -2, -2, -2, 0, -4, 0, -2, 0, 0, -2, 0, -2, -2, 4, 4, 2, -2, 0, 0, 0, 0, 4, 2, -2, -2, 2, -2, 2, -4, 0, 0, -2, 4, -4, -2, 0, -2, 2, 0, 0, -2, 2, -2, -2, -2, -2, 2, 4, 0, 0, 0, 0, 4, -2, 2, -2, 0, 2, -2, 0, -2, 0, 0, -2, -2, 0, 4, 2, -2, -2, -2, -2, 0, 4, 0, 0, 4, 0, 2, 2, -2, 4, -2, 2, 0, -2, 4, 0, -2, -2, 0, 0, -2, -2, -2, -2, -2, 0, 0, 4, 0, 0, 0, 2, 2, 2, 0, -2, 2, 4, 2, 0, 0, -2, -2, 0, 0, 2, -2, -2, -2, 2, 0, 0, 0, 4, 0, 0, -2, 2, 2, 0, 2, -2, 0, 2, 0, 4, -2, -2, -4, 0, 2, -2, -2, -2, -2, 0, 4, 0, 0, 4, 0, 2, 2, -2, 4, -2, 2, 0, -2, 4, 0, -2, -2, 0, 0, -2, -2, -2, -2, 2, 4, 0, 0, 0, 0, 4, -2, 2, -2, 0, 2, -2, 0, -2, 0, 0, -2, -2, 0, 4, 0, 0, 0, 0, -4, -2, 2, 2, -2, 2, -2, 4, 0, 0, 2, -4, 4, 2, 0, 2, -2, 0, 0, 2, -2, 0, -4, -4, -4, 0, 2, 2, 2, 2, 2, 2, 0, 4, 0, 2, 0, 0, 2, 0, 2, 2, -4, -4, -2, 2, 0, 0, 0, 0, 0, -2, -2, 2, 2, -2, -2, 0, 0, 4, -2, 0, 0, 2, 4, -2, 2, 0, 0, -2, -2, 2, -2, -2, -2, -2, 0, 4, 0, 0, 4, 0, 2, 2, -2, 4, -2, 2, 0, -2, 4, 0, -2, -2, 0, 0, 0, 0, 0, 0, 4, 2, -2, -2, 2, -2, 2, -4, 0, 0, -2, 4, -4, -2, 0, -2, 2, 0, 0, -2, 2, 0, 0, 0, 0, -4, -2, 2, 2, -2, 2, -2, 4, 0, 0, 2, -4, 4, 2, 0, 2, -2, 0, 0, 2, -2, -2, -2, -2, -2, -2, 0, 0, 4, 0, 0, 0, 2, 2, 2, 0, -2, 2, 4, 2, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, -2, -2, 2, 2, -2, -2, 0, 0, 4, -2, 0, 0, 2, 4, -2, 2, 0, 0, -2, -2, 2, -2, -2, -2, -2, 0, 4, 0, 0, 4, 0, 2, 2, -2, 4, -2, 2, 0, -2, 4, 0, -2, -2, 0, 0, 2, -2, -2, -2, 2, 0, 0, 0, 4, 0, 0, -2, 2, 2, 0, 2, -2, 0, 2, 0, 4, -2, -2, -4, 0, 0, 4, 4, 4, 0, -2, -2, -2, -2, -2, -2, 0, -4, 0, -2, 0, 0, -2, 0, -2, -2, 4, 4, 2, -2, 0, 4, 4, 4, 0, -2, -2, -2, -2, -2, -2, 0, -4, 0, -2, 0, 0, -2, 0, -2, -2, 4, 4, 2, -2, -2, 2, 2, 2, -2, 0, 0, 0, -4, 0, 0, 2, -2, -2, 0, -2, 2, 0, -2, 0, -4, 2, 2, 4, 0, -2, -2, -2, -2, 2, 4, 0, 0, 0, 0, 4, -2, 2, -2, 0, 2, -2, 0, -2, 0, 0, -2, -2, 0, 4,
};
void show(int p[]) {
int i, j;
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++)
putchar(p[i * 5 + j] > 0 ? '#' : ' ');
putchar('\n');
}
putchar('\n');
}
void hopfield(int inp[], int lin[]) {
int sum, i, j;
for (i = 0; i < 25; i++) {
sum = 0;
for (j = 0; j < 25; j++)
sum += inp[j] * lin[i * 25 + j];
inp[i] = (sum >= 0) ? 1 : -1;
}
}
int main(void) {
int input[25] = {
-1, 1,-1, 1, 1,
-1,-1,-1, 1,-1,
-1,-1,-1, 1,-1,
-1,-1,-1, 1,-1,
-1, 1, 1,-1,-1
};
printf("example\n");
show(input);
printf("recognition\n");
hopfield(input, links);
show(input);
return 0;
}
結果
このコードをverilogに置き換えていく
その前に
verilogで読み込ませるときの形で重みを出力しておく....と思ったが
https://github.com/imaoca/neuroC/blob/main/links.txt
用意されていたのでこちらをありがたく使わさせてもらう
Verilog
参考
コード
module neuro (input rst,input clk,input [3:0]btn, output reg [4:0] led);
reg [24:0] neuros;
reg signed[7:0] links[624:0];
reg[4:0] i=0,jj=0;
reg signed [7:0]sum;
reg [24:0]count12;
always @(posedge(clk))count12 = count12 + 1;
integer k,m;
always @(posedge(clk))begin
if (rst==0) begin i = 0;neuros = 25'b0011101001010000100011111;led <= 5'b11110; end //0111010011100100001001110D 0011101001010000100011111J 1111000001000010000111110C 1000110001101011101110001M
if ((btn[0]==0)&&(i==0))begin
for (k=0;k<25;k=k+1) begin
sum=0;
for (m=0;m<25;m=m+1)
sum = sum + ((neuros[m]==1)?links[(k<<4)+(k<<3)+k+m]:(-links[(k<<4)+(k<<3)+k+m]));
neuros[k]=(sum>0)?1:0;
end
i = 1;
if(i == 1)begin led <= {neuros[9:5]}; end //ここでLEDの見る場所をきめてうまくいっているか確認する
end
end
always @(posedge(clk))if (rst==0) begin `include "links.txt" end
endmodule
IO_LOC "led[4]" 15;
IO_LOC "led[3]" 14;
IO_LOC "led[2]" 13;
IO_LOC "led[1]" 11;
IO_LOC "led[0]" 10;
IO_LOC "btn[0]" 3;
IO_LOC "clk" 52;
IO_LOC "rst" 4;
書きこみ方
参考まとめ
https://monoist.itmedia.co.jp/mn/articles/2403/11/news023_2.html
https://github.com/imaoca/neurosFPGA/blob/main/neuro9k/src/neuro9k.v
https://github.com/imaoca/neuroC/blob/main/links.txt
https://zenn.dev/nihinihikun/articles/87066301959b48
おわりに
当初は学習も行うつもりだったが論理合成の際にPCのメモリが足りなくなりクラッシュしたためあきらめた(友人のPCでためしたらメモリは60以上使われていた...)
目的である活用方法を探す、はまだ達成されていないのでカメラからの入力をNN推論して画像認識に挑戦してみるつもりです
言葉足らずなとこらが多いため今後追記していきます
読んでくださりありがとうございました



