Files
circomlib-ml/models/separableConv2D.ipynb
Semar Augusto 418917338a Add separable convolution circuit implementation (#7)
* add circuits and tests for separable convolution. Circuits do not yet comply with repo`s quantization

* make depthwise circuit compliant with quantization method from repo

* make pointwise circuit compliant with quantization method from repo

* separable convolution test works

* clean up

* fix typos and skip failing test

* clean up duplicated code for depthwise conv

* clean up duplicated code for pointwise conv

* clean up duplicated code for separable conv notebook

* chore: update filename to capital case

---------

Co-authored-by: drCathieSo.eth <socathie@users.noreply.github.com>
2023-11-26 18:53:14 +08:00

500 lines
26 KiB
Plaintext

{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "aa5be75a-ee5f-45b0-891b-da2dd340dd00",
"metadata": {},
"outputs": [],
"source": [
"import torch\n",
"import torch.nn as nn\n",
"import torch.nn.functional as F\n",
"import numpy as np\n",
"import json"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "f85ed78d-97ef-4979-acac-8d95b34a84ae",
"metadata": {},
"outputs": [],
"source": [
"p = 21888242871839275222246405745257275088548364400416034343698204186575808495617\n",
"CIRCOM_PRIME = 21888242871839275222246405745257275088548364400416034343698204186575808495617\n",
"MAX_POSITIVE = CIRCOM_PRIME // 2\n",
"MAX_NEGATIVE = MAX_POSITIVE + 1 # The most positive number\n",
"CIRCOM_NEGATIVE_1 = 21888242871839275222246405745257275088548364400416034343698204186575808495617 - 1\n",
"EXPONENT = 15\n",
"\n",
"class SeparableConv2D(nn.Module):\n",
" '''Separable convolution'''\n",
" def __init__(self, in_channels, out_channels, stride=1):\n",
" super(SeparableConv2D, self).__init__()\n",
" self.dw_conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=stride, padding=1, groups=in_channels, bias=False)\n",
" self.pw_conv = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False)\n",
"\n",
" def forward(self, x):\n",
" x = self.dw_conv(x)\n",
" x = self.pw_conv(x)\n",
" return x\n",
"\n",
"def from_circom(x):\n",
" if type(x) != int:\n",
" x = int(x)\n",
" if x > MAX_POSITIVE: \n",
" return x - CIRCOM_PRIME\n",
" return x\n",
" \n",
"def to_circom(x):\n",
" if type(x) != int:\n",
" x = int(x)\n",
" if x < 0:\n",
" return x + CIRCOM_PRIME \n",
" return x"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "32e117a1-32aa-4b4b-91d0-4b4b78071b6b",
"metadata": {},
"outputs": [],
"source": [
"# def DepthwiseConv(nRows, nCols, nChannels, nFilters, kernelSize, strides, n, input, weights, bias):\n",
"# assert(nFilters % nChannels == 0)\n",
"# outRows = (nRows - kernelSize)//strides + 1\n",
"# outCols = (nCols - kernelSize)//strides + 1\n",
" \n",
"# out = np.zeros((outRows, outCols, nFilters))\n",
"# remainder = np.zeros((outRows, outCols, nFilters))\n",
" \n",
"# for row in range(outRows):\n",
"# for col in range(outCols):\n",
"# for channel in range(nChannels):\n",
"# for x in range(kernelSize):\n",
"# for y in range(kernelSize):\n",
"# out[row, col, channel] += input[row*strides+x, col*strides+y, channel] * weights[x, y, channel]\n",
" \n",
"# out[row][col][channel] += bias[channel]\n",
"# remainder[row][col][channel] = out[row][col][channel] % n\n",
"# out[row][col][channel] = out[row][col][channel] / n\n",
" \n",
"# return out, remainder\n",
" \n",
"# def PointwiseConv2d(nRows, nCols, nChannels, nFilters, strides, n, input, weights, bias):\n",
"# kernelSize = 1\n",
"# outRows = (nRows - kernelSize)//strides + 1\n",
"# outCols = (nCols - kernelSize)//strides + 1\n",
"# out = np.zeros((outRows, outCols, nFilters))\n",
"# for row in range(outRows):\n",
"# for col in range(outCols):\n",
"# for filter in range(nFilters):\n",
"# for k in range(nChannels):\n",
"# out[row, col, filter] += input[row*strides, col*strides, k] * weights[k, filter]\n",
" \n",
"# out[row][col][filter] += bias[filter]\n",
"# out[row][col][filter] = out[row][col][filter] / n\n",
" \n",
"# return out\n",
"\n",
"# def SeparableConvImpl(nRows, nCols, nChannels, nDepthFilters, nPointFilters, kernelSize, strides, n, input, depthWeights, pointWeights, depthBias, pointBias):\n",
"# outRows = (nRows - kernelSize)//strides + 1\n",
"# outCols = (nCols - kernelSize)//strides + 1\n",
"\n",
"# depthOut, rem = DepthwiseConv(nRows, nCols, nChannels, nDepthFilters, kernelSize, strides, n, input, depthWeights, depthBias)\n",
"# pointOut = PointwiseConv2d(outRows, outCols, nChannels, nPointFilters, strides, n, depthOut, pointWeights, pointBias)\n",
"# return pointOut"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "e3dfadfd-2587-4708-9dd5-535a999ed359",
"metadata": {},
"outputs": [],
"source": [
"# def DepthwiseConvInt(nRows, nCols, nChannels, nFilters, kernelSize, strides, n, input, weights, bias):\n",
"# assert(nFilters % nChannels == 0)\n",
"# outRows = (nRows - kernelSize)//strides + 1\n",
"# outCols = (nCols - kernelSize)//strides + 1\n",
" \n",
"# Input = [[[str(input[i][j][k] % p) for k in range(nChannels)] for j in range(nCols)] for i in range(nRows)]\n",
"# Weights = [[[str(weights[i][j][k] % p) for k in range(nChannels)] for j in range(kernelSize)] for i in range(kernelSize)]\n",
"# Bias = [str(bias[i] % p) for i in range(nFilters)]\n",
"# out = [[[0 for _ in range(nFilters)] for _ in range(outCols)] for _ in range(outRows)]\n",
"# str_out = [[[0 for _ in range(nFilters)] for _ in range(outCols)] for _ in range(outRows)]\n",
"# remainder = [[[None for _ in range(nFilters)] for _ in range(outCols)] for _ in range(outRows)]\n",
" \n",
"# for row in range(outRows):\n",
"# for col in range(outCols):\n",
"# for channel in range(nChannels):\n",
"# for x in range(kernelSize):\n",
"# for y in range(kernelSize):\n",
"# out[row][col][channel] += int(input[row*strides+x][col*strides+y][channel]) * int(weights[x][y][channel])\n",
" \n",
"# out[row][col][channel] += int(bias[channel])\n",
"# remainder[row][col][channel] = str(int(out[row][col][channel] % n))\n",
"# out[row][col][channel] = int((out[row][col][channel] // n))\n",
"# str_out[row][col][channel] = str(out[row][col][channel] % p)\n",
" \n",
"# return Input, Weights, Bias, out, str_out, remainder\n",
" \n",
"# def PointwiseConv2dInt(nRows, nCols, nChannels, nFilters, strides, n, input, weights, bias):\n",
"# kernelSize = 1\n",
"# outRows = (nRows - kernelSize)//strides + 1\n",
"# outCols = (nCols - kernelSize)//strides + 1\n",
" \n",
"# Input = [[[str(input[i][j][k] % p) for k in range(nChannels)] for j in range(nCols)] for i in range(nRows)]\n",
"# Weights = [[str(weights[k][l] % p) for l in range(nFilters)] for k in range(nChannels)]\n",
"# Bias = [str(bias[i] % p) for i in range(nFilters)]\n",
"# out = [[[0 for _ in range(nFilters)] for _ in range(outCols)] for _ in range(outRows)]\n",
"# str_out = [[[0 for _ in range(nFilters)] for _ in range(outCols)] for _ in range(outRows)]\n",
"# remainder = [[[None for _ in range(nFilters)] for _ in range(outCols)] for _ in range(outRows)]\n",
" \n",
"# for row in range(outRows):\n",
"# for col in range(outCols):\n",
"# for filter in range(nFilters):\n",
"# for channel in range(nChannels):\n",
"# out[row][col][filter] += int(input[row*strides][col*strides][channel]) * int(weights[channel][filter])\n",
" \n",
"# out[row][col][filter] += int(bias[filter])\n",
"# remainder[row][col][filter] = str(int(out[row][col][filter] % n))\n",
"# out[row][col][filter] = str(out[row][col][filter] // n % p)\n",
"# return Input, Weights, Bias, out, remainder\n",
"\n",
"# def SeparableConvInt(nRows, nCols, nChannels, nDepthFilters, nPointFilters, kernelSize, strides, n, input, depthWeights, pointWeights, depthBias, pointBias):\n",
"# outRows = (nRows - kernelSize)//strides + 1\n",
"# outCols = (nCols - kernelSize)//strides + 1\n",
"\n",
"# Input, DepthWeights, DepthBias, depthOut, depthStrOut, depthRemainder = DepthwiseConvInt(nRows, nCols, nChannels, nDepthFilters, kernelSize, strides, n, input, depthWeights, depthBias)\n",
"# test = [[[from_circom(int(depthStrOut[i][j][k])) for k in range(3)] for j in range(5)] for i in range(5)]\n",
"# assert(test == depthOut)\n",
"# pInput, PointWeights, PointBias, pointOut, pointRem = PointwiseConv2dInt(outRows, outCols, nChannels, nPointFilters, strides, n, depthOut, pointWeights, pointBias)\n",
" \n",
"# return Input, DepthWeights, DepthBias, depthOut, depthStrOut, depthRemainder, PointWeights, PointBias, pointOut, pointRem"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "cc1a4a27-a1dc-4565-90e3-12e6d7122157",
"metadata": {},
"outputs": [],
"source": [
"def DepthwiseConv(nRows, nCols, nChannels, nFilters, kernelSize, strides, n, input, weights, bias):\n",
" assert(nFilters % nChannels == 0)\n",
" outRows = (nRows - kernelSize)//strides + 1\n",
" outCols = (nCols - kernelSize)//strides + 1\n",
" \n",
" # out = np.zeros((outRows, outCols, nFilters))\n",
" out = [[[0 for _ in range(nFilters)] for _ in range(outCols)] for _ in range(outRows)]\n",
" remainder = [[[0 for _ in range(nFilters)] for _ in range(outCols)] for _ in range(outRows)]\n",
" # remainder = np.zeros((outRows, outCols, nFilters))\n",
" \n",
" for row in range(outRows):\n",
" for col in range(outCols):\n",
" for channel in range(nChannels):\n",
" for x in range(kernelSize):\n",
" for y in range(kernelSize):\n",
" out[row][col][channel] += int(input[row*strides+x, col*strides+y, channel]) * int(weights[x, y, channel])\n",
" \n",
" out[row][col][channel] += int(bias[channel])\n",
" remainder[row][col][channel] = str(int(out[row][col][channel] % n))\n",
" out[row][col][channel] = int(out[row][col][channel] // n)\n",
" \n",
" return out, remainder\n",
" \n",
"def PointwiseConv2d(nRows, nCols, nChannels, nFilters, strides, n, input, weights, bias):\n",
" kernelSize = 1\n",
" outRows = (nRows - kernelSize)//strides + 1\n",
" outCols = (nCols - kernelSize)//strides + 1\n",
" out = [[[0 for _ in range(nFilters)] for _ in range(outCols)] for _ in range(outRows)]\n",
" str_out = [[[0 for _ in range(nFilters)] for _ in range(outCols)] for _ in range(outRows)]\n",
" remainder = [[[None for _ in range(nFilters)] for _ in range(outCols)] for _ in range(outRows)]\n",
" for row in range(outRows):\n",
" for col in range(outCols):\n",
" for filter in range(nFilters):\n",
" for k in range(nChannels):\n",
" out[row][col][filter] += int(input[row*strides][col*strides][k]) * int(weights[k, filter])\n",
" \n",
" out[row][col][filter] += int(bias[filter])\n",
" remainder[row][col][filter] = str(int(out[row][col][filter] % n))\n",
" out[row][col][filter] = int(out[row][col][filter] // n)\n",
" str_out[row][col][filter] = str(out[row][col][filter] % p)\n",
" \n",
" return out, str_out, remainder\n",
" \n",
"def SeparableConvImpl(nRows, nCols, nChannels, nDepthFilters, nPointFilters, kernelSize, strides, n, input, depthWeights, pointWeights, depthBias, pointBias):\n",
" outRows = (nRows - kernelSize)//strides + 1\n",
" outCols = (nCols - kernelSize)//strides + 1\n",
"\n",
" depth_out, depth_remainder = DepthwiseConv(nRows, nCols, nChannels, nDepthFilters, kernelSize, strides, n, input, depthWeights, depthBias)\n",
" point_out, point_str_out, point_remainder = PointwiseConv2d(outRows, outCols, nChannels, nPointFilters, strides, n, depth_out, pointWeights, pointBias)\n",
" return depth_out, depth_remainder, point_out, point_str_out, point_remainder"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "cfa6df6a-9a0c-4150-9df0-30e2700d4f6b",
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'torch' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[2], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[43mtorch\u001b[49m\u001b[38;5;241m.\u001b[39mrandn((\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m3\u001b[39m, \u001b[38;5;241m5\u001b[39m, \u001b[38;5;241m5\u001b[39m))\n\u001b[1;32m 2\u001b[0m model \u001b[38;5;241m=\u001b[39m SeparableConv2D(\u001b[38;5;241m3\u001b[39m, \u001b[38;5;241m6\u001b[39m)\n",
"\u001b[0;31mNameError\u001b[0m: name 'torch' is not defined"
]
}
],
"source": [
"input = torch.randn((1, 3, 5, 5))\n",
"model = SeparableConv2D(3, 6)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "5db59f3a-e610-473a-8dfc-1d5e812748f4",
"metadata": {},
"outputs": [],
"source": [
"# weights = model.dw_conv.weight.squeeze().detach().numpy()\n",
"# bias = torch.zeros(weights.shape[0]).numpy()\n",
"\n",
"# expected = model.dw_conv(input).detach().numpy()\n",
"\n",
"# padded = F.pad(input, (1,1,1,1), \"constant\", 0) # Padding for convolution with \"same\" configuration\n",
"# padded = padded.squeeze().numpy().transpose((1, 2, 0))\n",
"# weights = weights.transpose((1, 2, 0))\n",
"\n",
"# actual, rem = DepthwiseConv(7, 7, 3, 3, 3, 1, 1, padded, weights, bias)\n",
"# expected = expected.squeeze().transpose((1, 2, 0))\n",
"\n",
"# assert(np.allclose(expected, actual, atol=0.00001))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "47ce42c7-b417-46ba-a31b-1ae23234a2cd",
"metadata": {},
"outputs": [],
"source": [
"# weights = model.pw_conv.weight.detach().numpy()\n",
"# print(f\"{weights.shape=}\")\n",
"# bias = torch.zeros(weights.shape[0]).numpy()\n",
"\n",
"# expected = model.pw_conv(input).detach().numpy()\n",
"\n",
"# padded = input.squeeze().numpy().transpose((1, 2, 0))\n",
"# print(padded.shape)\n",
"# weights = weights.transpose((2, 3, 1, 0)).squeeze()\n",
"\n",
"# actual = PointwiseConv2d(5, 5, 3, 6, 1, 1, padded, weights, bias)\n",
"\n",
"# expected = expected.squeeze().transpose((1, 2, 0))\n",
"\n",
"# assert(np.allclose(expected, actual, atol=0.00001))"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "7a36a0a1-6965-4184-93a5-5d121d6d1856",
"metadata": {},
"outputs": [],
"source": [
"# depthWeights = model.dw_conv.weight.squeeze().detach().numpy()\n",
"# depthBias = torch.zeros(depthWeights.shape[0]).numpy()\n",
"\n",
"# depthWeights = depthWeights.transpose((1, 2, 0))\n",
"\n",
"# pointWeights = model.pw_conv.weight.detach().numpy()\n",
"# print(f\"{depthWeights.shape=}\")\n",
"# pointBias = torch.zeros(pointWeights.shape[0]).numpy()\n",
"# pointWeights = pointWeights.transpose((2, 3, 1, 0)).squeeze()\n",
"\n",
"# expected = model(input).detach().numpy()\n",
"# print(f\"{expected.shape=}\")\n",
"\n",
"# padded = F.pad(input, (1,1,1,1), \"constant\", 0) # Padding for convolution with \"same\" configuration\n",
"# padded = padded.squeeze().numpy().transpose((1, 2, 0))\n",
"\n",
"# print(pointBias.shape)\n",
"# actual = SeparableConvImpl(7, 7, 3, 3, 6, 3, 1, 1, padded, depthWeights, pointWeights, depthBias, pointBias)\n",
"# expected = expected.squeeze().transpose((1, 2, 0))\n",
"\n",
"# assert(np.allclose(expected, actual, atol=0.00001))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "fd587b58-1646-4ec8-9a79-4f891dab0276",
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"depthWeights.shape=(3, 3, 3)\n",
"expected.shape=(1, 6, 5, 5)\n",
"(6,)\n"
]
},
{
"ename": "NameError",
"evalue": "name 'depthOut' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[10], line 23\u001b[0m\n\u001b[1;32m 20\u001b[0m quantized_depth_weights \u001b[38;5;241m=\u001b[39m depthWeights \u001b[38;5;241m*\u001b[39m \u001b[38;5;241m10\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mEXPONENT\n\u001b[1;32m 21\u001b[0m quantized_point_weights \u001b[38;5;241m=\u001b[39m pointWeights \u001b[38;5;241m*\u001b[39m \u001b[38;5;241m10\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mEXPONENT\n\u001b[0;32m---> 23\u001b[0m depth_out, depth_remainder, point_out, point_str_out, point_remainder \u001b[38;5;241m=\u001b[39m \u001b[43mSeparableConvImpl\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m7\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m7\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m6\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m10\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mEXPONENT\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mquantized_image\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mround\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mastype\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mint\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mquantized_depth_weights\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mround\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mastype\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mint\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mquantized_point_weights\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mround\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mastype\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mint\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdepthBias\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mastype\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mint\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpointBias\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mastype\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mint\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 25\u001b[0m actual_scaled \u001b[38;5;241m=\u001b[39m [[[point_out[i][j][k] \u001b[38;5;241m/\u001b[39m \u001b[38;5;241m10\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mEXPONENT \u001b[38;5;28;01mfor\u001b[39;00m k \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m6\u001b[39m)] \u001b[38;5;28;01mfor\u001b[39;00m j \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m5\u001b[39m)] \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m5\u001b[39m)]\n\u001b[1;32m 27\u001b[0m expected \u001b[38;5;241m=\u001b[39m expected\u001b[38;5;241m.\u001b[39msqueeze()\u001b[38;5;241m.\u001b[39mtranspose((\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m, \u001b[38;5;241m0\u001b[39m))\n",
"Cell \u001b[0;32mIn[5], line 60\u001b[0m, in \u001b[0;36mSeparableConvImpl\u001b[0;34m(nRows, nCols, nChannels, nDepthFilters, nPointFilters, kernelSize, strides, n, input, depthWeights, pointWeights, depthBias, pointBias)\u001b[0m\n\u001b[1;32m 57\u001b[0m outCols \u001b[38;5;241m=\u001b[39m (nCols \u001b[38;5;241m-\u001b[39m kernelSize)\u001b[38;5;241m/\u001b[39m\u001b[38;5;241m/\u001b[39mstrides \u001b[38;5;241m+\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[1;32m 59\u001b[0m depth_out, depth_remainder \u001b[38;5;241m=\u001b[39m DepthwiseConv(nRows, nCols, nChannels, nDepthFilters, kernelSize, strides, n, \u001b[38;5;28minput\u001b[39m, depthWeights, depthBias)\n\u001b[0;32m---> 60\u001b[0m point_out, point_str_out, point_remainder \u001b[38;5;241m=\u001b[39m PointwiseConv2d(outRows, outCols, nChannels, nPointFilters, strides, n, \u001b[43mdepthOut\u001b[49m, pointWeights, pointBias)\n\u001b[1;32m 61\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m depth_out, depth_remainder, point_out, point_str_out, point_remainder\n",
"\u001b[0;31mNameError\u001b[0m: name 'depthOut' is not defined"
]
}
],
"source": [
"depthWeights = model.dw_conv.weight.squeeze().detach().numpy()\n",
"depthBias = torch.zeros(depthWeights.shape[0]).numpy()\n",
"\n",
"depthWeights = depthWeights.transpose((1, 2, 0))\n",
"\n",
"pointWeights = model.pw_conv.weight.detach().numpy()\n",
"print(f\"{depthWeights.shape=}\")\n",
"pointBias = torch.zeros(pointWeights.shape[0]).numpy()\n",
"pointWeights = pointWeights.transpose((2, 3, 1, 0)).squeeze()\n",
"\n",
"expected = model(input).detach().numpy()\n",
"print(f\"{expected.shape=}\")\n",
"\n",
"padded = F.pad(input, (1,1,1,1), \"constant\", 0) # Padding for convolution with \"same\" configuration\n",
"padded = padded.squeeze().numpy().transpose((1, 2, 0))\n",
"\n",
"print(pointBias.shape)\n",
"# actual = SeparableConvImpl(7, 7, 3, 3, 6, 3, 1, 1, padded, depthWeights, pointWeights, depthBias, pointBias)\n",
"quantized_image = padded * 10**EXPONENT\n",
"quantized_depth_weights = depthWeights * 10**EXPONENT\n",
"quantized_point_weights = pointWeights * 10**EXPONENT\n",
"\n",
"depth_out, depth_remainder, point_out, point_str_out, point_remainder = SeparableConvImpl(7, 7, 3, 3, 6, 3, 1, 10**EXPONENT, quantized_image.round().astype(int), quantized_depth_weights.round().astype(int), quantized_point_weights.round().astype(int), depthBias.astype(int), pointBias.astype(int))\n",
"\n",
"actual_scaled = [[[point_out[i][j][k] / 10**EXPONENT for k in range(6)] for j in range(5)] for i in range(5)]\n",
"\n",
"expected = expected.squeeze().transpose((1, 2, 0))\n",
"\n",
"assert(np.allclose(expected, actual_scaled, atol=0.00001))\n",
"\n",
"\n",
"# Input, DepthWeights, DepthBias, depthOut, depthStrOut, DepthRem, PointWeights, PointBias, pointOut, pointRem = SeparableConvInt(7, 7, 3, 3, 6, 3, 1, 10**EXPONENT, quantized_image.round().astype(int), quantized_depth_weights.round().astype(int), quantized_point_weights.round().astype(int), depthBias.astype(int), pointBias.astype(int))\n",
"\n",
"circuit_in = quantized_image.round().astype(int).astype(str).tolist()\n",
"circuit_depth_weights = quantized_depth_weights.round().astype(int).astype(str).tolist()\n",
"circuit_point_weights = quantized_point_weights.round().astype(int).astype(str).tolist()\n",
"circuit_depth_bias = depthBias.round().astype(int).astype(str).tolist()\n",
"circuit_point_bias = pointBias.round().astype(int).astype(str).tolist()\n",
"\n",
"\n",
"input_json_path = \"separableConv2D_input.json\"\n",
"with open(input_json_path, \"w\") as input_file:\n",
" json.dump({\"in\": circuit_in,\n",
" \"depthWeights\": circuit_depth_weights,\n",
" \"depthBias\": circuit_depth_bias,\n",
" \"depthRemainder\": depth_remainder,\n",
" \"depthOut\": depth_out,\n",
" \n",
" \"pointWeights\": circuit_point_weights,\n",
" \"pointBias\": circuit_point_bias,\n",
" \"pointRemainder\": point_remainder,\n",
" \"pointOut\": point_str_out,\n",
" },\n",
" input_file)\n"
]
},
{
"cell_type": "code",
"execution_count": 44,
"id": "f0dcbca8-7f2f-47ea-b662-29a8560774b1",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 289246014266912, 458852178050435, -104551710192411,\n",
" -85286796832706, 70991076566637, -373719950995314])"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"test = np.array(actual)\n",
"test[0][0]"
]
},
{
"cell_type": "code",
"execution_count": 45,
"id": "3a652322-2fa0-4f51-bb2f-ed49bd94c65a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0.289246 , 0.45885214, -0.10455171, -0.0852868 , 0.07099106,\n",
" -0.37371993], dtype=float32)"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expected[0][0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "56d3dda8-af64-402e-9c86-b333ca6782ba",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}