오늘 해볼것은 Post_Conv_top의 Review입니다
드디어 하나의 Layer동작에 대해서 마무리 짓게 되네요
Post_Conv_top은 Activation과 Pooling Layer가 존재합니다
Yolo Series에 대해서 보게되면 Activation Layer와 Maxpooling Layer가 사용되게 됩니다
1.Activation Layer
이게 ReLu함수인데 음수의 값은 다 0으로 만들어 주게됩니다
이와같은 이유로 Activation Function을 사용하게됩니다
2. MaxPooling Layer
이와같은 이유로 사용하게 됩니다
코드는 비교적 간단합니다
input clk,
input nRst,
input [DW*16-1:0] data_in,
input post_enable,
output wire [Out_ch-1:0] Pool_valid,
output [DW*16-1:0] Layer0_poolout
);
genvar i, j;
wire [Out_ch-1:0] Act_valid;
wire [DW-1:0] Act_out[0:Out_ch-1];
wire [DW-1:0] Pool_out[0:Out_ch-1];
generate
for(i=0;i<Out_ch;i=i+1) begin : Out_Ch
Activation Active_Function(.clk(clk), .nRst(nRst), .act_en(post_enable), .Act_in(data_in[DW*(16-i)-1:DW*(15-i)]), .Act_out(Act_out[i]), .Act_valid(Act_valid[i]));
end
endgenerate
generate
for(j=0;j<Out_ch;j=j+1) begin : Out_CH
Pooling Max_Pooling(.clk(clk), .nRst(nRst), .Pool_en(Act_valid[j]), .Pool_in(Act_out[j]), .valid(Pool_valid[j]), .Pool_out(Pool_out[j]));
end
endgenerate
assign Layer0_poolout = {Pool_out[0], Pool_out[1], Pool_out[2], Pool_out[3],
Pool_out[4], Pool_out[5], Pool_out[6], Pool_out[7],
Pool_out[8], Pool_out[9], Pool_out[10], Pool_out[11],
Pool_out[12], Pool_out[13], Pool_out[14], Pool_out[15]};
이와같이 선언하면되는데 여기서 data in은 Conv0_Layer의 결과인 Cram_da_out_bundle
assign Cram_da_out_bundle = {Cram_da_out[0], Cram_da_out[1], Cram_da_out[2], Cram_da_out[3],
Cram_da_out[4], Cram_da_out[5], Cram_da_out[6], Cram_da_out[7],
Cram_da_out[8], Cram_da_out[9], Cram_da_out[10], Cram_da_out[11],
Cram_da_out[12], Cram_da_out[13], Cram_da_out[14], Cram_da_out[15]};
이 결과입니다
post_enable은 Cram_rd_en이 on 되면 on되어 데이터를 읽게됩니다
이와같이 구성된다고 보면될거같습니다
Conv_Control의 state가 Active라면 해당 data를 보내게 됩니다
generate
for(i=0;i<Out_ch;i=i+1) begin : Out_Ch
Activation Active_Function(.clk(clk), .nRst(nRst), .act_en(post_enable), .Act_in(data_in[DW*(16-i)-1:DW*(15-i)]), .Act_out(Act_out[i]), .Act_valid(Act_valid[i]));
end
endgenerate
해당 문을 보면 채널마다 Act_in이 들어오게되는데
module Activation#(
parameter DW = 16
)(
input clk,
input nRst,
input act_en,
input [DW-1:0] Act_in,
output reg [DW-1:0] Act_out,
output reg Act_valid
);
always @ (posedge clk or negedge nRst)
begin
if(!nRst)
begin
Act_out <= 0;
Act_valid <= 0;
end
else
begin
if(Act_in[DW-1]==0)
Act_out <= Act_in;
else
Act_out <= 16'b0;
Act_valid <= act_en;
end
end
endmodule
이 구문을 보게되면 최상위 비트가 0이라면 즉 양수라면 Relu함수이기떄문에 그대로 입력값이 출력되고
최상위비트가 그렇지않다면 0을 내보내 음수의값은 0이 출력되도록합니다
간단하죠?
Maxpooling 시 Cram에서 읽는방법
cram에서 data를 읽을때 저장은
이처럼 한 행씩 저장하게 됩니다
하지만 Maxpooling은
이와같이 Maxpooling에 이루어져야하는데 어떻게 해야 그렇게 할수있을까요? 바로 읽는방법에서 차이가 있습니다
reg [1:0] Cram_rd_cnt;
reg [3:0] Cram_row_cnt;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
Cram_raddr <= 0;
Cram_rd_cnt <= 0;
Cram_row_cnt <= 0;
end
else
begin
if(Cram_rd_en)
begin
if(Cram_raddr == Conv0_slice**2 - 1)
begin
Cram_raddr <= 0;
end
else
begin
if(Cram_rd_cnt == 3)
begin
if(Cram_row_cnt == 13)
begin
Cram_row_cnt <= 0;
Cram_raddr <= Cram_raddr + 1;
end
else
begin
Cram_raddr <= Cram_raddr - Conv0_slice + 1;
Cram_row_cnt <= Cram_row_cnt + 1;
end
end
else if(Cram_rd_cnt == 1)
begin
Cram_raddr <= Cram_raddr + Conv0_slice - 1;
end
else
begin
Cram_raddr <= Cram_raddr + 1;
end
end
Cram_rd_cnt <= Cram_rd_cnt + 1;
end
else
begin
Cram_raddr <= 0;
Cram_rd_cnt <= 0;
Cram_row_cnt <= 0;
end
end
end
처음 이걸 보면 무슨말 하는지 모를수 있습니다 다시 정리해보면
이와같이 정리할수있습니다. 이걸봐도 모를수도 있습니다
그림으로 설명하면
이와같이 읽기동작이 나타나게됩니다
rd_cnt는 열을 읽는동작이고 Row_cnt는 행을 읽는 동작입니다
그렇게되면 이와같이 동작한다는것을 볼 수 있습니다
generate
for(j=0;j<Out_ch;j=j+1) begin : Out_CH
Pooling Max_Pooling(.clk(clk), .nRst(nRst), .Pool_en(Act_valid[j]), .Pool_in(Act_out[j]), .valid(Pool_valid[j]), .Pool_out(Pool_out[j]));
end
endgenerate
이 구문을 보게되면
Maxpooling은
이와같이 선언되어있습니다. 즉 2*2 Maxpooling이기때문에 4개의 값중 가장 큰값을 비교해 내보내도록됩니다
4개의 pixel을 비교해 valid신호를 on시켜 4개의 pixel중 가장 큰값을 Pool_out으로 나가게 만드는것입니다
Poolout의 결과도 다음 Layer에서 효율적으로 이용하기위해 Bundle로 묶어
assign Layer0_poolout = {Pool_out[0], Pool_out[1], Pool_out[2], Pool_out[3],
Pool_out[4], Pool_out[5], Pool_out[6], Pool_out[7],
Pool_out[8], Pool_out[9], Pool_out[10], Pool_out[11],
Pool_out[12], Pool_out[13], Pool_out[14], Pool_out[15]};
이렇게 출력되도록 만들어줍니다