---
# System prepended metadata

title: 8-bit Unet Verification

---

# 8-bit Unet Verification

目前還沒完工，但快了，還有一些小 bug 要解，以及 M 要用 fixed-point 運算的問題

- inference_Unet_v1_8bit(ver1)

```python=
# -*- coding: utf-8 -*-
"""
Created on Mon Sep 18 04:02:01 2023

@author: Jay
"""

from os import listdir
import cv2 as cv
import os
import CONV
from CONV import GEMMConv3D
from CONV import Conv3D
from CONV import Maxpool_3D
from CONV import De_Conv2x2
#from CONV import De_Conv2x2_fast
import math
from skimage.measure import block_reduce as maxpooling
import matplotlib.pyplot as plt
import numpy as np

                                                                   
layer = ['conv'+str(i) for i in range(1, 24)]

current_path = os.getcwd()

all_file_name = os.listdir(current_path)
print(all_file_name)

parameter = {}
floatingVar = {}

Load_parameter = 0

if Load_parameter == 1:
    parameter = np.load('./parameter/parameter.npy',allow_pickle='TRUE').item()
    floatingVar = np.load('./parameter/floatingVar.npy',allow_pickle='TRUE').item()
else:

    for item in all_file_name:
        if item in layer:
            file_name = os.listdir(current_path+'/'+item)
            print(file_name)
            for item_in in file_name:
                parameter[item+'_'+item_in[:-4]] = np.load(current_path+'/'+item+'/'+item_in)
        
        elif item.endswith("npy"):
            print('npy:', item)
            floatingVar[item[:-4]] = np.load(current_path+'/'+item)
            
# resize the output activations
for i in range(1, 32):
    floatingVar['out'+str(i)] = np.reshape(floatingVar['out'+str(i)], (floatingVar['out'+str(i)].shape[1],floatingVar['out'+str(i)].shape[2],floatingVar['out'+str(i)].shape[3]))
    floatingVar['out'+str(i)+'_quantFloating'] = np.reshape(floatingVar['out'+str(i)+'_quantFloating'], (floatingVar['out'+str(i)+'_quantFloating'].shape[1],floatingVar['out'+str(i)+'_quantFloating'].shape[2],floatingVar['out'+str(i)+'_quantFloating'].shape[3]))


# Initialize the input_scale of each layer
for idx in range(2, 24):
    parameter['conv' + str(idx) + '_input_scale'] = parameter['conv' + str(idx-1) + '_output_scale'].copy()
    parameter['conv'+str(idx)+'_input_zero_point'] = parameter['conv'+str(idx-1)+'_output_zero']


use_shift_instead_of_divide = 2

print(" ==================== Unet inference (Int8 model) ====================")

Unet = {}
debug = {}

input_data = floatingVar['input_np'][0,]

out_num = 0
Unet['q_out'+str(out_num)] = np.round( (input_data / parameter['conv1_input_scale'])  + parameter['conv1_input_zero_point'])
print("max = ", np.max(Unet['q_out'+str(out_num)]))
print("min = ", np.min(Unet['q_out'+str(out_num)]))

out_num += 1
weight_num = 1
bit = 32
# =========================================== Encoder ===========================================
for times in range(5):

    print("\n-------- out{} --------".format(out_num))
    # Conv + Relu
    Unet['q_out'+str(out_num)] = GEMMConv3D( (Unet['q_out'+str(out_num-1)] - parameter['conv'+str(weight_num)+'_input_zero_point'] ) , parameter['conv'+str(weight_num)+'_weight_int'])
    # calculate left shift bit
    ratio =  ( parameter['conv' + str(weight_num) + '_input_scale'] * parameter['conv' + str(weight_num) + '_weight_scale'] / parameter['conv' + str(weight_num) + '_output_scale'] )
    shift_bit = math.log(ratio, 2)
    shift_bit = abs( math.ceil(shift_bit) )
    M = ratio / 2**(-shift_bit)
    M_fixed = round(M * 2**bit)
    Unet['shift_bit'+str(out_num)] = shift_bit
    Unet['M'+str(out_num)] = M
    Unet['M_fixed'+str(out_num)] = M_fixed
    # Relu
    Unet['q_out'+str(out_num)] [ Unet['q_out'+str(out_num)] < 0.0 ] = 0.0
    print('ratio = {}, shift_bit = {}'.format(ratio, shift_bit))
    if use_shift_instead_of_divide == 1 :
        Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
        Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] // (2**(bit+Unet['shift_bit'+str(out_num)]))
    elif use_shift_instead_of_divide == 2 :
        one = np.ones(Unet['q_out'+str(out_num)].shape)
        tmp = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
        float_int_err = ( tmp / (2**(bit+Unet['shift_bit'+str(out_num)])) ) - ( tmp // (2**(bit+Unet['shift_bit'+str(out_num)])) )
        outTmp = tmp // (2**(bit+Unet['shift_bit'+str(out_num)]))
        tag = float_int_err > 0.5
        Unet['q_out'+str(out_num)] = outTmp.copy()
        Unet['q_out'+str(out_num)][tag] = outTmp[tag] + one[tag]
    else: 
        Unet['q_out'+str(out_num)] = np.round( Unet['q_out'+str(out_num)] * ratio )   
    Unet['q_out'+str(out_num)] += parameter['conv' + str(weight_num) + '_output_zero'] 
    Unet['q_out'+str(out_num)] [ Unet['q_out'+str(out_num)] > 255.0 ] = 255.0
    print("max = ", np.max(Unet['q_out'+str(out_num)]))
    print("min = ", np.min(Unet['q_out'+str(out_num)]))
    
    Unet['ratio'+str(out_num)] = ratio
    Unet['q_out_floating'+str(out_num)] = parameter['conv' + str(weight_num) + '_output_scale'] * (Unet['q_out'+str(out_num)] - parameter['conv'+str(weight_num)+'_output_zero'] )
    debug['out'+str(out_num)+'_quantFloating_quant'] = np.round( (floatingVar['out'+str(out_num)+'_quantFloating'] / parameter['conv' + str(weight_num) + '_output_scale'])  + parameter['conv'+str(weight_num)+'_output_zero'])
    out_num += 1
    weight_num += 1
    
    
    
    
    #--------------------------------------------------------------------------------------------------------
    
    print("\n-------- out{} --------".format(out_num))
    # Conv + Relu
    Unet['q_out'+str(out_num)] = GEMMConv3D( (Unet['q_out'+str(out_num-1)] - parameter['conv'+str(weight_num)+'_input_zero_point'] ) , parameter['conv'+str(weight_num)+'_weight_int'])
    # calculate left shift bit
    ratio =  ( parameter['conv' + str(weight_num) + '_input_scale'] * parameter['conv' + str(weight_num) + '_weight_scale'] / parameter['conv' + str(weight_num) + '_output_scale'] )
    shift_bit = math.log(ratio, 2)
    shift_bit = abs( math.ceil(shift_bit) )
    M = ratio / 2**(-shift_bit)
    M_fixed = round(M * 2**bit)
    Unet['shift_bit'+str(out_num)] = shift_bit
    Unet['M'+str(out_num)] = M
    Unet['M_fixed'+str(out_num)] = M_fixed
    # Relu
    Unet['q_out'+str(out_num)] [ Unet['q_out'+str(out_num)] < 0.0 ] = 0.0
    print('ratio = {}, shift_bit = {}'.format(ratio, shift_bit))
    if use_shift_instead_of_divide == 1 :
        Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
        Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] // (2**(bit+Unet['shift_bit'+str(out_num)]))
    elif use_shift_instead_of_divide == 2 :
        one = np.ones(Unet['q_out'+str(out_num)].shape)
        tmp = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
        float_int_err = ( tmp / (2**(bit+Unet['shift_bit'+str(out_num)])) ) - ( tmp // (2**(bit+Unet['shift_bit'+str(out_num)])) )
        outTmp = tmp // (2**(bit+Unet['shift_bit'+str(out_num)]))
        tag = float_int_err > 0.5
        Unet['q_out'+str(out_num)] = outTmp.copy()
        Unet['q_out'+str(out_num)][tag] = outTmp[tag] + one[tag]
    else: 
        Unet['q_out'+str(out_num)] = np.round( Unet['q_out'+str(out_num)] * ratio )   
    Unet['q_out'+str(out_num)] += parameter['conv' + str(weight_num) + '_output_zero'] 
    Unet['q_out'+str(out_num)] [ Unet['q_out'+str(out_num)] > 255.0 ] = 255.0
    print("max = ", np.max(Unet['q_out'+str(out_num)]))
    print("min = ", np.min(Unet['q_out'+str(out_num)]))
    
    Unet['ratio'+str(out_num)] = ratio
    Unet['q_out_floating'+str(out_num)] = parameter['conv' + str(weight_num) + '_output_scale'] * (Unet['q_out'+str(out_num)] - parameter['conv'+str(weight_num)+'_output_zero'] )
    debug['out'+str(out_num)+'_quantFloating_quant'] = np.round( (floatingVar['out'+str(out_num)+'_quantFloating'] / parameter['conv' + str(weight_num) + '_output_scale'])  + parameter['conv'+str(weight_num)+'_output_zero'])
    out_num += 1
    weight_num += 1
    
    
    
    if(times < 4):
        print("\n-------- out{} --------".format(out_num))
        # Pooling
        Unet['q_out'+str(out_num)] = Maxpool_3D(Unet['q_out'+str(out_num-1)])
        
        out_num += 1
        


'''
print(" ===================== check with Ans (each layer) ===================== ")

checkList = [1, 2]
for i in range(len(checkList)):
    print('---------check out{}------------'.format(checkList[i]))
    temp1 = Unet['q_out'+str(checkList[i])]
    temp2 = debug['out'+str(checkList[i])+'_quantFloating_quant']
    err = temp1 - temp2
    print("max err = ", np.max(err))
    print("min err = ", np.min(err))
''' 
    
print("====================================================================================================")
print('------check input------')
input_int = floatingVar['input_int']
my_input_int = Unet['q_out'+str(0)]
err_input = input_int - my_input_int
print("max err = ", np.max(err_input))
print("min err = ", np.min(err_input))

if((input_int == my_input_int).all()):
    print("same")
else:
    print('different')



print('------check weight1------')
weight1_int = parameter['conv'+str(1)+'_weight_int']
weight1_int_fromFloat = np.round   ( (floatingVar['conv1_weight'] / parameter['conv1_weight_scale']  + parameter['conv1_weight_zero'] )  )
err_weight1 = weight1_int - weight1_int_fromFloat
print("max err = ", np.max(err_weight1))
print("min err = ", np.min(err_weight1))

if((weight1_int == weight1_int_fromFloat).all()):
    print("same")
else:
    print('different')
    

print("====================================================================================================")


#print(out_num)
#print(weight_num)



# =========================================== Decoder ===========================================
catNum = 11

for times in range(4):
    
    
    #--------------------------------------------------------------------------------------------------------
    
    print("\n-------- out{} --------".format(out_num))
    # de-Conv
    Unet['q_out'+str(out_num)] = De_Conv2x2((Unet['q_out'+str(out_num-1)] - parameter['conv'+str(weight_num)+'_input_zero_point'] ) , parameter['conv'+str(weight_num)+'_weight_int'])
    # calculate left shift bit
    ratio =  ( parameter['conv' + str(weight_num) + '_input_scale'] * parameter['conv' + str(weight_num) + '_weight_scale'] / parameter['conv' + str(weight_num) + '_output_scale'] )
    shift_bit = math.log(ratio, 2)
    shift_bit = abs( math.ceil(shift_bit) )
    M = ratio / 2**(-shift_bit)
    M_fixed = round(M * 2**bit)
    Unet['shift_bit'+str(out_num)] = shift_bit
    Unet['M'+str(out_num)] = M
    Unet['M_fixed'+str(out_num)] = M_fixed
    print('ratio = {}, shift_bit = {}'.format(ratio, shift_bit))
    if use_shift_instead_of_divide == 1 :
        Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
        Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] // (2**(bit+Unet['shift_bit'+str(out_num)]))
    elif use_shift_instead_of_divide == 2 :
        one = np.ones(Unet['q_out'+str(out_num)].shape)
        tmp = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
        float_int_err = ( tmp / (2**(bit+Unet['shift_bit'+str(out_num)])) ) - ( tmp // (2**(bit+Unet['shift_bit'+str(out_num)])) )
        outTmp = tmp // (2**(bit+Unet['shift_bit'+str(out_num)]))
        tag = float_int_err > 0.5
        Unet['q_out'+str(out_num)] = outTmp.copy()
        Unet['q_out'+str(out_num)][tag] = outTmp[tag] + one[tag]
    else: 
        Unet['q_out'+str(out_num)] = np.round( Unet['q_out'+str(out_num)] * ratio )   
    Unet['q_out'+str(out_num)] += parameter['conv' + str(weight_num) + '_output_zero'] 
    Unet['q_out'+str(out_num)] [ Unet['q_out'+str(out_num)] > 255.0 ] = 255.0
    Unet['q_out'+str(out_num)] [ Unet['q_out'+str(out_num)] < 0.0 ] = 0.0
    #Unet['q_out'+str(out_num)] += abs( np.min(Unet['q_out'+str(out_num)]) )
    print("max = ", np.max(Unet['q_out'+str(out_num)]))
    print("min = ", np.min(Unet['q_out'+str(out_num)]))
    Unet['ratio'+str(out_num)] = ratio
    Unet['q_out_floating'+str(out_num)] = parameter['conv' + str(weight_num) + '_output_scale'] * (Unet['q_out'+str(out_num)] - parameter['conv'+str(weight_num)+'_output_zero'] )
    debug['out'+str(out_num)+'_quantFloating_quant'] = np.round( (floatingVar['out'+str(out_num)+'_quantFloating'] / parameter['conv' + str(weight_num) + '_output_scale'])  + parameter['conv'+str(weight_num)+'_output_zero'])
    out_num += 1
    weight_num += 1
    
    
    
    #--------------------------------------------------------------------------------------------------------
    
    print("\n-------- out{} --------".format(out_num))
    # concatenate
    Unet['q_out'+str(out_num)] = np.concatenate([Unet['q_out'+str(out_num-1)], Unet['q_out'+str(catNum)]], axis=0)
    out_num += 1
    
    
    #--------------------------------------------------------------------------------------------------------
    
    print("\n-------- out{} --------".format(out_num))
    # Conv + Relu
    Unet['q_out'+str(out_num)] = GEMMConv3D( (Unet['q_out'+str(out_num-1)] - parameter['conv'+str(weight_num)+'_input_zero_point'] ) , parameter['conv'+str(weight_num)+'_weight_int'])
    # calculate left shift bit
    ratio =  ( parameter['conv' + str(weight_num) + '_input_scale'] * parameter['conv' + str(weight_num) + '_weight_scale'] / parameter['conv' + str(weight_num) + '_output_scale'] )
    shift_bit = math.log(ratio, 2)
    shift_bit = abs( math.ceil(shift_bit) )
    M = ratio / 2**(-shift_bit)
    M_fixed = round(M * 2**bit)
    Unet['shift_bit'+str(out_num)] = shift_bit
    Unet['M'+str(out_num)] = M
    Unet['M_fixed'+str(out_num)] = M_fixed
    # Relu
    Unet['q_out'+str(out_num)] [ Unet['q_out'+str(out_num)] < 0.0 ] = 0.0
    print('ratio = {}, shift_bit = {}'.format(ratio, shift_bit))
    if use_shift_instead_of_divide == 1 :
        Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
        Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] // (2**(bit+Unet['shift_bit'+str(out_num)]))
    elif use_shift_instead_of_divide == 2 :
        one = np.ones(Unet['q_out'+str(out_num)].shape)
        tmp = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
        float_int_err = ( tmp / (2**(bit+Unet['shift_bit'+str(out_num)])) ) - ( tmp // (2**(bit+Unet['shift_bit'+str(out_num)])) )
        outTmp = tmp // (2**(bit+Unet['shift_bit'+str(out_num)]))
        tag = float_int_err > 0.5
        Unet['q_out'+str(out_num)] = outTmp.copy()
        Unet['q_out'+str(out_num)][tag] = outTmp[tag] + one[tag]
    else: 
        Unet['q_out'+str(out_num)] = np.round( Unet['q_out'+str(out_num)] * ratio )   
    Unet['q_out'+str(out_num)] += parameter['conv' + str(weight_num) + '_output_zero'] 
    Unet['q_out'+str(out_num)] [ Unet['q_out'+str(out_num)] > 255.0 ] = 255.0
    print("max = ", np.max(Unet['q_out'+str(out_num)]))
    print("min = ", np.min(Unet['q_out'+str(out_num)]))
    
    Unet['ratio'+str(out_num)] = ratio
    Unet['q_out_floating'+str(out_num)] = parameter['conv' + str(weight_num) + '_output_scale'] * (Unet['q_out'+str(out_num)] - parameter['conv'+str(weight_num)+'_output_zero'] )
    debug['out'+str(out_num)+'_quantFloating_quant'] = np.round( (floatingVar['out'+str(out_num)+'_quantFloating'] / parameter['conv' + str(weight_num) + '_output_scale'])  + parameter['conv'+str(weight_num)+'_output_zero'])
    out_num += 1
    weight_num += 1
    
    
    
    #--------------------------------------------------------------------------------------------------------
    
    print("\n-------- out{} --------".format(out_num))
    # Conv + Relu
    Unet['q_out'+str(out_num)] = GEMMConv3D( (Unet['q_out'+str(out_num-1)] - parameter['conv'+str(weight_num)+'_input_zero_point'] ) , parameter['conv'+str(weight_num)+'_weight_int'])
    # calculate left shift bit
    ratio =  ( parameter['conv' + str(weight_num) + '_input_scale'] * parameter['conv' + str(weight_num) + '_weight_scale'] / parameter['conv' + str(weight_num) + '_output_scale'] )
    shift_bit = math.log(ratio, 2)
    shift_bit = abs( math.ceil(shift_bit) )
    M = ratio / 2**(-shift_bit)
    M_fixed = round(M * 2**bit)
    Unet['shift_bit'+str(out_num)] = shift_bit
    Unet['M'+str(out_num)] = M
    Unet['M_fixed'+str(out_num)] = M_fixed
    # Relu
    Unet['q_out'+str(out_num)] [ Unet['q_out'+str(out_num)] < 0.0 ] = 0.0
    print('ratio = {}, shift_bit = {}'.format(ratio, shift_bit))
    if use_shift_instead_of_divide == 1 :
        Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
        Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] // (2**(bit+Unet['shift_bit'+str(out_num)]))
    elif use_shift_instead_of_divide == 2 :
        one = np.ones(Unet['q_out'+str(out_num)].shape)
        tmp = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
        float_int_err = ( tmp / (2**(bit+Unet['shift_bit'+str(out_num)])) ) - ( tmp // (2**(bit+Unet['shift_bit'+str(out_num)])) )
        outTmp = tmp // (2**(bit+Unet['shift_bit'+str(out_num)]))
        tag = float_int_err > 0.5
        Unet['q_out'+str(out_num)] = outTmp.copy()
        Unet['q_out'+str(out_num)][tag] = outTmp[tag] + one[tag]
    else: 
        Unet['q_out'+str(out_num)] = np.round( Unet['q_out'+str(out_num)] * ratio )   
    Unet['q_out'+str(out_num)] += parameter['conv' + str(weight_num) + '_output_zero'] 
    Unet['q_out'+str(out_num)] [ Unet['q_out'+str(out_num)] > 255.0 ] = 255.0
    print("max = ", np.max(Unet['q_out'+str(out_num)]))
    print("min = ", np.min(Unet['q_out'+str(out_num)]))
    
    Unet['ratio'+str(out_num)] = ratio
    Unet['q_out_floating'+str(out_num)] = parameter['conv' + str(weight_num) + '_output_scale'] * (Unet['q_out'+str(out_num)] - parameter['conv'+str(weight_num)+'_output_zero'] )
    debug['out'+str(out_num)+'_quantFloating_quant'] = np.round( (floatingVar['out'+str(out_num)+'_quantFloating'] / parameter['conv' + str(weight_num) + '_output_scale'])  + parameter['conv'+str(weight_num)+'_output_zero'])
    out_num += 1
    weight_num += 1
    
    

    catNum -= 3







print("\n-------- out{} --------".format(out_num))
# =========================================== Output Layer ===========================================
output_channel = floatingVar['conv'+str(weight_num)+'_weight'].shape[0]
input_channel  = floatingVar['conv'+str(weight_num)+'_weight'].shape[1]

floatingVar['conv'+str(weight_num)+'_weight'] = np.reshape(floatingVar['conv'+str(weight_num)+'_weight'], (-1, floatingVar['conv'+str(weight_num)+'_weight'].shape[1]))

parameter['conv'+str(weight_num)+'_weight_int'] = np.reshape( parameter['conv'+str(weight_num)+'_weight_int'], (-1, parameter['conv'+str(weight_num)+'_weight_int'].shape[1]))


Unet['q_out'+str(out_num)] = np.zeros([output_channel, Unet['q_out'+str(out_num-1)].shape[1], Unet['q_out'+str(out_num-1)].shape[2]])

outTmp = np.zeros([output_channel, Unet['q_out'+str(out_num-1)].shape[1], Unet['q_out'+str(out_num-1)].shape[2]])


Unet['q_out'+str(out_num-1)] -= parameter['conv'+str(weight_num)+'_input_zero_point'] 
for oc in range(output_channel):
    for ic in range(input_channel):
        for y in range(Unet['q_out'+str(out_num-1)].shape[1]):
            for x in range(Unet['q_out'+str(out_num-1)].shape[2]):
                Unet['q_out'+str(out_num)][oc, y, x] += Unet['q_out'+str(out_num-1)][ic, y, x] * parameter['conv'+str(weight_num)+'_weight_int'][0, ic]


# calculate left shift bit
ratio =  ( parameter['conv' + str(weight_num) + '_input_scale'] * parameter['conv' + str(weight_num) + '_weight_scale'] / parameter['conv' + str(weight_num) + '_output_scale'] )
shift_bit = math.log(ratio, 2)
shift_bit = abs( math.ceil(shift_bit) )
M = ratio / 2**(-shift_bit)
M_fixed = round(M * 2**bit)
Unet['shift_bit'+str(out_num)] = shift_bit
Unet['M'+str(out_num)] = M
Unet['M_fixed'+str(out_num)] = M_fixed
print('ratio = {}, shift_bit = {}'.format(ratio, shift_bit))
if use_shift_instead_of_divide == 1 :
    Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
    Unet['q_out'+str(out_num)] = Unet['q_out'+str(out_num)] // (2**(bit+Unet['shift_bit'+str(out_num)]))
elif use_shift_instead_of_divide == 2 :
    one = np.ones(Unet['q_out'+str(out_num)].shape)
    tmp = Unet['q_out'+str(out_num)] * Unet['M_fixed'+str(out_num)]
    float_int_err = ( tmp / (2**(bit+Unet['shift_bit'+str(out_num)])) ) - ( tmp // (2**(bit+Unet['shift_bit'+str(out_num)])) )
    outTmp = tmp // (2**(bit+Unet['shift_bit'+str(out_num)]))
    tag = float_int_err > 0.5
    Unet['q_out'+str(out_num)] = outTmp.copy()
    Unet['q_out'+str(out_num)][tag] = outTmp[tag] + one[tag]
else: 
    Unet['q_out'+str(out_num)] = np.round( Unet['q_out'+str(out_num)] * ratio )   
Unet['q_out'+str(out_num)] += parameter['conv' + str(weight_num) + '_output_zero'] 
Unet['q_out'+str(out_num)] [ Unet['q_out'+str(out_num)] > 255.0 ] = 255.0
print("max = ", np.max(Unet['q_out'+str(out_num)]))
print("min = ", np.min(Unet['q_out'+str(out_num)]))

Unet['ratio'+str(out_num)] = ratio
Unet['q_out_floating'+str(out_num)] = parameter['conv' + str(weight_num) + '_output_scale'] * (Unet['q_out'+str(out_num)] - parameter['conv'+str(weight_num)+'_output_zero'] )
debug['out'+str(out_num)+'_quantFloating_quant'] = np.round( (floatingVar['out'+str(out_num)+'_quantFloating'] / parameter['conv' + str(weight_num) + '_output_scale'])  + parameter['conv'+str(weight_num)+'_output_zero'])
    




print(" ===================== check with Ans (each layer) ===================== ")

checkList = [1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 15, 17, 18, 19, 21, 22, 23, 25, 26, 27, 29, 30, 31]
for i in range(len(checkList)):
    print('---------check out{}------------'.format(checkList[i]))
    temp1 = Unet['q_out'+str(checkList[i])]
    temp2 = debug['out'+str(checkList[i])+'_quantFloating_quant']
    err = temp1 - temp2
    print("max err = ", np.max(err))
    print("min err = ", np.min(err))


print(" ===================== check with out31 (floating point) ===================== ")

out31_floating = parameter['conv' + str(weight_num) + '_output_scale'] * ( Unet['q_out'+str(out_num)] - parameter['conv'+str(weight_num)+'_output_zero'] )
out31_floating_ans = floatingVar['out'+str(out_num)+'_quantFloating']
err = out31_floating - out31_floating_ans
print("max err = ", np.max(err))
print("min err = ", np.min(err))




# =========================================== Sigmoid ===========================================


myOutput = out31_floating
one = np.ones([1, 224, 224])
mySigmoidOutput = one / (one + np.exp(-myOutput))

ans = floatingVar['output_np'][0]


print(" ===================== check with Sigmoid output (floating point) ===================== ")
err = mySigmoidOutput - ans
print("max err = ", np.max(err))
print("min err = ", np.min(err))




inputImage = (input_data[0] * 255).astype("uint8")
label = (floatingVar['label_np'][0, 0] * 255).astype("uint8")
imageAns = (ans[0] * 255).astype("uint8")
imageMy = (mySigmoidOutput[0] * 255).astype("uint8")


print(" ===================== check with Ans (uint8 of image) ===================== ")
err = imageAns.astype("int32") - imageMy.astype("int32")
print("max err = ", np.max(err))
print("min err = ", np.min(err))


def IOU_calculate(arr1_one_tag, arr2_one_tag):
    intersect = np.sum(arr1_one_tag * arr2_one_tag)
    union = np.sum(arr1_one_tag) + np.sum(arr2_one_tag) - intersect
    iou = round(intersect/union, 5)
    return iou


label_tag = label >= 250
floating_tag = imageAns >= 250
uint8_floating_tag = floatingVar['Image_output'] >= 250
uint8_tag = imageMy >= 250

print("-------------------- IOU --------------------")
print("IOU of floating = ", IOU_calculate(label_tag, floating_tag))
print("IOU of uint8 floating = ", IOU_calculate(label_tag, uint8_floating_tag))
print("IOU of uint8 = ", IOU_calculate(label_tag, uint8_tag))




# =========================================== visualization ===========================================

fig, axes = plt.subplots(ncols=4, figsize=(10, 3), sharex=True, sharey=True)
ax = axes.ravel()
ax[0].imshow(inputImage, cmap=plt.cm.gray)
ax[0].set_title('input data')
ax[1].imshow(label, cmap=plt.cm.gray)
ax[1].set_title('label')
ax[2].imshow(imageAns, cmap=plt.cm.gray)
ax[2].set_title('floating Unet(IOU=' + str( IOU_calculate(label_tag, uint8_floating_tag) )  + ')')
ax[3].imshow(imageMy, cmap=plt.cm.gray)
ax[3].set_title('8-bit Unet(IOU=' + str( IOU_calculate(label_tag, uint8_tag) )  + ')')


#fig.show()
fig.tight_layout()
#plt.subplots_adjust(wspace=0, hspace=0)
fig.savefig('8-bit Unet result.png')



```

















