Skip to content

Commit

Permalink
Python packaging & documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Aba committed Nov 15, 2023
1 parent 0f80a19 commit 36a206d
Show file tree
Hide file tree
Showing 13 changed files with 372 additions and 2 deletions.
33 changes: 31 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,34 @@ test/temp

test/py/*

docs/*
.svls.toml
.svls.toml


# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Sphinx documentation
docs/_build/
13 changes: 13 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: "2"

build:
os: "ubuntu-22.04"
tools:
python: "3.10"

python:
install:
- requirements: docs/requirements.txt

sphinx:
configuration: docs/source/conf.py
1 change: 1 addition & 0 deletions deepsocflow/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from deepsocflow.hardware import Hardware, example_function
138 changes: 138 additions & 0 deletions deepsocflow/hardware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# from deepsocflow import Hardware, Bundle, QInput, BundleModel, QConvCore, QDenseCore, QAdd, QPool, Softmax, QLeakyReLu
import numpy as np
from abc import ABC, abstractmethod
import json
from deepsocflow.utils import *


class Hardware:
"""_summary_
"""
def __init__(
self,
processing_elements: (int, int) = (8,24),
frequency_mhz: int = 250,
bits_input: int = 4,
bits_weights: int = 4,
bits_sum: int = 16,
bits_bias: int = 16,
max_batch_size: int = 512,
max_channels_in: int = 512,
max_channels_out: int = 512,
max_kernel_size: int = 13,
max_image_size: int = 32,
weights_cache_kbytes: int =384,
edge_cache_kbytes: int|None = None
):

self.params = locals()
self.params = {k:self.params[k] for k in self.params if not k == 'self'}

'''
Validation
'''
assert bits_input in [1,2,4,8] and bits_weights in [1,2,4,8]
assert bits_bias in [8,16,32]

self.ROWS, self.COLS = processing_elements
self.FREQ = frequency_mhz
self.X_BITS = bits_input
self.K_BITS = bits_weights
self.Y_BITS = bits_sum
self.B_BITS = bits_bias
self.XN_MAX = max_batch_size
self.CI_MAX = max_channels_in
self.CO_MAX = max_channels_out
self.KH_MAX, self.KW_MAX = max_kernel_size if (type(max_kernel_size) == tuple) else (max_kernel_size, max_kernel_size)
self.XH_MAX, self.XW_MAX = max_image_size if (type(max_image_size) == tuple) else (max_image_size, max_image_size)

'''
Width of weights RAM = K_BITS * COLS
Number of weights RAMs = 2
'''
self.RAM_WEIGHTS_DEPTH = int((weights_cache_kbytes*1024)/(self.K_BITS*self.COLS*2))

'''
Depth of RAM needed for edge padding = k != 1 ? ci*xw*(blocks-1) : 0
'''
self.RAM_EDGES_DEPTH = edge_cache_kbytes if edge_cache_kbytes is not None else int(self.CI_MAX * self.XW_MAX * np.ceil(self.XH_MAX/self.ROWS)-1)

self.L_MAX = int(np.ceil(self.XH_MAX//self.ROWS))
self.CONFIG_BEATS = 0
self.X_PAD = int(np.ceil(self.KH_MAX//2))
self.BITS_KW2 = clog2((self.KW_MAX+1)/2)
self.BITS_KH2 = clog2((self.KH_MAX+1)/2)
self.BITS_CIN_MAX = clog2(self.CI_MAX)
self.BITS_COLS_MAX = clog2(self.XW_MAX)
self.BITS_BLOCKS_MAX = clog2(self.L_MAX)
self.BITS_XN_MAX = clog2(self.XN_MAX)
self.BITS_RAM_WEIGHTS_ADDR = clog2(self.RAM_WEIGHTS_DEPTH)

self.IN_BITS = self.OUT_BITS = 64


def export_json(self, path='./hardware.json'):
with open(path, 'w') as f:
json.dump(self.params, f, indent=4)


@staticmethod
def from_json(path='./hardware.json'):
with open(path, 'r') as f:
hw = Hardware(**json.load(f))
return hw


def export(self):

with open('rtl/include/config_hw.svh', 'w') as f:
f.write(f'''
// Written from Hardware.export()
`define ROWS {self.ROWS :<10} // PE rows, constrained by resources
`define COLS {self.COLS :<10} // PE cols, constrained by resources
`define X_BITS {self.X_BITS :<10} // Bits per word in input
`define K_BITS {self.K_BITS :<10} // Bits per word in input
`define Y_BITS {self.Y_BITS :<10} // Bits per word in output of conv
`define KH_MAX {self.KH_MAX :<10} // max of kernel height, across layers
`define KW_MAX {self.KW_MAX :<10} // max of kernel width, across layers
`define XH_MAX {self.XH_MAX :<10} // max of input image height, across layers
`define XW_MAX {self.XW_MAX :<10} // max of input image width, across layers
`define XN_MAX {self.XN_MAX :<10} // max of input batch size, across layers
`define CI_MAX {self.CI_MAX :<10} // max of input channels, across layers
`define CONFIG_BEATS {self.CONFIG_BEATS :<10} // constant, for now
`define RAM_WEIGHTS_DEPTH {self.RAM_WEIGHTS_DEPTH :<10} // CONFIG_BEATS + max(KW * CI), across layers
`define RAM_EDGES_DEPTH {self.RAM_EDGES_DEPTH :<10} // max (KW * CI * XW), across layers when KW != 1
`define DELAY_ACC 1 // constant, for now
`define DELAY_MUL 2 // constant, for now
`define DELAY_W_RAM 2 // constant, for now
`define S_WEIGHTS_WIDTH_LF {self.IN_BITS :<10} // constant (64), for now
`define S_PIXELS_WIDTH_LF {self.IN_BITS :<10} // constant (64), for now
`define M_OUTPUT_WIDTH_LF {self.OUT_BITS :<10} // constant (64), for now
''')


with open('fpga/scripts/config_hw.tcl', 'w') as f:
f.write(f'''
# Written from Hardware.export()
set RAM_WEIGHTS_DEPTH {self.RAM_WEIGHTS_DEPTH}
set ROWS {self.ROWS}
set COLS {self.COLS}
set X_BITS {self.X_BITS}
set K_BITS {self.K_BITS}
set Y_BITS {self.Y_BITS}
set DELAY_W_RAM 2
set RAM_EDGES_DEPTH {self.RAM_EDGES_DEPTH}
set KH_MAX {self.KH_MAX}
set S_WEIGHTS_WIDTH_LF {self.IN_BITS}
set S_PIXELS_WIDTH_LF {self.IN_BITS}
set M_OUTPUT_WIDTH_LF {self.OUT_BITS}
''')


def example_function():
print("Hello World!")
4 changes: 4 additions & 0 deletions deepsocflow/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import numpy as np

def clog2(x):
return int(np.ceil(np.log2(x)))
20 changes: 20 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
35 changes: 35 additions & 0 deletions docs/make.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@ECHO OFF

pushd %~dp0

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)

if "%1" == "" goto help

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%

:end
popd
5 changes: 5 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
sphinx==5.0.2
sphinx-rtd-theme==1.3.0
numpy==1.23.5
qkeras==0.9.0
tensorflow==2.12.0
59 changes: 59 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('../../'))


# -- Project information -----------------------------------------------------

project = 'deepsocflow'
copyright = '2023, Abarajithan G, Zhenghua Ma'
author = 'Abarajithan G, Zhenghua Ma'

# The full version, including alpha/beta/rc tags
release = '0.0.1'


# -- General configuration ---------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx_rtd_theme',
'sphinx.ext.autodoc',
'sphinx.ext.viewcode',
'sphinx.ext.napoleon',
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []


# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
21 changes: 21 additions & 0 deletions docs/source/deepsocflow.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
deepsocflow package
===================

Submodules
----------

deepsocflow.hardware module
---------------------------

.. automodule:: deepsocflow.hardware
:members:
:undoc-members:
:show-inheritance:

Module contents
---------------

.. automodule:: deepsocflow
:members:
:undoc-members:
:show-inheritance:
20 changes: 20 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.. deepsocflow documentation master file, created by
sphinx-quickstart on Wed Nov 15 10:48:07 2023.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to deepsocflow's documentation!
=======================================

.. toctree::
:maxdepth: 2
:caption: Contents:

modules

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
7 changes: 7 additions & 0 deletions docs/source/modules.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
deepsocflow
===========

.. toctree::
:maxdepth: 4

deepsocflow
18 changes: 18 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"

[project]
name = "deepsocflow"
authors = [{name = "Abarajithan G", email = "[email protected]"}]
version = "0.0.1"
description = "Your DNNs to FPGA/ASIC SoCs in minutes!"
requires-python = ">=3.10"
license = {file = "LICENSE"}
readme = "README.md"
repository = "https://github.com/abarajithan11/deepsocflow"
classifiers=[
"Development Status :: 3 - Alpha",
"Programming Language :: Python :: 3.10",
"Operating System :: OS Independent",
]

0 comments on commit 36a206d

Please sign in to comment.