Fixed point 란?
verilog로 프로그래밍 하기 위해서는 값의 형태가 fixed point로 구성되어야 한다.
위의 그림처럼 sign / Integer / Fraction 으로 되어 있다.
특히 quantization의 경우, Integer와 scaler로 나눠서 연산하며 scaler의 integer와 fraction이 각각 몇 bit인지를 알고 있어야 된다.
Fixed point Scaler 연산
아래와 같이 quantization하는 pytorch 코드가 있다.
// rescaling
rescale = self.a_max / self.a_max_origin
inp = inp * rescale
// rounding
inp = torch.round(inp)
inp = inp * (1. / self.fqa.alpha)
// rounding
inp_Q = torch.round(inp)
// clamping
inp_Q = torch.clamp(inp_Q, 0, self.fqa.a_qmax)
이를 verilog로 구현하기 위해서는 아래와 같은 조건이 필요하다.
- Q_conv는 input에 따라 변경되는 integer 값일 것
- S_y는 고정된 값이므로 측정을 통해 알아두고 verilog 코드에 fixed 해둠.
- rounding에서는 scaler의 fraction bit만큼 잘라내면 됨.
- rounding을 통해 scaler의 sign과 integer bit이 남고 이는 output bit를 넘어가게 함. 이때 임의로 맵핑하면 MSB bit을 가지고 함. rounding 후 값이므로 MSB bit만 중요함.
- clamping에서는 Q_conv에 할당된 bit의 min, max 기준으로 쳐냄.
위 조건을 따라서 verilog 코드를 짜면 다음과 같다.
module Scaler #(
parameter SCALE_WL = 16, // whole length
parameter SCALE_FL = 14, // fraction length
parameter INP_WL = 16,
parameter OUT_WL = 16,
parameter RESCALE_WL = 18, // integer bit: 6
parameter RESCALE_FL = 12, // fraction bit: 12
parameter ALPHA_WL = 21,
parameter ALPHA_FL = 20
)(
input wire clk,
input wire reset,
input wire [SCALE_WL-1:0] scale,
input wire [INP_WL-1:0] data_in,
input wire valid_in,
output wire [OUT_WL-1:0] data_out,
output wire valid_out
);
wire [RESCALE_WL-1:0] s_y;
// 측정한 특정 layer의 s_y 값 (sign, integer, fraction 순)
assign s_y = {{1'b0}, {5'b10000}, {12'b000000001111}};
wire [INP_WL+RESCALE_WL-1:0] mult0 = $signed(data_in) * $signed(s_y); // data_in = Q_conv
wire [INP_WL+RESCALE_WL-RESCALE_FL-1:0] round_mult0;
// rounding
SignedRoundSaturate #(
.IN_WLEN(INP_WL+RESCALE_WL),
.OUT_WLEN(INP_WL+RESCALE_WL-RESCALE_FL),
.IN_FLEN(RESCALE_FL)
) ROUND_MULT0 (
.din(mult0),
.dout(round_mult0)
);
wire [ALPHA_WL-1:0] fqa_alpha; // <= 1 / self.fqa.alpha
assign fqa_alpha = 21'b0_1111_1111_0110_1001_1011; // 0.99770606 // sign bit
// calculate
wire [INP_WL+RESCALE_WL-RESCALE_FL+ALPHA_WL-1:0] mult1 = $signed(round_mult0) * $signed(fqa_alpha); // signed casting
wire [INP_WL+RESCALE_WL-RESCALE_FL-1:0] round_mult1;
// round
SignedRoundSaturate #(
.IN_WLEN(INP_WL+RESCALE_WL-RESCALE_FL+ALPHA_WL),
.OUT_WLEN(INP_WL+RESCALE_WL-RESCALE_FL+ALPHA_WL-ALPHA_FL),
.IN_FLEN(ALPHA_FL)
) ROUND_MULT1 (
.din(mult1),
.dout(round_mult1)
);
// clamp
wire [15:0] clamp_max = 16'd65535;
wire [OUT_WL-1:0] clamp = (round_mult1 < 0) ? 0 : (round_mult1 > clamp_max) ? clamp_max : round_mult1;
반응형
'Digital Logic > Verilog' 카테고리의 다른 글
[Verilog] Fixed point Scaler 연산 (Quantization - 비트 수가 다른 파라미터와 연산) (0) | 2023.09.06 |
---|---|
[Verilog] Fixed point Scaler 연산 (Quantization - sign 곱셈/덧셈 연산) (0) | 2023.09.06 |
Verilog 설계에서 중요한 존재들 - Counter (카운터) (0) | 2021.05.10 |
Verilog 설계에서 중요한 존재들 - 순차 논리 회로(Sequential logic circuits)_#Flip-Flop (0) | 2021.05.09 |
Verilog 설계에서 중요한 존재들 - 조합 논리 회로(Combinational logic circuits) (0) | 2021.05.08 |
댓글