```python=
# -*- coding: utf-8 -*-
"""
Created on Mon Sep 18 21:58:04 2023

@author: leots
"""

import os
import numpy as np
import torch
from CONV import GEMMConv3D
from CONV import Maxpool_3D
from CONV import De_Conv2x2


#====================================Read Files=========================================#
current_path = os.getcwd()

all_file_name = os.listdir(current_path) # it prints out all file names in this directory
#print("all_file_name",all_file_name)

layer = ['conv'+str(i) for i in range(1, 24)]

parameter = {}
floatingVar = {}
quantizedOutAct = {}
Load_parameter = 1


if Load_parameter == 1:
    parameter = np.load('parameter.npy',allow_pickle='TRUE').item()
    floatingVar = np.load('floatingVar.npy',allow_pickle='TRUE').item()
    
else:
    for item in all_file_name:
        if item in layer:
            file_name = os.listdir(current_path+'/'+item)
            '''
            if item == 'conv1':
                print(item)
                print(file_name)
            '''
            for item_in in file_name:
                #if item == 'conv1':
                    #print(item_in[:-4]) # excludes .npy -> clever!!!
                parameter[item+'_'+item_in[:-4]] = np.load(current_path+'/'+item+'/'+item_in)
        
        elif item.endswith("npy"):
            #print('npy:', item)
            floatingVar[item[:-4]] = np.load(current_path+'/'+item)
            

#============================Load Quantized act. output=======================================#

for item in all_file_name:
    if item == 'quantized_act_out':
        file_name = os.listdir(current_path+'/'+item)
        for in_item in file_name:
            #print(in_item)
            quantizedOutAct[in_item[:-4]] = np.load(current_path+'/'+item+'/'+in_item)
# CONV1 first
#///////////////////////////////Computation starts!!!//////////////////////////////////////#

#convi_wight is 4D, except conv23_weigth, which is 1x1 conv
#==============================Converts input_np into quantized tensor==================================#
input_tensor = torch.tensor(floatingVar['input_np'])
#torch.quantize_per_tensor(input, scale, zero_point, dtype) → Tensor, using .int_rep() shows integer representation
input_scale = torch.tensor(parameter['conv1_input_scale'])
input_zero_point = torch.tensor(parameter['conv1_input_zero_point'])
quantized_input = torch.round(input_tensor/input_scale+ input_zero_point)
quantized_input = torch.tensor(quantized_input, dtype=torch.uint8)

quantized_input = quantized_input.numpy() #transforms tensor into np for GEMM
# before calling GEMM3D the operands need to be formated into 3D array
quantized_input = quantized_input.reshape(quantized_input.shape[1], quantized_input.shape[2], quantized_input.shape[3])
output = GEMMConv3D(quantized_input, parameter['conv1_weight_int']) #GEMM
output = torch.tensor(output, dtype=torch.float32) # the same

#print(np.max(quantized_conv1_output_np), np.min(quantized_conv1_output_np)) #max: 46355, min: 0

# verify dequantized output and the real output
# Note: dequantize() seems not to be working
output_scale = torch.tensor(parameter['conv1_output_scale'])
output_zero_point = torch.tensor(parameter['conv1_output_zero'])

weight_scale = parameter['conv1_weight_scale']
'''
output_torch = torch.quantize_per_tensor(output, output_scale, output_zero_point, torch.quint8).int_repr() # quantize the GEMM output
output_torch = output_torch.numpy()
'''

output_my = output*input_scale*weight_scale/output_scale+output_zero_point
#output_my_round = np.round(output_my)
#output_my_round = output_my_round.numpy()
output_my = np.round(output_my.numpy())
output_my[output_my < 0.0] = 0.0 #ReLU
#output_my_round[output_my_round < 0.0] = 0.0

# quantize the golden data to compare with my quantized output
golden_output = torch.tensor(floatingVar['out1'])
#golden_output = torch.quantize_per_tensor(golden_output, output_scale, output_zero_point, torch.quint8).int_repr()
golden_output = torch.round(golden_output/output_scale+output_zero_point)
golden_output = golden_output.numpy()


# error between floating and quantized output still exists -> 0.9799
'''
ans = golden_output
error = np.abs(quantizedOutAct['qout1'] - floatingVar['out1']) 

print('max of error = ', np.max(error))
if (np.max(error) < 1e-5):
    print("pass!!")
else:
    print("failed.....")
'''

ans = golden_output
error = np.abs(output_my - ans) 

print('max of error = ', np.max(error))
print('max error index = ', np.where(error == np.max(error)))
if (np.max(error) < 3):
    print("pass!!")
else:
    print("failed.....")

```