TensorFlow에서 bfloat16 데이터를 생성하고 FPGA에서 사용

TensorFlow에서 매우 간단한 MNIST 모델을 만들고 bfloat16으로 변환하여 궁극적으로 FPGA (Zybo)로 움직이려고했습니다.

MNIST 데이터



흩어져 쓰여 있기 때문에 생략.
htps : // 기주 b. 코 m / 료 s 36 / 포 lyp 호 ny-u th-t fm
에 소스 등을 넣었다. 어쨌든 부동 소수점 데이터를 만들어야합니다.

bfloat16으로 변환



Session 에서 eval 로 하면 NumPy 형식으로 떨어뜨린다. tf.cast로 캐스트하면 된다.

bfloat16.py
import numpy as np
import tensorflow as tf

w_np = np.loadtxt('w_value.txt', delimiter=',')
b_np = np.loadtxt('b_value.txt', delimiter=',')

print(type(w_np), type(w_np[0][0]))

w_b = tf.cast(w_np, tf.bfloat16)
b_b = tf.cast(b_np, tf.bfloat16)

print(type(w_b), type(w_b[0][0]))

with tf.Session() as sess:
    w_b_np = w_b.eval()
    b_b_np = b_b.eval()

print(type(w_b_np[0][0]))

NumPy로 저장한 것을 조금 가공



헤더 첨부의 바이너리 형식으로 세이브된다. pickle?python:save.py
np.save('w_b_value.npy', w_b_np)
np.save('b_b_value.npy', b_b_np)
dd로 128바이트 건너뜁니다.

Python으로 예측 프로그램 만들기



mnist7
def do_mnist7_mem(a:List[bit16], _mem:List[bit16], lst_len = LEN):
    rom_w = W_PARAM
    rom_b = B_PARAM
    mem = [0] * 10

    xi = 0
    for i in range(lst_len):
        x = a[i]
        for j in range(10):
            mem[j] = bfloat.mul_add(x, rom_w[xi + j], mem[j])

        xi += 10

    for j in range(10):
        _mem[j] = bfloat.add(mem[j], rom_b[j])

컴파일하고 Zybo로 가져 가라.



가져갈 때 조금 세공. 이제 Vivado BRAM의 I/F와 리셋 극성이 설정됩니다. 그리고 BRAM용으로 클럭도 추가.

인터페이스
    input wire clk,
(* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 rst RST" *)
(* X_INTERFACE_PARAMETER = "POLARITY ACTIVE_HIGH" *)
    input wire rst,
    input wire do_mnist7_mem_ready,
    input wire do_mnist7_mem_accept,
    output reg do_mnist7_mem_valid,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in CLK" *)
    output wire do_mnist7_in_a_clk,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in DOUT" *)
    input wire signed [15:0] do_mnist7_mem_in_a_q,
    input wire [10:0] do_mnist7_mem_in_a_len,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in ADDR" *)
    output wire signed [10:0] do_mnist7_mem_in_a_addr,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in DIN" *)
    output wire signed [15:0] do_mnist7_mem_in_a_d,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in WE" *)
    output wire do_mnist7_mem_in_a_we,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in EN" *)
    output wire do_mnist7_mem_in_a_req,

<中略>

  assign do_mnist7_in_a_clk = clk;


놀라운 Polyphony 최적화



상당히 최적화가 효과적이며 거의 assign가 된다. 그냥 DSP를 사용하지 않습니다.
그래서 조금 이것도 Verilog를 세공하고 DSP를 사용하도록 해본다.
  assign new_n_inl1_inl13 = (t622_inl1_inl1 * t623_inl1_inl1);

의 부분을 reg 로 하고 스테이트를 하나 넣어 보았다. 확실히 DSP를 사용하게 되었다. 다만, 결국 fmax 의 병목은 메모리 액세스이므로 이 개조는 의미가 없었다.

unroll 시도



이것은 실패로 끝난다. 잘 생각하면 메모리 액세스를 동시에 할 수 없다면 의미가 없다. 여기는 미래의 검토 항목.

전체 시스템은 이런 느낌





VIO로 확인





10진이니까 알기 힘들다.

미래 전개



Retro FORTH와 협력합니다. AXI Stream과 함께 작동합니다. unroll 대응을 한다. 같은 곳인가.
현시점에서도 사용할 수 있기 때문에, 파라미터의 리얼타임의 가시화라든지 할 수 있을 것 같은 생각이 들고 있다.

좋은 웹페이지 즐겨찾기